source: branches/2.2.5/mindi-busybox/coreutils/expand.c @ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 13 years ago

Update to busybox 1.7.2

  • Property svn:eol-style set to native
File size: 4.7 KB
RevLine 
[1765]1/* expand - convert tabs to spaces
2 * unexpand - convert spaces to tabs
3 *
4 * Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc.
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 *
8 * David MacKenzie <djm@gnu.ai.mit.edu>
9 *
10 * Options for expand:
11 * -t num  --tabs=NUM      Convert tabs to num spaces (default 8 spaces).
12 * -i      --initial       Only convert initial tabs on each line to spaces.
13 *
14 * Options for unexpand:
15 * -a      --all           Convert all blanks, instead of just initial blanks.
16 * -f      --first-only    Convert only leading sequences of blanks (default).
17 * -t num  --tabs=NUM      Have tabs num characters apart instead of 8.
18 *
19 *  Busybox version (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
20 *
21 *  Caveat: this versions of expand and unexpand don't accept tab lists.
22 */
23
24#include "libbb.h"
25
26enum {
27    OPT_INITIAL     = 1 << 0,
28    OPT_TABS        = 1 << 1,
29    OPT_ALL         = 1 << 2,
30};
31
32static void xputchar(char c)
33{
34    if (putchar(c) < 0)
35        bb_error_msg_and_die(bb_msg_write_error);
36}
37
38#if ENABLE_EXPAND
39static void expand(FILE *file, unsigned tab_size, unsigned opt)
40{
41    char *line;
42    char *ptr;
43    int convert;
44    int pos;
45
46    /* Increment tab_size by 1 locally.*/
47    tab_size++;
48
49    while ((line = xmalloc_fgets(file)) != NULL) {
50        convert = 1;
51        pos = 0;
52        ptr = line;
53        while (*line) {
54            pos++;
55            if (*line == '\t' && convert) {
56                for (; pos < tab_size; pos++) {
57                    xputchar(' ');
58                }
59            } else {
60                if ((opt & OPT_INITIAL) && !isblank(*line)) {
61                    convert = 0;
62                }
63                xputchar(*line);
64            }
65            if (pos == tab_size) {
66                pos = 0;
67            }
68            line++;
69        }
70        free(ptr);
71    }
72}
73#endif
74
75#if ENABLE_UNEXPAND
76static void unexpand(FILE *file, unsigned int tab_size, unsigned opt)
77{
78    char *line;
79    char *ptr;
80    int convert;
81    int pos;
82    int i = 0;
83    int column = 0;
84
85    while ((line = xmalloc_fgets(file)) != NULL) {
86        convert = 1;
87        pos = 0;
88        ptr = line;
89        while (*line) {
90            while ((*line == ' ' || *line == '\t') && convert) {
91                pos += (*line == ' ') ? 1 : tab_size;
92                line++;
93                column++;
94                if ((opt & OPT_ALL) && column == tab_size) {
95                    column = 0;
96                    goto put_tab;
97                }
98            }
99            if (pos) {
100                i = pos / tab_size;
101                if (i) {
102                    for (; i > 0; i--) {
103 put_tab:
104                        xputchar('\t');
105                    }
106                } else {
107                    for (i = pos % tab_size; i > 0; i--) {
108                        xputchar(' ');
109                    }
110                }
111                pos = 0;
112            } else {
113                if (opt & OPT_INITIAL) {
114                    convert = 0;
115                }
116                if (opt & OPT_ALL) {
117                    column++;
118                }
119                xputchar(*line);
120                line++;
121            }
122        }
123        free(ptr);
124    }
125}
126#endif
127
128int expand_main(int argc, char **argv);
129int expand_main(int argc, char **argv)
130{
131    /* Default 8 spaces for 1 tab */
132    const char *opt_t = "8";
133    FILE *file;
134    unsigned tab_size;
135    unsigned opt;
136    int exit_status = EXIT_SUCCESS;
137
138#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS
139    static const char expand_longopts[] ALIGN1 =
140        /* name, has_arg, val */
141        "initial\0"          No_argument       "i"
142        "tabs\0"             Required_argument "t"
143    ;
144#endif
145#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS
146    static const char unexpand_longopts[] ALIGN1 =
147        /* name, has_arg, val */
148        "first-only\0"       No_argument       "i"
149        "tabs\0"             Required_argument "t"
150        "all\0"              No_argument       "a"
151    ;
152#endif
153
154    if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
155        USE_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
156        opt = getopt32(argv, "it:", &opt_t);
157    } else if (ENABLE_UNEXPAND) {
158        USE_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
159        /* -t NUM sets also -a */
160        opt_complementary = "ta";
161        opt = getopt32(argv, "ft:a", &opt_t);
162        /* -f --first-only is the default */
163        if (!(opt & OPT_ALL)) opt |= OPT_INITIAL;
164    }
165    tab_size = xatou_range(opt_t, 1, UINT_MAX);
166
167    argv += optind;
168
169    /* If no args are given, read from stdin */
170    if (!*argv) {
171        *--argv = (char*)bb_msg_standard_input;
172        goto use_stdin;
173    }
174
175    do {
176        if (NOT_LONE_CHAR(*argv, '-')) {
177            file = fopen_or_warn(*argv, "r");
178            if (!file) {
179                exit_status = EXIT_FAILURE;
180                continue;
181            }
182        } else {
183 use_stdin:
184            file = stdin;
185        }
186
187        if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
188            USE_EXPAND(expand(file, tab_size, opt));
189        else if (ENABLE_UNEXPAND)
190            USE_UNEXPAND(unexpand(file, tab_size, opt));
191
192        /* Check and close the file */
193        /* We do want all of them to execute, thus | instead of || */
194        if (ferror(file) | fclose_if_not_stdin(file)) {
195            bb_perror_msg("%s", *argv);
196            exit_status = EXIT_FAILURE;
197        }
198        /* If stdin also clear EOF */
199        if (file == stdin)
200            clearerr(file);
201    } while (*++argv);
202
203    /* Now close stdin also */
204    /* (if we didn't read from it, it's a no-op) */
205    if (fclose(stdin))
206        bb_perror_msg_and_die(bb_msg_standard_input);
207
208    fflush_stdout_and_exit(exit_status);
209}
Note: See TracBrowser for help on using the repository browser.