4 * Convert lf ('\x0a') characters in a file to cr lf ('\x0d' '\x0a')
7 * The dos2unix package is distributed under FreeBSD style license.
8 * See also http://www.freebsd.org/copyright/freebsd-license.html
11 * Copyright (C) 2009-2014 Erwin Waterlander
12 * Copyright (C) 1994-1995 Benjamin Lin.
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice in the documentation and/or other materials provided with
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * == 1.0 == 1989.10.04 == John Birchfield (jb@koko.csustan.edu)
37 * == 1.1 == 1994.12.20 == Benjamin Lin (blin@socs.uts.edu.au)
38 * Cleaned up for Borland C/C++ 4.02
39 * == 1.2 == 1995.03.09 == Benjamin Lin (blin@socs.uts.edu.au)
40 * Fixed minor typo error
41 * == 1.3 == 1995.03.16 == Benjamin Lin (blin@socs.uts.edu.au)
42 * Modified to more conform to UNIX style.
43 * == 2.0 == 1995.03.19 == Benjamin Lin (blin@socs.uts.edu.au)
44 * Rewritten from scratch.
45 * == 2.2 == 1995.03.30 == Benjamin Lin (blin@socs.uts.edu.au)
46 * Conversion from SunOS charset implemented.
48 * See ChangeLog.txt for complete version history.
59 #if !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__) /* Unix, Cygwin */
60 # include <langinfo.h>
64 void PrintLicense(void)
67 Copyright (C) 2009-2014 Erwin Waterlander\n\
68 Copyright (C) 1994-1995 Benjamin Lin\n\
69 All rights reserved.\n\n"));
74 void AddDOSNewLineW(FILE* ipOutF, CFlag *ipFlag, wint_t CurChar, wint_t PrevChar)
76 if (ipFlag->NewLine) { /* add additional CR-LF? */
77 /* Don't add line ending if it is a DOS line ending. Only in case of Unix line ending. */
78 if ((CurChar == 0x0a) && (PrevChar != 0x0d)) {
79 d2u_putwc(0x0d, ipOutF, ipFlag);
80 d2u_putwc(0x0a, ipOutF, ipFlag);
86 void AddDOSNewLine(FILE* ipOutF, CFlag *ipFlag, int CurChar, int PrevChar)
88 if (ipFlag->NewLine) { /* add additional CR-LF? */
89 /* Don't add line ending if it is a DOS line ending. Only in case of Unix line ending. */
90 if ((CurChar == '\x0a') && (PrevChar != '\x0d')) {
91 fputc('\x0d', ipOutF);
92 fputc('\x0a', ipOutF);
97 /* converts stream ipInF to DOS format text and write to stream ipOutF
98 * RetVal: 0 if success
102 int ConvertUnixToDosW(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, char *progname)
106 wint_t PreviousChar = 0;
113 /* CR-LF -> CR-LF, in case the input file is a DOS text file */
114 /* \x0a = Newline/Line Feed (LF) */
115 /* \x0d = Carriage Return (CR) */
117 switch (ipFlag->FromToMode)
119 case FROMTO_UNIX2DOS: /* unix2dos */
120 while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) { /* get character */
121 if ((ipFlag->Force == 0) &&
123 (TempChar != 0x0a) && /* Not an LF */
124 (TempChar != 0x0d) && /* Not a CR */
125 (TempChar != 0x09) && /* Not a TAB */
126 (TempChar != 0x0c)) { /* Not a form feed */
128 ipFlag->status |= BINARY_FILE ;
131 fprintf(stderr, "%s: ", progname);
132 fprintf(stderr, _("Binary symbol 0x00%02X found at line %d\n"),TempChar, line_nr);
136 if (TempChar == 0x0a)
138 d2u_putwc(0x0d, ipOutF, ipFlag); /* got LF, put extra CR */
140 if (TempChar == 0x0d) /* got CR */
142 if ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) == WEOF) /* get next char (possibly LF) */
143 TempChar = 0x0d; /* Read error, or end of file. */
146 d2u_putwc(0x0d, ipOutF, ipFlag); /* put CR */
151 if (TempChar == 0x0a) /* Count all DOS and Unix line breaks */
153 if (d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF)
158 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR))
160 errstr = strerror(errno);
161 fprintf(stderr, "%s: ", progname);
162 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
167 AddDOSNewLineW( ipOutF, ipFlag, TempChar, PreviousChar);
169 PreviousChar = TempChar;
172 case FROMTO_UNIX2MAC: /* unix2mac */
173 while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) {
174 if ((ipFlag->Force == 0) &&
176 (TempChar != 0x0a) && /* Not an LF */
177 (TempChar != 0x0d) && /* Not a CR */
178 (TempChar != 0x09) && /* Not a TAB */
179 (TempChar != 0x0c)) { /* Not a form feed */
181 ipFlag->status |= BINARY_FILE ;
184 fprintf(stderr, "%s: ", progname);
185 fprintf(stderr, _("Binary symbol 0x00%02X found at line %d\n"),TempChar, line_nr);
189 if ((TempChar != 0x0a)) /* Not an LF */
191 if(d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF){
195 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR))
197 errstr = strerror(errno);
198 fprintf(stderr, "%s: ", progname);
199 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
204 PreviousChar = TempChar;
207 /* TempChar is an LF */
209 /* Don't touch this delimiter if it's a CR,LF pair. */
210 if ( PreviousChar == 0x0d ) {
211 if (d2u_putwc(0x0a, ipOutF, ipFlag) == WEOF) /* CR,LF pair. Put LF */
216 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR))
218 errstr = strerror(errno);
219 fprintf(stderr, "%s: ", progname);
220 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
225 PreviousChar = TempChar;
228 PreviousChar = TempChar;
229 if (d2u_putwc(0x0d, ipOutF, ipFlag) == WEOF) /* Unix line end (LF). Put CR */
234 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR))
236 errstr = strerror(errno);
237 fprintf(stderr, "%s: ", progname);
238 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
243 if (ipFlag->NewLine) { /* add additional CR? */
244 d2u_putwc(0x0d, ipOutF, ipFlag);
249 default: /* unknown FromToMode */
252 fprintf(stderr, "%s: ", progname);
253 fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
261 /* converts stream ipInF to DOS format text and write to stream ipOutF
262 * RetVal: 0 if success
265 int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, char *progname)
269 int PreviousChar = 0;
276 switch (ipFlag->ConvMode)
278 case CONVMODE_ASCII: /* ascii */
279 case CONVMODE_UTF16LE: /* Assume UTF-16LE */
280 case CONVMODE_UTF16BE: /* Assume UTF-16BE */
281 ConvTable = U2DAsciiTable;
283 case CONVMODE_7BIT: /* 7bit */
284 ConvTable = U2D7BitTable;
286 case CONVMODE_437: /* iso */
287 ConvTable = U2DIso437Table;
289 case CONVMODE_850: /* iso */
290 ConvTable = U2DIso850Table;
292 case CONVMODE_860: /* iso */
293 ConvTable = U2DIso860Table;
295 case CONVMODE_863: /* iso */
296 ConvTable = U2DIso863Table;
298 case CONVMODE_865: /* iso */
299 ConvTable = U2DIso865Table;
301 case CONVMODE_1252: /* iso */
302 ConvTable = U2DIso1252Table;
304 default: /* unknown convmode */
305 ipFlag->status |= WRONG_CODEPAGE ;
308 if ((ipFlag->ConvMode > 1) && (!ipFlag->Quiet)) /* not ascii or 7bit */
310 fprintf(stderr, "%s: ", progname);
311 fprintf(stderr, _("using code page %d.\n"), ipFlag->ConvMode);
315 /* CR-LF -> CR-LF, in case the input file is a DOS text file */
316 /* \x0a = Newline/Line Feed (LF) */
317 /* \x0d = Carriage Return (CR) */
319 switch (ipFlag->FromToMode)
321 case FROMTO_UNIX2DOS: /* unix2dos */
322 while ((TempChar = fgetc(ipInF)) != EOF) { /* get character */
323 if ((ipFlag->Force == 0) &&
325 (TempChar != '\x0a') && /* Not an LF */
326 (TempChar != '\x0d') && /* Not a CR */
327 (TempChar != '\x09') && /* Not a TAB */
328 (TempChar != '\x0c')) { /* Not a form feed */
330 ipFlag->status |= BINARY_FILE ;
333 fprintf(stderr, "%s: ", progname);
334 fprintf(stderr, _("Binary symbol 0x%02X found at line %d\n"),TempChar, line_nr);
338 if (TempChar == '\x0a')
340 fputc('\x0d', ipOutF); /* got LF, put extra CR */
342 if (TempChar == '\x0d') /* got CR */
344 if ((TempChar = fgetc(ipInF)) == EOF) /* get next char (possibly LF) */
345 TempChar = '\x0d'; /* Read error, or end of file. */
348 fputc('\x0d', ipOutF); /* put CR */
349 PreviousChar = '\x0d';
353 if (TempChar == '\x0a') /* Count all DOS and Unix line breaks */
355 if (fputc(ConvTable[TempChar], ipOutF) == EOF) /* put LF or other char */
360 errstr = strerror(errno);
361 fprintf(stderr, "%s: ", progname);
362 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
366 AddDOSNewLine( ipOutF, ipFlag, TempChar, PreviousChar);
368 PreviousChar = TempChar;
371 case FROMTO_UNIX2MAC: /* unix2mac */
372 while ((TempChar = fgetc(ipInF)) != EOF) {
373 if ((ipFlag->Force == 0) &&
375 (TempChar != '\x0a') && /* Not an LF */
376 (TempChar != '\x0d') && /* Not a CR */
377 (TempChar != '\x09') && /* Not a TAB */
378 (TempChar != '\x0c')) { /* Not a form feed */
380 ipFlag->status |= BINARY_FILE ;
383 fprintf(stderr, "%s: ", progname);
384 fprintf(stderr, _("Binary symbol 0x%02X found at line %d\n"),TempChar, line_nr);
388 if ((TempChar != '\x0a')) /* Not an LF */
390 if(fputc(ConvTable[TempChar], ipOutF) == EOF){
394 errstr = strerror(errno);
395 fprintf(stderr, "%s: ", progname);
396 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
400 PreviousChar = TempChar;
403 /* TempChar is an LF */
405 /* Don't touch this delimiter if it's a CR,LF pair. */
406 if ( PreviousChar == '\x0d' ) {
407 if (fputc('\x0a', ipOutF) == EOF) /* CR,LF pair. Put LF */
412 errstr = strerror(errno);
413 fprintf(stderr, "%s: ", progname);
414 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
418 PreviousChar = TempChar;
421 PreviousChar = TempChar;
422 if (fputc('\x0d', ipOutF) == EOF) /* Unix line end (LF). Put CR */
427 errstr = strerror(errno);
428 fprintf(stderr, "%s: ", progname);
429 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
433 if (ipFlag->NewLine) { /* add additional CR? */
434 fputc('\x0d', ipOutF);
439 default: /* unknown FromToMode */
442 fprintf(stderr, "%s: ", progname);
443 fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
450 /* convert file ipInFN to DOS format text and write to file ipOutFN
451 * RetVal: 0 if success
454 int ConvertUnixToDosNewFile(char *ipInFN, char *ipOutFN, CFlag *ipFlag, char *progname)
462 struct utimbuf UTimeBuf;
471 char *TargetFN = NULL;
472 int ResolveSymlinkResult = 0;
476 /* Test if output file is a symbolic link */
477 if (symbolic_link(ipOutFN) && !ipFlag->Follow)
479 ipFlag->status |= OUTPUTFILE_SYMLINK ;
480 /* Not a failure, skipping input file according spec. (keep symbolic link unchanged) */
484 /* Test if input file is a regular file or symbolic link */
485 if (regfile(ipInFN, 1, ipFlag, progname))
487 ipFlag->status |= NO_REGFILE ;
488 /* Not a failure, skipping non-regular input file according spec. */
492 /* Test if input file target is a regular file */
493 if (symbolic_link(ipInFN) && regfile_target(ipInFN, ipFlag,progname))
495 ipFlag->status |= INPUT_TARGET_NO_REGFILE ;
496 /* Not a failure, skipping non-regular input file according spec. */
500 /* Test if output file target is a regular file */
501 if (symbolic_link(ipOutFN) && (ipFlag->Follow == SYMLINK_FOLLOW) && regfile_target(ipOutFN, ipFlag,progname))
503 ipFlag->status |= OUTPUT_TARGET_NO_REGFILE ;
504 /* Failure, input is regular, cannot produce output. */
505 if (!ipFlag->error) ipFlag->error = 1;
509 /* retrieve ipInFN file date stamp */
510 if (stat(ipInFN, &StatBuf))
514 ipFlag->error = errno;
515 errstr = strerror(errno);
516 fprintf(stderr, "%s: %s: %s\n", progname, ipInFN, errstr);
522 if((fd = MakeTempFileFrom(ipOutFN, &TempPath))==NULL) {
524 if((fd = MakeTempFileFrom (ipOutFN, &TempPath)) < 0) {
528 ipFlag->error = errno;
529 errstr = strerror(errno);
530 fprintf(stderr, "%s: ", progname);
531 fprintf(stderr, _("Failed to open temporary output file: %s\n"), errstr);
537 fprintf(stderr, "%s: ", progname);
538 fprintf(stderr, _("using %s as temporary file\n"), TempPath);
541 /* can open in file? */
544 InF=OpenInFile(ipInFN);
547 ipFlag->error = errno;
548 errstr = strerror(errno);
549 fprintf(stderr, "%s: %s: %s\n", progname, ipInFN, errstr);
554 /* can open output file? */
555 if ((!RetVal) && (InF))
558 if ((TempF=fd) == NULL)
561 if ((TempF=OpenOutFile(fd)) == NULL)
563 ipFlag->error = errno;
564 errstr = strerror(errno);
565 fprintf(stderr, "%s: %s\n", progname, errstr);
573 InF = read_bom(InF, &ipFlag->bomtype);
575 if ((ipFlag->bomtype == FILE_MBS) && (ipFlag->ConvMode == CONVMODE_UTF16LE))
576 ipFlag->bomtype = FILE_UTF16LE;
577 if ((ipFlag->bomtype == FILE_MBS) && (ipFlag->ConvMode == CONVMODE_UTF16BE))
578 ipFlag->bomtype = FILE_UTF16BE;
582 #if !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__) /* Unix, Cygwin */
583 if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE))
585 if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
587 /* Don't convert UTF-16 files when the locale encoding is not UTF-8
588 * to prevent loss of characters. */
589 ipFlag->status |= LOCALE_NOT_UTF8 ;
590 if (!ipFlag->error) ipFlag->error = 1;
595 #if !defined(_WIN32) && !defined(__CYGWIN__) /* Not Windows or Cygwin */
596 if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE))
598 if (sizeof(wchar_t) < 4)
600 /* A decoded UTF-16 surrogate pair must fit in a wchar_t */
601 ipFlag->status |= WCHAR_T_TOO_SMALL ;
602 if (!ipFlag->error) ipFlag->error = 1;
609 if ((ipFlag->add_bom) || (ipFlag->bomtype > 0))
610 fprintf(TempF, "%s", "\xEF\xBB\xBF"); /* UTF-8 BOM */
612 /* Turn off ISO and 7-bit conversion for Unicode text files */
613 /* When we assume UTF16, don't change the conversion mode. We need to remember it. */
614 if ((ipFlag->bomtype > 0) && (ipFlag->ConvMode != CONVMODE_UTF16LE) && (ipFlag->ConvMode != CONVMODE_UTF16BE))
615 ipFlag->ConvMode = CONVMODE_ASCII;
617 /* conversion sucessful? */
619 if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE))
621 if ((!RetVal) && (ConvertUnixToDosW(InF, TempF, ipFlag, progname)))
623 if (ipFlag->status & UNICODE_CONVERSION_ERROR)
625 if (!ipFlag->error) ipFlag->error = 1;
629 if ((!RetVal) && (ConvertUnixToDos(InF, TempF, ipFlag, progname)))
633 if ((!RetVal) && (ConvertUnixToDos(InF, TempF, ipFlag, progname)))
637 /* can close in file? */
638 if ((InF) && (fclose(InF) == EOF))
641 /* can close output file? */
644 if (fclose(TempF) == EOF)
648 ipFlag->error = errno;
649 errstr = strerror(errno);
650 fprintf(stderr, "%s: ", progname);
651 fprintf(stderr, _("Failed to write to temporary output file %s: %s\n"), TempPath, errstr);
668 if (ipFlag->NewFile == 0) /* old-file mode */
670 RetVal = chmod (TempPath, StatBuf.st_mode); /* set original permissions */
674 mask = umask(0); /* get process's umask */
675 umask(mask); /* set umask back to original */
676 RetVal = chmod(TempPath, StatBuf.st_mode & ~mask); /* set original permissions, minus umask */
683 ipFlag->error = errno;
684 errstr = strerror(errno);
685 fprintf(stderr, "%s: ", progname);
686 fprintf(stderr, _("Failed to change the permissions of temporary output file %s: %s\n"), TempPath, errstr);
693 if (!RetVal && (ipFlag->NewFile == 0)) /* old-file mode */
695 /* Change owner and group of the temporary output file to the original file's uid and gid. */
696 /* Required when a different user (e.g. root) has write permission on the original file. */
697 /* Make sure that the original owner can still access the file. */
698 if (chown(TempPath, StatBuf.st_uid, StatBuf.st_gid))
702 ipFlag->error = errno;
703 errstr = strerror(errno);
704 fprintf(stderr, "%s: ", progname);
705 fprintf(stderr, _("Failed to change the owner and group of temporary output file %s: %s\n"), TempPath, errstr);
712 if ((!RetVal) && (ipFlag->KeepDate))
714 UTimeBuf.actime = StatBuf.st_atime;
715 UTimeBuf.modtime = StatBuf.st_mtime;
716 /* can change output file time to in file time? */
717 if (utime(TempPath, &UTimeBuf) == -1)
721 ipFlag->error = errno;
722 errstr = strerror(errno);
723 fprintf(stderr, "%s: %s: %s\n", progname, TempPath, errstr);
729 /* any error? cleanup the temp file */
730 if (RetVal && (TempPath != NULL))
732 if (unlink(TempPath) && (errno != ENOENT))
736 ipFlag->error = errno;
737 errstr = strerror(errno);
738 fprintf(stderr, "%s: %s: %s\n", progname, TempPath, errstr);
744 /* If output file is a symbolic link, optional resolve the link and modify */
745 /* the target, instead of removing the link and creating a new regular file */
747 if (symbolic_link(ipOutFN) && !RetVal)
749 ResolveSymlinkResult = 0; /* indicates that TargetFN need not be freed */
750 if (ipFlag->Follow == SYMLINK_FOLLOW)
752 ResolveSymlinkResult = ResolveSymbolicLink(ipOutFN, &TargetFN, ipFlag, progname);
753 if (ResolveSymlinkResult < 0)
757 fprintf(stderr, "%s: ", progname);
758 fprintf(stderr, _("problems resolving symbolic link '%s'\n"), ipOutFN);
759 fprintf(stderr, _(" output file remains in '%s'\n"), TempPath);
766 /* can rename temporary file to output file? */
770 if (unlink(TargetFN) && (errno != ENOENT))
774 ipFlag->error = errno;
775 errstr = strerror(errno);
776 fprintf(stderr, "%s: %s: %s\n", progname, TargetFN, errstr);
781 if (rename(TempPath, TargetFN) == -1)
785 ipFlag->error = errno;
786 errstr = strerror(errno);
787 fprintf(stderr, "%s: ", progname);
788 fprintf(stderr, _("problems renaming '%s' to '%s': %s\n"), TempPath, TargetFN, errstr);
790 if (ResolveSymlinkResult > 0)
791 fprintf(stderr, _(" which is the target of symbolic link '%s'\n"), ipOutFN);
793 fprintf(stderr, _(" output file remains in '%s'\n"), TempPath);
798 if (ResolveSymlinkResult > 0)
805 /* convert stdin to DOS format text and write to stdout
806 * RetVal: 0 if success
809 int ConvertUnixToDosStdio(CFlag *ipFlag, char *progname)
813 ipFlag->KeepDate = 0;
816 #if defined(_WIN32) && !defined(__CYGWIN__)
818 /* stdin and stdout are by default text streams. We need
819 * to set them to binary mode. Otherwise an LF will
820 * automatically be converted to CR-LF on DOS/Windows.
823 /* POSIX 'setmode' was deprecated by MicroSoft since
824 * Visual C++ 2005. Use ISO C++ conformant '_setmode' instead. */
826 _setmode(_fileno(stdout), _O_BINARY);
827 _setmode(_fileno(stdin), _O_BINARY);
828 #elif defined(__MSDOS__) || defined(__CYGWIN__) || defined(__OS2__)
829 setmode(fileno(stdout), O_BINARY);
830 setmode(fileno(stdin), O_BINARY);
833 read_bom(stdin, &ipFlag->bomtype);
835 if ((ipFlag->bomtype == FILE_MBS) && (ipFlag->ConvMode == CONVMODE_UTF16LE))
836 ipFlag->bomtype = FILE_UTF16LE;
837 if ((ipFlag->bomtype == FILE_MBS) && (ipFlag->ConvMode == CONVMODE_UTF16BE))
838 ipFlag->bomtype = FILE_UTF16BE;
841 if ((ipFlag->add_bom) || (ipFlag->bomtype > 0))
842 fprintf(stdout, "%s", "\xEF\xBB\xBF"); /* UTF-8 BOM */
845 if ((ipFlag->bomtype == FILE_UTF16LE) || (ipFlag->bomtype == FILE_UTF16BE))
847 return (ConvertUnixToDosW(stdin, stdout, ipFlag, progname));
849 return (ConvertUnixToDos(stdin, stdout, ipFlag, progname));
852 return (ConvertUnixToDos(stdin, stdout, ipFlag, progname));
857 int main (int argc, char *argv[])
859 /* variable declarations */
862 int CanSwitchFileMode;
865 int process_options = 1;
869 char localedir[1024];
872 int _dowildcard = -1; /* enable wildcard expansion for Win64 */
876 strcpy(progname,"unix2dos");
879 ptr = getenv("DOS2UNIX_LOCALEDIR");
881 strcpy(localedir,LOCALEDIR);
884 if (strlen(ptr) < sizeof(localedir))
885 strcpy(localedir,ptr);
888 fprintf(stderr,"%s: ",progname);
889 fprintf(stderr, "%s", _("error: Value of environment variable DOS2UNIX_LOCALEDIR is too long.\n"));
890 strcpy(localedir,LOCALEDIR);
895 #if defined(ENABLE_NLS) || (defined(D2U_UNICODE) && !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__))
896 /* setlocale() is also needed for nl_langinfo() */
897 setlocale (LC_ALL, "");
901 bindtextdomain (PACKAGE, localedir);
902 textdomain (PACKAGE);
906 /* variable initialisations */
908 CanSwitchFileMode = 1;
910 pFlag = (CFlag*)malloc(sizeof(CFlag));
914 pFlag->ConvMode = CONVMODE_ASCII; /* default ascii */
915 pFlag->FromToMode = FROMTO_UNIX2DOS; /* default unix2dos */
918 pFlag->Follow = SYMLINK_SKIP;
920 pFlag->stdio_mode = 1;
923 pFlag->bomtype = FILE_MBS;
927 if ( ((ptr=strrchr(argv[0],'/')) == NULL) && ((ptr=strrchr(argv[0],'\\')) == NULL) )
932 if ((strcmpi("unix2mac", ptr) == 0) || (strcmpi("unix2mac.exe", ptr) == 0))
934 pFlag->FromToMode = FROMTO_UNIX2MAC;
935 strcpy(progname,"unix2mac");
938 while ((++ArgIdx < argc) && (!ShouldExit))
940 /* is it an option? */
941 if ((argv[ArgIdx][0] == '-') && process_options)
944 if (strcmp(argv[ArgIdx],"--") == 0)
946 else if ((strcmp(argv[ArgIdx],"-h") == 0) || (strcmp(argv[ArgIdx],"--help") == 0))
948 PrintUsage(progname);
949 return(pFlag->error);
951 else if ((strcmp(argv[ArgIdx],"-k") == 0) || (strcmp(argv[ArgIdx],"--keepdate") == 0))
953 else if ((strcmp(argv[ArgIdx],"-f") == 0) || (strcmp(argv[ArgIdx],"--force") == 0))
955 else if ((strcmp(argv[ArgIdx],"-s") == 0) || (strcmp(argv[ArgIdx],"--safe") == 0))
957 else if ((strcmp(argv[ArgIdx],"-q") == 0) || (strcmp(argv[ArgIdx],"--quiet") == 0))
959 else if ((strcmp(argv[ArgIdx],"-l") == 0) || (strcmp(argv[ArgIdx],"--newline") == 0))
961 else if ((strcmp(argv[ArgIdx],"-m") == 0) || (strcmp(argv[ArgIdx],"--add-bom") == 0))
963 else if ((strcmp(argv[ArgIdx],"-S") == 0) || (strcmp(argv[ArgIdx],"--skip-symlink") == 0))
964 pFlag->Follow = SYMLINK_SKIP;
965 else if ((strcmp(argv[ArgIdx],"-F") == 0) || (strcmp(argv[ArgIdx],"--follow-symlink") == 0))
966 pFlag->Follow = SYMLINK_FOLLOW;
967 else if ((strcmp(argv[ArgIdx],"-R") == 0) || (strcmp(argv[ArgIdx],"--replace-symlink") == 0))
968 pFlag->Follow = SYMLINK_REPLACE;
969 else if ((strcmp(argv[ArgIdx],"-V") == 0) || (strcmp(argv[ArgIdx],"--version") == 0))
971 PrintVersion(progname);
973 PrintLocaledir(localedir);
975 return(pFlag->error);
977 else if ((strcmp(argv[ArgIdx],"-L") == 0) || (strcmp(argv[ArgIdx],"--license") == 0))
980 return(pFlag->error);
982 else if (strcmp(argv[ArgIdx],"-ascii") == 0) /* SunOS compatible options */
983 pFlag->ConvMode = CONVMODE_ASCII;
984 else if (strcmp(argv[ArgIdx],"-7") == 0)
985 pFlag->ConvMode = CONVMODE_7BIT;
986 else if (strcmp(argv[ArgIdx],"-iso") == 0)
988 pFlag->ConvMode = (int)query_con_codepage();
991 fprintf(stderr,"%s: ",progname);
992 fprintf(stderr,_("active code page: %d\n"), pFlag->ConvMode);
994 if (pFlag->ConvMode < 2)
995 pFlag->ConvMode = CONVMODE_437;
997 else if (strcmp(argv[ArgIdx],"-437") == 0)
998 pFlag->ConvMode = CONVMODE_437;
999 else if (strcmp(argv[ArgIdx],"-850") == 0)
1000 pFlag->ConvMode = CONVMODE_850;
1001 else if (strcmp(argv[ArgIdx],"-860") == 0)
1002 pFlag->ConvMode = CONVMODE_860;
1003 else if (strcmp(argv[ArgIdx],"-863") == 0)
1004 pFlag->ConvMode = CONVMODE_863;
1005 else if (strcmp(argv[ArgIdx],"-865") == 0)
1006 pFlag->ConvMode = CONVMODE_865;
1007 else if (strcmp(argv[ArgIdx],"-1252") == 0)
1008 pFlag->ConvMode = CONVMODE_1252;
1010 else if ((strcmp(argv[ArgIdx],"-ul") == 0) || (strcmp(argv[ArgIdx],"--assume-utf16le") == 0))
1011 pFlag->ConvMode = CONVMODE_UTF16LE;
1012 else if ((strcmp(argv[ArgIdx],"-ub") == 0) || (strcmp(argv[ArgIdx],"--assume-utf16be") == 0))
1013 pFlag->ConvMode = CONVMODE_UTF16BE;
1015 else if ((strcmp(argv[ArgIdx],"-c") == 0) || (strcmp(argv[ArgIdx],"--convmode") == 0))
1017 if (++ArgIdx < argc)
1019 if (strcmpi(argv[ArgIdx],"ascii") == 0) /* Benjamin Lin's legacy options */
1020 pFlag->ConvMode = CONVMODE_ASCII;
1021 else if (strcmpi(argv[ArgIdx], "7bit") == 0)
1022 pFlag->ConvMode = CONVMODE_7BIT;
1023 else if (strcmpi(argv[ArgIdx], "iso") == 0)
1025 pFlag->ConvMode = (int)query_con_codepage();
1028 fprintf(stderr,"%s: ",progname);
1029 fprintf(stderr,_("active code page: %d\n"), pFlag->ConvMode);
1031 if (pFlag->ConvMode < 2)
1032 pFlag->ConvMode = CONVMODE_437;
1034 else if (strcmpi(argv[ArgIdx], "mac") == 0)
1035 pFlag->FromToMode = FROMTO_UNIX2MAC;
1038 fprintf(stderr,"%s: ",progname);
1039 fprintf(stderr, _("invalid %s conversion mode specified\n"),argv[ArgIdx]);
1042 pFlag->stdio_mode = 0;
1048 fprintf(stderr,"%s: ",progname);
1049 fprintf(stderr,_("option '%s' requires an argument\n"),argv[ArgIdx]);
1052 pFlag->stdio_mode = 0;
1056 else if ((strcmp(argv[ArgIdx],"-o") == 0) || (strcmp(argv[ArgIdx],"--oldfile") == 0))
1058 /* last convert not paired */
1059 if (!CanSwitchFileMode)
1061 fprintf(stderr,"%s: ",progname);
1062 fprintf(stderr, _("target of file %s not specified in new-file mode\n"), argv[ArgIdx-1]);
1065 pFlag->stdio_mode = 0;
1070 else if ((strcmp(argv[ArgIdx],"-n") == 0) || (strcmp(argv[ArgIdx],"--newfile") == 0))
1072 /* last convert not paired */
1073 if (!CanSwitchFileMode)
1075 fprintf(stderr,"%s: ",progname);
1076 fprintf(stderr, _("target of file %s not specified in new-file mode\n"), argv[ArgIdx-1]);
1079 pFlag->stdio_mode = 0;
1083 else { /* wrong option */
1084 PrintUsage(progname);
1087 pFlag->stdio_mode = 0;
1092 pFlag->stdio_mode = 0;
1096 if (CanSwitchFileMode)
1097 CanSwitchFileMode = 0;
1100 RetVal = ConvertUnixToDosNewFile(argv[ArgIdx-1], argv[ArgIdx], pFlag, progname);
1101 if (pFlag->status & NO_REGFILE)
1105 fprintf(stderr,"%s: ",progname);
1106 fprintf(stderr, _("Skipping %s, not a regular file.\n"), argv[ArgIdx-1]);
1108 } else if (pFlag->status & OUTPUTFILE_SYMLINK)
1112 fprintf(stderr,"%s: ",progname);
1113 fprintf(stderr, _("Skipping %s, output file %s is a symbolic link.\n"), argv[ArgIdx-1], argv[ArgIdx]);
1115 } else if (pFlag->status & INPUT_TARGET_NO_REGFILE)
1119 fprintf(stderr,"%s: ",progname);
1120 fprintf(stderr, _("Skipping symbolic link %s, target is not a regular file.\n"), argv[ArgIdx-1]);
1122 } else if (pFlag->status & OUTPUT_TARGET_NO_REGFILE)
1126 fprintf(stderr,"%s: ",progname);
1127 fprintf(stderr, _("Skipping %s, target of symbolic link %s is not a regular file.\n"), argv[ArgIdx-1], argv[ArgIdx]);
1129 } else if (pFlag->status & BINARY_FILE)
1133 fprintf(stderr,"%s: ",progname);
1134 fprintf(stderr, _("Skipping binary file %s\n"), argv[ArgIdx-1]);
1136 } else if (pFlag->status & WRONG_CODEPAGE)
1140 fprintf(stderr,"%s: ",progname);
1141 fprintf(stderr, _("code page %d is not supported.\n"), pFlag->ConvMode);
1143 } else if (pFlag->status & LOCALE_NOT_UTF8)
1147 fprintf(stderr,"%s: ",progname);
1148 fprintf(stderr, _("Skipping UTF-16 file %s, the current locale character encoding is not UTF-8.\n"), argv[ArgIdx-1]);
1150 } else if (pFlag->status & WCHAR_T_TOO_SMALL)
1154 fprintf(stderr,"%s: ",progname);
1155 fprintf(stderr, _("Skipping UTF-16 file %s, the size of wchar_t is %d bytes.\n"), argv[ArgIdx-1], (int)sizeof(wchar_t));
1157 } else if (pFlag->status & UNICODE_CONVERSION_ERROR)
1161 fprintf(stderr,"%s: ",progname);
1162 fprintf(stderr, _("Skipping UTF-16 file %s, an UTF-16 conversion error occurred.\n"), argv[ArgIdx-1]);
1167 fprintf(stderr,"%s: ",progname);
1168 if (pFlag->FromToMode == FROMTO_UNIX2MAC)
1169 fprintf(stderr, _("converting file %s to file %s in Mac format...\n"), argv[ArgIdx-1], argv[ArgIdx]);
1171 fprintf(stderr, _("converting file %s to file %s in DOS format...\n"), argv[ArgIdx-1], argv[ArgIdx]);
1177 fprintf(stderr,"%s: ",progname);
1178 fprintf(stderr, _("problems converting file %s to file %s\n"), argv[ArgIdx-1], argv[ArgIdx]);
1182 CanSwitchFileMode = 1;
1187 RetVal = ConvertUnixToDosNewFile(argv[ArgIdx], argv[ArgIdx], pFlag, progname);
1188 if (pFlag->status & NO_REGFILE)
1192 fprintf(stderr,"%s: ",progname);
1193 fprintf(stderr, _("Skipping %s, not a regular file.\n"), argv[ArgIdx]);
1195 } else if (pFlag->status & OUTPUTFILE_SYMLINK)
1199 fprintf(stderr,"%s: ",progname);
1200 fprintf(stderr, _("Skipping symbolic link %s.\n"), argv[ArgIdx]);
1202 } else if (pFlag->status & INPUT_TARGET_NO_REGFILE)
1206 fprintf(stderr,"%s: ",progname);
1207 fprintf(stderr, _("Skipping symbolic link %s, target is not a regular file.\n"), argv[ArgIdx]);
1209 } else if (pFlag->status & BINARY_FILE)
1213 fprintf(stderr,"%s: ",progname);
1214 fprintf(stderr, _("Skipping binary file %s\n"), argv[ArgIdx]);
1216 } else if (pFlag->status & WRONG_CODEPAGE)
1220 fprintf(stderr,"%s: ",progname);
1221 fprintf(stderr, _("code page %d is not supported.\n"), pFlag->ConvMode);
1223 } else if (pFlag->status & LOCALE_NOT_UTF8)
1227 fprintf(stderr,"%s: ",progname);
1228 fprintf(stderr, _("Skipping UTF-16 file %s, the current locale character encoding is not UTF-8.\n"), argv[ArgIdx]);
1230 } else if (pFlag->status & WCHAR_T_TOO_SMALL)
1234 fprintf(stderr,"%s: ",progname);
1235 fprintf(stderr, _("Skipping UTF-16 file %s, the size of wchar_t is %d bytes.\n"), argv[ArgIdx], (int)sizeof(wchar_t));
1237 } else if (pFlag->status & UNICODE_CONVERSION_ERROR)
1241 fprintf(stderr,"%s: ",progname);
1242 fprintf(stderr, _("Skipping UTF-16 file %s, an UTF-16 conversion error occurred.\n"), argv[ArgIdx]);
1247 fprintf(stderr,"%s: ",progname);
1248 if (pFlag->FromToMode == FROMTO_UNIX2MAC)
1249 fprintf(stderr, _("converting file %s to Mac format...\n"), argv[ArgIdx]);
1251 fprintf(stderr, _("converting file %s to DOS format...\n"), argv[ArgIdx]);
1257 fprintf(stderr,"%s: ",progname);
1258 fprintf(stderr, _("problems converting file %s\n"), argv[ArgIdx]);
1266 /* no file argument, use stdin and stdout */
1267 if (pFlag->stdio_mode)
1269 exit(ConvertUnixToDosStdio(pFlag, progname));
1273 if (!CanSwitchFileMode)
1275 fprintf(stderr,"%s: ",progname);
1276 fprintf(stderr, _("target of file %s not specified in new-file mode\n"), argv[ArgIdx-1]);
1279 return (pFlag->error);