diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2025-07-31 18:35:11 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2025-07-31 18:35:11 +0200 |
| commit | 551bfdb97f45f0277a408ec2d44ee18967b98304 (patch) | |
| tree | 6aaeb1b0e4319b3eae4a4e5fb0f3a690e6afe914 | |
| parent | a98b95b715359a8b002d1cb8e1f998a4afa2c73e (diff) | |
| download | busybox-w32-551bfdb97f45f0277a408ec2d44ee18967b98304.tar.gz busybox-w32-551bfdb97f45f0277a408ec2d44ee18967b98304.tar.bz2 busybox-w32-551bfdb97f45f0277a408ec2d44ee18967b98304.zip | |
ls: implement -q, fix -w0, reduce startup time
function old new delta
ls_main 598 660 +62
ls_longopts - 47 +47
G_isatty - 36 +36
print_name 102 134 +32
display_files 358 374 +16
.rodata 105829 105833 +4
vgetopt32 1330 1317 -13
static.ls_longopts 47 - -47
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 4/1 up/down: 197/-60) Total: 137 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | coreutils/ls.c | 171 | ||||
| -rw-r--r-- | libbb/getopt32.c | 13 |
2 files changed, 122 insertions, 62 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c index cc809b797..eaccd1a17 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
| @@ -126,6 +126,8 @@ | |||
| 126 | //usage: "\n -F Append indicator (one of */=@|) to names" | 126 | //usage: "\n -F Append indicator (one of */=@|) to names" |
| 127 | //usage: ) | 127 | //usage: ) |
| 128 | //usage: "\n -l Long format" | 128 | //usage: "\n -l Long format" |
| 129 | ////usage: "\n -g Long format without group column" | ||
| 130 | ////TODO: support -G too ("suppress owner column", GNUism) | ||
| 129 | //usage: "\n -i List inode numbers" | 131 | //usage: "\n -i List inode numbers" |
| 130 | //usage: "\n -n List numeric UIDs and GIDs instead of names" | 132 | //usage: "\n -n List numeric UIDs and GIDs instead of names" |
| 131 | //usage: "\n -s List allocated blocks" | 133 | //usage: "\n -s List allocated blocks" |
| @@ -159,6 +161,8 @@ | |||
| 159 | //usage: IF_FEATURE_LS_WIDTH( | 161 | //usage: IF_FEATURE_LS_WIDTH( |
| 160 | //usage: "\n -w N Format N columns wide" | 162 | //usage: "\n -w N Format N columns wide" |
| 161 | //usage: ) | 163 | //usage: ) |
| 164 | ////usage: "\n -Q Double-quote names" | ||
| 165 | ////usage: "\n -q Replace unprintable chars with '?'" | ||
| 162 | //usage: IF_FEATURE_LS_COLOR( | 166 | //usage: IF_FEATURE_LS_COLOR( |
| 163 | //usage: "\n --color[={always,never,auto}]" | 167 | //usage: "\n --color[={always,never,auto}]" |
| 164 | //usage: ) | 168 | //usage: ) |
| @@ -196,27 +200,47 @@ SPLIT_SUBDIR = 2, | |||
| 196 | 200 | ||
| 197 | /* -Cadi1l Std options, busybox always supports */ | 201 | /* -Cadi1l Std options, busybox always supports */ |
| 198 | /* -gnsxA Std options, busybox always supports */ | 202 | /* -gnsxA Std options, busybox always supports */ |
| 199 | /* -Q GNU option, busybox always supports */ | 203 | /* -Q GNU option, busybox always supports: */ |
| 200 | /* -k Std option, busybox always supports (by ignoring) */ | 204 | /* -Q, --quote-name */ |
| 201 | /* It means "for -s, show sizes in kbytes" */ | 205 | /* enclose entry names in double quotes */ |
| 202 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
| 203 | /* since otherwise -s shows kbytes anyway */ | ||
| 204 | /* -LHRctur Std options, busybox optionally supports */ | 206 | /* -LHRctur Std options, busybox optionally supports */ |
| 205 | /* -Fp Std options, busybox optionally supports */ | 207 | /* -Fp Std options, busybox optionally supports */ |
| 206 | /* -SXvhTw GNU options, busybox optionally supports */ | 208 | /* -SXvhTw GNU options, busybox optionally supports */ |
| 207 | /* -T WIDTH Ignored (we don't use tabs on output) */ | 209 | /* -T WIDTH Ignored (we don't use tabs on output) */ |
| 208 | /* -Z SELinux mandated option, busybox optionally supports */ | 210 | /* -Z SELinux mandated option, busybox optionally supports */ |
| 211 | /* -q Std option, busybox always supports: */ | ||
| 212 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: */ | ||
| 213 | /* Force each instance of non-printable filename characters and */ | ||
| 214 | /* <tab> characters to be written as the <question-mark> ('?') */ | ||
| 215 | /* character. Implementations may provide this option by default */ | ||
| 216 | /* if the output is to a terminal device. */ | ||
| 217 | /* -k Std option, busybox always supports (by ignoring) */ | ||
| 218 | /* It means "for -s, show sizes in kbytes" */ | ||
| 219 | /* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ | ||
| 220 | /* since otherwise -s shows kbytes anyway */ | ||
| 209 | #define ls_options \ | 221 | #define ls_options \ |
| 210 | "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ | 222 | "Cadi1lgnsxA" /* 11 opts, total 11 */ \ |
| 211 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ | 223 | IF_FEATURE_LS_FILETYPES("Fp") /* 2, 13 */ \ |
| 212 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ | 224 | IF_FEATURE_LS_RECURSIVE("R") /* 1, 14 */ \ |
| 213 | IF_SELINUX("Z") /* 1, 16 */ \ | 225 | IF_SELINUX("Z") /* 1, 15 */ \ |
| 214 | "Q" /* 1, 17 */ \ | 226 | "Q" /* 1, 16 */ \ |
| 215 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ | 227 | IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 19 */ \ |
| 216 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ | 228 | IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 23 */ \ |
| 217 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ | 229 | IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 25 */ \ |
| 218 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ | 230 | IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ \ |
| 219 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ | 231 | IF_FEATURE_LS_WIDTH("T:w:") /* 2, 28 */ \ |
| 232 | IF_LONG_OPTS("\xff") /* 1, 29 */ \ | ||
| 233 | IF_LONG_OPTS("\xfe") /* 1, 30 */ \ | ||
| 234 | IF_LONG_OPTS("\xfd") /* 1, 31 */ \ | ||
| 235 | "qk" /* 2, 33 */ | ||
| 236 | |||
| 237 | #if ENABLE_LONG_OPTS | ||
| 238 | static const char ls_longopts[] ALIGN1 = | ||
| 239 | "full-time\0" No_argument "\xff" | ||
| 240 | "group-directories-first\0" No_argument "\xfe" | ||
| 241 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
| 242 | ; | ||
| 243 | #endif | ||
| 220 | 244 | ||
| 221 | enum { | 245 | enum { |
| 222 | OPT_C = (1 << 0), | 246 | OPT_C = (1 << 0), |
| @@ -230,29 +254,31 @@ enum { | |||
| 230 | OPT_s = (1 << 8), | 254 | OPT_s = (1 << 8), |
| 231 | OPT_x = (1 << 9), | 255 | OPT_x = (1 << 9), |
| 232 | OPT_A = (1 << 10), | 256 | OPT_A = (1 << 10), |
| 233 | //OPT_k = (1 << 11), | ||
| 234 | 257 | ||
| 235 | OPTBIT_F = 12, | 258 | OPTBIT_F = 11, |
| 236 | OPTBIT_p, /* 13 */ | 259 | OPTBIT_p, /* 12 */ |
| 237 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, | 260 | OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, |
| 238 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, | 261 | OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, |
| 239 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, | 262 | OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, |
| 240 | OPTBIT_c, /* 17 */ | 263 | OPTBIT_c, /* 16 */ |
| 241 | OPTBIT_t, /* 18 */ | 264 | OPTBIT_t, /* 17 */ |
| 242 | OPTBIT_u, /* 19 */ | 265 | OPTBIT_u, /* 18 */ |
| 243 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, | 266 | OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, |
| 244 | OPTBIT_X, /* 21 */ | 267 | OPTBIT_X, /* 20 */ |
| 245 | OPTBIT_r, /* 22 */ | 268 | OPTBIT_r, /* 21 */ |
| 246 | OPTBIT_v, /* 23 */ | 269 | OPTBIT_v, /* 22 */ |
| 247 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, | 270 | OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, |
| 248 | OPTBIT_H, /* 25 */ | 271 | OPTBIT_H, /* 24 */ |
| 249 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, | 272 | OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, |
| 250 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, | 273 | OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, |
| 251 | OPTBIT_w, /* 28 */ | 274 | OPTBIT_w, /* 27 */ |
| 252 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, | 275 | OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, |
| 253 | OPTBIT_dirs_first, | 276 | OPTBIT_dirs_first, |
| 254 | OPTBIT_color, /* 31 */ | 277 | OPTBIT_color, /* 30 */ |
| 255 | /* with long opts, we use all 32 bits */ | 278 | OPTBIT_q = OPTBIT_color + 1, /* 31 */ |
| 279 | OPTBIT_k = OPTBIT_q + 1, /* 32 */ | ||
| 280 | /* with all options enabled, we use all 32 bits and even one extra bit! */ | ||
| 281 | /* this works because -k is ignored, and getopt32 allows such "ignore" options past 31th bit */ | ||
| 256 | 282 | ||
| 257 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, | 283 | OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, |
| 258 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, | 284 | OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, |
| @@ -274,6 +300,8 @@ enum { | |||
| 274 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, | 300 | OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, |
| 275 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, | 301 | OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, |
| 276 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, | 302 | OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, |
| 303 | OPT_q = (1 << OPTBIT_q), | ||
| 304 | //-k is ignored: OPT_k = (1 << OPTBIT_k), | ||
| 277 | }; | 305 | }; |
| 278 | 306 | ||
| 279 | /* | 307 | /* |
| @@ -327,6 +355,7 @@ struct globals { | |||
| 327 | #endif | 355 | #endif |
| 328 | smallint exit_code; | 356 | smallint exit_code; |
| 329 | smallint show_dirname; | 357 | smallint show_dirname; |
| 358 | smallint tty_out; | ||
| 330 | #if ENABLE_FEATURE_LS_WIDTH | 359 | #if ENABLE_FEATURE_LS_WIDTH |
| 331 | unsigned terminal_width; | 360 | unsigned terminal_width; |
| 332 | # define G_terminal_width (G.terminal_width) | 361 | # define G_terminal_width (G.terminal_width) |
| @@ -343,16 +372,21 @@ struct globals { | |||
| 343 | setup_common_bufsiz(); \ | 372 | setup_common_bufsiz(); \ |
| 344 | /* we have to zero it out because of NOEXEC */ \ | 373 | /* we have to zero it out because of NOEXEC */ \ |
| 345 | memset(&G, 0, sizeof(G)); \ | 374 | memset(&G, 0, sizeof(G)); \ |
| 346 | IF_FEATURE_LS_WIDTH(G_terminal_width = TERMINAL_WIDTH;) \ | 375 | IF_FEATURE_LS_WIDTH(G_terminal_width = ~0U;) \ |
| 347 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ | 376 | IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ |
| 348 | } while (0) | 377 | } while (0) |
| 349 | 378 | ||
| 350 | #define ESC "\033" | 379 | #define ESC "\033" |
| 351 | 380 | ||
| 381 | static int G_isatty(void) | ||
| 382 | { | ||
| 383 | if (!G.tty_out) /* not known yet? */ | ||
| 384 | G.tty_out = isatty(STDOUT_FILENO) + 1; | ||
| 385 | return (G.tty_out == 2); | ||
| 386 | } | ||
| 352 | 387 | ||
| 353 | /*** Output code ***/ | 388 | /*** Output code ***/ |
| 354 | 389 | ||
| 355 | |||
| 356 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket | 390 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket |
| 357 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file | 391 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file |
| 358 | * 3/7:multiplexed char/block device) | 392 | * 3/7:multiplexed char/block device) |
| @@ -420,6 +454,9 @@ static unsigned calc_name_len(const char *name) | |||
| 420 | unsigned len; | 454 | unsigned len; |
| 421 | uni_stat_t uni_stat; | 455 | uni_stat_t uni_stat; |
| 422 | 456 | ||
| 457 | if (!(option_mask32 & OPT_q)) | ||
| 458 | return strlen(name); | ||
| 459 | |||
| 423 | // TODO: quote tab as \t, etc, if -Q | 460 | // TODO: quote tab as \t, etc, if -Q |
| 424 | name = printable_string2(&uni_stat, name); | 461 | name = printable_string2(&uni_stat, name); |
| 425 | 462 | ||
| @@ -449,6 +486,11 @@ static unsigned print_name(const char *name) | |||
| 449 | unsigned len; | 486 | unsigned len; |
| 450 | uni_stat_t uni_stat; | 487 | uni_stat_t uni_stat; |
| 451 | 488 | ||
| 489 | if (!(option_mask32 & OPT_q)) { | ||
| 490 | fputs_stdout(name); | ||
| 491 | return strlen(name); | ||
| 492 | } | ||
| 493 | |||
| 452 | // TODO: quote tab as \t, etc, if -Q | 494 | // TODO: quote tab as \t, etc, if -Q |
| 453 | name = printable_string2(&uni_stat, name); | 495 | name = printable_string2(&uni_stat, name); |
| 454 | 496 | ||
| @@ -646,7 +688,7 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
| 646 | unsigned i, ncols, nrows, row, nc; | 688 | unsigned i, ncols, nrows, row, nc; |
| 647 | unsigned column; | 689 | unsigned column; |
| 648 | unsigned nexttab; | 690 | unsigned nexttab; |
| 649 | unsigned column_width = 0; /* used only by coulmnal output */ | 691 | unsigned column_width = 0; /* used only by columnar output */ |
| 650 | 692 | ||
| 651 | if (option_mask32 & (OPT_l|OPT_1)) { | 693 | if (option_mask32 & (OPT_l|OPT_1)) { |
| 652 | ncols = 1; | 694 | ncols = 1; |
| @@ -691,6 +733,11 @@ static void display_files(struct dnode **dn, unsigned nfiles) | |||
| 691 | } | 733 | } |
| 692 | nexttab = column + column_width; | 734 | nexttab = column + column_width; |
| 693 | column += display_single(dn[i]); | 735 | column += display_single(dn[i]); |
| 736 | } else { | ||
| 737 | /* if -w999999999, ncols can be very large */ | ||
| 738 | //bb_error_msg(" col:%u ncol:%u i:%i", nc, ncols, i); sleep1(); | ||
| 739 | /* without "break", we loop millions of times here */ | ||
| 740 | break; | ||
| 694 | } | 741 | } |
| 695 | } | 742 | } |
| 696 | putchar('\n'); | 743 | putchar('\n'); |
| @@ -1090,25 +1137,11 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1090 | /* need to initialize since --color has _an optional_ argument */ | 1137 | /* need to initialize since --color has _an optional_ argument */ |
| 1091 | const char *color_opt = color_str; /* "always" */ | 1138 | const char *color_opt = color_str; /* "always" */ |
| 1092 | #endif | 1139 | #endif |
| 1093 | #if ENABLE_LONG_OPTS | ||
| 1094 | static const char ls_longopts[] ALIGN1 = | ||
| 1095 | "full-time\0" No_argument "\xff" | ||
| 1096 | "group-directories-first\0" No_argument "\xfe" | ||
| 1097 | IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") | ||
| 1098 | ; | ||
| 1099 | #endif | ||
| 1100 | 1140 | ||
| 1101 | INIT_G(); | 1141 | INIT_G(); |
| 1102 | 1142 | ||
| 1103 | init_unicode(); | 1143 | init_unicode(); |
| 1104 | 1144 | ||
| 1105 | #if ENABLE_FEATURE_LS_WIDTH | ||
| 1106 | /* obtain the terminal width */ | ||
| 1107 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
| 1108 | /* go one less... */ | ||
| 1109 | G_terminal_width--; | ||
| 1110 | #endif | ||
| 1111 | |||
| 1112 | /* process options */ | 1145 | /* process options */ |
| 1113 | opt = getopt32long(argv, "^" | 1146 | opt = getopt32long(argv, "^" |
| 1114 | ls_options | 1147 | ls_options |
| @@ -1144,6 +1177,17 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1144 | exit(0); | 1177 | exit(0); |
| 1145 | #endif | 1178 | #endif |
| 1146 | 1179 | ||
| 1180 | #if ENABLE_FEATURE_LS_WIDTH | ||
| 1181 | if ((int)G_terminal_width < 0) { | ||
| 1182 | /* obtain the terminal width */ | ||
| 1183 | G_terminal_width = get_terminal_width(STDIN_FILENO); | ||
| 1184 | /* go one less... */ | ||
| 1185 | G_terminal_width--; | ||
| 1186 | } | ||
| 1187 | if (G_terminal_width == 0) /* -w0 */ | ||
| 1188 | G_terminal_width = INT_MAX; /* "infinite" */ | ||
| 1189 | #endif | ||
| 1190 | |||
| 1147 | #if ENABLE_SELINUX | 1191 | #if ENABLE_SELINUX |
| 1148 | if (opt & OPT_Z) { | 1192 | if (opt & OPT_Z) { |
| 1149 | if (!is_selinux_enabled()) | 1193 | if (!is_selinux_enabled()) |
| @@ -1157,7 +1201,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1157 | char *p = getenv("LS_COLORS"); | 1201 | char *p = getenv("LS_COLORS"); |
| 1158 | /* LS_COLORS is unset, or (not empty && not "none") ? */ | 1202 | /* LS_COLORS is unset, or (not empty && not "none") ? */ |
| 1159 | if (!p || (p[0] && strcmp(p, "none") != 0)) { | 1203 | if (!p || (p[0] && strcmp(p, "none") != 0)) { |
| 1160 | if (isatty(STDOUT_FILENO)) { | 1204 | if (G_isatty()) { |
| 1161 | /* check isatty() last because it's expensive (syscall) */ | 1205 | /* check isatty() last because it's expensive (syscall) */ |
| 1162 | G_show_color = 1; | 1206 | G_show_color = 1; |
| 1163 | } | 1207 | } |
| @@ -1166,15 +1210,19 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1166 | if (opt & OPT_color) { | 1210 | if (opt & OPT_color) { |
| 1167 | if (color_opt[0] == 'n') | 1211 | if (color_opt[0] == 'n') |
| 1168 | G_show_color = 0; | 1212 | G_show_color = 0; |
| 1169 | else switch (index_in_substrings(color_str, color_opt)) { | 1213 | else if (!G_show_color) { |
| 1170 | case 3: | 1214 | /* if() is not needed, but avoids extra isatty() if G_show_color is already set */ |
| 1171 | case 4: | 1215 | /* Check --color=COLOR_OPT and maybe set show_color=1 */ |
| 1172 | case 5: | 1216 | switch (index_in_substrings(color_str, color_opt)) { |
| 1173 | if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { | 1217 | case 3: // auto |
| 1174 | case 0: | 1218 | case 4: // tty |
| 1175 | case 1: | 1219 | case 5: // if-tty |
| 1176 | case 2: | 1220 | if (!is_TERM_dumb() && G_isatty()) { |
| 1177 | G_show_color = 1; | 1221 | case 0: // always |
| 1222 | case 1: // yes | ||
| 1223 | case 2: // force | ||
| 1224 | G_show_color = 1; | ||
| 1225 | } | ||
| 1178 | } | 1226 | } |
| 1179 | } | 1227 | } |
| 1180 | } | 1228 | } |
| @@ -1182,7 +1230,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1182 | 1230 | ||
| 1183 | /* sort out which command line options take precedence */ | 1231 | /* sort out which command line options take precedence */ |
| 1184 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) | 1232 | if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) |
| 1185 | option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ | 1233 | opt = option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ |
| 1186 | if (!(opt & OPT_l)) { /* not -l? */ | 1234 | if (!(opt & OPT_l)) { /* not -l? */ |
| 1187 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { | 1235 | if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { |
| 1188 | /* when to sort by time? -t[cu] sorts by time even with -l */ | 1236 | /* when to sort by time? -t[cu] sorts by time even with -l */ |
| @@ -1190,18 +1238,21 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
| 1190 | /* without -l, bare -c or -u enable sort too */ | 1238 | /* without -l, bare -c or -u enable sort too */ |
| 1191 | /* (with -l, bare -c or -u just select which time to show) */ | 1239 | /* (with -l, bare -c or -u just select which time to show) */ |
| 1192 | if (opt & (OPT_c|OPT_u)) { | 1240 | if (opt & (OPT_c|OPT_u)) { |
| 1193 | option_mask32 |= OPT_t; | 1241 | opt = option_mask32 |= OPT_t; |
| 1194 | } | 1242 | } |
| 1195 | } | 1243 | } |
| 1196 | } | 1244 | } |
| 1197 | 1245 | ||
| 1198 | /* choose a display format if one was not already specified by an option */ | 1246 | /* choose a display format if one was not already specified by an option */ |
| 1199 | if (!(option_mask32 & (OPT_l|OPT_1|OPT_x|OPT_C))) | 1247 | if (!(opt & (OPT_l|OPT_1|OPT_x|OPT_C))) |
| 1200 | option_mask32 |= (isatty(STDOUT_FILENO) ? OPT_C : OPT_1); | 1248 | opt = option_mask32 |= (G_isatty() ? OPT_C : OPT_1); |
| 1249 | |||
| 1250 | if (!(opt & OPT_q) && G_isatty()) | ||
| 1251 | opt = option_mask32 |= OPT_q; | ||
| 1201 | 1252 | ||
| 1202 | if (ENABLE_FTPD && applet_name[0] == 'f') { | 1253 | if (ENABLE_FTPD && applet_name[0] == 'f') { |
| 1203 | /* ftpd secret backdoor. dirs first are much nicer */ | 1254 | /* ftpd secret backdoor. dirs first are much nicer */ |
| 1204 | option_mask32 |= OPT_dirs_first; | 1255 | opt = option_mask32 |= OPT_dirs_first; |
| 1205 | } | 1256 | } |
| 1206 | 1257 | ||
| 1207 | argv += optind; | 1258 | argv += optind; |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index b5efa19ac..4c05dcb97 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
| @@ -530,6 +530,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
| 530 | * "fake" short options, like this one: | 530 | * "fake" short options, like this one: |
| 531 | * wget $'-\203' "Test: test" http://kernel.org/ | 531 | * wget $'-\203' "Test: test" http://kernel.org/ |
| 532 | * (supposed to act as --header, but doesn't) */ | 532 | * (supposed to act as --header, but doesn't) */ |
| 533 | next_opt: | ||
| 533 | #if ENABLE_LONG_OPTS | 534 | #if ENABLE_LONG_OPTS |
| 534 | while ((c = getopt_long(argc, argv, applet_opts, | 535 | while ((c = getopt_long(argc, argv, applet_opts, |
| 535 | long_options, NULL)) != -1) { | 536 | long_options, NULL)) != -1) { |
| @@ -544,8 +545,16 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options, | |||
| 544 | * but we construct long opts so that flag | 545 | * but we construct long opts so that flag |
| 545 | * is always NULL (see above) */ | 546 | * is always NULL (see above) */ |
| 546 | if (on_off->opt_char == '\0' /* && c != '\0' */) { | 547 | if (on_off->opt_char == '\0' /* && c != '\0' */) { |
| 547 | /* c is probably '?' - "bad option" */ | 548 | /* We reached the end of complementary[] and did not find -c */ |
| 548 | goto error; | 549 | if (c == '?') /* getopt says: "bad option, or option has no required argument" */ |
| 550 | goto error; | ||
| 551 | /* if there were options beyond 32 bits (example: ls), | ||
| 552 | * they got no complementary[] slot, and no result bit. | ||
| 553 | * IOW: they must be "accept but ignore" options. | ||
| 554 | * For them, we end up here. | ||
| 555 | */ | ||
| 556 | //bb_error_msg("ignored option '%c', skipping", c); | ||
| 557 | goto next_opt; | ||
| 549 | } | 558 | } |
| 550 | } | 559 | } |
| 551 | if (flags & on_off->incongruously) | 560 | if (flags & on_off->incongruously) |
