source: branches/3.2/mindi-busybox/coreutils/expand.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
  • Property svn:eol-style set to native
File size: 5.8 KB
Line 
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 source tree.
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//usage:#define expand_trivial_usage
25//usage:       "[-i] [-t N] [FILE]..."
26//usage:#define expand_full_usage "\n\n"
27//usage:       "Convert tabs to spaces, writing to stdout\n"
28//usage:    IF_FEATURE_EXPAND_LONG_OPTIONS(
29//usage:     "\n    -i,--initial    Don't convert tabs after non blanks"
30//usage:     "\n    -t,--tabs=N Tabstops every N chars"
31//usage:    )
32//usage:    IF_NOT_FEATURE_EXPAND_LONG_OPTIONS(
33//usage:     "\n    -i  Don't convert tabs after non blanks"
34//usage:     "\n    -t  Tabstops every N chars"
35//usage:    )
36
37//usage:#define unexpand_trivial_usage
38//usage:       "[-fa][-t N] [FILE]..."
39//usage:#define unexpand_full_usage "\n\n"
40//usage:       "Convert spaces to tabs, writing to stdout\n"
41//usage:    IF_FEATURE_UNEXPAND_LONG_OPTIONS(
42//usage:     "\n    -a,--all    Convert all blanks"
43//usage:     "\n    -f,--first-only Convert only leading blanks"
44//usage:     "\n    -t,--tabs=N Tabstops every N chars"
45//usage:    )
46//usage:    IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS(
47//usage:     "\n    -a  Convert all blanks"
48//usage:     "\n    -f  Convert only leading blanks"
49//usage:     "\n    -t N    Tabstops every N chars"
50//usage:    )
51
52#include "libbb.h"
53#include "unicode.h"
54
55enum {
56    OPT_INITIAL     = 1 << 0,
57    OPT_TABS        = 1 << 1,
58    OPT_ALL         = 1 << 2,
59};
60
61#if ENABLE_EXPAND
62static void expand(FILE *file, unsigned tab_size, unsigned opt)
63{
64    char *line;
65
66    while ((line = xmalloc_fgets(file)) != NULL) {
67        unsigned char c;
68        char *ptr;
69        char *ptr_strbeg;
70
71        ptr = ptr_strbeg = line;
72        while ((c = *ptr) != '\0') {
73            if ((opt & OPT_INITIAL) && !isblank(c)) {
74                /* not space or tab */
75                break;
76            }
77            if (c == '\t') {
78                unsigned len;
79                *ptr = '\0';
80# if ENABLE_UNICODE_SUPPORT
81                {
82                    uni_stat_t uni_stat;
83                    printable_string(&uni_stat, ptr_strbeg);
84                    len = uni_stat.unicode_width;
85                }
86# else
87                len = ptr - ptr_strbeg;
88# endif
89                len = tab_size - (len % tab_size);
90                /*while (ptr[1] == '\t') { ptr++; len += tab_size; } - can handle many tabs at once */
91                printf("%s%*s", ptr_strbeg, len, "");
92                ptr_strbeg = ptr + 1;
93            }
94            ptr++;
95        }
96        fputs(ptr_strbeg, stdout);
97        free(line);
98    }
99}
100#endif
101
102#if ENABLE_UNEXPAND
103static void unexpand(FILE *file, unsigned tab_size, unsigned opt)
104{
105    char *line;
106
107    while ((line = xmalloc_fgets(file)) != NULL) {
108        char *ptr = line;
109        unsigned column = 0;
110
111        while (*ptr) {
112            unsigned n;
113            unsigned len = 0;
114
115            while (*ptr == ' ') {
116                ptr++;
117                len++;
118            }
119            column += len;
120            if (*ptr == '\t') {
121                column += tab_size - (column % tab_size);
122                ptr++;
123                continue;
124            }
125
126            n = column / tab_size;
127            if (n) {
128                len = column = column % tab_size;
129                while (n--)
130                    putchar('\t');
131            }
132
133            if ((opt & OPT_INITIAL) && ptr != line) {
134                printf("%*s%s", len, "", ptr);
135                break;
136            }
137            n = strcspn(ptr, "\t ");
138            printf("%*s%.*s", len, "", n, ptr);
139# if ENABLE_UNICODE_SUPPORT
140            {
141                char c;
142                uni_stat_t uni_stat;
143                c = ptr[n];
144                ptr[n] = '\0';
145                printable_string(&uni_stat, ptr);
146                len = uni_stat.unicode_width;
147                ptr[n] = c;
148            }
149# else
150            len = n;
151# endif
152            ptr += n;
153            column = (column + len) % tab_size;
154        }
155        free(line);
156    }
157}
158#endif
159
160int expand_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
161int expand_main(int argc UNUSED_PARAM, char **argv)
162{
163    /* Default 8 spaces for 1 tab */
164    const char *opt_t = "8";
165    FILE *file;
166    unsigned tab_size;
167    unsigned opt;
168    int exit_status = EXIT_SUCCESS;
169
170#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS
171    static const char expand_longopts[] ALIGN1 =
172        /* name, has_arg, val */
173        "initial\0"          No_argument       "i"
174        "tabs\0"             Required_argument "t"
175    ;
176#endif
177#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS
178    static const char unexpand_longopts[] ALIGN1 =
179        /* name, has_arg, val */
180        "first-only\0"       No_argument       "i"
181        "tabs\0"             Required_argument "t"
182        "all\0"              No_argument       "a"
183    ;
184#endif
185    init_unicode();
186
187    if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
188        IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
189        opt = getopt32(argv, "it:", &opt_t);
190    } else {
191        IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
192        /* -t NUM sets also -a */
193        opt_complementary = "ta";
194        opt = getopt32(argv, "ft:a", &opt_t);
195        /* -f --first-only is the default */
196        if (!(opt & OPT_ALL)) opt |= OPT_INITIAL;
197    }
198    tab_size = xatou_range(opt_t, 1, UINT_MAX);
199
200    argv += optind;
201
202    if (!*argv) {
203        *--argv = (char*)bb_msg_standard_input;
204    }
205    do {
206        file = fopen_or_warn_stdin(*argv);
207        if (!file) {
208            exit_status = EXIT_FAILURE;
209            continue;
210        }
211
212        if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
213            IF_EXPAND(expand(file, tab_size, opt));
214        else
215            IF_UNEXPAND(unexpand(file, tab_size, opt));
216
217        /* Check and close the file */
218        if (fclose_if_not_stdin(file)) {
219            bb_simple_perror_msg(*argv);
220            exit_status = EXIT_FAILURE;
221        }
222        /* If stdin also clear EOF */
223        if (file == stdin)
224            clearerr(file);
225    } while (*++argv);
226
227    /* Now close stdin also */
228    /* (if we didn't read from it, it's a no-op) */
229    if (fclose(stdin))
230        bb_perror_msg_and_die(bb_msg_standard_input);
231
232    fflush_stdout_and_exit(exit_status);
233}
Note: See TracBrowser for help on using the repository browser.