d26404dd0474396e2fc54b3e48da5cee05333708
[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-2015 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-2015 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 %u\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 %u\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           } else{
204             /* TempChar is an LF */
205             if (PreviousChar != 0x0d) /* CR already counted */
206               ++line_nr;
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 */
210                   RetVal = -1;
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);
217                     }
218                   }
219                   break;
220                 }
221               PreviousChar = TempChar;
222               continue;
223             }
224             PreviousChar = TempChar;
225             if (d2u_putwc(0x0d, ipOutF, ipFlag) == WEOF) { /* Unix line end (LF). Put CR */
226                 RetVal = -1;
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);
233                   }
234                 }
235                 break;
236               }
237             converted++;
238             if (ipFlag->NewLine) {  /* add additional CR? */
239               d2u_putwc(0x0d, ipOutF, ipFlag);
240             }
241           }
242         }
243         break;
244       default: /* unknown FromToMode */
245       ;
246 #if DEBUG
247       fprintf(stderr, "%s: ", progname);
248       fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
249       exit(1);
250 #endif
251     }
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);
255     }
256     return RetVal;
257 }
258 #endif
259
260 /* converts stream ipInF to DOS format text and write to stream ipOutF
261  * RetVal: 0  if success
262  *         -1  otherwise
263  */
264 int ConvertUnixToDos(FILE* ipInF, FILE* ipOutF, CFlag *ipFlag, const char *progname)
265 {
266     int RetVal = 0;
267     int TempChar;
268     int PreviousChar = 0;
269     int *ConvTable;
270     unsigned int line_nr = 1;
271     unsigned int converted = 0;
272     char *errstr;
273
274     ipFlag->status = 0;
275
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;
281         break;
282       case CONVMODE_7BIT: /* 7bit */
283         ConvTable = U2D7BitTable;
284         break;
285       case CONVMODE_437: /* iso */
286         ConvTable = U2DIso437Table;
287         break;
288       case CONVMODE_850: /* iso */
289         ConvTable = U2DIso850Table;
290         break;
291       case CONVMODE_860: /* iso */
292         ConvTable = U2DIso860Table;
293         break;
294       case CONVMODE_863: /* iso */
295         ConvTable = U2DIso863Table;
296         break;
297       case CONVMODE_865: /* iso */
298         ConvTable = U2DIso865Table;
299         break;
300       case CONVMODE_1252: /* iso */
301         ConvTable = U2DIso1252Table;
302         break;
303       default: /* unknown convmode */
304         ipFlag->status |= WRONG_CODEPAGE ;
305         return(-1);
306     }
307     /* Turn off ISO and 7-bit conversion for Unicode text files */
308     if (ipFlag->bomtype > 0)
309       ConvTable = U2DAsciiTable;
310
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);
314     }
315
316     /* LF    -> CR-LF */
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) */
320
321     switch (ipFlag->FromToMode) {
322       case FROMTO_UNIX2DOS: /* unix2dos */
323         while ((TempChar = fgetc(ipInF)) != EOF) {  /* get character */
324           if ((ipFlag->Force == 0) &&
325               (TempChar < 32) &&
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 */
330             RetVal = -1;
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);
336             }
337             break;
338           }
339           if (TempChar == '\x0a')
340           {
341             fputc('\x0d', ipOutF); /* got LF, put extra CR */
342             converted++;
343           } else {
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. */
347                else {
348                  fputc('\x0d', ipOutF); /* put CR */
349                  PreviousChar = '\x0d';
350                }
351              }
352           }
353           if (TempChar == '\x0a') /* Count all DOS and Unix line breaks */
354             ++line_nr;
355           if (fputc(ConvTable[TempChar], ipOutF) == EOF) { /* put LF or other char */
356               RetVal = -1;
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);
362               }
363               break;
364           } else {
365             AddDOSNewLine( ipOutF, ipFlag, TempChar, PreviousChar);
366           }
367           PreviousChar = TempChar;
368         }
369         break;
370       case FROMTO_UNIX2MAC: /* unix2mac */
371         while ((TempChar = fgetc(ipInF)) != EOF) {
372           if ((ipFlag->Force == 0) &&
373               (TempChar < 32) &&
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 */
378             RetVal = -1;
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);
384             }
385             break;
386           }
387           if (TempChar != '\x0a') { /* Not an LF */
388             if(fputc(ConvTable[TempChar], ipOutF) == EOF) {
389               RetVal = -1;
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);
395               }
396               break;
397             }
398             PreviousChar = TempChar;
399             if (TempChar == '\x0d') /* CR */
400               ++line_nr;
401           } else {
402             /* TempChar is an LF */
403             if (PreviousChar != '\x0d') /* CR already counted */
404               ++line_nr;
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 */
408                   RetVal = -1;
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);
414                   }
415                   break;
416                 }
417               PreviousChar = TempChar;
418               continue;
419             }
420             PreviousChar = TempChar;
421             if (fputc('\x0d', ipOutF) == EOF) { /* Unix line end (LF). Put CR */
422                 RetVal = -1;
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);
428                 }
429                 break;
430               }
431             converted++;
432             if (ipFlag->NewLine) {  /* add additional CR? */
433               fputc('\x0d', ipOutF);
434             }
435           }
436         }
437         break;
438       default: /* unknown FromToMode */
439       ;
440 #if DEBUG
441       fprintf(stderr, "%s: ", progname);
442       fprintf(stderr, _("program error, invalid conversion mode %d\n"),ipFlag->FromToMode);
443       exit(1);
444 #endif
445     }
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);
449     }
450     return RetVal;
451 }
452
453
454 int main (int argc, char *argv[])
455 {
456   /* variable declarations */
457   char progname[9];
458   CFlag *pFlag;
459   char *ptr;
460   char localedir[1024];
461 # ifdef __MINGW64__
462   int _dowildcard = -1; /* enable wildcard expansion for Win64 */
463 # endif
464
465   progname[8] = '\0';
466   strcpy(progname,"unix2dos");
467
468 #ifdef ENABLE_NLS
469    ptr = getenv("DOS2UNIX_LOCALEDIR");
470    if (ptr == NULL)
471       strcpy(localedir,LOCALEDIR);
472    else {
473       if (strlen(ptr) < sizeof(localedir))
474          strcpy(localedir,ptr);
475       else {
476          fprintf(stderr,"%s: ",progname);
477          fprintf(stderr, "%s", _("error: Value of environment variable DOS2UNIX_LOCALEDIR is too long.\n"));
478          strcpy(localedir,LOCALEDIR);
479       }
480    }
481 #endif
482
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, "");
486 #endif
487
488 #ifdef ENABLE_NLS
489    bindtextdomain (PACKAGE, localedir);
490    textdomain (PACKAGE);
491 #endif
492
493
494   /* variable initialisations */
495   pFlag = (CFlag*)malloc(sizeof(CFlag));
496   pFlag->FromToMode = FROMTO_UNIX2DOS;  /* default unix2dos */
497   pFlag->keep_bom = 1;
498
499   if ( ((ptr=strrchr(argv[0],'/')) == NULL) && ((ptr=strrchr(argv[0],'\\')) == NULL) )
500     ptr = argv[0];
501   else
502     ptr++;
503
504   if ((strcmpi("unix2mac", ptr) == 0) || (strcmpi("unix2mac.exe", ptr) == 0)) {
505     pFlag->FromToMode = FROMTO_UNIX2MAC;
506     strcpy(progname,"unix2mac");
507   }
508
509 #ifdef D2U_UNICODE
510   return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos, ConvertUnixToDosW);
511 #else
512   return parse_options(argc, argv, pFlag, localedir, progname, PrintLicense, ConvertUnixToDos);
513 #endif
514 }
515