Commit 50ace6ea authored by Markus Koschany's avatar Markus Koschany

Merge tag 'upstream/1.7.13+ds'

Upstream version 1.7.13+ds

# gpg: Signature made Mon 28 Oct 2013 11:47:28 CET using RSA key ID 513B51E4
# gpg: Good signature from "Markus Koschany <apo@gambaru.de>" [ultimate]
# gpg:                 aka "Markus Koschany <markus@koschany.net>" [ultimate]
parents 81e0a047 2105b315
Distribution file list and directory structure
Copyright 2002-2012 by Christopher Heng. All rights reserved.
Distribution file list and directory structure for Tofrodos
http://www.thefreecountry.com/tofrodos/index.shtml
Copyright 2002-2013 by Christopher Heng. All rights reserved.
-------------------------------------------------------------
# Main directory
......
Tofrodos Ver 1.7.12
Copyright 1996-2012 Christopher Heng. All rights reserved.
Tofrodos Ver 1.7.13
Copyright 1996-2013 Christopher Heng. All rights reserved.
----------------------------------------------------------
......@@ -23,9 +23,9 @@ as their new line delimiters while Unix text files traditionally have
LFs (line feeds) to terminate each line.
Tofrodos comprises two programs, "fromdos" and "todos", which convert
text files to and from these formats. Use "fromdos" to convert DOS
text files to the Unix format, and "todos" to convert Unix text files
to the DOS format.
ASCII and Unicode UTF-8 text files to and from these formats. Use "fromdos"
to convert DOS text files to the Unix format, and "todos" to convert Unix
text files to the DOS format.
2. How To Install Tofrodos
......@@ -255,6 +255,21 @@ with people using it on HP-UX and others.
Dates given are the dates where the code base was finalised and do not
necessarily refer to the date of public release.
Version 1.7.13 25 October 2013
- [Hurd, NetBSD, FreeBSD kernel] Added support for Hurd,
NetBSD and FreeBSD kernel (a system that uses the FreeBSD
kernel, but is not necessarily the full FreeBSD system).
As a side benefit, tofrodos is slightly more portable since
it no longer depends on certain system-specific macros
(namely MAXPATHLEN from sys/param.h).
- [All] Tofrodos now displays information on what to do if
it is not able to rename the temporary file back to the
original filename after a successful conversion.
- [All] The -a option is now documented as "deprecated",
since you shouldn't use it unless you have an unusual
text file that you're trying to fix.
- [All] Minor improvements to the documentation.
Version 1.7.12 1 October 2012
- [All] Under certain error conditions, Tofrodos may fail to
remove the temporary files that it creates. This is now fixed.
......
/*
config.h Handles system dependencies.
Copyright (c) 1996-2012 by Christopher Heng. All rights reserved.
Copyright (c) 1996-2013 by Christopher Heng. All rights reserved.
*/
/*
......@@ -96,7 +96,9 @@ extern "C" {
#endif
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) /* seems to work like Linux... */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__GNU__)
/* these systems seem to work like Linux. Note to self: __GNU__ == Hurd */
#if !defined(LINUX)
#define LINUX
#endif
......@@ -122,7 +124,6 @@ extern "C" {
#define UNIX
#endif
#define HAVE_UNISTD_H
#define MAXPATHLEN_HEADER <sys/param.h>
#endif
/* define what headers we have (based on the systems) */
......@@ -166,30 +167,6 @@ extern "C" {
#define S_IWUSR S_IWRITE
#endif
/* This block is for Unix-type systems only. It is not relevant to */
/* MSDOS and Windows systems. */
/* Basically we need to have MAXPATHLEN defined somewhere. This is */
/* the maximum size that a pathname can be, and it is used to allocate */
/* storage for a pathname we construct in the program. In BSD systems */
/* and Linux systems, MAXPATHLEN is defined in <sys/param.h>. If your */
/* system has MAXPATHLEN defined somewhere, put the header name in */
/* MAXPATHLEN_HEADER (eg, you can try checking your <limits.h> */
/* and <sys/param.h> to see if MAXPATHLEN is there). If not, you will just */
/* have to create some sort of value for MAXPATHLEN by defining it below. */
/* Note: I realize that there are ways around */
/* this need for a constant value, but I can't be bothered to implement it. */
/* You might also want to try using pathconf() in a test program to find out */
/* if your system returns any sensible value for _PC_PATH_MAX. If all else */
/* fails, you might want to consider the Linux value of 4096 for MAXPATHLEN. */
/* That is, add a line like */
/* #define MAXPATHLEN 4096 */
/* below. */
#if defined(LINUX)
#define MAXPATHLEN_HEADER <sys/param.h>
#endif
/* End of block that is relevant for Unix-type systems only */
#if defined(__cplusplus)
}
#endif
......
/*
emsg.h Error messages.
Copyright (c) 1996-2012 by Christopher Heng. All rights reserved.
Copyright 1996-2013 by Christopher Heng. All rights reserved.
*/
#if !defined(EMSG_H_INCLUDED)
......@@ -30,6 +30,11 @@ extern "C" {
#define EMSG_SYMLINK "Unable to dereference symbolic link \"%s\".\n"
#define EMSG_CREATETEMP "Unable to create temporary file \"%s\" for converting \"%s\".\n"
#define EMSG_ERRORLOG "%s: Unable to create error log file \"%s\". Defaulting to stderr.\n" /* special case with progname */
#define EMSG_RENAMEBAK "Unable to save original file %s as %s.\n"\
"Reason: %s\n"
#define EMSG_RENAMETMP "Unable to rename temporary file %s back to %s after converting it.\n"\
"Reason: %s\n"\
"Please recover your converted file by manually renaming it back.\n"
/* internal error macros */
#define EINTNL_DIRECTION "unknown direction"
......
.TH tofrodos 1 "Version 1.7.12" "2012"
.TH tofrodos 1 "Version 1.7.13" "2013"
.SH NAME
tofrodos
\- Converts text files between DOS and Unix formats.
......@@ -18,9 +18,9 @@ DOS text files traditionally have carriage return and line feed pairs
as their newline characters while Unix text files have the line feed
as their newline character.
.I fromdos
converts text files from the DOS format to the Unix format, while
converts ASCII and Unicode UTF-8 text files from the DOS format to the Unix format, while
.I todos
converts text files from the Unix format to the DOS format.
converts them from the Unix format to the DOS format.
.PP
The programs accept multiple filenames and wildcards as their arguments.
You may also use them in a pipe.
......@@ -29,13 +29,14 @@ and place the output on stdout.
.SH OPTIONS
.TP
.BI \-a
Always convert. If converting from DOS to Unix, this option will
cause the program to remove ALL carriage returns. The default is to
remove carriage returns only if they are followed by line feeds.
If converting from
Unix to DOS, this option will cause the program to convert ALL
linefeeds to carriage return pairs. The default is to convert linefeeds
only if they are not already preceded by a carriage return.
This option is deprecated. Do not use it unless you know what you're doing. By default,
Tofrodos does the expected thing for text files. That is, when converting from
DOS to Unix, it will remove carriage returns only if they are followed by line feeds.
When converting from Unix to DOS, it will add carriage returns only if the linefeeds
are not already preceeded by carriage returns. When Tofrodos is run on a normal text file that
has already been converted, the resulting file should be identical to the original. However,
if you use this option, the program will always remove carriage returns in the DOS to Unix mode
and always add carriage returns in the Unix to DOS mode even if it is not appropriate.
.TP
.BI \-b
Make a backup of original file. The original file with a
......@@ -76,11 +77,7 @@ any errors. This option causes it to abort on errors.
.TP
.BI \-f
Force: convert even if the file is not writeable (read-only). By default,
if
.I fromdos
or
.I todos
finds that the file does not have write permission, it will not process
if the program finds that the file does not have write permission, it will not process
that file. This option forces the conversion even if the file is read-only.
.TP
.BI \-h
......@@ -100,7 +97,7 @@ preserves the file time. Note that on many Unix-type systems, including Linux, t
ownership will only be preserved if the program is run as root, otherwise it
will just set the file time and silently fail the change of file
ownership. On such systems, if you want a warning message when the file ownership
cannot be changed, use \-v.
cannot be changed, use \-v (the verbose flag) as well.
.TP
.BI \-u
Convert from Unix to DOS. See the
......@@ -120,7 +117,7 @@ file in the list if an error is encountered with any file. In such a case, the e
status of the last file processed (ie, 0 on success, 1 on failure). If this is not desirable, use the \-e option,
which will force the program to abort immediately with the appropriate exit code on encountering any error.
.SH AUTHOR
The program and its documentation are copyrighted (c) 1996-2012 by
The program and its documentation are copyrighted (c) 1996-2013 by
Christopher Heng. All rights reserved. They are distributed under
the terms of the GNU General Public License Version 2.
.PP
......
/*
init.c Initialisation functions.
Copyright 1996-2012 Christopher Heng. All rights reserved.
Copyright 1996-2013 Christopher Heng. All rights reserved.
*/
/* this should always be first */
......@@ -13,7 +13,7 @@
#include <signal.h> /* signal() (surprise!) */
#include <stdlib.h> /* _splitpath(), _MAX_FNAME, exit, EXIT_SUCCESS */
#include <stdio.h> /* EOF */
#include <stdio.h> /* fprintf() */
#include <string.h> /* stricmp() */
#if defined(HAVE_UNISTD_H)
......@@ -28,8 +28,7 @@
/* macros */
#define HELPFMT "Usage: %s [options] [file...]\n"\
"-a\tAlways convert (DOS to Unix: kill all CRs;\n"\
"\tUnix to DOS: convert all LFs to CRLFs)\n"\
"-a\t(Deprecated option, see manual for info.)\n"\
"-b\tMake backup of original file (.bak).\n"\
"-d\tConvert DOS to Unix.\n"\
"-e\tAbort processing files on error in any file.\n"\
......@@ -44,8 +43,9 @@
#define OPTLIST "abdefhl:opuvV"
#define VERFMT "%s Ver %d.%d.%d "\
"Converts text files between DOS and Unix formats.\n"\
"Copyright 1996-2012 Christopher Heng. "\
"All rights reserved.\n"
"Copyright 1996-2013 Christopher Heng. "\
"All rights reserved.\n"\
"http://www.thefreecountry.com/tofrodos/index.shtml\n"
#if defined(MSDOS) || defined(WIN32)
#if !defined(_MAX_NAME) || (_MAX_NAME < 260)
......@@ -111,6 +111,7 @@ int init ( char * firstarg )
/* depends on the system. If we are on a DOS system, it is to */
/* convert from Unix to DOS. If we are on a Unix system, it */
/* is to convert from DOS to Unix. */
/* The default direction is set in tofrodos.c using a macro defined in tofrodos.h */
if (!stricmp( progname, FROMDOSNAME ) ||
!stricmp( progname, FROMDOSNAME2 ))
direction = DOSTOUNIX ;
......@@ -141,7 +142,7 @@ int parseargs ( int argc, char ** argv )
{
int c ;
while ((c = getopt( argc, argv, OPTLIST )) != EOF) {
while ((c = getopt( argc, argv, OPTLIST )) != -1) {
switch( c ) {
case 'a': /* force conversion of all \r\n to \n */
alwaysconvert = 1 ;
......
/*
getopt.c
Copyright (c) 1997-2005 by Christopher Heng. All rights reserved.
$Id: getopt.c,v 1.2 2005/03/06 05:40:49 chris Exp $
Copyright 1997-2013 by Christopher Heng. All rights reserved.
This code is released under the terms of the GNU General Public
License Version 2. You should have received a copy of the GNU
......@@ -25,6 +23,7 @@
5. Added Microsoft Windows GUI support. To enable this, just
define GUI_APPLICATION to have the message displayed in a message
box.
6. It returns -1 instead of EOF.
This function is primarily designed for MSDOS and Windows, since those
systems lack getopt(). Linux, BSD, and other Unix-type systems already
......@@ -37,7 +36,7 @@
preceding the function itself.
*/
#include <stdio.h> /* EOF and fprintf() */
#include <stdio.h> /* fprintf() */
#include <string.h> /* strchr() */
#include "getopt.h" /* our very own header */
......@@ -122,11 +121,11 @@ static void error_message ( char * s );
list of options (unless one of those characters are themselves
specified in the option list, optlist). The character ':'
can never be an option. A solitary '-' or '/' will also cause
getopt() to return EOF.
getopt() to return -1.
Returns:
EOF No more options to parse.
-1 No more options to parse.
OPT_BADOPT An option character was encountered which
was not in the list of valid options.
OPT_BADARG An option was supposed to have an argument
......@@ -136,8 +135,7 @@ static void error_message ( char * s );
Differences from the Unix version:
1. '?' can be a valid option, since we do not return '?' when
there is an error. Unix getopt()s returns '?' when there is
an error. We return OPT_BADOPT (which is equated to 0). (Hope
EOF is not 0).
an error. We return OPT_BADOPT (which is equated to 0).
2. the options are preceded by either '-' or '/' and the end
of option list demarcator can be "--", "-/", "//" or "/-".
Because our options begin with '/', filenames cannot begin
......@@ -155,7 +153,7 @@ static void error_message ( char * s );
argument to an option. The version supplied with BSD 4.4
returns ':' for the latter error. We follow the protocol of
the BSD 4.4 version in this respect.
7. A solitary '-' or '/' will cause EOF to be returned.
7. A solitary '-' or '/' will cause -1 to be returned.
According to the getopt manual page in BSD, this appears
to be the behaviour in System V. This is the behaviour in
Borland C/C++'s example getopt.c also.
......@@ -178,7 +176,7 @@ int getopt ( int argc, char * const * argv, const char * optlist )
if(optind >= argc ||
(*(curptr = argv[optind]) != OPT_SW1 && *curptr != OPT_SW2)) {
curptr = nullstring ; /* reset */
return EOF;
return -1;
}
/* got to set curptr since we could have got here by */
/* optind < argc prior to curptr being set */
......@@ -188,7 +186,7 @@ int getopt ( int argc, char * const * argv, const char * optlist )
(*curptr == OPT_SW1 || *curptr == OPT_SW2)) { /* "--" */
optind++; /* point to next argument */
curptr = nullstring ; /* reset */
return EOF;
return -1;
}
}
/* by the time we get here, we have skipped over the option */
......
/*
tofrodos.c Converts text files between DOS and Unix formats.
Copyright 1996-2012 Christopher Heng. All rights reserved.
Copyright 1996-2013 Christopher Heng. All rights reserved.
*/
/* this should always be first */
#include "config.h"
/* standard headers */
#include <errno.h> /* errno */
#include <signal.h> /* signal() */
#include <stdio.h> /* FILE functions */
#include <stdlib.h> /* EXIT_SUCCESS, mkstemp() in some systems, ltoa() */
#include <string.h> /* strrchr(), strlen(), strcpy(), strcat() */
#include <string.h> /* strrchr(), strlen(), strcpy(), strcat(), strerror() */
#include <sys/stat.h> /* stat() */
#if defined(UNIX)
#if defined(MAXPATHLEN_HEADER)
#include MAXPATHLEN_HEADER
#endif
#endif
#if defined(_MSC_VER) || defined(__WATCOMC__)
#include <sys/utime.h>
#else /* everybody else keeps this in the include directory */
......@@ -308,7 +303,7 @@ static int convert ( FILE * infp, FILE * outfp )
/* actually it is very simple to do the conversion in DOS/WIN32 */
/* because the stdio library does this work automatically for */
/* us. But because we want this program to work on Linux as */
/* us. But since we want this program to work on Linux as */
/* well, a little bit of work stands before us (but only a little). */
prevch = EOF ;
......@@ -351,7 +346,7 @@ static int convert ( FILE * infp, FILE * outfp )
if (putc( c, outfp ) == EOF)
break ;
}
else { /* prevch was a standalone '\r' */
else { /* prevch was a standalone '\r' but the current char is not '\n' */
/* emit the standalone '\r' */
if (putc( '\r', outfp ) == EOF)
break ;
......@@ -418,8 +413,9 @@ static int convert ( FILE * infp, FILE * outfp )
static int openandconvert_preamble ( char * filename )
{
struct stat statbuf ;
char realfilepath[MAXPATHLEN+1] ;
char * realfilepath ;
int len ;
int err ;
/* get the file information */
if (lstat( filename, &statbuf )) {
......@@ -436,17 +432,31 @@ static int openandconvert_preamble ( char * filename )
/* eg, #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) */
/* or something like that. */
if ((len = readlink( filename, realfilepath, (sizeof(realfilepath) - 1) )) != -1) {
/* for symbolic links, st_size contains the length of the pathname sans terminating null byte */
if (statbuf.st_size == 0) {
/* There's a report somewhere of a discovery that Mac OS X returns st_size == 0 for "/dev/stdin" when it
is a symlink to "fd/0". I'm not sure if it is a valid report, but let's play it safe. */
emsg ( EMSG_SYMLINK, filename );
return -1 ;
}
realfilepath = xmalloc( statbuf.st_size + 1 );
if ((len = readlink( filename, realfilepath, statbuf.st_size )) != -1) {
/* got to null terminate the string - there is always space because */
/* we passed readlink() the size of the buffer less 1. */
realfilepath[len] = '\0' ;
if (verbose) {
emsg( VERBOSE_SYMLINKSRC, filename, realfilepath );
}
return openandconvert( realfilepath );
err = openandconvert( realfilepath );
}
emsg( EMSG_SYMLINK, filename );
return -1 ;
else {
emsg( EMSG_SYMLINK, filename );
err = -1 ;
}
free ( realfilepath );
return err ;
}
/* If we reach here, "filename" is not a symbolic link */
return openandconvert( filename );
......@@ -644,28 +654,34 @@ err_freetempfn:
goto err_freebakfn ;
}
/* if we need to back up, delete any backup files of the */
/* same name first (in case we are running on DOS where */
/* a rename does not delete the file automatically) */
if (!overwrite) {
/* remove existing backup files of same name */
remove( bakfilename );
/* rename the original file to the back up name */
rename( filename, bakfilename );
}
else { /* if we do not need to back up delete the original file */
#if defined(MSDOS) || defined(WIN32)
/* for MSDOS and Windows, we need to make sure the file is writeable */
/* otherwise we cannot delete it. Under Unix, this is not */
/* necessary, since a file can be deleted if we */
/* have write permissions for the directory */
chmod( filename, S_IRUSR|S_IWUSR );
/* delete any backup file of the same name first, since a rename() does not delete it automatically */
/* on DOS and Windows */
chmod( bakfilename, S_IRUSR|S_IWUSR ); /* make it writeable (in case it's not) so that it can be deleted */
remove( bakfilename ); /* don't check for error returns since the file may not even exist in the first place */
#endif
remove( filename );
/* rename the original file to the back up name */
if (rename( filename, bakfilename )) {
emsg( EMSG_RENAMEBAK, filename, bakfilename, strerror( errno ) );
}
}
#if defined(MSDOS) || defined(WIN32) /* we need to delete the original file because a rename() operation will not */
/* automatically delete it for us on DOS and Windows the way it does on POSIX systems */
else { /* if we do not need to back up the original file */
chmod( filename, S_IRUSR|S_IWUSR ); /* make it writeable (in case it's not) so that it can be deleted. */
remove( filename ); /* delete the original file */
/* we don't check for error returns for this, since any error message about its failure will just */
/* confuse the user. "What? Why is it deleting my file?" If this fails, the next rename() will fail too */
/* since rename() on Windows will not delete the target automatically, and the error message will from the */
/* failed rename() will tell the user what happened. */
}
#endif
/* rename the temp file to the original file name */
rename( tempfilename, filename );
if (rename( tempfilename, filename )) {
emsg( EMSG_RENAMETMP, tempfilename, filename, strerror( errno ) );
}
/* remove the temp file name from the global for our */
/* signal handler*/
......
/*
version.h Version number header.
Copyright 1996-2012 Christopher Heng. All rights reserved.
Copyright 1996-2013 Christopher Heng. All rights reserved.
*/
#if !defined(VERSION_H_INCLUDED)
......@@ -9,7 +9,7 @@
/* macros */
#define VERSN_MAJOR 1
#define VERSN_MINOR 7
#define VERSN_PATCH 12
#define VERSN_PATCH 13
#define VERSN_PROGNAME "tofrodos"
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- Copyright 1996-2012 Christopher Heng. All rights reserved. -->
<!-- Copyright 1996-2013 Christopher Heng. All rights reserved. -->
<title>tofrodos - Converts text files between MSDOS and Unix file formats</title>
<style type="text/css">
h1, h2, p { font-family: Arial, Helvetica, sans-serif ; }
......@@ -44,9 +44,9 @@ p.copyright {
DOS text files traditionally have carriage return and line feed pairs
as their newline characters while Unix text files have the line feed
as their newline character. <span class="programname">fromdos</span>
converts text files from the DOS format to the Unix format, while
converts ASCII and Unicode UTF-8 text files from the DOS format to the Unix format, while
<span class="programname">todos</span>
converts text files from the Unix format to the DOS format.
converts them from the Unix format to the DOS format.
</p>
<p>
......@@ -61,13 +61,14 @@ and place the output on stdout.
<dl title="List of options available for Tofrodos">
<dt>-a</dt>
<dd>
Always convert. If converting from DOS to Unix, this option will
cause the program to remove ALL carriage returns. The default is to
remove carriage returns only if they are followed by line feeds.
If converting from
Unix to DOS, this option will cause the program to convert ALL
linefeeds to carriage return pairs. The default is to convert linefeeds
only if they are not already preceded by a carriage return.
This option is deprecated. Do not use it unless you know what you're doing. By default,
Tofrodos does the expected thing for text files. That is, when converting from
DOS to Unix, it will remove carriage returns only if they are followed by line feeds.
When converting from Unix to DOS, it will add carriage returns only if the linefeeds
are not already preceeded by carriage returns. When Tofrodos is run on a normal text file that
has already been converted, the resulting file should be identical to the original. However,
if you use this option, the program will always remove carriage returns in the DOS to Unix mode
and always add carriage returns in the Unix to DOS mode even if it is not appropriate.
</dd>
<dt>-b</dt>
<dd>
......@@ -105,8 +106,7 @@ any errors. This option causes it to abort on errors.
<dt>-f</dt>
<dd>
Force: convert even if the file is not writeable (read-only). By default,
if <span class="programname">fromdos</span> or <span class="programname">todos</span>
finds that the file does not have write permission, it will not process
if the program finds that the file does not have write permission, it will not process
that file. This option forces the conversion even if the file is read-only.
</dd>
<dt>-h</dt>
......@@ -130,7 +130,7 @@ preserves the file time. Note that on many Unix-type systems, including Linux, t
ownership will only be preserved if the program is run as root, otherwise it
will just set the file time and silently fail the change of file
ownership. On such systems, if you want a warning message when the file ownership
cannot be changed, use <span class="optionchar">-v</span>.
cannot be changed, use <span class="optionchar">-v</span> (the verbose flag) as well.
</dd>
<dt>-u</dt>
<dd>
......@@ -162,7 +162,7 @@ code on encountering any error.
<h2>Author</h2>
<p>
The program and its documentation are copyrighted &copy; 1996-2012 by
The program and its documentation are copyrighted &copy; 1996-2013 by
Christopher Heng. All rights reserved. They are distributed under
the terms of the GNU General Public License Version 2.
</p>
......@@ -175,7 +175,7 @@ The latest version of Tofrodos can be obtained from
<hr />
<p class="copyright">
Copyright &copy; 1996-2012 Christopher Heng. All rights reserved.
Copyright &copy; 1996-2013 Christopher Heng. All rights reserved.
</p>
</body>
......
Begin4
Title: tofrodos
Version: 1.7.11
Entered-date: 2012-09-27
Version: 1.7.13
Entered-date: 2013-10-25
Description: DOS text files traditionally have CR/LF (carriage return
and line feed) pairs as their new line delimiters while
Unix text files traditionally have LFs (line feeds) to
terminate each line.
tofrodos comprises two programs, "fromdos" and "todos",
which convert text files to and from these formats.
Comes with source code and prebuilt binaries for Linux,
Win32 and DOS.
which convert ASCII and Unicode UTF-8 text files to and from
these formats.
Keywords: todos, fromdos, unix2dos, dos2unix, text file, line feed,
linefeed, newline, carriage return, CR, LF, conversion,
convert, tofrodos, dostounix, unixtodos, dtou, utod, msdos,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment