Initial public busybox maemo commit, 3:1.10.2.legal-1osso12
[busybox4maemo] / coreutils / fold.c
1 /* vi: set sw=4 ts=4: */
2 /* fold -- wrap each input line to fit in specified width.
3
4    Written by David MacKenzie, djm@gnu.ai.mit.edu.
5    Copyright (C) 91, 1995-2002 Free Software Foundation, Inc.
6
7    Modified for busybox based on coreutils v 5.0
8    Copyright (C) 2003 Glenn McGrath
9
10    Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
11 */
12
13 #include "libbb.h"
14
15 /* Must match getopt32 call */
16 #define FLAG_COUNT_BYTES        1
17 #define FLAG_BREAK_SPACES       2
18 #define FLAG_WIDTH              4
19
20 /* Assuming the current column is COLUMN, return the column that
21    printing C will move the cursor to.
22    The first column is 0. */
23 static int adjust_column(int column, char c)
24 {
25         if (!(option_mask32 & FLAG_COUNT_BYTES)) {
26                 if (c == '\b') {
27                         if (column > 0)
28                                 column--;
29                 } else if (c == '\r')
30                         column = 0;
31                 else if (c == '\t')
32                         column = column + 8 - column % 8;
33                 else                    /* if (isprint (c)) */
34                         column++;
35         } else
36                 column++;
37         return column;
38 }
39
40 int fold_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
41 int fold_main(int argc, char **argv)
42 {
43         char *line_out = NULL;
44         int allocated_out = 0;
45         char *w_opt;
46         int width = 80;
47         int i;
48         int errs = 0;
49
50         if (ENABLE_INCLUDE_SUSv2) {
51                 /* Turn any numeric options into -w options.  */
52                 for (i = 1; i < argc; i++) {
53                         char const *a = argv[i];
54
55                         if (*a++ == '-') {
56                                 if (*a == '-' && !a[1]) /* "--" */
57                                         break;
58                                 if (isdigit(*a))
59                                         argv[i] = xasprintf("-w%s", a);
60                         }
61                 }
62         }
63
64         getopt32(argv, "bsw:", &w_opt);
65         if (option_mask32 & FLAG_WIDTH)
66                 width = xatoul_range(w_opt, 1, 10000);
67
68         argv += optind;
69         if (!*argv)
70                 *--argv = (char*)"-";
71
72         do {
73                 FILE *istream = fopen_or_warn_stdin(*argv);
74                 int c;
75                 int column = 0;         /* Screen column where next char will go. */
76                 int offset_out = 0;     /* Index in 'line_out' for next char. */
77
78                 if (istream == NULL) {
79                         errs |= EXIT_FAILURE;
80                         continue;
81                 }
82
83                 while ((c = getc(istream)) != EOF) {
84                         if (offset_out + 1 >= allocated_out) {
85                                 allocated_out += 1024;
86                                 line_out = xrealloc(line_out, allocated_out);
87                         }
88
89                         if (c == '\n') {
90                                 line_out[offset_out++] = c;
91                                 fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
92                                 column = offset_out = 0;
93                                 continue;
94                         }
95  rescan:
96                         column = adjust_column(column, c);
97
98                         if (column > width) {
99                                 /* This character would make the line too long.
100                                    Print the line plus a newline, and make this character
101                                    start the next line. */
102                                 if (option_mask32 & FLAG_BREAK_SPACES) {
103                                         /* Look for the last blank. */
104                                         int logical_end;
105
106                                         for (logical_end = offset_out - 1; logical_end >= 0; logical_end--) {
107                                                 if (isblank(line_out[logical_end])) {
108                                                         break;
109                                                 }
110                                         }
111                                         if (logical_end >= 0) {
112                                                 /* Found a blank.  Don't output the part after it. */
113                                                 logical_end++;
114                                                 fwrite(line_out, sizeof(char), (size_t) logical_end, stdout);
115                                                 bb_putchar('\n');
116                                                 /* Move the remainder to the beginning of the next line.
117                                                    The areas being copied here might overlap. */
118                                                 memmove(line_out, line_out + logical_end, offset_out - logical_end);
119                                                 offset_out -= logical_end;
120                                                 for (column = i = 0; i < offset_out; i++) {
121                                                         column = adjust_column(column, line_out[i]);
122                                                 }
123                                                 goto rescan;
124                                         }
125                                 } else {
126                                         if (offset_out == 0) {
127                                                 line_out[offset_out++] = c;
128                                                 continue;
129                                         }
130                                 }
131                                 line_out[offset_out++] = '\n';
132                                 fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
133                                 column = offset_out = 0;
134                                 goto rescan;
135                         }
136
137                         line_out[offset_out++] = c;
138                 }
139
140                 if (offset_out) {
141                         fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
142                 }
143
144                 if (fclose_if_not_stdin(istream)) {
145                         bb_simple_perror_msg(*argv);    /* Avoid multibyte problems. */
146                         errs |= EXIT_FAILURE;
147                 }
148         } while (*++argv);
149
150         fflush_stdout_and_exit(errs);
151 }