6dac27455fed5a5acb29218027812e281db0925e
[platform/upstream/dos2unix.git] / unix2dos.c
1 /*
2  *  Name: unix2dos
3  *  Documentation:
4  *    Convert lf ('\x0a') characters in a file to cr lf ('\x0d' '\x0a')
5  *    combinations.
6  *
7  *  The dos2unix package is distributed under FreeBSD style license.
8  *  See also http://www.freebsd.org/copyright/freebsd-license.html
9  *  --------
10  *
11  *  Copyright (C) 2009-2014 Erwin Waterlander
12  *  Copyright (C) 1994-1995 Benjamin Lin.
13  *  All rights reserved.
14  *
15  *  Redistribution and use in source and binary forms, with or without
16  *  modification, are permitted provided that the following conditions
17  *  are met:
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
22  *     the distribution.
23  *
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.
35  *
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.
47  *
48  *  See ChangeLog.txt for complete version history.
49  *
50  */
51
52
53 /* #define DEBUG 1 */
54 #define __UNIX2DOS_C
55
56 #include "common.h"
57 #include "unix2dos.h"
58 #ifdef D2U_UNICODE
59 #if !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__)  /* Unix, Cygwin */
60 # include <langinfo.h>
61 #endif
62 #endif
63
64 void PrintLicense(void)
65 {
66   printf("%s", _("\
67 Copyright (C) 2009-2014 Erwin Waterlander\n\
68 Copyright (C) 1994-1995 Benjamin Lin\n\
69 All rights reserved.\n\n"));
70   PrintBSDLicense();
71 }
72
73 #ifdef D2U_UNICODE
74 void AddDOSNewLineW(FILE* ipOutF, CFlag *ipFlag, wint_t CurChar, wint_t PrevChar)
75 {
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);
81     }
82   }
83 }
84 #endif
85
86 void AddDOSNewLine(FILE* ipOutF, CFlag *ipFlag, int CurChar, int PrevChar)
87 {
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);
93     }
94   }
95 }
96
97 /* converts stream ipInF to DOS format text and write to stream ipOutF
98  * RetVal: 0  if success
99  *         -1  otherwise
100  */
101 #ifdef D2U_UNICODE
102 int ConvertUnixToDosW(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, const char *progname)
103 {
104     int RetVal = 0;
105     wint_t TempChar;
106     wint_t PreviousChar = 0;
107     unsigned int line_nr = 1;
108     unsigned int converted = 0;
109     char *errstr;
110
111     ipFlag->status = 0;
112
113     /* LF    -> CR-LF */
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) */
117
118     switch (ipFlag->FromToMode)
119     {
120       case FROMTO_UNIX2DOS: /* unix2dos */
121         while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) {  /* get character */
122           if ((ipFlag->Force == 0) &&
123               (TempChar < 32) &&
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 */
128             RetVal = -1;
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 %d\n"),TempChar, line_nr);
134             }
135             break;
136           }
137           if (TempChar == 0x0a) {
138             d2u_putwc(0x0d, ipOutF, ipFlag); /* got LF, put extra CR */
139             converted++;
140           } else {
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. */
144                else {
145                  d2u_putwc(0x0d, ipOutF, ipFlag); /* put CR */
146                  PreviousChar = 0x0d;
147                }
148              }
149           }
150           if (TempChar == 0x0a) /* Count all DOS and Unix line breaks */
151             ++line_nr;
152           if (d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF)
153           {
154               RetVal = -1;
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);
161                 }
162               }
163               break;
164           } else {
165             AddDOSNewLineW( ipOutF, ipFlag, TempChar, PreviousChar);
166           }
167           PreviousChar = TempChar;
168         }
169         break;
170       case FROMTO_UNIX2MAC: /* unix2mac */
171         while ((TempChar = d2u_getwc(ipInF, ipFlag->bomtype)) != WEOF) {
172           if ((ipFlag->Force == 0) &&
173               (TempChar < 32) &&
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 */
178             RetVal = -1;
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 %d\n"),TempChar, line_nr);
184             }
185             break;
186           }
187           if (TempChar != 0x0a) { /* Not an LF */
188             if(d2u_putwc(TempChar, ipOutF, ipFlag) == WEOF) {
189               RetVal = -1;
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);
196                 }
197               }
198               break;
199             }
200             PreviousChar = TempChar;
201             if (TempChar == 0x0d) /* CR */
202               ++line_nr;
203           }
204           else{
205             /* TempChar is an LF */
206             if (PreviousChar != 0x0d) /* CR already counted */
207               ++line_nr;
208             /* Don't touch this delimiter if it's a CR,LF pair. */
209             if ( PreviousChar == 0x0d ) {
210               if (d2u_putwc(0x0a, ipOutF, ipFlag) == WEOF) { /* CR,LF pair. Put LF */
211                   RetVal = -1;
212                   if (ipFlag->verbose) {
213                     if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
214                       ipFlag->error = errno;
215                       errstr = strerror(errno);
216                       fprintf(stderr, "%s: ", progname);
217                       fprintf(stderr, _("can not write to output file: %s\n"), errstr);
218                     }
219                   }
220                   break;
221                 }
222               PreviousChar = TempChar;
223               continue;
224             }
225             PreviousChar = TempChar;
226             if (d2u_putwc(0x0d, ipOutF, ipFlag) == WEOF) { /* Unix line end (LF). Put CR */
227                 RetVal = -1;
228                 if (ipFlag->verbose) {
229                   if (!(ipFlag->status & UNICODE_CONVERSION_ERROR)) {
230                     ipFlag->error = errno;
231                     errstr = strerror(errno);
232                     fprintf(stderr, "%s: ", progname);
233                     fprintf(stderr, _("can not write to output file: %s\n"), errstr);
234                   }
235                 }
236                 break;
237               }
238             converted++;
239             if (ipFlag->NewLine) {  /* add additional CR? */
240               d2u_putwc(0x0d, ipOutF, ipFlag);
241             }
242           }
243         }
244         break;
245       default: /* unknown FromToMode */
246       ;
247 #if DEBUG
248       fprintf(stderr, "%s: ", progname);
249       fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
250       exit(1);
251 #endif
252     }
253     if (ipFlag->verbose > 1) {
254       fprintf(stderr, "%s: ", progname);
255       fprintf(stderr, _("Converted %d out of %d line breaks.\n"),converted, line_nr -1);
256     }
257     return RetVal;
258 }
259 #endif
260
261 /* converts stream ipInF to DOS format text and write to stream ipOutF
262  * RetVal: 0  if success
263  *         -1  otherwise
264  */
265 int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, const char *progname)
266 {
267     int RetVal = 0;
268     int TempChar;
269     int PreviousChar = 0;
270     int *ConvTable;
271     unsigned int line_nr = 1;
272     unsigned int converted = 0;
273     char *errstr;
274
275     ipFlag->status = 0;
276
277     switch (ipFlag->ConvMode) {
278       case CONVMODE_ASCII: /* ascii */
279       case CONVMODE_UTF16LE: /* Assume UTF-16LE, bomtype = FILE_UTF8 */
280       case CONVMODE_UTF16BE: /* Assume UTF-16BE, bomtype = FILE_UTF8 */
281         ConvTable = U2DAsciiTable;
282         break;
283       case CONVMODE_7BIT: /* 7bit */
284         ConvTable = U2D7BitTable;
285         break;
286       case CONVMODE_437: /* iso */
287         ConvTable = U2DIso437Table;
288         break;
289       case CONVMODE_850: /* iso */
290         ConvTable = U2DIso850Table;
291         break;
292       case CONVMODE_860: /* iso */
293         ConvTable = U2DIso860Table;
294         break;
295       case CONVMODE_863: /* iso */
296         ConvTable = U2DIso863Table;
297         break;
298       case CONVMODE_865: /* iso */
299         ConvTable = U2DIso865Table;
300         break;
301       case CONVMODE_1252: /* iso */
302         ConvTable = U2DIso1252Table;
303         break;
304       default: /* unknown convmode */
305         ipFlag->status |= WRONG_CODEPAGE ;
306         return(-1);
307     }
308     /* Turn off ISO and 7-bit conversion for Unicode text files */
309     if (ipFlag->bomtype > 0)
310       ConvTable = U2DAsciiTable;
311
312     if ((ipFlag->ConvMode > CONVMODE_7BIT) && (ipFlag->verbose)) { /* not ascii or 7bit */
313        fprintf(stderr, "%s: ", progname);
314        fprintf(stderr, _("using code page %d.\n"), ipFlag->ConvMode);
315     }
316
317     /* LF    -> CR-LF */
318     /* CR-LF -> CR-LF, in case the input file is a DOS text file */
319     /* \x0a = Newline/Line Feed (LF) */
320     /* \x0d = Carriage Return (CR) */
321
322     switch (ipFlag->FromToMode) {
323       case FROMTO_UNIX2DOS: /* unix2dos */
324         while ((TempChar = fgetc(ipInF)) != EOF) {  /* get character */
325           if ((ipFlag->Force == 0) &&
326               (TempChar < 32) &&
327               (TempChar != '\x0a') &&  /* Not an LF */
328               (TempChar != '\x0d') &&  /* Not a CR */
329               (TempChar != '\x09') &&  /* Not a TAB */
330               (TempChar != '\x0c')) {  /* Not a form feed */
331             RetVal = -1;
332             ipFlag->status |= BINARY_FILE ;
333             if (ipFlag->verbose) {
334               if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
335               fprintf(stderr, "%s: ", progname);
336               fprintf(stderr, _("Binary symbol 0x%02X found at line %d\n"),TempChar, line_nr);
337             }
338             break;
339           }
340           if (TempChar == '\x0a')
341           {
342             fputc('\x0d', ipOutF); /* got LF, put extra CR */
343             converted++;
344           } else {
345              if (TempChar == '\x0d') { /* got CR */
346                if ((TempChar = fgetc(ipInF)) == EOF) /* get next char (possibly LF) */
347                  TempChar = '\x0d';  /* Read error, or end of file. */
348                else {
349                  fputc('\x0d', ipOutF); /* put CR */
350                  PreviousChar = '\x0d';
351                }
352              }
353           }
354           if (TempChar == '\x0a') /* Count all DOS and Unix line breaks */
355             ++line_nr;
356           if (fputc(ConvTable[TempChar], ipOutF) == EOF) { /* put LF or other char */
357               RetVal = -1;
358               if (ipFlag->verbose) {
359                 ipFlag->error = errno;
360                 errstr = strerror(errno);
361                 fprintf(stderr, "%s: ", progname);
362                 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
363               }
364               break;
365           } else {
366             AddDOSNewLine( ipOutF, ipFlag, TempChar, PreviousChar);
367           }
368           PreviousChar = TempChar;
369         }
370         break;
371       case FROMTO_UNIX2MAC: /* unix2mac */
372         while ((TempChar = fgetc(ipInF)) != EOF) {
373           if ((ipFlag->Force == 0) &&
374               (TempChar < 32) &&
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 */
379             RetVal = -1;
380             ipFlag->status |= BINARY_FILE ;
381             if (ipFlag->verbose) {
382               if ((ipFlag->stdio_mode) && (!ipFlag->error)) ipFlag->error = 1;
383               fprintf(stderr, "%s: ", progname);
384               fprintf(stderr, _("Binary symbol 0x%02X found at line %d\n"),TempChar, line_nr);
385             }
386             break;
387           }
388           if (TempChar != '\x0a') { /* Not an LF */
389             if(fputc(ConvTable[TempChar], ipOutF) == EOF) {
390               RetVal = -1;
391               if (ipFlag->verbose) {
392                 ipFlag->error = errno;
393                 errstr = strerror(errno);
394                 fprintf(stderr, "%s: ", progname);
395                 fprintf(stderr, _("can not write to output file: %s\n"), errstr);
396               }
397               break;
398             }
399             PreviousChar = TempChar;
400             if (TempChar == '\x0d') /* CR */
401               ++line_nr;
402           }
403           else {
404             /* TempChar is an LF */
405             if (PreviousChar != '\x0d') /* CR already counted */
406               ++line_nr;
407             /* Don't touch this delimiter if it's a CR,LF pair. */
408             if ( PreviousChar == '\x0d' ) {
409               if (fputc('\x0a', ipOutF) == EOF) { /* CR,LF pair. Put LF */
410                   RetVal = -1;
411                   if (ipFlag->verbose) {
412                     ipFlag->error = errno;
413                     errstr = strerror(errno);
414                     fprintf(stderr, "%s: ", progname);
415                     fprintf(stderr, _("can not write to output file: %s\n"), errstr);
416                   }
417                   break;
418                 }
419               PreviousChar = TempChar;
420               continue;
421             }
422             PreviousChar = TempChar;
423             if (fputc('\x0d', ipOutF) == EOF) { /* Unix line end (LF). Put CR */
424                 RetVal = -1;
425                 if (ipFlag->verbose) {
426                   ipFlag->error = errno;
427                   errstr = strerror(errno);
428                   fprintf(stderr, "%s: ", progname);
429                   fprintf(stderr, _("can not write to output file: %s\n"), errstr);
430                 }
431                 break;
432               }
433             converted++;
434             if (ipFlag->NewLine) {  /* add additional CR? */
435               fputc('\x0d', ipOutF);
436             }
437           }
438         }
439         break;
440       default: /* unknown FromToMode */
441       ;
442 #if DEBUG
443       fprintf(stderr, "%s: ", progname);
444       fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
445       exit(1);
446 #endif
447     }
448     if (ipFlag->verbose > 1) {
449       fprintf(stderr, "%s: ", progname);
450       fprintf(stderr, _("Converted %d out of %d line breaks.\n"),converted, line_nr -1);
451     }
452     return RetVal;
453 }
454
455
456 int main (int argc, char *argv[])
457 {
458   /* variable declarations */
459   char progname[9];
460   CFlag *pFlag;
461   char *ptr;
462   char localedir[1024];
463 # ifdef __MINGW64__
464   int _dowildcard = -1; /* enable wildcard expansion for Win64 */
465 # endif
466
467   progname[8] = '\0';
468   strcpy(progname,"unix2dos");
469
470 #ifdef ENABLE_NLS
471    ptr = getenv("DOS2UNIX_LOCALEDIR");
472    if (ptr == NULL)
473       strcpy(localedir,LOCALEDIR);
474    else {
475       if (strlen(ptr) < sizeof(localedir))
476          strcpy(localedir,ptr);
477       else {
478          fprintf(stderr,"%s: ",progname);
479          fprintf(stderr, "%s", _("error: Value of environment variable DOS2UNIX_LOCALEDIR is too long.\n"));
480          strcpy(localedir,LOCALEDIR);
481       }
482    }
483 #endif
484
485 #if defined(ENABLE_NLS) || (defined(D2U_UNICODE) && !defined(__MSDOS__) && !defined(_WIN32) && !defined(__OS2__))
486 /* setlocale() is also needed for nl_langinfo() */
487    setlocale (LC_ALL, "");
488 #endif
489
490 #ifdef ENABLE_NLS
491    bindtextdomain (PACKAGE, localedir);
492    textdomain (PACKAGE);
493 #endif
494
495
496   /* variable initialisations */
497   pFlag = (CFlag*)malloc(sizeof(CFlag));
498   pFlag->FromToMode = FROMTO_UNIX2DOS;  /* default unix2dos */
499   pFlag->keep_bom = 1;
500
501   if ( ((ptr=strrchr(argv[0],'/')) == NULL) && ((ptr=strrchr(argv[0],'\\')) == NULL) )
502     ptr = argv[0];
503   else
504     ptr++;
505
506   if ((strcmpi("unix2mac", ptr) == 0) || (strcmpi("unix2mac.exe", ptr) == 0)) {
507     pFlag->FromToMode = FROMTO_UNIX2MAC;
508     strcpy(progname,"unix2mac");
509   }
510
511 #ifdef D2U_UNICODE
512   return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos, ConvertUnixToDosW);
513 #else
514   return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos);
515 #endif
516 }
517