aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--coreutils/cut.c455
-rw-r--r--coreutils/date.c2
-rw-r--r--coreutils/df.c33
-rw-r--r--coreutils/expr.c4
-rw-r--r--coreutils/ls.c246
-rw-r--r--coreutils/md5_sha1_sum.c58
-rw-r--r--coreutils/stty.c148
-rw-r--r--coreutils/truncate.c6
8 files changed, 661 insertions, 291 deletions
diff --git a/coreutils/cut.c b/coreutils/cut.c
index f7b501a46..d81f36bcd 100644
--- a/coreutils/cut.c
+++ b/coreutils/cut.c
@@ -27,21 +27,34 @@
27//kbuild:lib-$(CONFIG_CUT) += cut.o 27//kbuild:lib-$(CONFIG_CUT) += cut.o
28 28
29//usage:#define cut_trivial_usage 29//usage:#define cut_trivial_usage
30//usage: "[OPTIONS] [FILE]..." 30//usage: "{-b|c LIST | -f"IF_FEATURE_CUT_REGEX("|F")" LIST [-d SEP] [-s]} [-D] [-O SEP] [FILE]..."
31// --output-delimiter SEP is too long to fit into 80 char-wide help ----------------^^^^^^^^
31//usage:#define cut_full_usage "\n\n" 32//usage:#define cut_full_usage "\n\n"
32//usage: "Print selected fields from FILEs to stdout\n" 33//usage: "Print selected fields from FILEs to stdout\n"
33//usage: "\n -b LIST Output only bytes from LIST" 34//usage: "\n -b LIST Output only bytes from LIST"
34//usage: "\n -c LIST Output only characters from LIST" 35//usage: "\n -c LIST Output only characters from LIST"
35//usage: "\n -d SEP Field delimiter for input (default -f TAB, -F run of whitespace)" 36//usage: IF_FEATURE_CUT_REGEX(
36//usage: "\n -O SEP Field delimeter for output (default = -d for -f, one space for -F)" 37//usage: "\n -d SEP Input field delimiter (default -f TAB, -F run of whitespace)"
37//usage: "\n -D Don't sort/collate sections or match -fF lines without delimeter" 38//usage: ) IF_NOT_FEATURE_CUT_REGEX(
39//usage: "\n -d SEP Input field delimiter (default TAB)"
40//usage: )
38//usage: "\n -f LIST Print only these fields (-d is single char)" 41//usage: "\n -f LIST Print only these fields (-d is single char)"
39//usage: IF_FEATURE_CUT_REGEX( 42//usage: IF_FEATURE_CUT_REGEX(
40//usage: "\n -F LIST Print only these fields (-d is regex)" 43//usage: "\n -F LIST Print only these fields (-d is regex)"
41//usage: ) 44//usage: )
42//usage: "\n -s Output only lines containing delimiter" 45//usage: "\n -s Drop lines with no delimiter (else print them in full)"
46//usage: "\n -D Don't sort ranges; line without delimiters has one field"
47//usage: IF_LONG_OPTS(
48//usage: "\n --output-delimiter SEP Output field delimeter"
49//usage: ) IF_NOT_LONG_OPTS(
50//usage: IF_FEATURE_CUT_REGEX(
51//usage: "\n -O SEP Output field delimeter (default = -d for -f, one space for -F)"
52//usage: ) IF_NOT_FEATURE_CUT_REGEX(
53//usage: "\n -O SEP Output field delimeter (default = -d)"
54//usage: )
55//usage: )
43//usage: "\n -n Ignored" 56//usage: "\n -n Ignored"
44//(manpage:-n with -b: don't split multibyte characters) 57//(manpage:-n with -b: don't split multibyte characters)
45//usage: 58//usage:
46//usage:#define cut_example_usage 59//usage:#define cut_example_usage
47//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" 60//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n"
@@ -53,11 +66,6 @@
53 66
54#if ENABLE_FEATURE_CUT_REGEX 67#if ENABLE_FEATURE_CUT_REGEX
55#include "xregex.h" 68#include "xregex.h"
56#else
57#define regex_t int
58typedef struct { int rm_eo, rm_so; } regmatch_t;
59#define xregcomp(x, ...) *(x) = 0
60#define regexec(...) 0
61#endif 69#endif
62 70
63/* This is a NOEXEC applet. Be very careful! */ 71/* This is a NOEXEC applet. Be very careful! */
@@ -65,265 +73,346 @@ typedef struct { int rm_eo, rm_so; } regmatch_t;
65 73
66/* option vars */ 74/* option vars */
67#define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" 75#define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n"
68#define CUT_OPT_BYTE_FLGS (1 << 0) 76#define OPT_BYTE (1 << 0)
69#define CUT_OPT_CHAR_FLGS (1 << 1) 77#define OPT_CHAR (1 << 1)
70#define CUT_OPT_FIELDS_FLGS (1 << 2) 78#define OPT_FIELDS (1 << 2)
71#define CUT_OPT_DELIM_FLGS (1 << 3) 79#define OPT_DELIM (1 << 3)
72#define CUT_OPT_ODELIM_FLGS (1 << 4) 80#define OPT_ODELIM (1 << 4)
73#define CUT_OPT_SUPPRESS_FLGS (1 << 5) 81#define OPT_SUPPRESS (1 << 5)
74#define CUT_OPT_NOSORT_FLGS (1 << 6) 82#define OPT_NOSORT (1 << 6)
75#define CUT_OPT_REGEX_FLGS ((1 << 7) * ENABLE_FEATURE_CUT_REGEX) 83#define OPT_REGEX ((1 << 7) * ENABLE_FEATURE_CUT_REGEX)
76 84
77struct cut_list { 85#define opt_REGEX (option_mask32 & OPT_REGEX)
78 int startpos; 86
79 int endpos; 87struct cut_range {
88 unsigned startpos;
89 unsigned endpos;
80}; 90};
81 91
82static int cmpfunc(const void *a, const void *b) 92static int cmpfunc(const void *a, const void *b)
83{ 93{
84 return (((struct cut_list *) a)->startpos - 94 const struct cut_range *aa = a;
85 ((struct cut_list *) b)->startpos); 95 const struct cut_range *bb = b;
96 return aa->startpos - bb->startpos;
86} 97}
87 98
99#define END_OF_LIST(list_elem) ((list_elem).startpos == UINT_MAX)
100#define NOT_END_OF_LIST(list_elem) ((list_elem).startpos != UINT_MAX)
101
88static void cut_file(FILE *file, const char *delim, const char *odelim, 102static void cut_file(FILE *file, const char *delim, const char *odelim,
89 const struct cut_list *cut_lists, unsigned nlists) 103 const struct cut_range *cut_list)
90{ 104{
91 char *line; 105 char *line;
92 unsigned linenum = 0; /* keep these zero-based to be consistent */ 106 unsigned linenum = 0; /* keep these zero-based to be consistent */
93 regex_t reg; 107 int first_print = 1;
94 int spos, shoe = option_mask32 & CUT_OPT_REGEX_FLGS;
95
96 if (shoe) xregcomp(&reg, delim, REG_EXTENDED);
97 108
98 /* go through every line in the file */ 109 /* go through every line in the file */
99 while ((line = xmalloc_fgetline(file)) != NULL) { 110 while ((line = xmalloc_fgetline(file)) != NULL) {
100 111
101 /* set up a list so we can keep track of what's been printed */ 112 /* set up a list so we can keep track of what's been printed */
102 int linelen = strlen(line); 113 unsigned linelen = strlen(line);
103 char *printed = xzalloc(linelen + 1);
104 char *orig_line = line;
105 unsigned cl_pos = 0; 114 unsigned cl_pos = 0;
106 115
107 /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ 116 /* Cut based on chars/bytes XXX: only works when sizeof(char) == byte */
108 if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) { 117 if (option_mask32 & (OPT_CHAR | OPT_BYTE)) {
118 char *printed = xzalloc(linelen + 1);
119 int need_odelim = 0;
120
109 /* print the chars specified in each cut list */ 121 /* print the chars specified in each cut list */
110 for (; cl_pos < nlists; cl_pos++) { 122 for (; NOT_END_OF_LIST(cut_list[cl_pos]); cl_pos++) {
111 for (spos = cut_lists[cl_pos].startpos; spos < linelen;) { 123 unsigned spos = cut_list[cl_pos].startpos;
124 while (spos < linelen) {
112 if (!printed[spos]) { 125 if (!printed[spos]) {
113 printed[spos] = 'X'; 126 printed[spos] = 'X';
127 if (need_odelim && spos != 0 && !printed[spos-1]) {
128 need_odelim = 0;
129 fputs_stdout(odelim);
130 }
114 putchar(line[spos]); 131 putchar(line[spos]);
115 } 132 }
116 if (++spos > cut_lists[cl_pos].endpos) { 133 spos++;
134 if (spos > cut_list[cl_pos].endpos) {
135 /* will print OSEP (if not empty) */
136 need_odelim = (odelim && odelim[0]);
117 break; 137 break;
118 } 138 }
119 } 139 }
120 } 140 }
121 } else if (*delim == '\n') { /* cut by lines */ 141 free(printed);
122 spos = cut_lists[cl_pos].startpos; 142 /* Cut by lines */
143 } else if (!opt_REGEX && *delim == '\n') {
144 unsigned spos = cut_list[cl_pos].startpos;
123 145
124 /* get out if we have no more lists to process or if the lines 146 linenum++;
147 /* get out if we have no more ranges to process or if the lines
125 * are lower than what we're interested in */ 148 * are lower than what we're interested in */
126 if (((int)linenum < spos) || (cl_pos >= nlists)) 149 if (linenum <= spos || END_OF_LIST(cut_list[cl_pos]))
127 goto next_line; 150 goto next_line;
128 151
129 /* if the line we're looking for is lower than the one we were 152 /* if the line we're looking for is lower than the one we were
130 * passed, it means we displayed it already, so move on */ 153 * passed, it means we displayed it already, so move on */
131 while (spos < (int)linenum) { 154 while (++spos < linenum) {
132 spos++;
133 /* go to the next list if we're at the end of this one */ 155 /* go to the next list if we're at the end of this one */
134 if (spos > cut_lists[cl_pos].endpos) { 156 if (spos > cut_list[cl_pos].endpos) {
135 cl_pos++; 157 cl_pos++;
136 /* get out if there's no more lists to process */ 158 /* get out if there's no more ranges to process */
137 if (cl_pos >= nlists) 159 if (END_OF_LIST(cut_list[cl_pos]))
138 goto next_line; 160 goto next_line;
139 spos = cut_lists[cl_pos].startpos; 161 spos = cut_list[cl_pos].startpos;
140 /* get out if the current line is lower than the one 162 /* get out if the current line is lower than the one
141 * we just became interested in */ 163 * we just became interested in */
142 if ((int)linenum < spos) 164 if (linenum <= spos)
143 goto next_line; 165 goto next_line;
144 } 166 }
145 } 167 }
146 168
147 /* If we made it here, it means we've found the line we're 169 /* If we made it here, it means we've found the line we're
148 * looking for, so print it */ 170 * looking for, so print it */
149 puts(line); 171 if (first_print) {
172 first_print = 0;
173 fputs_stdout(line);
174 } else
175 printf("%s%s", odelim, line);
150 goto next_line; 176 goto next_line;
151 } else { /* cut by fields */ 177 /* Cut by fields */
152 unsigned uu = 0, start = 0, end = 0, out = 0; 178 } else {
153 int dcount = 0; 179 unsigned next = 0, start = 0, end = 0;
180 unsigned dcount = 0; /* we saw Nth delimiter (0 - didn't see any yet) */
181
182 /* Blank line? Check -s (later check for -s does not catch empty lines) */
183 if (linelen == 0) {
184 if (option_mask32 & OPT_SUPPRESS)
185 goto next_line;
186 }
187
188 if (!odelim)
189 odelim = "\t";
190 first_print = 1;
154 191
155#if ENABLE_PLATFORM_MINGW32
156 /* An empty line can't contain a delimiter */
157 if (linelen == 0 && (option_mask32 & CUT_OPT_SUPPRESS_FLGS))
158 goto next_line;
159#endif
160 /* Loop through bytes, finding next delimiter */ 192 /* Loop through bytes, finding next delimiter */
161 for (;;) { 193 for (;;) {
162 /* End of current range? */ 194 /* End of current range? */
163 if (end == linelen || dcount > cut_lists[cl_pos].endpos) { 195 if (end == linelen || dcount > cut_list[cl_pos].endpos) {
164 if (++cl_pos >= nlists) break; 196 end_of_range:
165 if (option_mask32 & CUT_OPT_NOSORT_FLGS) 197 cl_pos++;
166 start = dcount = uu = 0; 198 if (END_OF_LIST(cut_list[cl_pos]))
167 end = 0; 199 break;
200 if (option_mask32 & OPT_NOSORT)
201 start = dcount = next = 0;
202 end = 0; /* (why?) */
203 //bb_error_msg("End of current range");
168 } 204 }
169 /* End of current line? */ 205 /* End of current line? */
170 if (uu == linelen) { 206 if (next == linelen) {
171 /* If we've seen no delimiters, check -s */ 207 end = linelen; /* print up to end */
172 if (!cl_pos && !dcount && !shoe) { 208 /* If we've seen no delimiters, and no -D, check -s */
173 if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) 209 if (!(option_mask32 & OPT_NOSORT) && cl_pos == 0 && dcount == 0) {
210 if (option_mask32 & OPT_SUPPRESS)
174 goto next_line; 211 goto next_line;
175 } else if (dcount < cut_lists[cl_pos].startpos) 212 /* else: will print entire line */
176 start = linelen; 213 } else if (dcount < cut_list[cl_pos].startpos) {
177 end = linelen; 214 /* echo 1.2 | cut -d. -f1,3: prints "1", not "1." */
215 //break;
216 /* ^^^ this fails a case with -D:
217 * echo 1 2 | cut -DF 1,3,2:
218 * do not end line processing when didn't find field#3
219 */
220 //if (option_mask32 & OPT_NOSORT) - no, just do it always
221 goto end_of_range;
222 }
223 //bb_error_msg("End of current line: s:%d e:%d", start, end);
178 } else { 224 } else {
179 /* Find next delimiter */ 225 /* Find next delimiter */
180 if (shoe) { 226#if ENABLE_FEATURE_CUT_REGEX
181 regmatch_t rr = {-1, -1}; 227 if (opt_REGEX) {
182 228 regmatch_t rr;
183 if (!regexec(&reg, line+uu, 1, &rr, REG_NOTBOL|REG_NOTEOL)) { 229 regex_t *reg = (void*) delim;
184 end = uu + rr.rm_so; 230
185 uu += rr.rm_eo; 231 if (regexec(reg, line + next, 1, &rr, REG_NOTBOL|REG_NOTEOL) != 0) {
186 } else { 232 /* not found, go to "end of line" logic */
187 uu = linelen; 233 next = linelen;
188 continue; 234 continue;
189 } 235 }
190 } else if (line[end = uu++] != *delim) 236 end = next + rr.rm_so;
191 continue; 237 next += (rr.rm_eo ? rr.rm_eo : 1);
192 238 /* ^^^ advancing by at least 1 prevents infinite loops */
193 /* Got delimiter. Loop if not yet within range. */ 239 /* testcase: echo "no at sign" | cut -d'@*' -F 1- */
194 if (dcount++ < cut_lists[cl_pos].startpos) { 240 } else
195 start = uu; 241#endif
242 {
243 end = next++;
244 if (line[end] != *delim)
245 continue;
246 }
247 /* Got delimiter */
248 dcount++;
249 if (dcount <= cut_list[cl_pos].startpos) {
250 /* Not yet within range - loop */
251 start = next;
196 continue; 252 continue;
197 } 253 }
254 /* -F N-M preserves intermediate delimiters: */
255 //printf "1 2 3 4 5 6 7\n" | toybox cut -O: -F2,4-6,7
256 //2:4 5 6:7
257 if (opt_REGEX && dcount <= cut_list[cl_pos].endpos)
258 continue;
259// NB: toybox does the above for -f too, but it's a compatibility bug:
260//printf "1 2 3 4 5 6 7 8\n" | toybox cut -d' ' -O: -f2,4-6,7
261//2:4 5 6:7 // WRONG!
262//printf "1 2 3 4 5 6 7 8\n" | cut -d' ' --output-delimiter=: -f2,4-6,7
263//2:4:5:6:7 // GNU coreutils 9.1
198 } 264 }
199 if (end != start || !shoe) 265#if ENABLE_FEATURE_CUT_REGEX
200 printf("%s%.*s", out++ ? odelim : "", end-start, line + start); 266 if (end != start || !opt_REGEX)
201 start = uu; 267#endif
202 if (!dcount) 268 {
203 break; 269 if (first_print) {
204 } 270 first_print = 0;
271 printf("%.*s", end - start, line + start);
272 } else
273 printf("%s%.*s", odelim, end - start, line + start);
274 }
275 start = next;
276 //if (dcount == 0)
277 // break; - why?
278 } /* byte loop */
205 } 279 }
206 /* if we printed anything, finish with newline */ 280 /* if we printed anything, finish with newline */
207 putchar('\n'); 281 putchar('\n');
208 next_line: 282 next_line:
209 linenum++; 283 free(line);
210 free(printed); 284 } /* while (got line) */
211 free(orig_line); 285
212 } 286 /* For -d$'\n' --output-delimiter=^, the overall output is still terminated with \n, not ^ */
287 if (!opt_REGEX && *delim == '\n' && !first_print)
288 putchar('\n');
213} 289}
214 290
215int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 291int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
216int cut_main(int argc UNUSED_PARAM, char **argv) 292int cut_main(int argc UNUSED_PARAM, char **argv)
217{ 293{
218 /* growable array holding a series of lists */ 294 /* growable array holding a series of ranges */
219 struct cut_list *cut_lists = NULL; 295 struct cut_range *cut_list = NULL;
220 unsigned nlists = 0; /* number of elements in above list */ 296 unsigned nranges = 0; /* number of elements in above list */
221 char *sopt, *ltok; 297 char *LIST, *ltok;
222 const char *delim = NULL; 298 const char *delim = NULL;
223 const char *odelim = NULL; 299 const char *odelim = NULL;
224 unsigned opt; 300 unsigned opt;
301#if ENABLE_FEATURE_CUT_REGEX
302 regex_t reg;
303#endif
304#if ENABLE_LONG_OPTS
305 static const char cut_longopts[] ALIGN1 =
306 "output-delimiter\0" Required_argument "O"
307 ;
308#endif
225 309
226#define ARG "bcf"IF_FEATURE_CUT_REGEX("F") 310#define ARG "bcf"IF_FEATURE_CUT_REGEX("F")
227 opt = getopt32(argv, "^" 311#if ENABLE_LONG_OPTS
312 opt = getopt32long
313#else
314 opt = getopt32
315#endif
316 (argv, "^"
228 OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" 317 OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n"
229 "\0" "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX("F--"ARG), 318 "\0" "b:c:f:" IF_FEATURE_CUT_REGEX("F:") /* one of -bcfF is required */
230 &sopt, &sopt, &sopt, &delim, &odelim IF_FEATURE_CUT_REGEX(, &sopt) 319 "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX(":F--"ARG), /* they are mutually exclusive */
231 ); 320 IF_LONG_OPTS(cut_longopts,)
232 if (!delim || !*delim) 321 &LIST, &LIST, &LIST, &delim, &odelim IF_FEATURE_CUT_REGEX(, &LIST)
233 delim = (opt & CUT_OPT_REGEX_FLGS) ? "[[:space:]]+" : "\t"; 322 );
234 if (!odelim) odelim = (opt & CUT_OPT_REGEX_FLGS) ? " " : delim; 323 if (!odelim)
324 odelim = (opt & OPT_REGEX) ? " " : delim;
325 if (!delim)
326 delim = (opt & OPT_REGEX) ? "[[:space:]]+" : "\t";
235 327
236// argc -= optind; 328// argc -= optind;
237 argv += optind; 329 argv += optind;
238 if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS | CUT_OPT_REGEX_FLGS))) 330 //if (!(opt & (OPT_BYTE | OPT_CHAR | OPT_FIELDS | OPT_REGEX)))
239 bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields"); 331 // bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields");
240 332 //^^^ handled by getopt32
241 /* non-field (char or byte) cutting has some special handling */ 333
242 if (!(opt & (CUT_OPT_FIELDS_FLGS|CUT_OPT_REGEX_FLGS))) { 334 /* non-field (char or byte) cutting has some special handling */
243 static const char _op_on_field[] ALIGN1 = " only when operating on fields"; 335 if (!(opt & (OPT_FIELDS|OPT_REGEX))) {
244 336 static const char requires_f[] ALIGN1 = " requires -f"
245 if (opt & CUT_OPT_SUPPRESS_FLGS) { 337 IF_FEATURE_CUT_REGEX(" or -F");
246 bb_error_msg_and_die 338 if (opt & OPT_SUPPRESS)
247 ("suppressing non-delimited lines makes sense%s", _op_on_field); 339 bb_error_msg_and_die("-s%s", requires_f);
248 } 340 if (opt & OPT_DELIM)
249 if (opt & CUT_OPT_DELIM_FLGS) { 341 bb_error_msg_and_die("-d DELIM%s", requires_f);
250 bb_error_msg_and_die
251 ("a delimiter may be specified%s", _op_on_field);
252 }
253 } 342 }
254 343
255 /* 344 /*
256 * parse list and put values into startpos and endpos. 345 * parse list and put values into startpos and endpos.
257 * valid list formats: N, N-, N-M, -M 346 * valid range formats: N, N-, N-M, -M
258 * more than one list can be separated by commas 347 * more than one range can be separated by commas
259 */ 348 */
260 { 349 /* take apart the ranges, one by one (separated with commas) */
350 while ((ltok = strsep(&LIST, ",")) != NULL) {
261 char *ntok; 351 char *ntok;
262 int s = 0, e = 0; 352 int s, e;
263 353
264 /* take apart the lists, one by one (they are separated with commas) */ 354 /* it's actually legal to pass an empty list */
265 while ((ltok = strsep(&sopt, ",")) != NULL) { 355 //if (!ltok[0])
356 // continue;
357 //^^^ testcase?
358
359 /* get the start pos */
360 ntok = strsep(&ltok, "-");
361 if (!ntok[0]) {
362 if (!ltok) /* testcase: -f '' */
363 bb_show_usage();
364 if (!ltok[0]) /* testcase: -f - */
365 bb_show_usage();
366 s = 0; /* "-M" means "1-M" */
367 } else {
368 /* "N" or "N-[M]" */
369 /* arrays are zero based, while the user expects
370 * the first field/char on the line to be char #1 */
371 s = xatoi_positive(ntok) - 1;
372 }
266 373
267 /* it's actually legal to pass an empty list */ 374 /* get the end pos */
268 if (!ltok[0]) 375 if (!ltok) {
269 continue; 376 e = s; /* "N" means "N-N" */
377 } else if (!ltok[0]) {
378 /* "N-" means "until the end of the line" */
379 e = INT_MAX;
380 } else {
381 /* again, arrays are zero based, fields are 1 based */
382 e = xatoi_positive(ltok) - 1;
383 }
270 384
271 /* get the start pos */ 385 if (s < 0 || e < s)
272 ntok = strsep(&ltok, "-"); 386 bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok);
273 if (!ntok[0]) {
274 s = 0;
275 } else {
276 s = xatoi_positive(ntok);
277 /* account for the fact that arrays are zero based, while
278 * the user expects the first char on the line to be char #1 */
279#if !ENABLE_PLATFORM_MINGW32
280 if (s != 0)
281 s--;
282#else
283 s--;
284#endif
285 }
286 387
287 /* get the end pos */ 388 /* add the new range */
288 if (ltok == NULL) { 389 cut_list = xrealloc_vector(cut_list, 4, nranges);
289 e = s; 390 /* NB: s is always >= 0 */
290 } else if (!ltok[0]) { 391 cut_list[nranges].startpos = s;
291 e = INT_MAX; 392 cut_list[nranges].endpos = e;
292 } else { 393 nranges++;
293 e = xatoi_positive(ltok); 394 }
294 /* if the user specified no end position, 395 cut_list[nranges].startpos = UINT_MAX; /* end indicator */
295 * that means "til the end of the line" */
296#if !ENABLE_PLATFORM_MINGW32
297 if (!*ltok)
298 e = INT_MAX;
299 else if (e < s)
300 bb_error_msg_and_die("%d<%d", e, s);
301#endif
302 e--; /* again, arrays are zero based, lines are 1 based */
303 }
304#if ENABLE_PLATFORM_MINGW32
305 if (s < 0 || e < s)
306 bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok);
307#endif
308 396
309 /* add the new list */ 397 /* make sure we got some cut positions out of all that */
310 cut_lists = xrealloc_vector(cut_lists, 4, nlists); 398 //if (nranges == 0)
311 /* NB: startpos is always >= 0 */ 399 // bb_simple_error_msg_and_die("missing list of positions");
312 cut_lists[nlists].startpos = s; 400 //^^^ this is impossible since one of -bcfF is required,
313 cut_lists[nlists].endpos = e; 401 // they populate LIST with non-NULL string and when it is parsed,
314 nlists++; 402 // cut_list[] gets at least one element.
315 }
316 403
317 /* make sure we got some cut positions out of all that */ 404 /* now that the lists are parsed, we need to sort them to make life
318 if (nlists == 0) 405 * easier on us when it comes time to print the chars / fields / lines
319 bb_simple_error_msg_and_die("missing list of positions"); 406 */
407 if (!(opt & OPT_NOSORT))
408 qsort(cut_list, nranges, sizeof(cut_list[0]), cmpfunc);
320 409
321 /* now that the lists are parsed, we need to sort them to make life 410#if ENABLE_FEATURE_CUT_REGEX
322 * easier on us when it comes time to print the chars / fields / lines 411 if (opt & OPT_REGEX) {
323 */ 412 xregcomp(&reg, delim, REG_EXTENDED);
324 if (!(opt & CUT_OPT_NOSORT_FLGS)) 413 delim = (void*) &reg;
325 qsort(cut_lists, nlists, sizeof(cut_lists[0]), cmpfunc);
326 } 414 }
415#endif
327 416
328 { 417 {
329 exitcode_t retval = EXIT_SUCCESS; 418 exitcode_t retval = EXIT_SUCCESS;
@@ -337,12 +426,12 @@ int cut_main(int argc UNUSED_PARAM, char **argv)
337 retval = EXIT_FAILURE; 426 retval = EXIT_FAILURE;
338 continue; 427 continue;
339 } 428 }
340 cut_file(file, delim, odelim, cut_lists, nlists); 429 cut_file(file, delim, odelim, cut_list);
341 fclose_if_not_stdin(file); 430 fclose_if_not_stdin(file);
342 } while (*++argv); 431 } while (*++argv);
343 432
344 if (ENABLE_FEATURE_CLEAN_UP) 433 if (ENABLE_FEATURE_CLEAN_UP)
345 free(cut_lists); 434 free(cut_list);
346 fflush_stdout_and_exit(retval); 435 fflush_stdout_and_exit(retval);
347 } 436 }
348} 437}
diff --git a/coreutils/date.c b/coreutils/date.c
index 3a89b6caf..ef482af1b 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -289,7 +289,7 @@ int date_main(int argc UNUSED_PARAM, char **argv)
289 289
290 /* if setting time, set it */ 290 /* if setting time, set it */
291 if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { 291 if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) {
292 bb_simple_perror_msg("can't set date"); 292 bb_simple_perror_msg_and_die("can't set date");
293 } 293 }
294 } 294 }
295 295
diff --git a/coreutils/df.c b/coreutils/df.c
index 03aa78148..01c41db38 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -64,7 +64,9 @@
64//usage: "[-Pk" 64//usage: "[-Pk"
65//usage: IF_FEATURE_HUMAN_READABLE("mh") 65//usage: IF_FEATURE_HUMAN_READABLE("mh")
66//usage: "T" 66//usage: "T"
67//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") 67//usage: IF_FEATURE_DF_FANCY("a"
68//usage: IF_PLATFORM_POSIX("i")
69//usage: "] [-B SIZE")
68//usage: "] [-t TYPE] [FILESYSTEM]..." 70//usage: "] [-t TYPE] [FILESYSTEM]..."
69//usage:#define df_full_usage "\n\n" 71//usage:#define df_full_usage "\n\n"
70//usage: "Print filesystem usage statistics\n" 72//usage: "Print filesystem usage statistics\n"
@@ -78,7 +80,9 @@
78//usage: "\n -t TYPE Print only mounts of this type" 80//usage: "\n -t TYPE Print only mounts of this type"
79//usage: IF_FEATURE_DF_FANCY( 81//usage: IF_FEATURE_DF_FANCY(
80//usage: "\n -a Show all filesystems" 82//usage: "\n -a Show all filesystems"
83//usage: IF_PLATFORM_POSIX(
81//usage: "\n -i Inodes" 84//usage: "\n -i Inodes"
85//usage: )
82//usage: "\n -B SIZE Blocksize" 86//usage: "\n -B SIZE Blocksize"
83//usage: ) 87//usage: )
84//usage: 88//usage:
@@ -109,6 +113,12 @@ static unsigned long kscale(unsigned long b, unsigned long bs)
109} 113}
110#endif 114#endif
111 115
116#if ENABLE_PLATFORM_MINGW32
117# define ENABLE_FEATURE_DF_FANCY_POSIX 0
118#else
119# define ENABLE_FEATURE_DF_FANCY_POSIX ENABLE_FEATURE_DF_FANCY
120#endif
121
112int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 122int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113int df_main(int argc UNUSED_PARAM, char **argv) 123int df_main(int argc UNUSED_PARAM, char **argv)
114{ 124{
@@ -124,11 +134,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
124 OPT_FSTYPE = (1 << 2), 134 OPT_FSTYPE = (1 << 2),
125 OPT_t = (1 << 3), 135 OPT_t = (1 << 3),
126 OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, 136 OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
127 OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, 137 OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY_POSIX,
128 OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, 138 OPT_BSIZE = (1 << (5 + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_DF_FANCY,
129 OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 139 OPT_HUMAN = (1 << (4 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
130 OPT_HUMANDEC = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 140 OPT_HUMANDEC = (1 << (5 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
131 OPT_MEGA = (1 << (6 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 141 OPT_MEGA = (1 << (6 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
132 }; 142 };
133 const char *disp_units_hdr = NULL; 143 const char *disp_units_hdr = NULL;
134 char *chp, *opt_t; 144 char *chp, *opt_t;
@@ -144,7 +154,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
144 154
145 opt = getopt32(argv, "^" 155 opt = getopt32(argv, "^"
146 "kPTt:" 156 "kPTt:"
157#if ENABLE_PLATFORM_POSIX
147 IF_FEATURE_DF_FANCY("aiB:") 158 IF_FEATURE_DF_FANCY("aiB:")
159#else
160 IF_FEATURE_DF_FANCY("aB:")
161#endif
148 IF_FEATURE_HUMAN_READABLE("hHm") 162 IF_FEATURE_HUMAN_READABLE("hHm")
149 "\0" 163 "\0"
150#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY 164#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
@@ -155,6 +169,9 @@ int df_main(int argc UNUSED_PARAM, char **argv)
155 , &opt_t 169 , &opt_t
156 IF_FEATURE_DF_FANCY(, &chp) 170 IF_FEATURE_DF_FANCY(, &chp)
157 ); 171 );
172 /* -k overrides $POSIXLY_CORRECT: */
173 if (opt & OPT_KILO)
174 df_disp_hr = 1024;
158 if (opt & OPT_MEGA) 175 if (opt & OPT_MEGA)
159 df_disp_hr = 1024*1024; 176 df_disp_hr = 1024*1024;
160 177
@@ -185,8 +202,8 @@ int df_main(int argc UNUSED_PARAM, char **argv)
185 if (disp_units_hdr == NULL) { 202 if (disp_units_hdr == NULL) {
186#if ENABLE_FEATURE_HUMAN_READABLE 203#if ENABLE_FEATURE_HUMAN_READABLE
187 disp_units_hdr = xasprintf("%s-blocks", 204 disp_units_hdr = xasprintf("%s-blocks",
188 /* print df_disp_hr, show no fractionals, 205 /* print df_disp_hr; show no fractionals;
189 * use suffixes if OPT_POSIX is set in opt */ 206 * if -P, unit=1 (print it in full, no KMG suffixes) */
190 make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) 207 make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX))
191 ); 208 );
192#else 209#else
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 3f7e21871..c00559e4c 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -97,6 +97,10 @@ typedef long arith_t;
97 97
98/* TODO: use bb_strtol[l]? It's easier to check for errors... */ 98/* TODO: use bb_strtol[l]? It's easier to check for errors... */
99 99
100#if ENABLE_PLATFORM_MINGW32
101# define STRING BB_STRING
102#endif
103
100/* The kinds of value we can have. */ 104/* The kinds of value we can have. */
101enum { 105enum {
102 INTEGER, 106 INTEGER,
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 5d2e96a1e..2153554e8 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -129,6 +129,8 @@
129//usage: "\n -F Append indicator (one of */=@|) to names" 129//usage: "\n -F Append indicator (one of */=@|) to names"
130//usage: ) 130//usage: )
131//usage: "\n -l Long format" 131//usage: "\n -l Long format"
132////usage: "\n -g Long format without group column"
133////TODO: support -G too ("suppress owner column", GNUism)
132//usage: "\n -i List inode numbers" 134//usage: "\n -i List inode numbers"
133//usage: "\n -n List numeric UIDs and GIDs instead of names" 135//usage: "\n -n List numeric UIDs and GIDs instead of names"
134//usage: "\n -s List allocated blocks" 136//usage: "\n -s List allocated blocks"
@@ -162,6 +164,8 @@
162//usage: IF_FEATURE_LS_WIDTH( 164//usage: IF_FEATURE_LS_WIDTH(
163//usage: "\n -w N Format N columns wide" 165//usage: "\n -w N Format N columns wide"
164//usage: ) 166//usage: )
167////usage: "\n -Q Double-quote names"
168////usage: "\n -q Replace unprintable chars with '?'"
165//usage: IF_FEATURE_LS_COLOR( 169//usage: IF_FEATURE_LS_COLOR(
166//usage: "\n --color[={always,never,auto}]" 170//usage: "\n --color[={always,never,auto}]"
167//usage: ) 171//usage: )
@@ -199,27 +203,47 @@ SPLIT_SUBDIR = 2,
199 203
200/* -Cadi1l Std options, busybox always supports */ 204/* -Cadi1l Std options, busybox always supports */
201/* -gnsxA Std options, busybox always supports */ 205/* -gnsxA Std options, busybox always supports */
202/* -Q GNU option, busybox always supports */ 206/* -Q GNU option, busybox always supports: */
203/* -k Std option, busybox always supports (by ignoring) */ 207/* -Q, --quote-name */
204/* It means "for -s, show sizes in kbytes" */ 208/* enclose entry names in double quotes */
205/* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */
206/* since otherwise -s shows kbytes anyway */
207/* -LHRctur Std options, busybox optionally supports */ 209/* -LHRctur Std options, busybox optionally supports */
208/* -Fp Std options, busybox optionally supports */ 210/* -Fp Std options, busybox optionally supports */
209/* -SXvhTw GNU options, busybox optionally supports */ 211/* -SXvhTw GNU options, busybox optionally supports */
210/* -T WIDTH Ignored (we don't use tabs on output) */ 212/* -T WIDTH Ignored (we don't use tabs on output) */
211/* -Z SELinux mandated option, busybox optionally supports */ 213/* -Z SELinux mandated option, busybox optionally supports */
214/* -q Std option, busybox always supports: */
215/* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: */
216/* Force each instance of non-printable filename characters and */
217/* <tab> characters to be written as the <question-mark> ('?') */
218/* character. Implementations may provide this option by default */
219/* if the output is to a terminal device. */
220/* -k Std option, busybox always supports (by ignoring) */
221/* It means "for -s, show sizes in kbytes" */
222/* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */
223/* since otherwise -s shows kbytes anyway */
212#define ls_options \ 224#define ls_options \
213 "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ 225 "Cadi1lgnsxA" /* 11 opts, total 11 */ \
214 IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ 226 IF_FEATURE_LS_FILETYPES("Fp") /* 2, 13 */ \
215 IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ 227 IF_FEATURE_LS_RECURSIVE("R") /* 1, 14 */ \
216 IF_SELINUX("Z") /* 1, 16 */ \ 228 IF_SELINUX("Z") /* 1, 15 */ \
217 "Q" /* 1, 17 */ \ 229 "Q" /* 1, 16 */ \
218 IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ 230 IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 19 */ \
219 IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ 231 IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 23 */ \
220 IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ 232 IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 25 */ \
221 IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ 233 IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ \
222 IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ 234 IF_FEATURE_LS_WIDTH("T:w:") /* 2, 28 */ \
235 IF_LONG_OPTS("\xff") /* 1, 29 */ \
236 IF_LONG_OPTS("\xfe") /* 1, 30 */ \
237 IF_LONG_OPTS("\xfd") /* 1, 31 */ \
238 "qk" /* 2, 33 */
239
240#if ENABLE_LONG_OPTS
241static const char ls_longopts[] ALIGN1 =
242 "full-time\0" No_argument "\xff"
243 "group-directories-first\0" No_argument "\xfe"
244 IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd")
245;
246#endif
223 247
224enum { 248enum {
225 OPT_C = (1 << 0), 249 OPT_C = (1 << 0),
@@ -233,29 +257,31 @@ enum {
233 OPT_s = (1 << 8), 257 OPT_s = (1 << 8),
234 OPT_x = (1 << 9), 258 OPT_x = (1 << 9),
235 OPT_A = (1 << 10), 259 OPT_A = (1 << 10),
236 //OPT_k = (1 << 11),
237 260
238 OPTBIT_F = 12, 261 OPTBIT_F = 11,
239 OPTBIT_p, /* 13 */ 262 OPTBIT_p, /* 12 */
240 OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, 263 OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES,
241 OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, 264 OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE,
242 OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, 265 OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX,
243 OPTBIT_c, /* 17 */ 266 OPTBIT_c, /* 16 */
244 OPTBIT_t, /* 18 */ 267 OPTBIT_t, /* 17 */
245 OPTBIT_u, /* 19 */ 268 OPTBIT_u, /* 18 */
246 OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, 269 OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS,
247 OPTBIT_X, /* 21 */ 270 OPTBIT_X, /* 20 */
248 OPTBIT_r, /* 22 */ 271 OPTBIT_r, /* 21 */
249 OPTBIT_v, /* 23 */ 272 OPTBIT_v, /* 22 */
250 OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, 273 OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES,
251 OPTBIT_H, /* 25 */ 274 OPTBIT_H, /* 24 */
252 OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, 275 OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS,
253 OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, 276 OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE,
254 OPTBIT_w, /* 28 */ 277 OPTBIT_w, /* 27 */
255 OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, 278 OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH,
256 OPTBIT_dirs_first, 279 OPTBIT_dirs_first,
257 OPTBIT_color, /* 31 */ 280 OPTBIT_color, /* 30 */
258 /* with long opts, we use all 32 bits */ 281 OPTBIT_q = OPTBIT_color + 1, /* 31 */
282 OPTBIT_k = OPTBIT_q + 1, /* 32 */
283 /* with all options enabled, we use all 32 bits and even one extra bit! */
284 /* this works because -k is ignored, and getopt32 allows such "ignore" options past 31th bit */
259 285
260 OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, 286 OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES,
261 OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, 287 OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES,
@@ -277,6 +303,8 @@ enum {
277 OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, 303 OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS,
278 OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, 304 OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS,
279 OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, 305 OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR,
306 OPT_q = (1 << OPTBIT_q),
307 //-k is ignored: OPT_k = (1 << OPTBIT_k),
280}; 308};
281 309
282/* 310/*
@@ -333,6 +361,7 @@ struct globals {
333#endif 361#endif
334 smallint exit_code; 362 smallint exit_code;
335 smallint show_dirname; 363 smallint show_dirname;
364 smallint tty_out;
336#if ENABLE_FEATURE_LS_WIDTH 365#if ENABLE_FEATURE_LS_WIDTH
337 unsigned terminal_width; 366 unsigned terminal_width;
338# define G_terminal_width (G.terminal_width) 367# define G_terminal_width (G.terminal_width)
@@ -353,16 +382,21 @@ struct globals {
353 setup_common_bufsiz(); \ 382 setup_common_bufsiz(); \
354 /* we have to zero it out because of NOEXEC */ \ 383 /* we have to zero it out because of NOEXEC */ \
355 memset(&G, 0, sizeof(G)); \ 384 memset(&G, 0, sizeof(G)); \
356 IF_FEATURE_LS_WIDTH(G_terminal_width = TERMINAL_WIDTH;) \ 385 IF_FEATURE_LS_WIDTH(G_terminal_width = ~0U;) \
357 IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ 386 IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \
358} while (0) 387} while (0)
359 388
360#define ESC "\033" 389#define ESC "\033"
361 390
391static int G_isatty(void)
392{
393 if (!G.tty_out) /* not known yet? */
394 G.tty_out = isatty(STDOUT_FILENO) + 1;
395 return (G.tty_out == 2);
396}
362 397
363/*** Output code ***/ 398/*** Output code ***/
364 399
365
366/* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket 400/* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket
367 * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file 401 * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file
368 * 3/7:multiplexed char/block device) 402 * 3/7:multiplexed char/block device)
@@ -425,56 +459,93 @@ static char append_char(mode_t mode)
425} 459}
426#endif 460#endif
427 461
462/* Return the number of used columns.
463 * Note that only columnar output uses return value.
464 * -l and -1 modes don't care.
465 * coreutils 7.2 also supports:
466 * ls -b (--escape) = octal escapes (although it doesn't look like working)
467 * ls -N (--literal) = not escape at all
468 */
428static unsigned calc_name_len(const char *name) 469static unsigned calc_name_len(const char *name)
429{ 470{
430 unsigned len; 471 unsigned len;
431 uni_stat_t uni_stat; 472 uni_stat_t uni_stat;
432 473
433 // TODO: quote tab as \t, etc, if -Q 474 if (!(option_mask32 & (OPT_q|OPT_Q)))
434 name = printable_string2(&uni_stat, name); 475 return strlen(name);
435 476
436 if (!(option_mask32 & OPT_Q)) { 477 if (!(option_mask32 & OPT_Q)) {
478 /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */
479 printable_string2(&uni_stat, name);
437 return uni_stat.unicode_width; 480 return uni_stat.unicode_width;
438 } 481 }
439 482
440 len = 2 + uni_stat.unicode_width; 483 len = 2 + strlen(name);
441 while (*name) { 484 while (*name) {
485 unsigned char ch = (unsigned char)*name;
486 if (ch < ' ' || ch > 0x7e) {
487 ch -= 7;
488 if (ch <= 6) {
489 /* quote chars 7..13 as \a,b,t,n,v,f,r */
490 goto two;
491 }
492 /* other chars <32 or >126 as \ooo octal */
493 len += 3;
494 goto next;
495 }
442 if (*name == '"' || *name == '\\') { 496 if (*name == '"' || *name == '\\') {
497 two:
443 len++; 498 len++;
444 } 499 }
500 next:
445 name++; 501 name++;
446 } 502 }
447 return len; 503 return len;
448} 504}
449
450/* Return the number of used columns.
451 * Note that only columnar output uses return value.
452 * -l and -1 modes don't care.
453 * coreutils 7.2 also supports:
454 * ls -b (--escape) = octal escapes (although it doesn't look like working)
455 * ls -N (--literal) = not escape at all
456 */
457static unsigned print_name(const char *name) 505static unsigned print_name(const char *name)
458{ 506{
459 unsigned len; 507 unsigned len;
460 uni_stat_t uni_stat; 508 uni_stat_t uni_stat;
461 509
462 // TODO: quote tab as \t, etc, if -Q 510 if (!(option_mask32 & (OPT_q|OPT_Q))) {
463 name = printable_string2(&uni_stat, name); 511 fputs_stdout(name);
512 return strlen(name);
513 }
464 514
465 if (!(option_mask32 & OPT_Q)) { 515 if (!(option_mask32 & OPT_Q)) {
516 /* the most likely branch: "ls" to tty (it auto-enables -q behavior) */
517 name = printable_string2(&uni_stat, name);
466 fputs_stdout(name); 518 fputs_stdout(name);
467 return uni_stat.unicode_width; 519 return uni_stat.unicode_width;
468 } 520 }
469 521
470 len = 2 + uni_stat.unicode_width; 522 len = 2 + strlen(name);
471 putchar('"'); 523 putchar('"');
472 while (*name) { 524 while (*name) {
473 if (*name == '"' || *name == '\\') { 525 unsigned char ch = (unsigned char)*name;
526 if (ch < ' ' || ch > 0x7e) {
474 putchar('\\'); 527 putchar('\\');
528 ch -= 7;
529 if (ch <= 6) {
530 /* quote chars 7..13 as \a,b,t,n,v,f,r */
531 ch = c_escape_conv_str07[1 + 3 * ch];
532 goto two;
533 }
534 /* other chars <32 or >126 as \ooo octal */
535 ch = (unsigned char)*name;
536 putchar('0' + (ch>>6));
537 putchar('0' + ((ch>>3) & 7));
538 ch = '0' + (ch & 7);
539 len += 3;
540 goto put_ch;
541 }
542 if (ch == '"' || ch == '\\') {
543 putchar('\\');
544 two:
475 len++; 545 len++;
476 } 546 }
477 putchar(*name); 547 put_ch:
548 putchar(ch);
478 name++; 549 name++;
479 } 550 }
480 putchar('"'); 551 putchar('"');
@@ -660,7 +731,7 @@ static void display_files(struct dnode **dn, unsigned nfiles)
660 unsigned i, ncols, nrows, row, nc; 731 unsigned i, ncols, nrows, row, nc;
661 unsigned column; 732 unsigned column;
662 unsigned nexttab; 733 unsigned nexttab;
663 unsigned column_width = 0; /* used only by coulmnal output */ 734 unsigned column_width = 0; /* used only by columnar output */
664 735
665 if (option_mask32 & (OPT_l|OPT_1)) { 736 if (option_mask32 & (OPT_l|OPT_1)) {
666 ncols = 1; 737 ncols = 1;
@@ -709,6 +780,11 @@ static void display_files(struct dnode **dn, unsigned nfiles)
709 } 780 }
710 nexttab = column + column_width; 781 nexttab = column + column_width;
711 column += display_single(dn[i]); 782 column += display_single(dn[i]);
783 } else {
784 /* if -w999999999, ncols can be very large */
785 //bb_error_msg(" col:%u ncol:%u i:%i", nc, ncols, i); sleep1();
786 /* without "break", we loop millions of times here */
787 break;
712 } 788 }
713 } 789 }
714 putchar('\n'); 790 putchar('\n');
@@ -1155,25 +1231,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1155 /* need to initialize since --color has _an optional_ argument */ 1231 /* need to initialize since --color has _an optional_ argument */
1156 const char *color_opt = color_str; /* "always" */ 1232 const char *color_opt = color_str; /* "always" */
1157#endif 1233#endif
1158#if ENABLE_LONG_OPTS
1159 static const char ls_longopts[] ALIGN1 =
1160 "full-time\0" No_argument "\xff"
1161 "group-directories-first\0" No_argument "\xfe"
1162 IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd")
1163 ;
1164#endif
1165 1234
1166 INIT_G(); 1235 INIT_G();
1167 1236
1168 init_unicode(); 1237 init_unicode();
1169 1238
1170#if ENABLE_FEATURE_LS_WIDTH
1171 /* obtain the terminal width */
1172 G_terminal_width = get_terminal_width(STDIN_FILENO);
1173 /* go one less... */
1174 G_terminal_width--;
1175#endif
1176
1177 /* process options */ 1239 /* process options */
1178 opt = getopt32long(argv, "^" 1240 opt = getopt32long(argv, "^"
1179 ls_options 1241 ls_options
@@ -1211,6 +1273,29 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1211 exit(0); 1273 exit(0);
1212#endif 1274#endif
1213 1275
1276 /* ftpd secret backdoor? */
1277 if (ENABLE_FTPD && applet_name[0] == 'f') {
1278 /* dirs first are much nicer */
1279 opt = option_mask32 |= OPT_dirs_first;
1280 /* don't show SEcontext */
1281 IF_SELINUX(opt = option_mask32 &= ~OPT_Z;)
1282 /* do not query stdout about size and tty-ness */
1283 IF_FEATURE_LS_WIDTH(G_terminal_width = INT_MAX;)
1284 G.tty_out = 1; /* not a tty */
1285 goto skip_if_ftpd;
1286 }
1287
1288#if ENABLE_FEATURE_LS_WIDTH
1289 if ((int)G_terminal_width < 0) {
1290 /* obtain the terminal width */
1291 G_terminal_width = get_terminal_width(STDIN_FILENO);
1292 /* go one less... */
1293 G_terminal_width--;
1294 }
1295 if (G_terminal_width == 0) /* -w0 */
1296 G_terminal_width = INT_MAX; /* "infinite" */
1297#endif
1298
1214#if ENABLE_SELINUX 1299#if ENABLE_SELINUX
1215 if (opt & OPT_Z) { 1300 if (opt & OPT_Z) {
1216 if (!is_selinux_enabled()) 1301 if (!is_selinux_enabled())
@@ -1229,7 +1314,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1229# endif 1314# endif
1230 /* LS_COLORS is unset, or (not empty && not "none") ? */ 1315 /* LS_COLORS is unset, or (not empty && not "none") ? */
1231 if (!p || (p[0] && strcmp(p, "none") != 0)) { 1316 if (!p || (p[0] && strcmp(p, "none") != 0)) {
1232 if (isatty(STDOUT_FILENO)) { 1317 if (G_isatty()) {
1233 /* check isatty() last because it's expensive (syscall) */ 1318 /* check isatty() last because it's expensive (syscall) */
1234 G_show_color = 1; 1319 G_show_color = 1;
1235 } 1320 }
@@ -1238,23 +1323,28 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1238 if (opt & OPT_color) { 1323 if (opt & OPT_color) {
1239 if (color_opt[0] == 'n') 1324 if (color_opt[0] == 'n')
1240 G_show_color = 0; 1325 G_show_color = 0;
1241 else switch (index_in_substrings(color_str, color_opt)) { 1326 else if (!G_show_color) {
1242 case 3: 1327 /* if() is not needed, but avoids extra isatty() if G_show_color is already set */
1243 case 4: 1328 /* Check --color=COLOR_OPT and maybe set show_color=1 */
1244 case 5: 1329 switch (index_in_substrings(color_str, color_opt)) {
1245 if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { 1330 case 3: // auto
1246 case 0: 1331 case 4: // tty
1247 case 1: 1332 case 5: // if-tty
1248 case 2: 1333 if (!is_TERM_dumb() && G_isatty()) {
1249 G_show_color = 1; 1334 case 0: // always
1335 case 1: // yes
1336 case 2: // force
1337 G_show_color = 1;
1338 }
1250 } 1339 }
1251 } 1340 }
1252 } 1341 }
1253#endif 1342#endif
1343 skip_if_ftpd:
1254 1344
1255 /* sort out which command line options take precedence */ 1345 /* sort out which command line options take precedence */
1256 if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) 1346 if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d))
1257 option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ 1347 opt = option_mask32 &= ~OPT_R; /* no recurse if listing only dir */
1258 if (!(opt & OPT_l)) { /* not -l? */ 1348 if (!(opt & OPT_l)) { /* not -l? */
1259 if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { 1349 if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) {
1260 /* when to sort by time? -t[cu] sorts by time even with -l */ 1350 /* when to sort by time? -t[cu] sorts by time even with -l */
@@ -1262,19 +1352,17 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1262 /* without -l, bare -c or -u enable sort too */ 1352 /* without -l, bare -c or -u enable sort too */
1263 /* (with -l, bare -c or -u just select which time to show) */ 1353 /* (with -l, bare -c or -u just select which time to show) */
1264 if (opt & (OPT_c|OPT_u)) { 1354 if (opt & (OPT_c|OPT_u)) {
1265 option_mask32 |= OPT_t; 1355 opt = option_mask32 |= OPT_t;
1266 } 1356 }
1267 } 1357 }
1268 } 1358 }
1269 1359
1270 /* choose a display format if one was not already specified by an option */ 1360 /* choose a display format if one was not already specified by an option */
1271 if (!(option_mask32 & (OPT_l|OPT_1|OPT_x|OPT_C))) 1361 if (!(opt & (OPT_l|OPT_1|OPT_x|OPT_C)))
1272 option_mask32 |= (isatty(STDOUT_FILENO) ? OPT_C : OPT_1); 1362 opt = option_mask32 |= (G_isatty() ? OPT_C : OPT_1);
1273 1363
1274 if (ENABLE_FTPD && applet_name[0] == 'f') { 1364 if (!(opt & OPT_q) && G_isatty())
1275 /* ftpd secret backdoor. dirs first are much nicer */ 1365 opt = option_mask32 |= OPT_q;
1276 option_mask32 |= OPT_dirs_first;
1277 }
1278 1366
1279#if ENABLE_FEATURE_EXTRA_FILE_DATA 1367#if ENABLE_FEATURE_EXTRA_FILE_DATA
1280 /* Enable accurate link counts for directories */ 1368 /* Enable accurate link counts for directories */
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index 978d328f1..4506aeb56 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -23,6 +23,12 @@
23//config: help 23//config: help
24//config: Compute and check SHA256 message digest 24//config: Compute and check SHA256 message digest
25//config: 25//config:
26//config:config SHA384SUM
27//config: bool "sha384sum (7.3 kb)"
28//config: default y
29//config: help
30//config: Compute and check SHA384 message digest
31//config:
26//config:config SHA512SUM 32//config:config SHA512SUM
27//config: bool "sha512sum (7.3 kb)" 33//config: bool "sha512sum (7.3 kb)"
28//config: default y 34//config: default y
@@ -35,13 +41,13 @@
35//config: help 41//config: help
36//config: Compute and check SHA3 message digest 42//config: Compute and check SHA3 message digest
37//config: 43//config:
38//config:comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum" 44//config:comment "Common options for md5sum, sha1sum, sha256sum, ..., sha3sum"
39//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM 45//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA384SUM || SHA512SUM || SHA3SUM
40//config: 46//config:
41//config:config FEATURE_MD5_SHA1_SUM_CHECK 47//config:config FEATURE_MD5_SHA1_SUM_CHECK
42//config: bool "Enable -c, -s and -w options" 48//config: bool "Enable -c, -s and -w options"
43//config: default y 49//config: default y
44//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM 50//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA384SUM || SHA512SUM || SHA3SUM
45//config: help 51//config: help
46//config: Enabling the -c options allows files to be checked 52//config: Enabling the -c options allows files to be checked
47//config: against pre-calculated hash values. 53//config: against pre-calculated hash values.
@@ -51,11 +57,13 @@
51//applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) 57//applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum))
52//applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) 58//applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum))
53//applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) 59//applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum))
60//applet:IF_SHA384SUM(APPLET_NOEXEC(sha384sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha384sum))
54//applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) 61//applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum))
55 62
56//kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o 63//kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o
57//kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o 64//kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o
58//kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o 65//kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o
66//kbuild:lib-$(CONFIG_SHA384SUM) += md5_sha1_sum.o
59//kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o 67//kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o
60//kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o 68//kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o
61 69
@@ -99,6 +107,16 @@
99//usage: "\n -w Warn about improperly formatted checksum lines" 107//usage: "\n -w Warn about improperly formatted checksum lines"
100//usage: ) 108//usage: )
101//usage: 109//usage:
110//usage:#define sha384sum_trivial_usage
111//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..."
112//usage:#define sha384sum_full_usage "\n\n"
113//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA384 checksums"
114//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n"
115//usage: "\n -c Check sums against list in FILEs"
116//usage: "\n -s Don't output anything, status code shows success"
117//usage: "\n -w Warn about improperly formatted checksum lines"
118//usage: )
119//usage:
102//usage:#define sha512sum_trivial_usage 120//usage:#define sha512sum_trivial_usage
103//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." 121//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..."
104//usage:#define sha512sum_full_usage "\n\n" 122//usage:#define sha512sum_full_usage "\n\n"
@@ -130,11 +148,12 @@
130 148
131enum { 149enum {
132 /* 4th letter of applet_name is... */ 150 /* 4th letter of applet_name is... */
133 HASH_MD5 = 's', /* "md5>s<um" */ 151 HASH_MD5 = 's', /* "md5>s<um" */
134 HASH_SHA1 = '1', 152 HASH_SHA1 = '1',
135 HASH_SHA256 = '2', 153 HASH_SHA256 = '2',
136 HASH_SHA3 = '3', 154 HASH_SHA3 = '3',
137 HASH_SHA512 = '5', 155 HASH_SHA512 = '5',
156 /* unfortunately, sha384sum has the same '3' as sha3 */
138}; 157};
139 158
140#define FLAG_SILENT 1 159#define FLAG_SILENT 1
@@ -158,10 +177,11 @@ static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
158#endif 177#endif
159static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned sha3_width) 178static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned sha3_width)
160{ 179{
161 int src_fd, hash_len, count; 180 int src_fd, count;
162 union _ctx_ { 181 union _ctx_ {
163 sha3_ctx_t sha3; 182 sha3_ctx_t sha3;
164 sha512_ctx_t sha512; 183 sha512_ctx_t sha512;
184 sha384_ctx_t sha384;
165 sha256_ctx_t sha256; 185 sha256_ctx_t sha256;
166 sha1_ctx_t sha1; 186 sha1_ctx_t sha1;
167 md5_ctx_t md5; 187 md5_ctx_t md5;
@@ -183,25 +203,31 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned
183 md5_begin(&context.md5); 203 md5_begin(&context.md5);
184 update = (void*)md5_hash; 204 update = (void*)md5_hash;
185 final = (void*)md5_end; 205 final = (void*)md5_end;
186 hash_len = 16;
187 } 206 }
188 else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) { 207 else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) {
189 sha1_begin(&context.sha1); 208 sha1_begin(&context.sha1);
190 update = (void*)sha1_hash; 209 update = (void*)sha1_hash;
191 final = (void*)sha1_end; 210 final = (void*)sha1_end;
192 hash_len = 20;
193 } 211 }
194 else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) { 212 else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) {
195 sha256_begin(&context.sha256); 213 sha256_begin(&context.sha256);
196 update = (void*)sha256_hash; 214 update = (void*)sha256_hash;
197 final = (void*)sha256_end; 215 final = (void*)sha256_end;
198 hash_len = 32; 216 }
217 else if (ENABLE_SHA384SUM
218 && (ENABLE_SHA3SUM
219 ? (applet_name[4] == '8') /* check for "sha384", but do not match "sha3" */
220 : (hash_algo == '3') /* applet_name = "sha3sum" is not possible */
221 )
222 ) {
223 sha384_begin(&context.sha384);
224 update = (void*)sha384_hash;
225 final = (void*)sha384_end;
199 } 226 }
200 else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) { 227 else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) {
201 sha512_begin(&context.sha512); 228 sha512_begin(&context.sha512);
202 update = (void*)sha512_hash; 229 update = (void*)sha512_hash;
203 final = (void*)sha512_end; 230 final = (void*)sha512_end;
204 hash_len = 64;
205 } 231 }
206#if ENABLE_SHA3SUM 232#if ENABLE_SHA3SUM
207 else if (ENABLE_SHA3SUM && hash_algo == HASH_SHA3) { 233 else if (ENABLE_SHA3SUM && hash_algo == HASH_SHA3) {
@@ -219,9 +245,7 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned
219 ) { 245 ) {
220 bb_error_msg_and_die("bad -a%u", sha3_width); 246 bb_error_msg_and_die("bad -a%u", sha3_width);
221 } 247 }
222 sha3_width /= 4; 248 context.sha3.input_block_bytes = 1600/8 - sha3_width/4;
223 context.sha3.input_block_bytes = 1600/8 - sha3_width;
224 hash_len = sha3_width/2;
225 } 249 }
226#endif 250#endif
227 else { 251 else {
@@ -236,7 +260,7 @@ static uint8_t *hash_file(unsigned char *in_buf, const char *filename, unsigned
236 if (count < 0) 260 if (count < 0)
237 bb_perror_msg("can't read '%s'", filename); 261 bb_perror_msg("can't read '%s'", filename);
238 else /* count == 0 */ { 262 else /* count == 0 */ {
239 final(&context, in_buf); 263 unsigned hash_len = final(&context, in_buf);
240 hash_value = hash_bin_to_hex(in_buf, hash_len); 264 hash_value = hash_bin_to_hex(in_buf, hash_len);
241 } 265 }
242 } 266 }
@@ -262,14 +286,14 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
262 /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ 286 /* -b "binary", -t "text" are ignored (shaNNNsum compat) */
263 /* -s and -w require -c */ 287 /* -s and -w require -c */
264#if ENABLE_SHA3SUM 288#if ENABLE_SHA3SUM
265 if (applet_name[3] == HASH_SHA3) 289 if (applet_name[3] == HASH_SHA3 && (!ENABLE_SHA384SUM || applet_name[4] != '8'))
266 flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width); 290 flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width);
267 else 291 else
268#endif 292#endif
269 flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c"); 293 flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c");
270 } else { 294 } else {
271#if ENABLE_SHA3SUM 295#if ENABLE_SHA3SUM
272 if (applet_name[3] == HASH_SHA3) 296 if (applet_name[3] == HASH_SHA3 && (!ENABLE_SHA384SUM || applet_name[4] != '8'))
273 getopt32(argv, "a:+", &sha3_width); 297 getopt32(argv, "a:+", &sha3_width);
274 else 298 else
275#endif 299#endif
diff --git a/coreutils/stty.c b/coreutils/stty.c
index c88ef07f4..92d5838c0 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -20,14 +20,30 @@
20//kbuild:lib-$(CONFIG_STTY) += stty.o 20//kbuild:lib-$(CONFIG_STTY) += stty.o
21 21
22//usage:#define stty_trivial_usage 22//usage:#define stty_trivial_usage
23//usage: IF_NOT_PLATFORM_MINGW32(
23//usage: "[-a|g] [-F DEVICE] [SETTING]..." 24//usage: "[-a|g] [-F DEVICE] [SETTING]..."
25//usage: )
26//usage: IF_PLATFORM_MINGW32(
27//usage: "[-a] [SETTING]..."
28//usage: )
24//usage:#define stty_full_usage "\n\n" 29//usage:#define stty_full_usage "\n\n"
30//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "Without arguments, prints baud rate, line discipline,\n" 31//usage: "Without arguments, prints baud rate, line discipline,\n"
26//usage: "and deviations from stty sane\n" 32//usage: "and deviations from stty sane\n"
27//usage: "\n -F DEVICE Open device instead of stdin" 33//usage: "\n -F DEVICE Open device instead of stdin"
34//usage: )
35//usage: IF_PLATFORM_MINGW32(
36//usage: "Without arguments, prints deviations from stty sane\n"
37//usage: )
28//usage: "\n -a Print all current settings in human-readable form" 38//usage: "\n -a Print all current settings in human-readable form"
39//usage: IF_NOT_PLATFORM_MINGW32(
29//usage: "\n -g Print in stty-readable form" 40//usage: "\n -g Print in stty-readable form"
30//usage: "\n [SETTING] See manpage" 41//usage: "\n [SETTING] See manpage"
42//usage: )
43//usage: IF_PLATFORM_MINGW32(
44//usage: "\n [SETTING] [-]echo [-]cooked [-]raw sane"
45//usage: "\n cols N rows N size"
46//usage: )
31 47
32/* If no args are given, write to stdout the baud rate and settings that 48/* If no args are given, write to stdout the baud rate and settings that
33 * have been changed from their defaults. Mode reading and changes 49 * have been changed from their defaults. Mode reading and changes
@@ -294,6 +310,7 @@ struct mode_info {
294 const tcflag_t bits; /* Bits to set for this mode */ 310 const tcflag_t bits; /* Bits to set for this mode */
295}; 311};
296 312
313#if !ENABLE_PLATFORM_MINGW32
297enum { 314enum {
298 /* Must match mode_name[] and mode_info[] order! */ 315 /* Must match mode_name[] and mode_info[] order! */
299 IDX_evenp = 0, 316 IDX_evenp = 0,
@@ -320,19 +337,30 @@ enum {
320 IDX_LCASE, 337 IDX_LCASE,
321#endif 338#endif
322}; 339};
340#else
341enum {
342 /* Must match mode_name[] and mode_info[] order! */
343 IDX_sane = 0,
344 IDX_cooked,
345 IDX_raw,
346};
347#endif
323 348
324#define MI_ENTRY(N,T,F,B,M) N "\0" 349#define MI_ENTRY(N,T,F,B,M) N "\0"
325 350
326/* Mode names given on command line */ 351/* Mode names given on command line */
327static const char mode_name[] ALIGN1 = 352static const char mode_name[] ALIGN1 =
353#if !ENABLE_PLATFORM_MINGW32
328 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) 354 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
329 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) 355 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
330 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) 356 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) 357 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("ek", combination, OMIT, 0, 0 ) 358 MI_ENTRY("ek", combination, OMIT, 0, 0 )
359#endif
333 MI_ENTRY("sane", combination, OMIT, 0, 0 ) 360 MI_ENTRY("sane", combination, OMIT, 0, 0 )
334 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) 361 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
335 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) 362 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
363#if !ENABLE_PLATFORM_MINGW32
336 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) 364 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) 365 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) 366 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
@@ -454,7 +482,9 @@ static const char mode_name[] ALIGN1 =
454#if IEXTEN 482#if IEXTEN
455 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) 483 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
456#endif 484#endif
485#endif /* !ENABLE_PLATFORM_MINGW32 */
457 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) 486 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
487#if !ENABLE_PLATFORM_MINGW32
458 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) 488 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
459 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) 489 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
460 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) 490 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
@@ -482,6 +512,7 @@ static const char mode_name[] ALIGN1 =
482#ifdef EXTPROC 512#ifdef EXTPROC
483 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) 513 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
484#endif 514#endif
515#endif /* !ENABLE_PLATFORM_MINGW32 */
485 ; 516 ;
486 517
487#undef MI_ENTRY 518#undef MI_ENTRY
@@ -489,14 +520,17 @@ static const char mode_name[] ALIGN1 =
489 520
490static const struct mode_info mode_info[] ALIGN4 = { 521static const struct mode_info mode_info[] ALIGN4 = {
491 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ 522 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
523#if !ENABLE_PLATFORM_MINGW32
492 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) 524 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
493 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) 525 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
494 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) 526 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
495 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) 527 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
496 MI_ENTRY("ek", combination, OMIT, 0, 0 ) 528 MI_ENTRY("ek", combination, OMIT, 0, 0 )
529#endif
497 MI_ENTRY("sane", combination, OMIT, 0, 0 ) 530 MI_ENTRY("sane", combination, OMIT, 0, 0 )
498 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) 531 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
499 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) 532 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
533#if !ENABLE_PLATFORM_MINGW32
500 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) 534 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
501 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) 535 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
502 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) 536 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
@@ -618,7 +652,9 @@ static const struct mode_info mode_info[] ALIGN4 = {
618#if IEXTEN 652#if IEXTEN
619 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) 653 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
620#endif 654#endif
655#endif /* !ENABLE_PLATFORM_MINGW32 */
621 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) 656 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
657#if !ENABLE_PLATFORM_MINGW32
622 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) 658 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
623 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) 659 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
624 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) 660 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
@@ -646,6 +682,7 @@ static const struct mode_info mode_info[] ALIGN4 = {
646#ifdef EXTPROC 682#ifdef EXTPROC
647 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) 683 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
648#endif 684#endif
685#endif /* !ENABLE_PLATFORM_MINGW32 */
649}; 686};
650 687
651enum { 688enum {
@@ -653,6 +690,7 @@ enum {
653}; 690};
654 691
655 692
693#if !ENABLE_PLATFORM_MINGW32
656/* Control characters */ 694/* Control characters */
657struct control_info { 695struct control_info {
658 const uint8_t saneval; /* Value to set for 'stty sane' */ 696 const uint8_t saneval; /* Value to set for 'stty sane' */
@@ -786,6 +824,7 @@ static const struct control_info control_info[] ALIGN2 = {
786enum { 824enum {
787 NUM_control_info = ARRAY_SIZE(control_info) 825 NUM_control_info = ARRAY_SIZE(control_info)
788}; 826};
827#endif
789 828
790 829
791struct globals { 830struct globals {
@@ -803,6 +842,7 @@ struct globals {
803 G.current_col = 0; /* we are noexec, must clear */ \ 842 G.current_col = 0; /* we are noexec, must clear */ \
804} while (0) 843} while (0)
805 844
845#if !ENABLE_PLATFORM_MINGW32
806static void set_speed_or_die(enum speed_setting type, const char *arg, 846static void set_speed_or_die(enum speed_setting type, const char *arg,
807 struct termios *mode) 847 struct termios *mode)
808{ 848{
@@ -817,6 +857,7 @@ static void set_speed_or_die(enum speed_setting type, const char *arg,
817 cfsetospeed(mode, baud); 857 cfsetospeed(mode, baud);
818 } 858 }
819} 859}
860#endif
820 861
821static NORETURN void perror_on_device_and_die(const char *fmt) 862static NORETURN void perror_on_device_and_die(const char *fmt)
822{ 863{
@@ -918,6 +959,7 @@ static const struct mode_info *find_mode(const char *name)
918 return i >= 0 ? &mode_info[i] : NULL; 959 return i >= 0 ? &mode_info[i] : NULL;
919} 960}
920 961
962#if !ENABLE_PLATFORM_MINGW32
921static const struct control_info *find_control(const char *name) 963static const struct control_info *find_control(const char *name)
922{ 964{
923 int i = index_in_strings(control_name, name); 965 int i = index_in_strings(control_name, name);
@@ -954,7 +996,32 @@ static int find_param(const char *name)
954 i |= 0x80; 996 i |= 0x80;
955 return i; 997 return i;
956} 998}
999#else
1000enum {
1001 param_need_arg = 0x80,
1002 param_rows = 1 | 0x80,
1003 param_cols = 2 | 0x80,
1004 param_columns = 3 | 0x80,
1005 param_size = 4,
1006};
957 1007
1008static int find_param(const char *name)
1009{
1010 static const char params[] ALIGN1 =
1011 "rows\0" /* 1 */
1012 "cols\0" /* 2 */
1013 "columns\0" /* 3 */
1014 "size\0"; /* 4 */
1015 int i = index_in_strings(params, name) + 1;
1016 if (i == 0)
1017 return 0;
1018 if (i != 4)
1019 i |= 0x80;
1020 return i;
1021}
1022#endif
1023
1024#if !ENABLE_PLATFORM_MINGW32
958static int recover_mode(const char *arg, struct termios *mode) 1025static int recover_mode(const char *arg, struct termios *mode)
959{ 1026{
960 int i, n; 1027 int i, n;
@@ -1013,6 +1080,9 @@ static void display_speed(const struct termios *mode, int fancy)
1013 if (fancy) fmt_str += 9; 1080 if (fancy) fmt_str += 9;
1014 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); 1081 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1015} 1082}
1083#else
1084# define display_speed(m, f) ((void)0)
1085#endif
1016 1086
1017static void do_display(const struct termios *mode, int all) 1087static void do_display(const struct termios *mode, int all)
1018{ 1088{
@@ -1030,6 +1100,7 @@ static void do_display(const struct termios *mode, int all)
1030 newline(); 1100 newline();
1031#endif 1101#endif
1032 1102
1103#if !ENABLE_PLATFORM_MINGW32
1033 for (i = 0; i != CIDX_min; ++i) { 1104 for (i = 0; i != CIDX_min; ++i) {
1034 char ch; 1105 char ch;
1035 char buf10[10]; 1106 char buf10[10];
@@ -1059,6 +1130,7 @@ static void do_display(const struct termios *mode, int all)
1059#endif 1130#endif
1060 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]); 1131 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1061 newline(); 1132 newline();
1133#endif
1062 1134
1063 for (i = 0; i < NUM_mode_info; ++i) { 1135 for (i = 0; i < NUM_mode_info; ++i) {
1064 if (mode_info[i].flags & OMIT) 1136 if (mode_info[i].flags & OMIT)
@@ -1086,6 +1158,7 @@ static void do_display(const struct termios *mode, int all)
1086 1158
1087static void sane_mode(struct termios *mode) 1159static void sane_mode(struct termios *mode)
1088{ 1160{
1161#if !ENABLE_PLATFORM_MINGW32
1089 int i; 1162 int i;
1090 1163
1091 for (i = 0; i < NUM_control_info; ++i) { 1164 for (i = 0; i < NUM_control_info; ++i) {
@@ -1110,6 +1183,11 @@ static void sane_mode(struct termios *mode)
1110 *bitsp = val & ~mode_info[i].bits; 1183 *bitsp = val & ~mode_info[i].bits;
1111 } 1184 }
1112 } 1185 }
1186#else
1187 mode->c_lflag |= ECHO;
1188 mode->w_mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT |
1189 ENABLE_PROCESSED_INPUT;
1190#endif
1113} 1191}
1114 1192
1115static void set_mode(const struct mode_info *info, int reversed, 1193static void set_mode(const struct mode_info *info, int reversed,
@@ -1129,6 +1207,7 @@ static void set_mode(const struct mode_info *info, int reversed,
1129 } 1207 }
1130 1208
1131 /* !bitsp - it's a "combination" mode */ 1209 /* !bitsp - it's a "combination" mode */
1210#if !ENABLE_PLATFORM_MINGW32
1132 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { 1211 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1133 if (reversed) 1212 if (reversed)
1134 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 1213 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
@@ -1150,9 +1229,14 @@ static void set_mode(const struct mode_info *info, int reversed,
1150 } else if (info == &mode_info[IDX_ek]) { 1229 } else if (info == &mode_info[IDX_ek]) {
1151 mode->c_cc[VERASE] = CERASE; 1230 mode->c_cc[VERASE] = CERASE;
1152 mode->c_cc[VKILL] = CKILL; 1231 mode->c_cc[VKILL] = CKILL;
1153 } else if (info == &mode_info[IDX_sane]) { 1232 }
1233 else
1234#endif /* !ENABLE_PLATFORM_MINGW32 */
1235 if (info == &mode_info[IDX_sane]) {
1154 sane_mode(mode); 1236 sane_mode(mode);
1155 } else if (info == &mode_info[IDX_cbreak]) { 1237 }
1238#if !ENABLE_PLATFORM_MINGW32
1239 else if (info == &mode_info[IDX_cbreak]) {
1156 if (reversed) 1240 if (reversed)
1157 mode->c_lflag |= ICANON; 1241 mode->c_lflag |= ICANON;
1158 else 1242 else
@@ -1175,11 +1259,14 @@ static void set_mode(const struct mode_info *info, int reversed,
1175 mode->c_iflag &= ~ISTRIP; 1259 mode->c_iflag &= ~ISTRIP;
1176 mode->c_oflag &= ~OPOST; 1260 mode->c_oflag &= ~OPOST;
1177 } 1261 }
1178 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) { 1262 }
1263#endif /* !ENABLE_PLATFORM_MINGW32 */
1264 else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1179 if ((info == &mode_info[IDX_raw] && reversed) 1265 if ((info == &mode_info[IDX_raw] && reversed)
1180 || (info == &mode_info[IDX_cooked] && !reversed) 1266 || (info == &mode_info[IDX_cooked] && !reversed)
1181 ) { 1267 ) {
1182 /* Cooked mode */ 1268 /* Cooked mode */
1269#if !ENABLE_PLATFORM_MINGW32
1183 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; 1270 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1184 mode->c_oflag |= OPOST; 1271 mode->c_oflag |= OPOST;
1185 mode->c_lflag |= ISIG | ICANON; 1272 mode->c_lflag |= ISIG | ICANON;
@@ -1189,15 +1276,23 @@ static void set_mode(const struct mode_info *info, int reversed,
1189#if VTIME == VEOL 1276#if VTIME == VEOL
1190 mode->c_cc[VEOL] = CEOL; 1277 mode->c_cc[VEOL] = CEOL;
1191#endif 1278#endif
1279#else
1280 mode->w_mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
1281#endif
1192 } else { 1282 } else {
1193 /* Raw mode */ 1283 /* Raw mode */
1284#if !ENABLE_PLATFORM_MINGW32
1194 mode->c_iflag = 0; 1285 mode->c_iflag = 0;
1195 mode->c_oflag &= ~OPOST; 1286 mode->c_oflag &= ~OPOST;
1196 mode->c_lflag &= ~(ISIG | ICANON | XCASE); 1287 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1197 mode->c_cc[VMIN] = 1; 1288 mode->c_cc[VMIN] = 1;
1198 mode->c_cc[VTIME] = 0; 1289 mode->c_cc[VTIME] = 0;
1290#else
1291 mode->w_mode &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
1292#endif
1199 } 1293 }
1200 } 1294 }
1295#if !ENABLE_PLATFORM_MINGW32
1201#if IXANY 1296#if IXANY
1202 else if (info == &mode_info[IDX_decctlq]) { 1297 else if (info == &mode_info[IDX_decctlq]) {
1203 if (reversed) 1298 if (reversed)
@@ -1244,8 +1339,10 @@ static void set_mode(const struct mode_info *info, int reversed,
1244 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; 1339 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1245 if (IXANY) mode->c_iflag &= ~IXANY; 1340 if (IXANY) mode->c_iflag &= ~IXANY;
1246 } 1341 }
1342#endif /*!ENABLE_PLATFORM_MINGW32 */
1247} 1343}
1248 1344
1345#if !ENABLE_PLATFORM_MINGW32
1249static void set_control_char_or_die(const struct control_info *info, 1346static void set_control_char_or_die(const struct control_info *info,
1250 const char *arg, struct termios *mode) 1347 const char *arg, struct termios *mode)
1251{ 1348{
@@ -1265,6 +1362,7 @@ static void set_control_char_or_die(const struct control_info *info,
1265 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); 1362 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1266 mode->c_cc[info->offset] = value; 1363 mode->c_cc[info->offset] = value;
1267} 1364}
1365#endif
1268 1366
1269#define STTY_require_set_attr (1 << 0) 1367#define STTY_require_set_attr (1 << 0)
1270#define STTY_speed_was_set (1 << 1) 1368#define STTY_speed_was_set (1 << 1)
@@ -1277,7 +1375,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1277{ 1375{
1278 struct termios mode; 1376 struct termios mode;
1279 void (*output_func)(const struct termios *, int); 1377 void (*output_func)(const struct termios *, int);
1378#if !ENABLE_PLATFORM_MINGW32
1280 const char *file_name = NULL; 1379 const char *file_name = NULL;
1380#endif
1281 int display_all = 0; 1381 int display_all = 0;
1282 int stty_state; 1382 int stty_state;
1283 int k; 1383 int k;
@@ -1291,7 +1391,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1291 k = 0; 1391 k = 0;
1292 while (argv[++k]) { 1392 while (argv[++k]) {
1293 const struct mode_info *mp; 1393 const struct mode_info *mp;
1394#if !ENABLE_PLATFORM_MINGW32
1294 const struct control_info *cp; 1395 const struct control_info *cp;
1396#endif
1295 const char *arg = argv[k]; 1397 const char *arg = argv[k];
1296 const char *argnext = argv[k+1]; 1398 const char *argnext = argv[k+1];
1297 int param; 1399 int param;
@@ -1314,6 +1416,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1314 output_func = do_display; 1416 output_func = do_display;
1315 display_all = 1; 1417 display_all = 1;
1316 break; 1418 break;
1419#if !ENABLE_PLATFORM_MINGW32
1317 case 'g': 1420 case 'g':
1318 stty_state |= STTY_recoverable_output; 1421 stty_state |= STTY_recoverable_output;
1319 output_func = display_recoverable; 1422 output_func = display_recoverable;
@@ -1334,11 +1437,14 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1334 } 1437 }
1335 } 1438 }
1336 goto end_option; 1439 goto end_option;
1440#endif
1337 default: 1441 default:
1338 goto invalid_argument; 1442 goto invalid_argument;
1339 } 1443 }
1340 } 1444 }
1445#if !ENABLE_PLATFORM_MINGW32
1341 end_option: 1446 end_option:
1447#endif
1342 continue; 1448 continue;
1343 } 1449 }
1344 1450
@@ -1348,6 +1454,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1348 continue; 1454 continue;
1349 } 1455 }
1350 1456
1457#if !ENABLE_PLATFORM_MINGW32
1351 cp = find_control(arg); 1458 cp = find_control(arg);
1352 if (cp) { 1459 if (cp) {
1353 if (!argnext) 1460 if (!argnext)
@@ -1358,6 +1465,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1358 ++k; 1465 ++k;
1359 continue; 1466 continue;
1360 } 1467 }
1468#endif
1361 1469
1362 param = find_param(arg); 1470 param = find_param(arg);
1363 if (param & param_need_arg) { 1471 if (param & param_need_arg) {
@@ -1381,7 +1489,11 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1381 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); 1489 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1382 break; 1490 break;
1383 case param_size: 1491 case param_size:
1492# if ENABLE_PLATFORM_MINGW32
1493 break;
1494# endif
1384#endif 1495#endif
1496#if !ENABLE_PLATFORM_MINGW32
1385 case param_speed: 1497 case param_speed:
1386 break; 1498 break;
1387 case param_ispeed: 1499 case param_ispeed:
@@ -1392,15 +1504,19 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1392 /* called for the side effect of xfunc death only */ 1504 /* called for the side effect of xfunc death only */
1393 set_speed_or_die(output_speed, argnext, &mode); 1505 set_speed_or_die(output_speed, argnext, &mode);
1394 break; 1506 break;
1507#endif
1395 default: 1508 default:
1509#if !ENABLE_PLATFORM_MINGW32
1396 if (recover_mode(arg, &mode) == 1) break; 1510 if (recover_mode(arg, &mode) == 1) break;
1397 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break; 1511 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1512#endif
1398 invalid_argument: 1513 invalid_argument:
1399 bb_error_msg_and_die("invalid argument '%s'", arg); 1514 bb_error_msg_and_die("invalid argument '%s'", arg);
1400 } 1515 }
1401 stty_state &= ~STTY_noargs; 1516 stty_state &= ~STTY_noargs;
1402 } 1517 }
1403 1518
1519#if !ENABLE_PLATFORM_MINGW32
1404 /* Specifying both -a and -g is an error */ 1520 /* Specifying both -a and -g is an error */
1405 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == 1521 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1406 (STTY_verbose_output | STTY_recoverable_output) 1522 (STTY_verbose_output | STTY_recoverable_output)
@@ -1413,13 +1529,22 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1413 ) { 1529 ) {
1414 bb_simple_error_msg_and_die("modes may not be set when -a or -g is used"); 1530 bb_simple_error_msg_and_die("modes may not be set when -a or -g is used");
1415 } 1531 }
1532#else
1533 /* Specifying -a with non-options is an error */
1534 if ((stty_state & STTY_verbose_output) && !(stty_state & STTY_noargs)
1535 ) {
1536 bb_simple_error_msg_and_die("modes may not be set when -a is used");
1537 }
1538#endif
1416 1539
1540#if !ENABLE_PLATFORM_MINGW32
1417 /* Now it is safe to start doing things */ 1541 /* Now it is safe to start doing things */
1418 if (file_name) { 1542 if (file_name) {
1419 G.device_name = file_name; 1543 G.device_name = file_name;
1420 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO); 1544 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1421 ndelay_off(STDIN_FILENO); 1545 ndelay_off(STDIN_FILENO);
1422 } 1546 }
1547#endif
1423 1548
1424 /* Initialize to all zeroes so there is no risk memcmp will report a 1549 /* Initialize to all zeroes so there is no risk memcmp will report a
1425 spurious difference in an uninitialized portion of the structure */ 1550 spurious difference in an uninitialized portion of the structure */
@@ -1437,7 +1562,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1437 k = 0; 1562 k = 0;
1438 while (argv[++k]) { 1563 while (argv[++k]) {
1439 const struct mode_info *mp; 1564 const struct mode_info *mp;
1565#if !ENABLE_PLATFORM_MINGW32
1440 const struct control_info *cp; 1566 const struct control_info *cp;
1567#endif
1441 const char *arg = argv[k]; 1568 const char *arg = argv[k];
1442 const char *argnext = argv[k+1]; 1569 const char *argnext = argv[k+1];
1443 int param; 1570 int param;
@@ -1459,6 +1586,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1459 continue; 1586 continue;
1460 } 1587 }
1461 1588
1589#if !ENABLE_PLATFORM_MINGW32
1462 cp = find_control(arg); 1590 cp = find_control(arg);
1463 if (cp) { 1591 if (cp) {
1464 ++k; 1592 ++k;
@@ -1466,6 +1594,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1466 stty_state |= STTY_require_set_attr; 1594 stty_state |= STTY_require_set_attr;
1467 continue; 1595 continue;
1468 } 1596 }
1597#endif
1469 1598
1470 param = find_param(arg); 1599 param = find_param(arg);
1471 if (param & param_need_arg) { 1600 if (param & param_need_arg) {
@@ -1491,6 +1620,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1491 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); 1620 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1492 break; 1621 break;
1493#endif 1622#endif
1623#if !ENABLE_PLATFORM_MINGW32
1494 case param_speed: 1624 case param_speed:
1495 display_speed(&mode, 0); 1625 display_speed(&mode, 0);
1496 break; 1626 break;
@@ -1502,7 +1632,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1502 set_speed_or_die(output_speed, argnext, &mode); 1632 set_speed_or_die(output_speed, argnext, &mode);
1503 stty_state |= (STTY_require_set_attr | STTY_speed_was_set); 1633 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1504 break; 1634 break;
1635#endif
1505 default: 1636 default:
1637#if !ENABLE_PLATFORM_MINGW32
1506 if (recover_mode(arg, &mode) == 1) 1638 if (recover_mode(arg, &mode) == 1)
1507 stty_state |= STTY_require_set_attr; 1639 stty_state |= STTY_require_set_attr;
1508 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{ 1640 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
@@ -1510,15 +1642,24 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1510 stty_state |= (STTY_require_set_attr | STTY_speed_was_set); 1642 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1511 } /* else - impossible (caught in the first pass): 1643 } /* else - impossible (caught in the first pass):
1512 bb_error_msg_and_die("invalid argument '%s'", arg); */ 1644 bb_error_msg_and_die("invalid argument '%s'", arg); */
1645#endif
1513 } 1646 }
1514 } 1647 }
1515 1648
1516 if (stty_state & STTY_require_set_attr) { 1649 if (stty_state & STTY_require_set_attr) {
1650#if !ENABLE_PLATFORM_MINGW32
1517 struct termios new_mode; 1651 struct termios new_mode;
1652#else
1653 if (mode.c_lflag & ECHO)
1654 mode.w_mode |= ENABLE_ECHO_INPUT;
1655 else
1656 mode.w_mode &= ~ENABLE_ECHO_INPUT;
1657#endif
1518 1658
1519 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) 1659 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1520 perror_on_device_and_die("%s"); 1660 perror_on_device_and_die("%s");
1521 1661
1662#if !ENABLE_PLATFORM_MINGW32
1522 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if 1663 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1523 it performs *any* of the requested operations. This means it 1664 it performs *any* of the requested operations. This means it
1524 can report 'success' when it has actually failed to perform 1665 can report 'success' when it has actually failed to perform
@@ -1554,6 +1695,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1554#endif 1695#endif
1555 perror_on_device_and_die("%s: cannot perform all requested operations"); 1696 perror_on_device_and_die("%s: cannot perform all requested operations");
1556 } 1697 }
1698#endif
1557 } 1699 }
1558 1700
1559 return EXIT_SUCCESS; 1701 return EXIT_SUCCESS;
diff --git a/coreutils/truncate.c b/coreutils/truncate.c
index 8826e6b4c..87a47bb09 100644
--- a/coreutils/truncate.c
+++ b/coreutils/truncate.c
@@ -73,6 +73,12 @@ int truncate_main(int argc UNUSED_PARAM, char **argv)
73 * do not report error, exitcode is also 0. 73 * do not report error, exitcode is also 0.
74 */ 74 */
75 } else { 75 } else {
76#if ENABLE_PLATFORM_MINGW32
77 struct stat st;
78
79 if (fstat(fd, &st) == 0 && size > st.st_size)
80 make_sparse(fd, st.st_size, size);
81#endif
76 if (ftruncate(fd, size) == -1) { 82 if (ftruncate(fd, size) == -1) {
77 bb_perror_msg("%s: truncate", *argv); 83 bb_perror_msg("%s: truncate", *argv);
78 ret = EXIT_FAILURE; 84 ret = EXIT_FAILURE;