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-2015 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-2015 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, const char *progname)
106 wint_t PreviousChar = 0;
107 unsigned int line_nr = 1;
108 unsigned int converted = 0;
114 /* CR-LF -> CR-LF, in case the input file is a DOS text file */
115 /* \x0a = Newline/Line Feed (LF) */
116 /* \x0d = Carriage Return (CR) */
118 switch (ipFlag->FromToMode)
120 case FROMTO_UNIX2DOS: /* unix2dos */
121 while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) { /* get character */
122 if ((ipFlag->Force == 0) &&
124 (TempChar != 0x0a) && /* Not an LF */
125 (TempChar != 0x0d) && /* Not a CR */
126 (TempChar != 0x09) && /* Not a TAB */
127 (TempChar != 0x0c)) { /* Not a form feed */
129 ipFlag->status |= BINARY_FILE ;
130 if (ipFlag->verbose) {
131 if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
132 fprintf(stderr, "%s: ", progname);
133 fprintf(stderr, _("Binary symbol 0x00%02X found at line %u\n"), TempChar, line_nr);
137 if (TempChar == 0x0a) {
138 d2u_putwc(0x0d, ipOutF, ipFlag); /* got LF, put extra CR */
141 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. */
145 d2u_putwc(0x0d, ipOutF, ipFlag); /* put CR */
150 if (TempChar == 0x0a) /* Count all DOS and Unix line breaks */
152 if (d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF)
155 if (ipFlag->verbose) {
156 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
157 ipFlag->error = errno;
158 errstr = strerror(errno);
159 fprintf(stderr, "%s: ", progname);
160 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
165 AddDOSNewLineW( ipOutF, ipFlag, TempChar, PreviousChar);
167 PreviousChar = TempChar;
170 case FROMTO_UNIX2MAC: /* unix2mac */
171 while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) {
172 if ((ipFlag->Force == 0) &&
174 (TempChar != 0x0a) && /* Not an LF */
175 (TempChar != 0x0d) && /* Not a CR */
176 (TempChar != 0x09) && /* Not a TAB */
177 (TempChar != 0x0c)) { /* Not a form feed */
179 ipFlag->status |= BINARY_FILE ;
180 if (ipFlag->verbose) {
181 if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
182 fprintf(stderr, "%s: ", progname);
183 fprintf(stderr, _("Binary symbol 0x00%02X found at line %u\n"), TempChar, line_nr);
187 if (TempChar != 0x0a) { /* Not an LF */
188 if(d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF) {
190 if (ipFlag->verbose) {
191 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
192 ipFlag->error = errno;
193 errstr = strerror(errno);
194 fprintf(stderr, "%s: ", progname);
195 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
200 PreviousChar = TempChar;
201 if (TempChar == 0x0d) /* CR */
204 /* TempChar is an LF */
205 if (PreviousChar != 0x0d) /* CR already counted */
207 /* Don't touch this delimiter if it's a CR,LF pair. */
208 if ( PreviousChar == 0x0d ) {
209 if (d2u_putwc(0x0a, ipOutF, ipFlag) == WEOF) { /* CR,LF pair. Put LF */
211 if (ipFlag->verbose) {
212 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
213 ipFlag->error = errno;
214 errstr = strerror(errno);
215 fprintf(stderr, "%s: ", progname);
216 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
221 PreviousChar = TempChar;
224 PreviousChar = TempChar;
225 if (d2u_putwc(0x0d, ipOutF, ipFlag) == WEOF) { /* Unix line end (LF). Put CR */
227 if (ipFlag->verbose) {
228 if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
229 ipFlag->error = errno;
230 errstr = strerror(errno);
231 fprintf(stderr, "%s: ", progname);
232 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
238 if (ipFlag->NewLine) { /* add additional CR? */
239 d2u_putwc(0x0d, ipOutF, ipFlag);
244 default: /* unknown FromToMode */
247 fprintf(stderr, "%s: ", progname);
248 fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
252 if (ipFlag->verbose > 1) {
253 fprintf(stderr, "%s: ", progname);
254 fprintf(stderr, _("Converted %u out of %u line breaks.\n"), converted, line_nr -1);
260 /* converts stream ipInF to DOS format text and write to stream ipOutF
261 * RetVal: 0 if success
264 int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, const char *progname)
268 int PreviousChar = 0;
270 unsigned int line_nr = 1;
271 unsigned int converted = 0;
276 switch (ipFlag->ConvMode) {
277 case CONVMODE_ASCII: /* ascii */
278 case CONVMODE_UTF16LE: /* Assume UTF-16LE, bomtype = FILE_UTF8 or GB18030 */
279 case CONVMODE_UTF16BE: /* Assume UTF-16BE, bomtype = FILE_UTF8 or GB18030 */
280 ConvTable = U2DAsciiTable;
282 case CONVMODE_7BIT: /* 7bit */
283 ConvTable = U2D7BitTable;
285 case CONVMODE_437: /* iso */
286 ConvTable = U2DIso437Table;
288 case CONVMODE_850: /* iso */
289 ConvTable = U2DIso850Table;
291 case CONVMODE_860: /* iso */
292 ConvTable = U2DIso860Table;
294 case CONVMODE_863: /* iso */
295 ConvTable = U2DIso863Table;
297 case CONVMODE_865: /* iso */
298 ConvTable = U2DIso865Table;
300 case CONVMODE_1252: /* iso */
301 ConvTable = U2DIso1252Table;
303 default: /* unknown convmode */
304 ipFlag->status |= WRONG_CODEPAGE ;
307 /* Turn off ISO and 7-bit conversion for Unicode text files */
308 if (ipFlag->bomtype > 0)
309 ConvTable = U2DAsciiTable;
311 if ((ipFlag->ConvMode > CONVMODE_7BIT) && (ipFlag->verbose)) { /* not ascii or 7bit */
312 fprintf(stderr, "%s: ", progname);
313 fprintf(stderr, _("using code page %d.\n"), ipFlag->ConvMode);
317 /* CR-LF -> CR-LF, in case the input file is a DOS text file */
318 /* \x0a = Newline/Line Feed (LF) */
319 /* \x0d = Carriage Return (CR) */
321 switch (ipFlag->FromToMode) {
322 case FROMTO_UNIX2DOS: /* unix2dos */
323 while ((TempChar = fgetc(ipInF)) != EOF) { /* get character */
324 if ((ipFlag->Force == 0) &&
326 (TempChar != '\x0a') && /* Not an LF */
327 (TempChar != '\x0d') && /* Not a CR */
328 (TempChar != '\x09') && /* Not a TAB */
329 (TempChar != '\x0c')) { /* Not a form feed */
331 ipFlag->status |= BINARY_FILE ;
332 if (ipFlag->verbose) {
333 if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
334 fprintf(stderr, "%s: ", progname);
335 fprintf(stderr, _("Binary symbol 0x%02X found at line %u\n"), TempChar, line_nr);
339 if (TempChar == '\x0a')
341 fputc('\x0d', ipOutF); /* got LF, put extra CR */
344 if (TempChar == '\x0d') { /* got CR */
345 if ((TempChar = fgetc(ipInF)) == EOF) /* get next char (possibly LF) */
346 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 */
357 if (ipFlag->verbose) {
358 ipFlag->error = errno;
359 errstr = strerror(errno);
360 fprintf(stderr, "%s: ", progname);
361 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
365 AddDOSNewLine( ipOutF, ipFlag, TempChar, PreviousChar);
367 PreviousChar = TempChar;
370 case FROMTO_UNIX2MAC: /* unix2mac */
371 while ((TempChar = fgetc(ipInF)) != EOF) {
372 if ((ipFlag->Force == 0) &&
374 (TempChar != '\x0a') && /* Not an LF */
375 (TempChar != '\x0d') && /* Not a CR */
376 (TempChar != '\x09') && /* Not a TAB */
377 (TempChar != '\x0c')) { /* Not a form feed */
379 ipFlag->status |= BINARY_FILE ;
380 if (ipFlag->verbose) {
381 if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
382 fprintf(stderr, "%s: ", progname);
383 fprintf(stderr, _("Binary symbol 0x%02X found at line %u\n"), TempChar, line_nr);
387 if (TempChar != '\x0a') { /* Not an LF */
388 if(fputc(ConvTable[TempChar], ipOutF) == EOF) {
390 if (ipFlag->verbose) {
391 ipFlag->error = errno;
392 errstr = strerror(errno);
393 fprintf(stderr, "%s: ", progname);
394 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
398 PreviousChar = TempChar;
399 if (TempChar == '\x0d') /* CR */
402 /* TempChar is an LF */
403 if (PreviousChar != '\x0d') /* CR already counted */
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 */
409 if (ipFlag->verbose) {
410 ipFlag->error = errno;
411 errstr = strerror(errno);
412 fprintf(stderr, "%s: ", progname);
413 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
417 PreviousChar = TempChar;
420 PreviousChar = TempChar;
421 if (fputc('\x0d', ipOutF) == EOF) { /* Unix line end (LF). Put CR */
423 if (ipFlag->verbose) {
424 ipFlag->error = errno;
425 errstr = strerror(errno);
426 fprintf(stderr, "%s: ", progname);
427 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
432 if (ipFlag->NewLine) { /* add additional CR? */
433 fputc('\x0d', ipOutF);
438 default: /* unknown FromToMode */
441 fprintf(stderr, "%s: ", progname);
442 fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
446 if (ipFlag->verbose > 1) {
447 fprintf(stderr, "%s: ", progname);
448 fprintf(stderr, _("Converted %u out of %u line breaks.\n"), converted, line_nr -1);
454 int main (int argc, char *argv[])
456 /* variable declarations */
460 char localedir[1024];
462 int _dowildcard = -1; /* enable wildcard expansion for Win64 */
466 strcpy(progname,"unix2dos");
469 ptr = getenv("DOS2UNIX_LOCALEDIR");
471 strcpy(localedir,LOCALEDIR);
473 if (strlen(ptr) < sizeof(localedir))
474 strcpy(localedir,ptr);
476 fprintf(stderr,"%s: ",progname);
477 fprintf(stderr, "%s", _("error: Value of environment variable DOS2UNIX_LOCALEDIR is too long.\n"));
478 strcpy(localedir,LOCALEDIR);
483 #if defined(ENABLE_NLS) || (defined(D2U_UNICODE) && !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__))
484 /* setlocale() is also needed for nl_langinfo() */
485 setlocale (LC_ALL, "");
489 bindtextdomain (PACKAGE, localedir);
490 textdomain (PACKAGE);
494 /* variable initialisations */
495 pFlag = (CFlag*)malloc(sizeof(CFlag));
496 pFlag->FromToMode = FROMTO_UNIX2DOS; /* default unix2dos */
499 if ( ((ptr=strrchr(argv[0],'/')) == NULL) && ((ptr=strrchr(argv[0],'\\')) == NULL) )
504 if ((strcmpi("unix2mac", ptr) == 0) || (strcmpi("unix2mac.exe", ptr) == 0)) {
505 pFlag->FromToMode = FROMTO_UNIX2MAC;
506 strcpy(progname,"unix2mac");
510 return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos, ConvertUnixToDosW);
512 return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos);