8d6cd954d3b497cac4bd90b5ae4e0d3868291e49
[oweals/busybox.git] / coreutils / dos2unix.c
1 /*
2  * dos2unix for BusyBox
3  *
4  * dos2unix '\n' convertor 0.5.0
5  * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
6  * Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
7  * All rights reserved.
8  *
9  * dos2unix filters reading input from stdin and writing output to stdout.
10  * Without arguments it reverts the format (e.i. if source is in UNIX format,
11  * output is in DOS format and vice versa).
12  *
13  *  Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
14 */
15
16 #include <string.h>
17 #include <unistd.h>
18 #include <stdint.h>
19 #include <fcntl.h>
20 #include <sys/time.h>
21 #include "busybox.h"
22
23 #define CT_UNIX2DOS     1
24 #define CT_DOS2UNIX     2
25 #define tempFn bb_common_bufsiz1
26
27 /* if fn is NULL then input is stdin and output is stdout */
28 static int convert(char *fn, int ConvType)
29 {
30         int c, fd;
31         FILE *in, *out;
32
33         if (fn != NULL) {
34                 in = bb_xfopen(fn, "rw");
35                 /*
36                 The file is then created with mode read/write and
37                 permissions 0666 for glibc 2.0.6 and earlier or
38                 0600  for glibc  2.0.7 and  later. 
39                 */
40                 snprintf(tempFn, sizeof(tempFn), "%sXXXXXX", fn);
41                 /*
42                 sizeof tempFn is 4096, so it should be big enough to hold the full
43                 path. however if the output is truncated the subsequent call to
44                 mkstemp would fail.
45                 */
46                 if ((fd = mkstemp(&tempFn[0])) == -1 || chmod(tempFn, 0600) == -1) {
47                         bb_perror_nomsg_and_die();
48                 }
49                 out = fdopen(fd, "w+");
50                 if (!out) {
51                         close(fd);
52                         remove(tempFn);
53                 }
54         } else {
55                 in = stdin;
56                 out = stdout;
57         }
58
59         while ((c = fgetc(in)) != EOF) {
60                 if (c == '\r')
61                         continue;
62                 if (c == '\n') {
63                         if (ConvType == CT_UNIX2DOS)
64                                 fputc('\r', out);
65                         fputc('\n', out);
66                         continue;
67                 }
68                 fputc(c, out);
69         }
70
71         if (fn != NULL) {
72                 if (fclose(in) < 0 || fclose(out) < 0) {
73                         bb_perror_nomsg();
74                         remove(tempFn);
75                         return -2;
76             }
77         
78                 /* Assume they are both on the same filesystem (which
79                 * should be true since we put them into the same directory
80                 * so we _should_ be ok, but you never know... */
81                 if (rename(tempFn, fn) < 0) {
82                         bb_perror_msg("cannot rename '%s' as '%s'", tempFn, fn);
83                         return -1;
84             }
85         }
86
87         return 0;
88 }
89
90 int dos2unix_main(int argc, char *argv[])
91 {
92         int ConvType;
93         int o;
94
95         /* See if we are supposed to be doing dos2unix or unix2dos */
96         if (argv[0][0]=='d') {
97             ConvType = CT_DOS2UNIX;  /*1*/
98         } else {
99             ConvType = CT_UNIX2DOS;  /*2*/
100         }
101         /* -u and -d are mutally exclusive */
102         bb_opt_complementally = "?:u--d:d--u";
103         /* process parameters */
104         /* -u convert to unix */
105         /* -d convert to dos  */
106         o = bb_getopt_ulflags(argc, argv, "du");
107
108         /* Do the conversion requested by an argument else do the default
109          * conversion depending on our name.  */
110         if (o)
111                 ConvType = o;
112
113         if (optind < argc) {
114                 while(optind < argc)
115                         if ((o = convert(argv[optind++], ConvType)) < 0)
116                                 break;
117         }
118         else
119                 o = convert(NULL, ConvType);
120
121         return o;
122 }