diff options
Diffstat (limited to 'unix2dos.c')
-rw-r--r-- | unix2dos.c | 1204 |
1 files changed, 1204 insertions, 0 deletions
diff --git a/unix2dos.c b/unix2dos.c new file mode 100644 index 0000000..7088d02 --- /dev/null +++ b/unix2dos.c @@ -0,0 +1,1204 @@ +/* + * Name: unix2dos + * Documentation: + * Convert lf ('\x0a') characters in a file to cr lf ('\x0d' '\x0a') + * combinations. + * + * The dos2unix package is distributed under FreeBSD style license. + * See also http://www.freebsd.org/copyright/freebsd-license.html + * -------- + * + * Copyright (C) 2009-2012 Erwin Waterlander + * Copyright (C) 1994-1995 Benjamin Lin. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice in the documentation and/or other materials provided with + * the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * == 1.0 == 1989.10.04 == John Birchfield (jb@koko.csustan.edu) + * == 1.1 == 1994.12.20 == Benjamin Lin (blin@socs.uts.edu.au) + * Cleaned up for Borland C/C++ 4.02 + * == 1.2 == 1995.03.09 == Benjamin Lin (blin@socs.uts.edu.au) + * Fixed minor typo error + * == 1.3 == 1995.03.16 == Benjamin Lin (blin@socs.uts.edu.au) + * Modified to more conform to UNIX style. + * == 2.0 == 1995.03.19 == Benjamin Lin (blin@socs.uts.edu.au) + * Rewritten from scratch. + * == 2.2 == 1995.03.30 == Benjamin Lin (blin@socs.uts.edu.au) + * Conversion from SunOS charset implemented. + * + * See ChangeLog.txt for complete version history. + * + */ + + +/* #define DEBUG 1 */ + +#include "common.h" +#include "unix2dos.h" +#include "querycp.h" +#ifdef D2U_UNICODE +#ifndef MSDOS /* Unix, Cygwin */ +# include <langinfo.h> +#endif +#endif + +void PrintLicense(void) +{ + fprintf(stderr, "%s", _("\ +Copyright (C) 2009-2012 Erwin Waterlander\n\ +Copyright (C) 1994-1995 Benjamin Lin\n\ +All rights reserved.\n\n")); + PrintBSDLicense(); +} + +#ifdef D2U_UNICODE +void AddDOSNewLineW(FILE* ipOutF, CFlag *ipFlag, wint_t CurChar, wint_t PrevChar) +{ + if (ipFlag->NewLine) { /* add additional CR-LF? */ + /* Don't add line ending if it is a DOS line ending. Only in case of Unix line ending. */ + if ((CurChar == 0x0a) && (PrevChar != 0x0d)) { + d2u_putwc(0x0d, ipOutF, ipFlag); + d2u_putwc(0x0a, ipOutF, ipFlag); + } + } +} +#endif + +void AddDOSNewLine(FILE* ipOutF, CFlag *ipFlag, int CurChar, int PrevChar) +{ + if (ipFlag->NewLine) { /* add additional CR-LF? */ + /* Don't add line ending if it is a DOS line ending. Only in case of Unix line ending. */ + if ((CurChar == '\x0a') && (PrevChar != '\x0d')) { + fputc('\x0d', ipOutF); + fputc('\x0a', ipOutF); + } + } +} + +/* converts stream ipInF to DOS format text and write to stream ipOutF + * RetVal: 0 if success + * -1 otherwise + */ +#ifdef D2U_UNICODE +int ConvertUnixToDosW(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, char *progname) +{ + int RetVal = 0; + wint_t TempChar; + wint_t PreviousChar = 0; + + ipFlag->status = 0; + + /* LF -> CR-LF */ + /* CR-LF -> CR-LF, in case the input file is a DOS text file */ + /* \x0a = Newline/Line Feed (LF) */ + /* \x0d = Carriage Return (CR) */ + + switch (ipFlag->FromToMode) + { + case FROMTO_UNIX2DOS: /* unix2dos */ + while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) { /* get character */ + if ((ipFlag->Force == 0) && + (TempChar < 32) && + (TempChar != 0x0a) && /* Not an LF */ + (TempChar != 0x0d) && /* Not a CR */ + (TempChar != 0x09) && /* Not a TAB */ + (TempChar != 0x0c)) { /* Not a form feed */ + RetVal = -1; + ipFlag->status |= BINARY_FILE ; + break; + } + if (TempChar == 0x0a) + { + d2u_putwc(0x0d, ipOutF, ipFlag); /* got LF, put CR */ + } else { + if (TempChar == 0x0d) /* got CR */ + { + if ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) == WEOF) /* get next char */ + TempChar = 0x0d; /* Read error, or end of file. */ + else + { + d2u_putwc(0x0d, ipOutF, ipFlag); /* put CR */ + PreviousChar = 0x0d; + } + } + } + if (d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF) + { + RetVal = -1; + if (!ipFlag->Quiet) + { + if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + } + break; + } else { + AddDOSNewLineW( ipOutF, ipFlag, TempChar, PreviousChar); + } + PreviousChar = TempChar; + } + break; + case FROMTO_UNIX2MAC: /* unix2mac */ + while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) { + if ((ipFlag->Force == 0) && + (TempChar < 32) && + (TempChar != 0x0a) && /* Not an LF */ + (TempChar != 0x0d) && /* Not a CR */ + (TempChar != 0x09) && /* Not a TAB */ + (TempChar != 0x0c)) { /* Not a form feed */ + RetVal = -1; + ipFlag->status |= BINARY_FILE ; + break; + } + if ((TempChar != 0x0a)) /* Not an LF */ + { + if(d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF){ + RetVal = -1; + if (!ipFlag->Quiet) + { + if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + } + break; + } + PreviousChar = TempChar; + } + else{ + /* TempChar is an LF */ + /* Don't touch this delimiter if it's a CR,LF pair. */ + if ( PreviousChar == 0x0d ) { + if (d2u_putwc(0x0a, ipOutF, ipFlag) == WEOF) /* CR,LF pair. Put LF */ + { + RetVal = -1; + if (!ipFlag->Quiet) + { + if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + } + break; + } + PreviousChar = TempChar; + continue; + } + PreviousChar = TempChar; + if (d2u_putwc(0x0d, ipOutF, ipFlag) == WEOF) /* Unix line end (LF). Put CR */ + { + RetVal = -1; + if (!ipFlag->Quiet) + { + if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + } + break; + } + if (ipFlag->NewLine) { /* add additional CR? */ + d2u_putwc(0x0d, ipOutF, ipFlag); + } + } + } + break; + default: /* unknown FromToMode */ + ; +#if DEBUG + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode); + exit(1); +#endif + } + return RetVal; +} +#endif + +/* converts stream ipInF to DOS format text and write to stream ipOutF + * RetVal: 0 if success + * -1 otherwise + */ +int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, char *progname) +{ + int RetVal = 0; + int TempChar; + int PreviousChar = 0; + int *ConvTable; + + ipFlag->status = 0; + + switch (ipFlag->ConvMode) + { + case CONVMODE_ASCII: /* ascii */ + ConvTable = U2DAsciiTable; + break; + case CONVMODE_7BIT: /* 7bit */ + ConvTable = U2D7BitTable; + break; + case CONVMODE_437: /* iso */ + ConvTable = U2DIso437Table; + break; + case CONVMODE_850: /* iso */ + ConvTable = U2DIso850Table; + break; + case CONVMODE_860: /* iso */ + ConvTable = U2DIso860Table; + break; + case CONVMODE_863: /* iso */ + ConvTable = U2DIso863Table; + break; + case CONVMODE_865: /* iso */ + ConvTable = U2DIso865Table; + break; + case CONVMODE_1252: /* iso */ + ConvTable = U2DIso1252Table; + break; + default: /* unknown convmode */ + ipFlag->status |= WRONG_CODEPAGE ; + return(-1); + } + if ((ipFlag->ConvMode > 1) && (!ipFlag->Quiet)) /* not ascii or 7bit */ + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("using code page %d.\n"), ipFlag->ConvMode); + } + + /* LF -> CR-LF */ + /* CR-LF -> CR-LF, in case the input file is a DOS text file */ + /* \x0a = Newline/Line Feed (LF) */ + /* \x0d = Carriage Return (CR) */ + + switch (ipFlag->FromToMode) + { + case FROMTO_UNIX2DOS: /* unix2dos */ + while ((TempChar = fgetc(ipInF)) != EOF) { /* get character */ + if ((ipFlag->Force == 0) && + (TempChar < 32) && + (TempChar != '\x0a') && /* Not an LF */ + (TempChar != '\x0d') && /* Not a CR */ + (TempChar != '\x09') && /* Not a TAB */ + (TempChar != '\x0c')) { /* Not a form feed */ + RetVal = -1; + ipFlag->status |= BINARY_FILE ; + break; + } + if (TempChar == '\x0a') + { + fputc('\x0d', ipOutF); /* got LF, put CR */ + } else { + if (TempChar == '\x0d') /* got CR */ + { + if ((TempChar = fgetc(ipInF)) == EOF) /* get next char */ + TempChar = '\x0d'; /* Read error, or end of file. */ + else + { + fputc('\x0d', ipOutF); /* put CR */ + PreviousChar = '\x0d'; + } + } + } + if (fputc(ConvTable[TempChar], ipOutF) == EOF) + { + RetVal = -1; + if (!ipFlag->Quiet) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + break; + } else { + AddDOSNewLine( ipOutF, ipFlag, TempChar, PreviousChar); + } + PreviousChar = TempChar; + } + break; + case FROMTO_UNIX2MAC: /* unix2mac */ + while ((TempChar = fgetc(ipInF)) != EOF) { + if ((ipFlag->Force == 0) && + (TempChar < 32) && + (TempChar != '\x0a') && /* Not an LF */ + (TempChar != '\x0d') && /* Not a CR */ + (TempChar != '\x09') && /* Not a TAB */ + (TempChar != '\x0c')) { /* Not a form feed */ + RetVal = -1; + ipFlag->status |= BINARY_FILE ; + break; + } + if ((TempChar != '\x0a')) /* Not an LF */ + { + if(fputc(ConvTable[TempChar], ipOutF) == EOF){ + RetVal = -1; + if (!ipFlag->Quiet) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + break; + } + PreviousChar = TempChar; + } + else{ + /* TempChar is an LF */ + /* Don't touch this delimiter if it's a CR,LF pair. */ + if ( PreviousChar == '\x0d' ) { + if (fputc('\x0a', ipOutF) == EOF) /* CR,LF pair. Put LF */ + { + RetVal = -1; + if (!ipFlag->Quiet) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + break; + } + PreviousChar = TempChar; + continue; + } + PreviousChar = TempChar; + if (fputc('\x0d', ipOutF) == EOF) /* Unix line end (LF). Put CR */ + { + RetVal = -1; + if (!ipFlag->Quiet) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, "%s", _("can not write to output file\n")); + } + break; + } + if (ipFlag->NewLine) { /* add additional CR? */ + fputc('\x0d', ipOutF); + } + } + } + break; + default: /* unknown FromToMode */ + ; +#if DEBUG + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode); + exit(1); +#endif + } + return RetVal; +} + +/* convert file ipInFN to DOS format text and write to file ipOutFN + * RetVal: 0 if success + * -1 otherwise + */ +int ConvertUnixToDosNewFile(char *ipInFN, char *ipOutFN, CFlag *ipFlag, char *progname) +{ + int RetVal = 0; + FILE *InF = NULL; + FILE *TempF = NULL; + char *TempPath; + char *errstr; + struct stat StatBuf; + struct utimbuf UTimeBuf; +#ifndef NO_CHMOD + mode_t mask; +#endif +#ifdef NO_MKSTEMP + FILE* fd; +#else + int fd; +#endif + char *TargetFN = NULL; + int ResolveSymlinkResult = 0; + + ipFlag->status = 0 ; + + /* Test if output file is a symbolic link */ + if (symbolic_link(ipOutFN) && !ipFlag->Follow) + { + ipFlag->status |= OUTPUTFILE_SYMLINK ; + /* Not a failure, skipping input file according spec. (keep symbolic link unchanged) */ + return -1; + } + + /* Test if input file is a regular file or symbolic link */ + if (regfile(ipInFN, 1, ipFlag, progname)) + { + ipFlag->status |= NO_REGFILE ; + /* Not a failure, skipping non-regular input file according spec. */ + return -1; + } + + /* Test if input file target is a regular file */ + if (symbolic_link(ipInFN) && regfile_target(ipInFN, ipFlag,progname)) + { + ipFlag->status |= INPUT_TARGET_NO_REGFILE ; + /* Not a failure, skipping non-regular input file according spec. */ + return -1; + } + + /* Test if output file target is a regular file */ + if (symbolic_link(ipOutFN) && (ipFlag->Follow == SYMLINK_FOLLOW) && regfile_target(ipOutFN, ipFlag,progname)) + { + ipFlag->status |= OUTPUT_TARGET_NO_REGFILE ; + /* Failure, input is regular, cannot produce output. */ + if (!ipFlag->error) ipFlag->error = 1; + return -1; + } + + /* retrieve ipInFN file date stamp */ + if (stat(ipInFN, &StatBuf)) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s: %s\n", progname, ipInFN, errstr); + } + RetVal = -1; + } + +#ifdef NO_MKSTEMP + if((fd = MakeTempFileFrom(ipOutFN, &TempPath))==NULL) { +#else + if((fd = MakeTempFileFrom (ipOutFN, &TempPath)) < 0) { +#endif + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("Failed to open temporary output file: %s\n"), errstr); + } + RetVal = -1; + } + +#if DEBUG + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("using %s as temporary file\n"), TempPath); +#endif + + /* can open in file? */ + if (!RetVal) + { + InF=OpenInFile(ipInFN); + if (InF == NULL) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s: %s\n", progname, ipInFN, errstr); + RetVal = -1; + } + } + + /* can open output file? */ + if ((!RetVal) && (InF)) + { +#ifdef NO_MKSTEMP + if ((TempF=fd) == NULL) + { +#else + if ((TempF=OpenOutFile(fd)) == NULL) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s\n", progname, errstr); +#endif + fclose (InF); + InF = NULL; + RetVal = -1; + } + } + + InF = read_bom(InF, &ipFlag->bomtype); + +#ifdef D2U_UNICODE +#ifndef MSDOS /* Unix, Cygwin */ + if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE)) + { + if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) + { + /* Don't convert UTF-16 files when the locale encoding is not UTF-8 + * to prevent loss of characters. */ + ipFlag->status |= LOCALE_NOT_UTF8 ; + if (!ipFlag->error) ipFlag->error = 1; + RetVal = -1; + } + } +#endif +#if !defined(WIN32) && !defined(__CYGWIN__) /* Not Windows or Cygwin */ + if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE)) + { + if (sizeof(wchar_t) < 4) + { + /* A decoded UTF-16 surrogate pair must fit in a wchar_t */ + ipFlag->status |= WCHAR_T_TOO_SMALL ; + if (!ipFlag->error) ipFlag->error = 1; + RetVal = -1; + } + } +#endif +#endif + + if ((ipFlag->add_bom) || (ipFlag->bomtype > 0)) + fprintf(TempF, "%s", "\xEF\xBB\xBF"); /* UTF-8 BOM */ + + /* Turn off ISO and 7-bit conversion for Unicode text files */ + if (ipFlag->bomtype > 0) + ipFlag->ConvMode = CONVMODE_ASCII; + + /* conversion sucessful? */ +#ifdef D2U_UNICODE + if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE)) + { + if ((!RetVal) && (ConvertUnixToDosW(InF, TempF, ipFlag, progname))) + RetVal = -1; + if (ipFlag->status & UNICODE_CONVERSION_ERROR) + { + if (!ipFlag->error) ipFlag->error = 1; + RetVal = -1; + } + } else { + if ((!RetVal) && (ConvertUnixToDos(InF, TempF, ipFlag, progname))) + RetVal = -1; + } +#else + if ((!RetVal) && (ConvertUnixToDos(InF, TempF, ipFlag, progname))) + RetVal = -1; +#endif + + /* can close in file? */ + if ((InF) && (fclose(InF) == EOF)) + RetVal = -1; + + /* can close output file? */ + if ((TempF) && (fclose(TempF) == EOF)) + RetVal = -1; + +#ifdef NO_MKSTEMP + if(fd!=NULL) + fclose(fd); +#else + if(fd>=0) + close(fd); +#endif + +#ifndef NO_CHMOD + if (!RetVal) + { + if (ipFlag->NewFile == 0) /* old file mode */ + { + RetVal = chmod (TempPath, StatBuf.st_mode); /* set original permissions */ + } + else + { + mask = umask(0); /* get process's umask */ + umask(mask); /* set umask back to original */ + RetVal = chmod(TempPath, StatBuf.st_mode & ~mask); /* set original permissions, minus umask */ + } + + if (RetVal) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("Failed to change the permissions of temporary output file %s: %s\n"), TempPath, errstr); + } + } + } +#endif + +#ifndef NO_CHOWN + if (!RetVal && (ipFlag->NewFile == 0)) /* old file mode */ + { + /* Change owner and group of the the tempory output file to the original file's uid and gid. */ + /* Required when a different user (e.g. root) has write permission on the original file. */ + /* Make sure that the original owner can still access the file. */ + if (chown(TempPath, StatBuf.st_uid, StatBuf.st_gid)) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("Failed to change the owner and group of temporary output file %s: %s\n"), TempPath, errstr); + } + RetVal = -1; + } + } +#endif + + if ((!RetVal) && (ipFlag->KeepDate)) + { + UTimeBuf.actime = StatBuf.st_atime; + UTimeBuf.modtime = StatBuf.st_mtime; + /* can change output file time to in file time? */ + if (utime(TempPath, &UTimeBuf) == -1) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s: %s\n", progname, TempPath, errstr); + } + RetVal = -1; + } + } + + /* any error? cleanup the temp file */ + if (RetVal && (TempPath != NULL)) + { + if (unlink(TempPath) && (errno != ENOENT)) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s: %s\n", progname, TempPath, errstr); + } + RetVal = -1; + } + } + + /* If output file is a symbolic link, optional resolve the link and modify */ + /* the target, instead of removing the link and creating a new regular file */ + TargetFN = ipOutFN; + if (symbolic_link(ipOutFN) && !RetVal) + { + ResolveSymlinkResult = 0; /* indicates that TargetFN need not be freed */ + if (ipFlag->Follow == SYMLINK_FOLLOW) + { + ResolveSymlinkResult = ResolveSymbolicLink(ipOutFN, &TargetFN, ipFlag, progname); + if (ResolveSymlinkResult < 0) + { + if (!ipFlag->Quiet) + { + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("problems resolving symbolic link '%s'\n"), ipOutFN); + fprintf(stderr, _(" output file remains in '%s'\n"), TempPath); + } + RetVal = -1; + } + } + } + + /* can rename temporary file to output file? */ + if (!RetVal) + { +#ifdef NEED_REMOVE + if (unlink(TargetFN) && (errno != ENOENT)) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: %s: %s\n", progname, TargetFN, errstr); + } + RetVal = -1; + } +#endif + if (rename(TempPath, TargetFN) == -1) + { + if (!ipFlag->Quiet) + { + ipFlag->error = errno; + errstr = strerror(errno); + fprintf(stderr, "%s: ", progname); + fprintf(stderr, _("problems renaming '%s' to '%s': %s\n"), TempPath, TargetFN, errstr); +#ifdef S_ISLNK + if (ResolveSymlinkResult > 0) + fprintf(stderr, _(" which is the target of symbolic link '%s'\n"), ipOutFN); +#endif + fprintf(stderr, _(" output file remains in '%s'\n"), TempPath); + } + RetVal = -1; + } + + if (ResolveSymlinkResult > 0) + free(TargetFN); + } + free(TempPath); + return RetVal; +} + +/* convert stdin to DOS format text and write to stdout + * RetVal: 0 if success + * -1 otherwise + */ +int ConvertUnixToDosStdio(CFlag *ipFlag, char *progname) +{ + ipFlag->NewFile = 1; + ipFlag->Quiet = 1; + ipFlag->KeepDate = 0; + ipFlag->Force = 1; + +#if defined(WIN32) && !defined(__CYGWIN__) + + /* stdin and stdout are by default text streams. We need + * to set them to binary mode. Otherwise an LF will + * automatically be converted to CR-LF on DOS/Windows. + * Erwin */ + + /* 'setmode' was deprecated by MicroSoft + * since Visual C++ 2005. Use '_setmode' instead. */ + + _setmode(fileno(stdout), O_BINARY); + _setmode(fileno(stdin), O_BINARY); +#elif defined(MSDOS) || defined(__CYGWIN__) || defined(__OS2__) + setmode(fileno(stdout), O_BINARY); + setmode(fileno(stdin), O_BINARY); +#endif + + read_bom(stdin, &ipFlag->bomtype); + + if ((ipFlag->add_bom) || (ipFlag->bomtype > 0)) + fprintf(stdout, "%s", "\xEF\xBB\xBF"); /* UTF-8 BOM */ + +#ifdef D2U_UNICODE + if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE)) + { + return (ConvertUnixToDosW(stdin, stdout, ipFlag, progname)); + } else { + return (ConvertUnixToDos(stdin, stdout, ipFlag, progname)); + } +#else + return (ConvertUnixToDos(stdin, stdout, ipFlag, progname)); +#endif +} + + +int main (int argc, char *argv[]) +{ + /* variable declarations */ + char progname[9]; + int ArgIdx; + int CanSwitchFileMode; + int ShouldExit; + int RetVal = 0; + int process_options = 1; + CFlag *pFlag; + char *ptr; +#ifdef ENABLE_NLS + char localedir[1024]; +#endif +# ifdef __MINGW64__ + int _dowildcard = -1; /* enable wildcard expansion for Win64 */ +# endif + + progname[8] = '\0'; + strcpy(progname,"unix2dos"); + +#ifdef ENABLE_NLS + ptr = getenv("DOS2UNIX_LOCALEDIR"); + if (ptr == NULL) + strcpy(localedir,LOCALEDIR); + else + { + if (strlen(ptr) < sizeof(localedir)) + strcpy(localedir,ptr); + else + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, "%s", _("error: Value of environment variable DOS2UNIX_LOCALEDIR is too long.\n")); + strcpy(localedir,LOCALEDIR); + } + } + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, localedir); + textdomain (PACKAGE); +#endif + + + /* variable initialisations */ + ArgIdx = 0; + CanSwitchFileMode = 1; + ShouldExit = 0; + pFlag = (CFlag*)malloc(sizeof(CFlag)); + pFlag->NewFile = 0; + pFlag->Quiet = 0; + pFlag->KeepDate = 0; + pFlag->ConvMode = CONVMODE_ASCII; /* default ascii */ + pFlag->FromToMode = FROMTO_UNIX2DOS; /* default unix2dos */ + pFlag->NewLine = 0; + pFlag->Force = 0; + pFlag->Follow = SYMLINK_SKIP; + pFlag->status = 0; + pFlag->stdio_mode = 1; + pFlag->error = 0; +#ifdef D2U_UNICODE + pFlag->bomtype = FILE_MBS; +#endif + pFlag->add_bom = 0; + + if ( ((ptr=strrchr(argv[0],'/')) == NULL) && ((ptr=strrchr(argv[0],'\\')) == NULL) ) + ptr = argv[0]; + else + ptr++; + + if ((strcmpi("unix2mac", ptr) == 0) || (strcmpi("unix2mac.exe", ptr) == 0)) + { + pFlag->FromToMode = FROMTO_UNIX2MAC; + strcpy(progname,"unix2mac"); + } + + while ((++ArgIdx < argc) && (!ShouldExit)) + { + /* is it an option? */ + if ((argv[ArgIdx][0] == '-') && process_options) + { + /* an option */ + if (strcmp(argv[ArgIdx],"--") == 0) + process_options = 0; + else if ((strcmp(argv[ArgIdx],"-h") == 0) || (strcmp(argv[ArgIdx],"--help") == 0)) + { + PrintUsage(progname); + return(pFlag->error); + } + else if ((strcmp(argv[ArgIdx],"-k") == 0) || (strcmp(argv[ArgIdx],"--keepdate") == 0)) + pFlag->KeepDate = 1; + else if ((strcmp(argv[ArgIdx],"-f") == 0) || (strcmp(argv[ArgIdx],"--force") == 0)) + pFlag->Force = 1; + else if ((strcmp(argv[ArgIdx],"-s") == 0) || (strcmp(argv[ArgIdx],"--safe") == 0)) + pFlag->Force = 0; + else if ((strcmp(argv[ArgIdx],"-q") == 0) || (strcmp(argv[ArgIdx],"--quiet") == 0)) + pFlag->Quiet = 1; + else if ((strcmp(argv[ArgIdx],"-l") == 0) || (strcmp(argv[ArgIdx],"--newline") == 0)) + pFlag->NewLine = 1; + else if ((strcmp(argv[ArgIdx],"-m") == 0) || (strcmp(argv[ArgIdx],"--add-bom") == 0)) + pFlag->add_bom = 1; + else if ((strcmp(argv[ArgIdx],"-S") == 0) || (strcmp(argv[ArgIdx],"--skip-symlink") == 0)) + pFlag->Follow = SYMLINK_SKIP; + else if ((strcmp(argv[ArgIdx],"-F") == 0) || (strcmp(argv[ArgIdx],"--follow-symlink") == 0)) + pFlag->Follow = SYMLINK_FOLLOW; + else if ((strcmp(argv[ArgIdx],"-R") == 0) || (strcmp(argv[ArgIdx],"--replace-symlink") == 0)) + pFlag->Follow = SYMLINK_REPLACE; + else if ((strcmp(argv[ArgIdx],"-V") == 0) || (strcmp(argv[ArgIdx],"--version") == 0)) + { + PrintVersion(progname); +#ifdef ENABLE_NLS + PrintLocaledir(localedir); +#endif + return(pFlag->error); + } + else if ((strcmp(argv[ArgIdx],"-L") == 0) || (strcmp(argv[ArgIdx],"--license") == 0)) + { + PrintLicense(); + return(pFlag->error); + } + else if (strcmp(argv[ArgIdx],"-ascii") == 0) /* SunOS compatible options */ + pFlag->ConvMode = CONVMODE_ASCII; + else if (strcmp(argv[ArgIdx],"-7") == 0) + pFlag->ConvMode = CONVMODE_7BIT; + else if (strcmp(argv[ArgIdx],"-iso") == 0) + { + pFlag->ConvMode = (int)query_con_codepage(); + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr,_("active code page: %d\n"), pFlag->ConvMode); + } + if (pFlag->ConvMode < 2) + pFlag->ConvMode = CONVMODE_437; + } + else if (strcmp(argv[ArgIdx],"-437") == 0) + pFlag->ConvMode = CONVMODE_437; + else if (strcmp(argv[ArgIdx],"-850") == 0) + pFlag->ConvMode = CONVMODE_850; + else if (strcmp(argv[ArgIdx],"-860") == 0) + pFlag->ConvMode = CONVMODE_860; + else if (strcmp(argv[ArgIdx],"-863") == 0) + pFlag->ConvMode = CONVMODE_863; + else if (strcmp(argv[ArgIdx],"-865") == 0) + pFlag->ConvMode = CONVMODE_865; + else if (strcmp(argv[ArgIdx],"-1252") == 0) + pFlag->ConvMode = CONVMODE_1252; + else if ((strcmp(argv[ArgIdx],"-c") == 0) || (strcmp(argv[ArgIdx],"--convmode") == 0)) + { + if (++ArgIdx < argc) + { + if (strcmpi(argv[ArgIdx],"ascii") == 0) /* Benjamin Lin's legacy options */ + pFlag->ConvMode = CONVMODE_ASCII; + else if (strcmpi(argv[ArgIdx], "7bit") == 0) + pFlag->ConvMode = CONVMODE_7BIT; + else if (strcmpi(argv[ArgIdx], "iso") == 0) + { + pFlag->ConvMode = (int)query_con_codepage(); + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr,_("active code page: %d\n"), pFlag->ConvMode); + } + if (pFlag->ConvMode < 2) + pFlag->ConvMode = CONVMODE_437; + } + else if (strcmpi(argv[ArgIdx], "mac") == 0) + pFlag->FromToMode = FROMTO_UNIX2MAC; + else + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("invalid %s conversion mode specified\n"),argv[ArgIdx]); + pFlag->error = 1; + ShouldExit = 1; + pFlag->stdio_mode = 0; + } + } + else + { + ArgIdx--; + fprintf(stderr,"%s: ",progname); + fprintf(stderr,_("option '%s' requires an argument\n"),argv[ArgIdx]); + pFlag->error = 1; + ShouldExit = 1; + pFlag->stdio_mode = 0; + } + } + + else if ((strcmp(argv[ArgIdx],"-o") == 0) || (strcmp(argv[ArgIdx],"--oldfile") == 0)) + { + /* last convert not paired */ + if (!CanSwitchFileMode) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("target of file %s not specified in new file mode\n"), argv[ArgIdx-1]); + pFlag->error = 1; + ShouldExit = 1; + pFlag->stdio_mode = 0; + } + pFlag->NewFile = 0; + } + + else if ((strcmp(argv[ArgIdx],"-n") == 0) || (strcmp(argv[ArgIdx],"--newfile") == 0)) + { + /* last convert not paired */ + if (!CanSwitchFileMode) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("target of file %s not specified in new file mode\n"), argv[ArgIdx-1]); + pFlag->error = 1; + ShouldExit = 1; + pFlag->stdio_mode = 0; + } + pFlag->NewFile = 1; + } + else { /* wrong option */ + PrintUsage(progname); + ShouldExit = 1; + pFlag->error = 1; + pFlag->stdio_mode = 0; + } + } + else + { + pFlag->stdio_mode = 0; + /* not an option */ + if (pFlag->NewFile) + { + if (CanSwitchFileMode) + CanSwitchFileMode = 0; + else + { + RetVal = ConvertUnixToDosNewFile(argv[ArgIdx-1], argv[ArgIdx], pFlag, progname); + if (pFlag->status & NO_REGFILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping %s, not a regular file.\n"), argv[ArgIdx-1]); + } + } else if (pFlag->status & OUTPUTFILE_SYMLINK) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping %s, output file %s is a symbolic link.\n"), argv[ArgIdx-1], argv[ArgIdx]); + } + } else if (pFlag->status & INPUT_TARGET_NO_REGFILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping symbolic link %s, target is not a regular file.\n"), argv[ArgIdx-1]); + } + } else if (pFlag->status & OUTPUT_TARGET_NO_REGFILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping %s, target of symbolic link %s is not a regular file.\n"), argv[ArgIdx-1], argv[ArgIdx]); + } + } else if (pFlag->status & BINARY_FILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping binary file %s\n"), argv[ArgIdx-1]); + } + } else if (pFlag->status & WRONG_CODEPAGE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("code page %d is not supported.\n"), pFlag->ConvMode); + } + } else if (pFlag->status & LOCALE_NOT_UTF8) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, the current locale character encoding is not UTF-8.\n"), argv[ArgIdx-1]); + } + } else if (pFlag->status & WCHAR_T_TOO_SMALL) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, the size of wchar_t is %d bytes.\n"), argv[ArgIdx-1], (int)sizeof(wchar_t)); + } + } else if (pFlag->status & UNICODE_CONVERSION_ERROR) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, an UTF-16 conversion error occurred.\n"), argv[ArgIdx-1]); + } + } else { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + if (pFlag->FromToMode == FROMTO_UNIX2MAC) + fprintf(stderr, _("converting file %s to file %s in Mac format ...\n"), argv[ArgIdx-1], argv[ArgIdx]); + else + fprintf(stderr, _("converting file %s to file %s in DOS format ...\n"), argv[ArgIdx-1], argv[ArgIdx]); + } + if (RetVal) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("problems converting file %s to file %s\n"), argv[ArgIdx-1], argv[ArgIdx]); + } + } + } + CanSwitchFileMode = 1; + } + } + else + { + RetVal = ConvertUnixToDosNewFile(argv[ArgIdx], argv[ArgIdx], pFlag, progname); + if (pFlag->status & NO_REGFILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping %s, not a regular file.\n"), argv[ArgIdx]); + } + } else if (pFlag->status & OUTPUTFILE_SYMLINK) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping symbolic link %s.\n"), argv[ArgIdx]); + } + } else if (pFlag->status & INPUT_TARGET_NO_REGFILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping symbolic link %s, target is not a regular file.\n"), argv[ArgIdx]); + } + } else if (pFlag->status & BINARY_FILE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping binary file %s\n"), argv[ArgIdx]); + } + } else if (pFlag->status & WRONG_CODEPAGE) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("code page %d is not supported.\n"), pFlag->ConvMode); + } + } else if (pFlag->status & LOCALE_NOT_UTF8) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, the current locale character encoding is not UTF-8.\n"), argv[ArgIdx]); + } + } else if (pFlag->status & WCHAR_T_TOO_SMALL) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, the size of wchar_t is %d bytes.\n"), argv[ArgIdx], (int)sizeof(wchar_t)); + } + } else if (pFlag->status & UNICODE_CONVERSION_ERROR) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("Skipping UTF-16 file %s, an UTF-16 conversion error occurred.\n"), argv[ArgIdx]); + } + } else { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + if (pFlag->FromToMode == FROMTO_UNIX2MAC) + fprintf(stderr, _("converting file %s to Mac format ...\n"), argv[ArgIdx]); + else + fprintf(stderr, _("converting file %s to DOS format ...\n"), argv[ArgIdx]); + } + if (RetVal) + { + if (!pFlag->Quiet) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("problems converting file %s\n"), argv[ArgIdx]); + } + } + } + } + } + } + + /* no file argument, use stdin and stdout */ + if (pFlag->stdio_mode) + { + exit(ConvertUnixToDosStdio(pFlag, progname)); + } + + + if (!CanSwitchFileMode) + { + fprintf(stderr,"%s: ",progname); + fprintf(stderr, _("target of file %s not specified in new file mode\n"), argv[ArgIdx-1]); + pFlag->error = 1; + } + return (pFlag->error); +} + |