20 |
* |
* |
21 |
* Caveat: this versions of expand and unexpand don't accept tab lists. |
* Caveat: this versions of expand and unexpand don't accept tab lists. |
22 |
*/ |
*/ |
|
|
|
23 |
#include "libbb.h" |
#include "libbb.h" |
24 |
|
#include "unicode.h" |
25 |
|
|
26 |
enum { |
enum { |
27 |
OPT_INITIAL = 1 << 0, |
OPT_INITIAL = 1 << 0, |
29 |
OPT_ALL = 1 << 2, |
OPT_ALL = 1 << 2, |
30 |
}; |
}; |
31 |
|
|
|
static void xputchar(char c) |
|
|
{ |
|
|
if (putchar(c) < 0) |
|
|
bb_error_msg_and_die(bb_msg_write_error); |
|
|
} |
|
|
|
|
32 |
#if ENABLE_EXPAND |
#if ENABLE_EXPAND |
33 |
static void expand(FILE *file, unsigned tab_size, unsigned opt) |
static void expand(FILE *file, unsigned tab_size, unsigned opt) |
34 |
{ |
{ |
35 |
char *line; |
char *line; |
|
char *ptr; |
|
|
int convert; |
|
|
unsigned pos; |
|
|
|
|
|
/* Increment tab_size by 1 locally.*/ |
|
|
tab_size++; |
|
36 |
|
|
37 |
while ((line = xmalloc_fgets(file)) != NULL) { |
while ((line = xmalloc_fgets(file)) != NULL) { |
38 |
convert = 1; |
unsigned char c; |
39 |
pos = 0; |
char *ptr; |
40 |
ptr = line; |
char *ptr_strbeg; |
41 |
while (*line) { |
|
42 |
pos++; |
ptr = ptr_strbeg = line; |
43 |
if (*line == '\t' && convert) { |
while ((c = *ptr) != '\0') { |
44 |
for (; pos < tab_size; pos++) { |
if ((opt & OPT_INITIAL) && !isblank(c)) { |
45 |
xputchar(' '); |
/* not space or tab */ |
46 |
} |
break; |
|
} else { |
|
|
if ((opt & OPT_INITIAL) && !isblank(*line)) { |
|
|
convert = 0; |
|
|
} |
|
|
xputchar(*line); |
|
47 |
} |
} |
48 |
if (pos == tab_size) { |
if (c == '\t') { |
49 |
pos = 0; |
unsigned len; |
50 |
|
*ptr = '\0'; |
51 |
|
# if ENABLE_FEATURE_ASSUME_UNICODE |
52 |
|
len = unicode_strlen(ptr_strbeg); |
53 |
|
# else |
54 |
|
len = ptr - ptr_strbeg; |
55 |
|
# endif |
56 |
|
len = tab_size - (len % tab_size); |
57 |
|
/*while (ptr[1] == '\t') { ptr++; len += tab_size; } - can handle many tabs at once */ |
58 |
|
printf("%s%*s", ptr_strbeg, len, ""); |
59 |
|
ptr_strbeg = ptr + 1; |
60 |
} |
} |
61 |
line++; |
ptr++; |
62 |
} |
} |
63 |
free(ptr); |
fputs(ptr_strbeg, stdout); |
64 |
|
free(line); |
65 |
} |
} |
66 |
} |
} |
67 |
#endif |
#endif |
68 |
|
|
69 |
#if ENABLE_UNEXPAND |
#if ENABLE_UNEXPAND |
70 |
static void unexpand(FILE *file, unsigned int tab_size, unsigned opt) |
static void unexpand(FILE *file, unsigned tab_size, unsigned opt) |
71 |
{ |
{ |
72 |
char *line; |
char *line; |
|
char *ptr; |
|
|
int convert; |
|
|
int pos; |
|
|
int i = 0; |
|
|
unsigned column = 0; |
|
73 |
|
|
74 |
while ((line = xmalloc_fgets(file)) != NULL) { |
while ((line = xmalloc_fgets(file)) != NULL) { |
75 |
convert = 1; |
char *ptr = line; |
76 |
pos = 0; |
unsigned column = 0; |
77 |
ptr = line; |
|
78 |
while (*line) { |
while (*ptr) { |
79 |
while ((*line == ' ' || *line == '\t') && convert) { |
unsigned n; |
80 |
pos += (*line == ' ') ? 1 : tab_size; |
unsigned len; |
81 |
line++; |
|
82 |
|
while (*ptr == ' ') { |
83 |
column++; |
column++; |
84 |
if ((opt & OPT_ALL) && column == tab_size) { |
ptr++; |
85 |
column = 0; |
} |
86 |
goto put_tab; |
if (*ptr == '\t') { |
87 |
} |
column += tab_size - (column % tab_size); |
88 |
} |
ptr++; |
89 |
if (pos) { |
continue; |
90 |
i = pos / tab_size; |
} |
91 |
if (i) { |
|
92 |
for (; i > 0; i--) { |
n = column / tab_size; |
93 |
put_tab: |
column = column % tab_size; |
94 |
xputchar('\t'); |
while (n--) |
95 |
} |
putchar('\t'); |
96 |
} else { |
|
97 |
for (i = pos % tab_size; i > 0; i--) { |
if ((opt & OPT_INITIAL) && ptr != line) { |
98 |
xputchar(' '); |
printf("%*s%s", column, "", ptr); |
99 |
} |
break; |
100 |
} |
} |
101 |
pos = 0; |
n = strcspn(ptr, "\t "); |
102 |
} else { |
printf("%*s%.*s", column, "", n, ptr); |
103 |
if (opt & OPT_INITIAL) { |
# if ENABLE_FEATURE_ASSUME_UNICODE |
104 |
convert = 0; |
{ |
105 |
} |
char c; |
106 |
if (opt & OPT_ALL) { |
c = ptr[n]; |
107 |
column++; |
ptr[n] = '\0'; |
108 |
} |
len = unicode_strlen(ptr); |
109 |
xputchar(*line); |
ptr[n] = c; |
|
line++; |
|
110 |
} |
} |
111 |
|
# else |
112 |
|
len = n; |
113 |
|
# endif |
114 |
|
ptr += n; |
115 |
|
column = (column + len) % tab_size; |
116 |
} |
} |
117 |
free(ptr); |
free(line); |
118 |
} |
} |
119 |
} |
} |
120 |
#endif |
#endif |
144 |
"all\0" No_argument "a" |
"all\0" No_argument "a" |
145 |
; |
; |
146 |
#endif |
#endif |
147 |
|
init_unicode(); |
148 |
|
|
149 |
if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { |
if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { |
150 |
USE_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts); |
IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts); |
151 |
opt = getopt32(argv, "it:", &opt_t); |
opt = getopt32(argv, "it:", &opt_t); |
152 |
} else { |
} else { |
153 |
USE_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts); |
IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts); |
154 |
/* -t NUM sets also -a */ |
/* -t NUM sets also -a */ |
155 |
opt_complementary = "ta"; |
opt_complementary = "ta"; |
156 |
opt = getopt32(argv, "ft:a", &opt_t); |
opt = getopt32(argv, "ft:a", &opt_t); |
172 |
} |
} |
173 |
|
|
174 |
if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) |
if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) |
175 |
USE_EXPAND(expand(file, tab_size, opt)); |
IF_EXPAND(expand(file, tab_size, opt)); |
176 |
else |
else |
177 |
USE_UNEXPAND(unexpand(file, tab_size, opt)); |
IF_UNEXPAND(unexpand(file, tab_size, opt)); |
178 |
|
|
179 |
/* Check and close the file */ |
/* Check and close the file */ |
180 |
if (fclose_if_not_stdin(file)) { |
if (fclose_if_not_stdin(file)) { |