diff options
author | Ron Yorston <rmy@pobox.com> | 2023-06-16 13:02:47 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-06-16 13:02:47 +0100 |
commit | 4b3d7e62cff6015e1c4b856165efd90cf9182a5c (patch) | |
tree | 0a59c6a94a47c3e8f1a47b0a3218f9591b842385 | |
parent | 0627e352656effac8d8e617378e7a68edfce41df (diff) | |
parent | 2ca39ffd447ca874fcea933194829717d5573247 (diff) | |
download | busybox-w32-4b3d7e62cff6015e1c4b856165efd90cf9182a5c.tar.gz busybox-w32-4b3d7e62cff6015e1c4b856165efd90cf9182a5c.tar.bz2 busybox-w32-4b3d7e62cff6015e1c4b856165efd90cf9182a5c.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | coreutils/od.c | 73 | ||||
-rw-r--r-- | coreutils/od_bloaty.c | 56 | ||||
-rw-r--r-- | editors/awk.c | 409 | ||||
-rw-r--r-- | include/dump.h | 7 | ||||
-rw-r--r-- | libbb/dump.c | 102 | ||||
-rw-r--r-- | networking/tunctl.c | 3 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/elif1.right | 4 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/elif1.tests | 6 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/elif2.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/elif2.tests | 8 | ||||
-rw-r--r-- | shell/hush.c | 31 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/elif1.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/elif1.tests | 6 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/elif2.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/elif2.tests | 8 | ||||
-rwxr-xr-x | testsuite/awk.tests | 116 | ||||
-rwxr-xr-x | testsuite/hexdump.tests | 48 | ||||
-rwxr-xr-x | testsuite/od.tests | 230 | ||||
-rw-r--r-- | testsuite/testing.sh | 10 | ||||
-rw-r--r-- | util-linux/hexdump.c | 30 | ||||
-rw-r--r-- | util-linux/hexdump_xxd.c | 2 |
21 files changed, 892 insertions, 265 deletions
diff --git a/coreutils/od.c b/coreutils/od.c index 6f22331e0..a7b1ba444 100644 --- a/coreutils/od.c +++ b/coreutils/od.c | |||
@@ -22,7 +22,9 @@ | |||
22 | 22 | ||
23 | //usage:#if !ENABLE_DESKTOP | 23 | //usage:#if !ENABLE_DESKTOP |
24 | //usage:#define od_trivial_usage | 24 | //usage:#define od_trivial_usage |
25 | //usage: "[-aBbcDdeFfHhIiLlOovXx] [FILE]" | 25 | //usage: "[-abcdeFfhiloxsv] [FILE]" |
26 | // We also support -BDOHXIL, but they are not documented in coreutils 9.1 | ||
27 | // manpage/help, so don't show them either. | ||
26 | //usage:#define od_full_usage "\n\n" | 28 | //usage:#define od_full_usage "\n\n" |
27 | //usage: "Print FILE (or stdin) unambiguously, as octal bytes by default" | 29 | //usage: "Print FILE (or stdin) unambiguously, as octal bytes by default" |
28 | //usage:#endif | 30 | //usage:#endif |
@@ -144,29 +146,50 @@ odoffset(dumper_t *dumper, int argc, char ***argvp) | |||
144 | } | 146 | } |
145 | } | 147 | } |
146 | 148 | ||
149 | // bb_dump_add(): | ||
150 | // A format string contains format units separated by [optional] whitespace. | ||
151 | // A format unit contains up to three items: an iteration count, a byte count, | ||
152 | // and a format. | ||
153 | // The iteration count is an optional integer (default 1). | ||
154 | // Each format is applied iteration count times. | ||
155 | // The byte count is an optional integer. It defines the number | ||
156 | // of bytes to be interpreted by each iteration of the format. | ||
157 | // If an iteration count and/or a byte count is specified, a slash must be | ||
158 | // placed after the iteration count and/or before the byte count | ||
159 | // to disambiguate them. | ||
160 | // The printf-style format is required and must be surrounded by " "s. | ||
161 | // (Below, each string contains two format units) | ||
147 | static const char *const add_strings[] ALIGN_PTR = { | 162 | static const char *const add_strings[] ALIGN_PTR = { |
148 | "16/1 \"%3_u \" \"\\n\"", /* a */ | 163 | "16/1 \" %3_u\"" "\"\n\"", /* 0: a */ |
149 | "8/2 \" %06o \" \"\\n\"", /* B, o */ | 164 | "8/2 \" %06o\"" "\"\n\"", /* 1: B (undocumented in od), o */ |
150 | "16/1 \"%03o \" \"\\n\"", /* b */ | 165 | "16/1 \" %03o\"" "\"\n\"", /* 2: b */ |
151 | "16/1 \"%3_c \" \"\\n\"", /* c */ | 166 | "16/1 \" %3_c\"" "\"\n\"", /* 3: c */ |
152 | "8/2 \" %05u \" \"\\n\"", /* d */ | 167 | "8/2 \" %5u\"" "\"\n\"", /* 4: d */ |
153 | "4/4 \" %010u \" \"\\n\"", /* D */ | 168 | "4/4 \" %10u\"" "\"\n\"", /* 5: D */ |
154 | "2/8 \" %21.14e \" \"\\n\"", /* e (undocumented in od), F */ | 169 | "2/8 \" %24.14e\"" "\"\n\"", /* 6: e (undocumented in od), F */ |
155 | "4/4 \" %14.7e \" \"\\n\"", /* f */ | 170 | "4/4 \" %15.7e\"" "\"\n\"", /* 7: f */ |
156 | "4/4 \" %08x \" \"\\n\"", /* H, X */ | 171 | "4/4 \" %08x\"" "\"\n\"", /* 8: H, X */ |
157 | "8/2 \" %04x \" \"\\n\"", /* h, x */ | 172 | "8/2 \" %04x\"" "\"\n\"", /* 9: h, x */ |
158 | "4/4 \" %11d \" \"\\n\"", /* I, L, l */ | 173 | "4/4 \" %11d\"" "\"\n\"", /* 10: i */ |
159 | "8/2 \" %6d \" \"\\n\"", /* i */ | 174 | "4/4 \" %011o\"" "\"\n\"", /* 11: O */ |
160 | "4/4 \" %011o \" \"\\n\"", /* O */ | 175 | "8/2 \" %6d\"" "\"\n\"", /* 12: s */ |
176 | /* -I,L,l: depend on word width of the arch (what is "long"?) */ | ||
177 | #if ULONG_MAX > 0xffffffff | ||
178 | "2/8 \" %20lld\"" "\"\n\"", /* 13: I, L, l */ | ||
179 | #define L_ 13 | ||
180 | #else | ||
181 | /* 32-bit arch: -I,L,l are the same as -i */ | ||
182 | #define L_ 10 | ||
183 | #endif | ||
161 | }; | 184 | }; |
162 | 185 | ||
163 | static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv"; | 186 | static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxsv"; |
164 | 187 | ||
165 | static const char od_o2si[] ALIGN1 = { | 188 | static const char od_o2si[] ALIGN1 = { |
166 | 0, 1, 2, 3, 5, | 189 | 0, 1, 2, 3, 5, /* aBbcD */ |
167 | 4, 6, 6, 7, 8, | 190 | 4, 6, 6, 7, 8, /* deFfH */ |
168 | 9, 0xa, 0xb, 0xa, 0xa, | 191 | 9, L_, 10, L_, L_, /* hIiLl */ |
169 | 0xb, 1, 8, 9, | 192 | 11, 1, 8, 9, 12 /* OoXxs */ |
170 | }; | 193 | }; |
171 | 194 | ||
172 | int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 195 | int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -184,19 +207,21 @@ int od_main(int argc, char **argv) | |||
184 | if (first) { | 207 | if (first) { |
185 | first = 0; | 208 | first = 0; |
186 | bb_dump_add(dumper, "\"%07.7_Ao\n\""); | 209 | bb_dump_add(dumper, "\"%07.7_Ao\n\""); |
187 | bb_dump_add(dumper, "\"%07.7_ao \""); | 210 | bb_dump_add(dumper, "\"%07.7_ao\""); |
188 | } else { | 211 | } else { |
189 | bb_dump_add(dumper, "\" \""); | 212 | bb_dump_add(dumper, "\" \""); |
190 | } | 213 | } |
191 | bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); | 214 | bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); |
192 | } else { /* P, p, s, w, or other unhandled */ | 215 | } else { /* P, p, w, or other unhandled */ |
193 | bb_show_usage(); | 216 | bb_show_usage(); |
194 | } | 217 | } |
195 | } | 218 | } |
196 | if (!dumper->fshead) { | 219 | if (!dumper->fshead) { |
197 | bb_dump_add(dumper, "\"%07.7_Ao\n\""); | 220 | bb_dump_add(dumper, "\"%07.7_Ao\n\""); |
198 | bb_dump_add(dumper, "\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); | 221 | bb_dump_add(dumper, "\"%07.7_ao\""); |
222 | bb_dump_add(dumper, add_strings[1]); /* -o format is default */ | ||
199 | } | 223 | } |
224 | dumper->od_eofstring = "\n"; | ||
200 | 225 | ||
201 | argc -= optind; | 226 | argc -= optind; |
202 | argv += optind; | 227 | argv += optind; |
@@ -205,7 +230,7 @@ int od_main(int argc, char **argv) | |||
205 | 230 | ||
206 | return bb_dump_dump(dumper, argv); | 231 | return bb_dump_dump(dumper, argv); |
207 | } | 232 | } |
208 | #endif /* ENABLE_DESKTOP */ | 233 | #endif /* !ENABLE_DESKTOP */ |
209 | 234 | ||
210 | /*- | 235 | /*- |
211 | * Copyright (c) 1990 The Regents of the University of California. | 236 | * Copyright (c) 1990 The Regents of the University of California. |
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index 1830aca83..641d93503 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c | |||
@@ -27,6 +27,8 @@ | |||
27 | //usage:#if ENABLE_DESKTOP | 27 | //usage:#if ENABLE_DESKTOP |
28 | //usage:#define od_trivial_usage | 28 | //usage:#define od_trivial_usage |
29 | //usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..." | 29 | //usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..." |
30 | // We also support -BDOHXIL, but they are not documented in coreutils 9.1 | ||
31 | // manpage/help, so don't show them either. | ||
30 | // We don't support: | 32 | // We don't support: |
31 | // ... [FILE] [[+]OFFSET[.][b]] | 33 | // ... [FILE] [[+]OFFSET[.][b]] |
32 | // Support is buggy for: | 34 | // Support is buggy for: |
@@ -43,26 +45,33 @@ enum { | |||
43 | OPT_b = 1 << 3, | 45 | OPT_b = 1 << 3, |
44 | OPT_c = 1 << 4, | 46 | OPT_c = 1 << 4, |
45 | OPT_d = 1 << 5, | 47 | OPT_d = 1 << 5, |
46 | OPT_f = 1 << 6, | 48 | OPT_D = 1 << 6, /* undocumented in coreutils 9.1 */ |
47 | OPT_h = 1 << 7, | 49 | OPT_f = 1 << 7, |
48 | OPT_i = 1 << 8, | 50 | OPT_h = 1 << 8, |
49 | OPT_j = 1 << 9, | 51 | OPT_H = 1 << 9, /* undocumented in coreutils 9.1 */ |
50 | OPT_l = 1 << 10, | 52 | OPT_i = 1 << 10, |
51 | OPT_o = 1 << 11, | 53 | OPT_I = 1 << 11, /* undocumented in coreutils 9.1 */ |
52 | OPT_t = 1 << 12, | 54 | OPT_j = 1 << 12, |
55 | OPT_l = 1 << 13, | ||
56 | OPT_L = 1 << 14, /* undocumented in coreutils 9.1 */ | ||
57 | OPT_o = 1 << 15, | ||
58 | OPT_O = 1 << 16, /* undocumented in coreutils 9.1 */ | ||
59 | OPT_B = 1 << 17, /* undocumented synonym to -o */ | ||
60 | OPT_t = 1 << 18, | ||
53 | /* When zero and two or more consecutive blocks are equal, format | 61 | /* When zero and two or more consecutive blocks are equal, format |
54 | only the first block and output an asterisk alone on the following | 62 | only the first block and output an asterisk alone on the following |
55 | line to indicate that identical blocks have been elided: */ | 63 | line to indicate that identical blocks have been elided: */ |
56 | OPT_v = 1 << 13, | 64 | OPT_v = 1 << 19, |
57 | OPT_x = 1 << 14, | 65 | OPT_x = 1 << 20, |
58 | OPT_s = 1 << 15, | 66 | OPT_X = 1 << 21, /* undocumented in coreutils 9.1 */ |
59 | OPT_S = 1 << 16, | 67 | OPT_s = 1 << 22, |
60 | OPT_w = 1 << 17, | 68 | OPT_S = 1 << 23, |
61 | OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, | 69 | OPT_w = 1 << 24, |
70 | OPT_traditional = (1 << 25) * ENABLE_LONG_OPTS, | ||
62 | }; | 71 | }; |
63 | 72 | ||
64 | #define OD_GETOPT32() getopt32long(argv, \ | 73 | #define OD_GETOPT32() getopt32long(argv, \ |
65 | "A:N:abcdfhij:lot:*vxsS:w:+:", od_longopts, \ | 74 | "A:N:abcdDfhHiIj:lLoOBt:*vxXsS:w:+:", od_longopts, \ |
66 | /* -w with optional param */ \ | 75 | /* -w with optional param */ \ |
67 | /* -S was -s and also had optional parameter */ \ | 76 | /* -S was -s and also had optional parameter */ \ |
68 | /* but in coreutils 6.3 it was renamed and now has */ \ | 77 | /* but in coreutils 6.3 it was renamed and now has */ \ |
@@ -1246,20 +1255,29 @@ int od_main(int argc UNUSED_PARAM, char **argv) | |||
1246 | if (opt & OPT_N) { | 1255 | if (opt & OPT_N) { |
1247 | max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes); | 1256 | max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes); |
1248 | } | 1257 | } |
1258 | |||
1249 | if (opt & OPT_a) decode_format_string("a"); | 1259 | if (opt & OPT_a) decode_format_string("a"); |
1250 | if (opt & OPT_b) decode_format_string("oC"); | 1260 | if (opt & OPT_b) decode_format_string("oC"); |
1251 | if (opt & OPT_c) decode_format_string("c"); | 1261 | if (opt & OPT_c) decode_format_string("c"); |
1252 | if (opt & OPT_d) decode_format_string("u2"); | 1262 | if (opt & OPT_d) decode_format_string("u2"); |
1263 | if (opt & OPT_D) decode_format_string("uI"); | ||
1253 | if (opt & OPT_f) decode_format_string("fF"); | 1264 | if (opt & OPT_f) decode_format_string("fF"); |
1254 | if (opt & OPT_h) decode_format_string("x2"); | 1265 | if (opt & (OPT_h|OPT_x)) decode_format_string("x2"); |
1255 | if (opt & OPT_i) decode_format_string("d2"); | 1266 | if (opt & (OPT_H|OPT_X)) decode_format_string("xI"); |
1267 | /* -I,L,l: depend on word width of the arch (what is "long"?) */ | ||
1268 | #if ULONG_MAX > 0xffffffff | ||
1269 | if (opt & OPT_i) decode_format_string("dI"); | ||
1270 | if (opt & (OPT_I|OPT_l|OPT_L)) decode_format_string("dL"); | ||
1271 | #else | ||
1272 | /* 32-bit arch: -I,L,l are the same as -i */ | ||
1273 | if (opt & (OPT_i|OPT_I|OPT_l|OPT_L)) decode_format_string("dI"); | ||
1274 | #endif | ||
1256 | if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes); | 1275 | if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes); |
1257 | if (opt & OPT_l) decode_format_string("d4"); | 1276 | if (opt & (OPT_o|OPT_B)) decode_format_string("o2"); |
1258 | if (opt & OPT_o) decode_format_string("o2"); | 1277 | if (opt & OPT_O) decode_format_string("oI"); |
1259 | while (lst_t) { | 1278 | while (lst_t) { |
1260 | decode_format_string(llist_pop(&lst_t)); | 1279 | decode_format_string(llist_pop(&lst_t)); |
1261 | } | 1280 | } |
1262 | if (opt & OPT_x) decode_format_string("x2"); | ||
1263 | if (opt & OPT_s) decode_format_string("d2"); | 1281 | if (opt & OPT_s) decode_format_string("d2"); |
1264 | if (opt & OPT_S) { | 1282 | if (opt & OPT_S) { |
1265 | G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); | 1283 | G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); |
diff --git a/editors/awk.c b/editors/awk.c index 2c1272554..878fffa1a 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -337,7 +337,9 @@ static void debug_parse_print_tc(uint32_t n) | |||
337 | #undef P | 337 | #undef P |
338 | #undef PRIMASK | 338 | #undef PRIMASK |
339 | #undef PRIMASK2 | 339 | #undef PRIMASK2 |
340 | #define P(x) (x << 24) | 340 | /* Smaller 'x' means _higher_ operator precedence */ |
341 | #define PRECEDENCE(x) (x << 24) | ||
342 | #define P(x) PRECEDENCE(x) | ||
341 | #define PRIMASK 0x7F000000 | 343 | #define PRIMASK 0x7F000000 |
342 | #define PRIMASK2 0x7E000000 | 344 | #define PRIMASK2 0x7E000000 |
343 | 345 | ||
@@ -360,7 +362,7 @@ enum { | |||
360 | OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100, | 362 | OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100, |
361 | OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400, | 363 | OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400, |
362 | OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700, | 364 | OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700, |
363 | OC_DONE = 0x2800, | 365 | OC_CONST = 0x2800, OC_DONE = 0x2900, |
364 | 366 | ||
365 | ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200, | 367 | ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200, |
366 | ST_WHILE = 0x3300 | 368 | ST_WHILE = 0x3300 |
@@ -440,9 +442,9 @@ static const uint32_t tokeninfo[] ALIGN4 = { | |||
440 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') | 442 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') |
441 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') | 443 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') |
442 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), | 444 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), |
443 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', | 445 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(38), OC_REPLACE|NV|P(38)|'+', OC_REPLACE|NV|P(38)|'-', |
444 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | 446 | OC_REPLACE|NV|P(38)|'*', OC_REPLACE|NV|P(38)|'/', OC_REPLACE|NV|P(38)|'%', OC_REPLACE|NV|P(38)|'&', |
445 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | 447 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(38)|'&', OC_BINARY|NV|P(15)|'&', |
446 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | 448 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
447 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | 449 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
448 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) | 450 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) |
@@ -546,7 +548,6 @@ struct globals { | |||
546 | chain beginseq, mainseq, endseq; | 548 | chain beginseq, mainseq, endseq; |
547 | chain *seq; | 549 | chain *seq; |
548 | node *break_ptr, *continue_ptr; | 550 | node *break_ptr, *continue_ptr; |
549 | rstream *iF; | ||
550 | xhash *ahash; /* argument names, used only while parsing function bodies */ | 551 | xhash *ahash; /* argument names, used only while parsing function bodies */ |
551 | xhash *fnhash; /* function names, used only in parsing stage */ | 552 | xhash *fnhash; /* function names, used only in parsing stage */ |
552 | xhash *vhash; /* variables and arrays */ | 553 | xhash *vhash; /* variables and arrays */ |
@@ -555,7 +556,7 @@ struct globals { | |||
555 | const char *g_progname; | 556 | const char *g_progname; |
556 | int g_lineno; | 557 | int g_lineno; |
557 | int nfields; | 558 | int nfields; |
558 | int maxfields; /* used in fsrealloc() only */ | 559 | unsigned maxfields; |
559 | var *Fields; | 560 | var *Fields; |
560 | char *g_pos; | 561 | char *g_pos; |
561 | char g_saved_ch; | 562 | char g_saved_ch; |
@@ -579,11 +580,13 @@ struct globals2 { | |||
579 | 580 | ||
580 | var *intvar[NUM_INTERNAL_VARS]; /* often used */ | 581 | var *intvar[NUM_INTERNAL_VARS]; /* often used */ |
581 | 582 | ||
583 | rstream iF; | ||
584 | |||
582 | /* former statics from various functions */ | 585 | /* former statics from various functions */ |
583 | char *split_f0__fstrings; | 586 | char *split_f0__fstrings; |
584 | 587 | ||
585 | rstream next_input_file__rsm; | 588 | unsigned next_input_file__argind; |
586 | smallint next_input_file__files_happen; | 589 | smallint next_input_file__input_file_seen; |
587 | 590 | ||
588 | smalluint exitcode; | 591 | smalluint exitcode; |
589 | 592 | ||
@@ -618,7 +621,6 @@ struct globals2 { | |||
618 | #define seq (G1.seq ) | 621 | #define seq (G1.seq ) |
619 | #define break_ptr (G1.break_ptr ) | 622 | #define break_ptr (G1.break_ptr ) |
620 | #define continue_ptr (G1.continue_ptr) | 623 | #define continue_ptr (G1.continue_ptr) |
621 | #define iF (G1.iF ) | ||
622 | #define ahash (G1.ahash ) | 624 | #define ahash (G1.ahash ) |
623 | #define fnhash (G1.fnhash ) | 625 | #define fnhash (G1.fnhash ) |
624 | #define vhash (G1.vhash ) | 626 | #define vhash (G1.vhash ) |
@@ -644,6 +646,7 @@ struct globals2 { | |||
644 | #define t_string (G.t_string ) | 646 | #define t_string (G.t_string ) |
645 | #define t_lineno (G.t_lineno ) | 647 | #define t_lineno (G.t_lineno ) |
646 | #define intvar (G.intvar ) | 648 | #define intvar (G.intvar ) |
649 | #define iF (G.iF ) | ||
647 | #define fsplitter (G.fsplitter ) | 650 | #define fsplitter (G.fsplitter ) |
648 | #define rsplitter (G.rsplitter ) | 651 | #define rsplitter (G.rsplitter ) |
649 | #define g_buf (G.g_buf ) | 652 | #define g_buf (G.g_buf ) |
@@ -978,6 +981,11 @@ static var *setvar_s(var *v, const char *value) | |||
978 | return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); | 981 | return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); |
979 | } | 982 | } |
980 | 983 | ||
984 | static var *setvar_sn(var *v, const char *value, int len) | ||
985 | { | ||
986 | return setvar_p(v, (value && *value && len > 0) ? xstrndup(value, len) : NULL); | ||
987 | } | ||
988 | |||
981 | /* same as setvar_s but sets USER flag */ | 989 | /* same as setvar_s but sets USER flag */ |
982 | static var *setvar_u(var *v, const char *value) | 990 | static var *setvar_u(var *v, const char *value) |
983 | { | 991 | { |
@@ -1005,6 +1013,11 @@ static var *setvar_i(var *v, double value) | |||
1005 | return v; | 1013 | return v; |
1006 | } | 1014 | } |
1007 | 1015 | ||
1016 | static void setvar_ERRNO(void) | ||
1017 | { | ||
1018 | setvar_i(intvar[ERRNO], errno); | ||
1019 | } | ||
1020 | |||
1008 | static const char *getvar_s(var *v) | 1021 | static const char *getvar_s(var *v) |
1009 | { | 1022 | { |
1010 | /* if v is numeric and has no cached string, convert it to string */ | 1023 | /* if v is numeric and has no cached string, convert it to string */ |
@@ -1290,7 +1303,7 @@ static uint32_t next_token(uint32_t expected) | |||
1290 | save_tclass = tc; | 1303 | save_tclass = tc; |
1291 | save_info = t_info; | 1304 | save_info = t_info; |
1292 | tc = TC_BINOPX; | 1305 | tc = TC_BINOPX; |
1293 | t_info = OC_CONCAT | SS | P(35); | 1306 | t_info = OC_CONCAT | SS | PRECEDENCE(35); |
1294 | } | 1307 | } |
1295 | 1308 | ||
1296 | t_tclass = tc; | 1309 | t_tclass = tc; |
@@ -1350,9 +1363,8 @@ static node *parse_expr(uint32_t term_tc) | |||
1350 | { | 1363 | { |
1351 | node sn; | 1364 | node sn; |
1352 | node *cn = &sn; | 1365 | node *cn = &sn; |
1353 | node *vn, *glptr; | 1366 | node *glptr; |
1354 | uint32_t tc, expected_tc; | 1367 | uint32_t tc, expected_tc; |
1355 | var *v; | ||
1356 | 1368 | ||
1357 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); | 1369 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); |
1358 | debug_parse_print_tc(term_tc); | 1370 | debug_parse_print_tc(term_tc); |
@@ -1363,11 +1375,12 @@ static node *parse_expr(uint32_t term_tc) | |||
1363 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP | term_tc; | 1375 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP | term_tc; |
1364 | 1376 | ||
1365 | while (!((tc = next_token(expected_tc)) & term_tc)) { | 1377 | while (!((tc = next_token(expected_tc)) & term_tc)) { |
1378 | node *vn; | ||
1366 | 1379 | ||
1367 | if (glptr && (t_info == TI_LESS)) { | 1380 | if (glptr && (t_info == TI_LESS)) { |
1368 | /* input redirection (<) attached to glptr node */ | 1381 | /* input redirection (<) attached to glptr node */ |
1369 | debug_printf_parse("%s: input redir\n", __func__); | 1382 | debug_printf_parse("%s: input redir\n", __func__); |
1370 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); | 1383 | cn = glptr->l.n = new_node(OC_CONCAT | SS | PRECEDENCE(37)); |
1371 | cn->a.n = glptr; | 1384 | cn->a.n = glptr; |
1372 | expected_tc = TS_OPERAND | TS_UOPPRE; | 1385 | expected_tc = TS_OPERAND | TS_UOPPRE; |
1373 | glptr = NULL; | 1386 | glptr = NULL; |
@@ -1379,24 +1392,42 @@ static node *parse_expr(uint32_t term_tc) | |||
1379 | * previous operators with higher priority */ | 1392 | * previous operators with higher priority */ |
1380 | vn = cn; | 1393 | vn = cn; |
1381 | while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) | 1394 | while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) |
1382 | || ((t_info == vn->info) && t_info == TI_COLON) | 1395 | || (t_info == vn->info && t_info == TI_COLON) |
1383 | ) { | 1396 | ) { |
1384 | vn = vn->a.n; | 1397 | vn = vn->a.n; |
1385 | if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); | 1398 | if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); |
1386 | } | 1399 | } |
1387 | if (t_info == TI_TERNARY) | 1400 | if (t_info == TI_TERNARY) |
1388 | //TODO: why? | 1401 | //TODO: why? |
1389 | t_info += P(6); | 1402 | t_info += PRECEDENCE(6); |
1390 | cn = vn->a.n->r.n = new_node(t_info); | 1403 | cn = vn->a.n->r.n = new_node(t_info); |
1391 | cn->a.n = vn->a.n; | 1404 | cn->a.n = vn->a.n; |
1392 | if (tc & TS_BINOP) { | 1405 | if (tc & TS_BINOP) { |
1393 | cn->l.n = vn; | 1406 | cn->l.n = vn; |
1394 | //FIXME: this is the place to detect and reject assignments to non-lvalues. | 1407 | |
1395 | //Currently we allow "assignments" to consts and temporaries, nonsense like this: | 1408 | /* Prevent: |
1396 | // awk 'BEGIN { "qwe" = 1 }' | 1409 | * awk 'BEGIN { "qwe" = 1 }' |
1397 | // awk 'BEGIN { 7 *= 7 }' | 1410 | * awk 'BEGIN { 7 *= 7 }' |
1398 | // awk 'BEGIN { length("qwe") = 1 }' | 1411 | * awk 'BEGIN { length("qwe") = 1 }' |
1399 | // awk 'BEGIN { (1+1) += 3 }' | 1412 | * awk 'BEGIN { (1+1) += 3 }' |
1413 | */ | ||
1414 | /* Assignment? (including *= and friends) */ | ||
1415 | if (((t_info & OPCLSMASK) == OC_MOVE) | ||
1416 | || ((t_info & OPCLSMASK) == OC_REPLACE) | ||
1417 | ) { | ||
1418 | debug_printf_parse("%s: MOVE/REPLACE vn->info:%08x\n", __func__, vn->info); | ||
1419 | /* Left side is a (variable or array element) | ||
1420 | * or function argument | ||
1421 | * or $FIELD ? | ||
1422 | */ | ||
1423 | if ((vn->info & OPCLSMASK) != OC_VAR | ||
1424 | && (vn->info & OPCLSMASK) != OC_FNARG | ||
1425 | && (vn->info & OPCLSMASK) != OC_FIELD | ||
1426 | ) { | ||
1427 | syntax_error(EMSG_UNEXP_TOKEN); /* no. bad */ | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1400 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; | 1431 | expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; |
1401 | if (t_info == TI_PGETLINE) { | 1432 | if (t_info == TI_PGETLINE) { |
1402 | /* it's a pipe */ | 1433 | /* it's a pipe */ |
@@ -1432,6 +1463,8 @@ static node *parse_expr(uint32_t term_tc) | |||
1432 | /* one should be very careful with switch on tclass - | 1463 | /* one should be very careful with switch on tclass - |
1433 | * only simple tclasses should be used (TC_xyz, not TS_xyz) */ | 1464 | * only simple tclasses should be used (TC_xyz, not TS_xyz) */ |
1434 | switch (tc) { | 1465 | switch (tc) { |
1466 | var *v; | ||
1467 | |||
1435 | case TC_VARIABLE: | 1468 | case TC_VARIABLE: |
1436 | case TC_ARRAY: | 1469 | case TC_ARRAY: |
1437 | debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); | 1470 | debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); |
@@ -1452,14 +1485,14 @@ static node *parse_expr(uint32_t term_tc) | |||
1452 | case TC_NUMBER: | 1485 | case TC_NUMBER: |
1453 | case TC_STRING: | 1486 | case TC_STRING: |
1454 | debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); | 1487 | debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); |
1455 | cn->info = OC_VAR; | 1488 | cn->info = OC_CONST; |
1456 | v = cn->l.v = xzalloc(sizeof(var)); | 1489 | v = cn->l.v = xzalloc(sizeof(var)); |
1457 | if (tc & TC_NUMBER) | 1490 | if (tc & TC_NUMBER) { |
1458 | setvar_i(v, t_double); | 1491 | setvar_i(v, t_double); |
1459 | else { | 1492 | } else { |
1460 | setvar_s(v, t_string); | 1493 | setvar_s(v, t_string); |
1461 | expected_tc &= ~TC_UOPPOST; /* "str"++ is not allowed */ | ||
1462 | } | 1494 | } |
1495 | expected_tc &= ~TC_UOPPOST; /* NUM++, "str"++ not allowed */ | ||
1463 | break; | 1496 | break; |
1464 | 1497 | ||
1465 | case TC_REGEXP: | 1498 | case TC_REGEXP: |
@@ -1931,9 +1964,9 @@ static void fsrealloc(int size) | |||
1931 | { | 1964 | { |
1932 | int i, newsize; | 1965 | int i, newsize; |
1933 | 1966 | ||
1934 | if (size >= maxfields) { | 1967 | if ((unsigned)size >= maxfields) { |
1935 | /* Sanity cap, easier than catering for overflows */ | 1968 | /* Sanity cap, easier than catering for over/underflows */ |
1936 | if (size > 0xffffff) | 1969 | if ((unsigned)size > 0xffffff) |
1937 | bb_die_memory_exhausted(); | 1970 | bb_die_memory_exhausted(); |
1938 | 1971 | ||
1939 | i = maxfields; | 1972 | i = maxfields; |
@@ -2049,13 +2082,17 @@ static int awk_split(const char *s, node *spl, char **slist) | |||
2049 | } | 2082 | } |
2050 | return n; | 2083 | return n; |
2051 | } | 2084 | } |
2052 | /* space split */ | 2085 | /* space split: "In the special case that FS is a single space, |
2086 | * fields are separated by runs of spaces and/or tabs and/or newlines" | ||
2087 | */ | ||
2053 | while (*s) { | 2088 | while (*s) { |
2054 | s = skip_whitespace(s); | 2089 | /* s = skip_whitespace(s); -- WRONG (also skips \v \f \r) */ |
2090 | while (*s == ' ' || *s == '\t' || *s == '\n') | ||
2091 | s++; | ||
2055 | if (!*s) | 2092 | if (!*s) |
2056 | break; | 2093 | break; |
2057 | n++; | 2094 | n++; |
2058 | while (*s && !isspace(*s)) | 2095 | while (*s && !(*s == ' ' || *s == '\t' || *s == '\n')) |
2059 | *s1++ = *s++; | 2096 | *s1++ = *s++; |
2060 | *s1++ = '\0'; | 2097 | *s1++ = '\0'; |
2061 | } | 2098 | } |
@@ -2232,9 +2269,9 @@ static int awk_getline(rstream *rsm, var *v) | |||
2232 | { | 2269 | { |
2233 | char *b; | 2270 | char *b; |
2234 | regmatch_t pmatch[1]; | 2271 | regmatch_t pmatch[1]; |
2235 | int size, a, p, pp = 0; | 2272 | int p, pp; |
2236 | int fd, so, eo, r, rp; | 2273 | int fd, so, eo, retval, rp; |
2237 | char c, *m, *s; | 2274 | char *m, *s; |
2238 | 2275 | ||
2239 | debug_printf_eval("entered %s()\n", __func__); | 2276 | debug_printf_eval("entered %s()\n", __func__); |
2240 | 2277 | ||
@@ -2243,23 +2280,22 @@ static int awk_getline(rstream *rsm, var *v) | |||
2243 | */ | 2280 | */ |
2244 | fd = fileno(rsm->F); | 2281 | fd = fileno(rsm->F); |
2245 | m = rsm->buffer; | 2282 | m = rsm->buffer; |
2246 | a = rsm->adv; | 2283 | if (!m) |
2284 | m = qrealloc(m, 256, &rsm->size); | ||
2247 | p = rsm->pos; | 2285 | p = rsm->pos; |
2248 | size = rsm->size; | ||
2249 | c = (char) rsplitter.n.info; | ||
2250 | rp = 0; | 2286 | rp = 0; |
2251 | 2287 | pp = 0; | |
2252 | if (!m) | ||
2253 | m = qrealloc(m, 256, &size); | ||
2254 | 2288 | ||
2255 | do { | 2289 | do { |
2256 | b = m + a; | 2290 | b = m + rsm->adv; |
2257 | so = eo = p; | 2291 | so = eo = p; |
2258 | r = 1; | 2292 | retval = 1; |
2259 | if (p > 0) { | 2293 | if (p > 0) { |
2294 | char c = (char) rsplitter.n.info; | ||
2260 | if (rsplitter.n.info == TI_REGEXP) { | 2295 | if (rsplitter.n.info == TI_REGEXP) { |
2261 | if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, | 2296 | if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, |
2262 | b, 1, pmatch, 0) == 0) { | 2297 | b, 1, pmatch, 0) == 0 |
2298 | ) { | ||
2263 | so = pmatch[0].rm_so; | 2299 | so = pmatch[0].rm_so; |
2264 | eo = pmatch[0].rm_eo; | 2300 | eo = pmatch[0].rm_eo; |
2265 | if (b[eo] != '\0') | 2301 | if (b[eo] != '\0') |
@@ -2288,45 +2324,38 @@ static int awk_getline(rstream *rsm, var *v) | |||
2288 | } | 2324 | } |
2289 | } | 2325 | } |
2290 | 2326 | ||
2291 | if (a > 0) { | 2327 | if (rsm->adv > 0) { |
2292 | memmove(m, m+a, p+1); | 2328 | memmove(m, m+rsm->adv, p+1); |
2293 | b = m; | 2329 | b = m; |
2294 | a = 0; | 2330 | rsm->adv = 0; |
2295 | } | 2331 | } |
2296 | 2332 | ||
2297 | m = qrealloc(m, a+p+128, &size); | 2333 | b = m = qrealloc(m, p+128, &rsm->size); |
2298 | b = m + a; | ||
2299 | pp = p; | 2334 | pp = p; |
2300 | p += safe_read(fd, b+p, size-p-1); | 2335 | p += safe_read(fd, b+p, rsm->size - p - 1); |
2301 | if (p < pp) { | 2336 | if (p < pp) { |
2302 | p = 0; | 2337 | p = 0; |
2303 | r = 0; | 2338 | retval = 0; |
2304 | setvar_i(intvar[ERRNO], errno); | 2339 | setvar_ERRNO(); |
2305 | } | 2340 | } |
2306 | b[p] = '\0'; | 2341 | b[p] = '\0'; |
2307 | |||
2308 | } while (p > pp); | 2342 | } while (p > pp); |
2309 | 2343 | ||
2310 | if (p == 0) { | 2344 | if (p == 0) { |
2311 | r--; | 2345 | retval--; |
2312 | } else { | 2346 | } else { |
2313 | c = b[so]; b[so] = '\0'; | 2347 | setvar_sn(v, b+rp, so-rp); |
2314 | setvar_s(v, b+rp); | ||
2315 | v->type |= VF_USER; | 2348 | v->type |= VF_USER; |
2316 | b[so] = c; | 2349 | setvar_sn(intvar[RT], b+so, eo-so); |
2317 | c = b[eo]; b[eo] = '\0'; | ||
2318 | setvar_s(intvar[RT], b+so); | ||
2319 | b[eo] = c; | ||
2320 | } | 2350 | } |
2321 | 2351 | ||
2322 | rsm->buffer = m; | 2352 | rsm->buffer = m; |
2323 | rsm->adv = a + eo; | 2353 | rsm->adv += eo; |
2324 | rsm->pos = p - eo; | 2354 | rsm->pos = p - eo; |
2325 | rsm->size = size; | ||
2326 | 2355 | ||
2327 | debug_printf_eval("returning from %s(): %d\n", __func__, r); | 2356 | debug_printf_eval("returning from %s(): %d\n", __func__, retval); |
2328 | 2357 | ||
2329 | return r; | 2358 | return retval; |
2330 | } | 2359 | } |
2331 | 2360 | ||
2332 | /* formatted output into an allocated buffer, return ptr to buffer */ | 2361 | /* formatted output into an allocated buffer, return ptr to buffer */ |
@@ -2382,7 +2411,7 @@ static char *awk_printf(node *n, size_t *len) | |||
2382 | while (1) { | 2411 | while (1) { |
2383 | if (isalpha(c)) | 2412 | if (isalpha(c)) |
2384 | break; | 2413 | break; |
2385 | if (c == '*') | 2414 | if (c == '*') /* gawk supports %*d and %*.*f, we don't... */ |
2386 | syntax_error("%*x formats are not supported"); | 2415 | syntax_error("%*x formats are not supported"); |
2387 | c = *++f; | 2416 | c = *++f; |
2388 | if (!c) { /* "....%...." and no letter found after % */ | 2417 | if (!c) { /* "....%...." and no letter found after % */ |
@@ -2415,12 +2444,18 @@ static char *awk_printf(node *n, size_t *len) | |||
2415 | double d = getvar_i(arg); | 2444 | double d = getvar_i(arg); |
2416 | if (strchr("diouxX", c)) { | 2445 | if (strchr("diouxX", c)) { |
2417 | //TODO: make it wider here (%x -> %llx etc)? | 2446 | //TODO: make it wider here (%x -> %llx etc)? |
2447 | //Can even print the value into a temp string with %.0f, | ||
2448 | //then replace diouxX with s and print that string. | ||
2449 | //This will correctly print even very large numbers, | ||
2450 | //but some replacements are not equivalent: | ||
2451 | //%09d -> %09s: breaks zero-padding; | ||
2452 | //%+d -> %+s: won't prepend +; etc | ||
2418 | s = xasprintf(s, (int)d); | 2453 | s = xasprintf(s, (int)d); |
2419 | } else if (strchr("eEfFgGaA", c)) { | 2454 | } else if (strchr("eEfFgGaA", c)) { |
2420 | s = xasprintf(s, d); | 2455 | s = xasprintf(s, d); |
2421 | } else { | 2456 | } else { |
2422 | //TODO: GNU Awk 5.0.1: printf "%W" prints "%W", does not error out | 2457 | /* gawk 5.1.1 printf("%W") prints "%W", does not error out */ |
2423 | syntax_error(EMSG_INV_FMT); | 2458 | s = xstrndup(s, f - s); |
2424 | } | 2459 | } |
2425 | } | 2460 | } |
2426 | slen = strlen(s); | 2461 | slen = strlen(s); |
@@ -2457,9 +2492,9 @@ static char *awk_printf(node *n, size_t *len) | |||
2457 | * store result into (dest), return number of substitutions. | 2492 | * store result into (dest), return number of substitutions. |
2458 | * If nm = 0, replace all matches. | 2493 | * If nm = 0, replace all matches. |
2459 | * If src or dst is NULL, use $0. | 2494 | * If src or dst is NULL, use $0. |
2460 | * If subexp != 0, enable subexpression matching (\1-\9). | 2495 | * If subexp != 0, enable subexpression matching (\0-\9). |
2461 | */ | 2496 | */ |
2462 | static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int subexp) | 2497 | static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest /*,int subexp*/) |
2463 | { | 2498 | { |
2464 | char *resbuf; | 2499 | char *resbuf; |
2465 | const char *sp; | 2500 | const char *sp; |
@@ -2467,17 +2502,48 @@ static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int | |||
2467 | int regexec_flags; | 2502 | int regexec_flags; |
2468 | regmatch_t pmatch[10]; | 2503 | regmatch_t pmatch[10]; |
2469 | regex_t sreg, *regex; | 2504 | regex_t sreg, *regex; |
2470 | 2505 | /* True only if called to implement gensub(): */ | |
2506 | int subexp = (src != dest); | ||
2507 | #if defined(REG_STARTEND) | ||
2508 | const char *src_string; | ||
2509 | size_t src_strlen; | ||
2510 | regexec_flags = REG_STARTEND; | ||
2511 | #else | ||
2512 | regexec_flags = 0; | ||
2513 | #endif | ||
2471 | resbuf = NULL; | 2514 | resbuf = NULL; |
2472 | residx = 0; | 2515 | residx = 0; |
2473 | match_no = 0; | 2516 | match_no = 0; |
2474 | regexec_flags = 0; | ||
2475 | regex = as_regex(rn, &sreg); | 2517 | regex = as_regex(rn, &sreg); |
2476 | sp = getvar_s(src ? src : intvar[F0]); | 2518 | sp = getvar_s(src ? src : intvar[F0]); |
2519 | #if defined(REG_STARTEND) | ||
2520 | src_string = sp; | ||
2521 | src_strlen = strlen(src_string); | ||
2522 | #endif | ||
2477 | replen = strlen(repl); | 2523 | replen = strlen(repl); |
2478 | while (regexec(regex, sp, 10, pmatch, regexec_flags) == 0) { | 2524 | for (;;) { |
2479 | int so = pmatch[0].rm_so; | 2525 | int so, eo; |
2480 | int eo = pmatch[0].rm_eo; | 2526 | |
2527 | #if defined(REG_STARTEND) | ||
2528 | // REG_STARTEND: "This flag is a BSD extension, not present in POSIX" | ||
2529 | size_t start_ofs = sp - src_string; | ||
2530 | pmatch[0].rm_so = start_ofs; | ||
2531 | pmatch[0].rm_eo = src_strlen; | ||
2532 | if (regexec(regex, src_string, 10, pmatch, regexec_flags) != 0) | ||
2533 | break; | ||
2534 | eo = pmatch[0].rm_eo - start_ofs; | ||
2535 | so = pmatch[0].rm_so - start_ofs; | ||
2536 | #else | ||
2537 | // BUG: | ||
2538 | // gsub(/\<b*/,"") on "abc" matches empty string at "a...", | ||
2539 | // advances sp one char (see "Empty match" comment later) to "bc" | ||
2540 | // ... and erroneously matches "b" even though it is NOT at the word start. | ||
2541 | enum { start_ofs = 0 }; | ||
2542 | if (regexec(regex, sp, 10, pmatch, regexec_flags) != 0) | ||
2543 | break; | ||
2544 | so = pmatch[0].rm_so; | ||
2545 | eo = pmatch[0].rm_eo; | ||
2546 | #endif | ||
2481 | 2547 | ||
2482 | //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp); | 2548 | //bb_error_msg("match %u: [%u,%u] '%s'%p", match_no+1, so, eo, sp,sp); |
2483 | resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize); | 2549 | resbuf = qrealloc(resbuf, residx + eo + replen, &resbufsize); |
@@ -2485,51 +2551,41 @@ static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int | |||
2485 | residx += eo; | 2551 | residx += eo; |
2486 | if (++match_no >= nm) { | 2552 | if (++match_no >= nm) { |
2487 | const char *s; | 2553 | const char *s; |
2488 | int nbs; | 2554 | int bslash; |
2489 | 2555 | ||
2490 | /* replace */ | 2556 | /* replace */ |
2491 | residx -= (eo - so); | 2557 | residx -= (eo - so); |
2492 | nbs = 0; | 2558 | bslash = 0; |
2493 | for (s = repl; *s; s++) { | 2559 | for (s = repl; *s; s++) { |
2494 | char c = resbuf[residx++] = *s; | 2560 | char c = *s; |
2495 | if (c == '\\') { | 2561 | if (c == '\\' && s[1]) { |
2496 | nbs++; | 2562 | bslash ^= 1; |
2497 | continue; | 2563 | if (bslash) |
2564 | continue; | ||
2498 | } | 2565 | } |
2499 | if (c == '&' || (subexp && c >= '0' && c <= '9')) { | 2566 | if ((!bslash && c == '&') |
2500 | int j; | 2567 | || (subexp && bslash && c >= '0' && c <= '9') |
2501 | residx -= ((nbs + 3) >> 1); | 2568 | ) { |
2502 | j = 0; | 2569 | int n, j = 0; |
2503 | if (c != '&') { | 2570 | if (c != '&') { |
2504 | j = c - '0'; | 2571 | j = c - '0'; |
2505 | nbs++; | ||
2506 | } | 2572 | } |
2507 | if (nbs % 2) { | 2573 | n = pmatch[j].rm_eo - pmatch[j].rm_so; |
2508 | resbuf[residx++] = c; | 2574 | resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize); |
2509 | } else { | 2575 | memcpy(resbuf + residx, sp + pmatch[j].rm_so - start_ofs, n); |
2510 | int n = pmatch[j].rm_eo - pmatch[j].rm_so; | 2576 | residx += n; |
2511 | resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize); | 2577 | } else |
2512 | memcpy(resbuf + residx, sp + pmatch[j].rm_so, n); | 2578 | resbuf[residx++] = c; |
2513 | residx += n; | 2579 | bslash = 0; |
2514 | } | ||
2515 | } | ||
2516 | nbs = 0; | ||
2517 | } | 2580 | } |
2518 | } | 2581 | } |
2519 | 2582 | ||
2520 | regexec_flags = REG_NOTBOL; | ||
2521 | sp += eo; | 2583 | sp += eo; |
2522 | if (match_no == nm) | 2584 | if (match_no == nm) |
2523 | break; | 2585 | break; |
2524 | if (eo == so) { | 2586 | if (eo == so) { |
2525 | /* Empty match (e.g. "b*" will match anywhere). | 2587 | /* Empty match (e.g. "b*" will match anywhere). |
2526 | * Advance by one char. */ | 2588 | * Advance by one char. */ |
2527 | //BUG (bug 1333): | ||
2528 | //gsub(/\<b*/,"") on "abc" will reach this point, advance to "bc" | ||
2529 | //... and will erroneously match "b" even though it is NOT at the word start. | ||
2530 | //we need REG_NOTBOW but it does not exist... | ||
2531 | //TODO: if EXTRA_COMPAT=y, use GNU matching and re_search, | ||
2532 | //it should be able to do it correctly. | ||
2533 | /* Subtle: this is safe only because | 2589 | /* Subtle: this is safe only because |
2534 | * qrealloc allocated at least one extra byte */ | 2590 | * qrealloc allocated at least one extra byte */ |
2535 | resbuf[residx] = *sp; | 2591 | resbuf[residx] = *sp; |
@@ -2538,6 +2594,7 @@ static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int | |||
2538 | sp++; | 2594 | sp++; |
2539 | residx++; | 2595 | residx++; |
2540 | } | 2596 | } |
2597 | regexec_flags |= REG_NOTBOL; | ||
2541 | } | 2598 | } |
2542 | 2599 | ||
2543 | resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize); | 2600 | resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize); |
@@ -2669,8 +2726,6 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2669 | } | 2726 | } |
2670 | 2727 | ||
2671 | case B_ss: { | 2728 | case B_ss: { |
2672 | char *s; | ||
2673 | |||
2674 | l = strlen(as[0]); | 2729 | l = strlen(as[0]); |
2675 | i = getvar_i(av[1]) - 1; | 2730 | i = getvar_i(av[1]) - 1; |
2676 | if (i > l) | 2731 | if (i > l) |
@@ -2680,8 +2735,7 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2680 | n = (nargs > 2) ? getvar_i(av[2]) : l-i; | 2735 | n = (nargs > 2) ? getvar_i(av[2]) : l-i; |
2681 | if (n < 0) | 2736 | if (n < 0) |
2682 | n = 0; | 2737 | n = 0; |
2683 | s = xstrndup(as[0]+i, n); | 2738 | setvar_sn(res, as[0]+i, n); |
2684 | setvar_p(res, s); | ||
2685 | break; | 2739 | break; |
2686 | } | 2740 | } |
2687 | 2741 | ||
@@ -2758,8 +2812,7 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2758 | i = strftime(g_buf, MAXVARFMT, | 2812 | i = strftime(g_buf, MAXVARFMT, |
2759 | ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), | 2813 | ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), |
2760 | localtime(&tt)); | 2814 | localtime(&tt)); |
2761 | g_buf[i] = '\0'; | 2815 | setvar_sn(res, g_buf, i); |
2762 | setvar_s(res, g_buf); | ||
2763 | break; | 2816 | break; |
2764 | 2817 | ||
2765 | case B_mt: | 2818 | case B_mt: |
@@ -2770,16 +2823,16 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2770 | res = do_match(an[1], as[0]); | 2823 | res = do_match(an[1], as[0]); |
2771 | break; | 2824 | break; |
2772 | 2825 | ||
2773 | case B_ge: | 2826 | case B_ge: /* gensub(regex, repl, matchnum, string) */ |
2774 | awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE); | 2827 | awk_sub(an[0], as[1], /*matchnum:*/getvar_i(av[2]), /*src:*/av[3], /*dst:*/res/*, TRUE*/); |
2775 | break; | 2828 | break; |
2776 | 2829 | ||
2777 | case B_gs: | 2830 | case B_gs: /* gsub(regex, repl, string) */ |
2778 | setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE)); | 2831 | setvar_i(res, awk_sub(an[0], as[1], /*matchnum:all*/0, /*src:*/av[2], /*dst:*/av[2]/*, FALSE*/)); |
2779 | break; | 2832 | break; |
2780 | 2833 | ||
2781 | case B_su: | 2834 | case B_su: /* sub(regex, repl, string) */ |
2782 | setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE)); | 2835 | setvar_i(res, awk_sub(an[0], as[1], /*matchnum:first*/1, /*src:*/av[2], /*dst:*/av[2]/*, FALSE*/)); |
2783 | break; | 2836 | break; |
2784 | } | 2837 | } |
2785 | 2838 | ||
@@ -2796,7 +2849,7 @@ static NOINLINE var *exec_builtin(node *op, var *res) | |||
2796 | 2849 | ||
2797 | /* if expr looks like "var=value", perform assignment and return 1, | 2850 | /* if expr looks like "var=value", perform assignment and return 1, |
2798 | * otherwise return 0 */ | 2851 | * otherwise return 0 */ |
2799 | static int is_assignment(const char *expr) | 2852 | static int try_to_assign(const char *expr) |
2800 | { | 2853 | { |
2801 | char *exprc, *val; | 2854 | char *exprc, *val; |
2802 | 2855 | ||
@@ -2825,42 +2878,55 @@ static void set_text_mode(FILE *f) | |||
2825 | #endif | 2878 | #endif |
2826 | 2879 | ||
2827 | /* switch to next input file */ | 2880 | /* switch to next input file */ |
2828 | static rstream *next_input_file(void) | 2881 | static int next_input_file(void) |
2829 | { | 2882 | { |
2830 | #define rsm (G.next_input_file__rsm) | 2883 | #define input_file_seen (G.next_input_file__input_file_seen) |
2831 | #define files_happen (G.next_input_file__files_happen) | 2884 | #define argind (G.next_input_file__argind) |
2885 | const char *fname; | ||
2832 | 2886 | ||
2833 | const char *fname, *ind; | 2887 | if (iF.F) { |
2834 | 2888 | fclose(iF.F); | |
2835 | if (rsm.F) | 2889 | iF.F = NULL; |
2836 | fclose(rsm.F); | 2890 | iF.pos = iF.adv = 0; |
2837 | rsm.F = NULL; | 2891 | } |
2838 | rsm.pos = rsm.adv = 0; | ||
2839 | 2892 | ||
2840 | for (;;) { | 2893 | for (;;) { |
2841 | if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { | 2894 | /* GNU Awk 5.1.1 does not _read_ ARGIND (but does read ARGC). |
2842 | if (files_happen) | 2895 | * It only sets ARGIND to 1, 2, 3... for every command-line filename |
2843 | return NULL; | 2896 | * (VAR=VAL params cause a gap in numbering). |
2897 | * If there are none and stdin is used, then ARGIND is not modified: | ||
2898 | * if it is set by e.g. 'BEGIN { ARGIND="foo" }', that value will | ||
2899 | * still be there. | ||
2900 | */ | ||
2901 | argind++; | ||
2902 | if (argind >= getvar_i(intvar[ARGC])) { | ||
2903 | if (input_file_seen) | ||
2904 | return FALSE; | ||
2844 | fname = "-"; | 2905 | fname = "-"; |
2845 | rsm.F = stdin; | 2906 | iF.F = stdin; |
2846 | break; | 2907 | break; |
2847 | } | 2908 | } |
2848 | ind = getvar_s(incvar(intvar[ARGIND])); | 2909 | fname = getvar_s(findvar(iamarray(intvar[ARGV]), utoa(argind))); |
2849 | fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); | 2910 | if (fname && *fname) { |
2850 | if (fname && *fname && !is_assignment(fname)) { | 2911 | /* "If a filename on the command line has the form |
2851 | rsm.F = xfopen_stdin(fname); | 2912 | * var=val it is treated as a variable assignment" |
2913 | */ | ||
2914 | if (try_to_assign(fname)) | ||
2915 | continue; | ||
2916 | iF.F = xfopen_stdin(fname); | ||
2917 | setvar_i(intvar[ARGIND], argind); | ||
2852 | break; | 2918 | break; |
2853 | } | 2919 | } |
2854 | } | 2920 | } |
2855 | #if ENABLE_PLATFORM_MINGW32 | 2921 | #if ENABLE_PLATFORM_MINGW32 |
2856 | set_text_mode(rsm.F); | 2922 | set_text_mode(iF.F); |
2857 | #endif | 2923 | #endif |
2858 | 2924 | ||
2859 | files_happen = TRUE; | ||
2860 | setvar_s(intvar[FILENAME], fname); | 2925 | setvar_s(intvar[FILENAME], fname); |
2861 | return &rsm; | 2926 | input_file_seen = TRUE; |
2862 | #undef rsm | 2927 | return TRUE; |
2863 | #undef files_happen | 2928 | #undef argind |
2929 | #undef input_file_seen | ||
2864 | } | 2930 | } |
2865 | 2931 | ||
2866 | #if ENABLE_PLATFORM_MINGW32 | 2932 | #if ENABLE_PLATFORM_MINGW32 |
@@ -2914,6 +2980,7 @@ static var *evaluate(node *op, var *res) | |||
2914 | uint32_t opinfo; | 2980 | uint32_t opinfo; |
2915 | int opn; | 2981 | int opn; |
2916 | node *op1; | 2982 | node *op1; |
2983 | var *old_Fields_ptr; | ||
2917 | 2984 | ||
2918 | opinfo = op->info; | 2985 | opinfo = op->info; |
2919 | opn = (opinfo & OPNMASK); | 2986 | opn = (opinfo & OPNMASK); |
@@ -2922,10 +2989,16 @@ static var *evaluate(node *op, var *res) | |||
2922 | debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); | 2989 | debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); |
2923 | 2990 | ||
2924 | /* execute inevitable things */ | 2991 | /* execute inevitable things */ |
2992 | old_Fields_ptr = NULL; | ||
2925 | if (opinfo & OF_RES1) { | 2993 | if (opinfo & OF_RES1) { |
2926 | if ((opinfo & OF_REQUIRED) && !op1) | 2994 | if ((opinfo & OF_REQUIRED) && !op1) |
2927 | syntax_error(EMSG_TOO_FEW_ARGS); | 2995 | syntax_error(EMSG_TOO_FEW_ARGS); |
2928 | L.v = evaluate(op1, TMPVAR0); | 2996 | L.v = evaluate(op1, TMPVAR0); |
2997 | /* Does L.v point to $n variable? */ | ||
2998 | if ((size_t)(L.v - Fields) < maxfields) { | ||
2999 | /* yes, remember where Fields[] is */ | ||
3000 | old_Fields_ptr = Fields; | ||
3001 | } | ||
2929 | if (opinfo & OF_STR1) { | 3002 | if (opinfo & OF_STR1) { |
2930 | L.s = getvar_s(L.v); | 3003 | L.s = getvar_s(L.v); |
2931 | debug_printf_eval("L.s:'%s'\n", L.s); | 3004 | debug_printf_eval("L.s:'%s'\n", L.s); |
@@ -2944,8 +3017,15 @@ static var *evaluate(node *op, var *res) | |||
2944 | */ | 3017 | */ |
2945 | if (opinfo & OF_RES2) { | 3018 | if (opinfo & OF_RES2) { |
2946 | R.v = evaluate(op->r.n, TMPVAR1); | 3019 | R.v = evaluate(op->r.n, TMPVAR1); |
2947 | //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? | 3020 | /* Seen in $5=$$5=$0: |
2948 | //L.v = NULL; | 3021 | * Evaluation of R.v ($$5=$0 expression) |
3022 | * made L.v ($5) invalid. It's detected here. | ||
3023 | */ | ||
3024 | if (old_Fields_ptr) { | ||
3025 | //if (old_Fields_ptr != Fields) | ||
3026 | // debug_printf_eval("L.v moved\n"); | ||
3027 | L.v += Fields - old_Fields_ptr; | ||
3028 | } | ||
2949 | if (opinfo & OF_STR2) { | 3029 | if (opinfo & OF_STR2) { |
2950 | R.s = getvar_s(R.v); | 3030 | R.s = getvar_s(R.v); |
2951 | debug_printf_eval("R.s:'%s'\n", R.s); | 3031 | debug_printf_eval("R.s:'%s'\n", R.s); |
@@ -3111,6 +3191,8 @@ static var *evaluate(node *op, var *res) | |||
3111 | 3191 | ||
3112 | /* -- recursive node type -- */ | 3192 | /* -- recursive node type -- */ |
3113 | 3193 | ||
3194 | case XC( OC_CONST ): | ||
3195 | debug_printf_eval("CONST "); | ||
3114 | case XC( OC_VAR ): | 3196 | case XC( OC_VAR ): |
3115 | debug_printf_eval("VAR\n"); | 3197 | debug_printf_eval("VAR\n"); |
3116 | L.v = op->l.v; | 3198 | L.v = op->l.v; |
@@ -3154,7 +3236,7 @@ static var *evaluate(node *op, var *res) | |||
3154 | /* make sure that we never return a temp var */ | 3236 | /* make sure that we never return a temp var */ |
3155 | if (L.v == TMPVAR0) | 3237 | if (L.v == TMPVAR0) |
3156 | L.v = res; | 3238 | L.v = res; |
3157 | /* if source is a temporary string, jusk relink it to dest */ | 3239 | /* if source is a temporary string, just relink it to dest */ |
3158 | if (R.v == TMPVAR1 | 3240 | if (R.v == TMPVAR1 |
3159 | && !(R.v->type & VF_NUMBER) | 3241 | && !(R.v->type & VF_NUMBER) |
3160 | /* Why check !NUMBER? if R.v is a number but has cached R.v->string, | 3242 | /* Why check !NUMBER? if R.v is a number but has cached R.v->string, |
@@ -3240,13 +3322,13 @@ static var *evaluate(node *op, var *res) | |||
3240 | #endif | 3322 | #endif |
3241 | } | 3323 | } |
3242 | } else { | 3324 | } else { |
3243 | if (!iF) | 3325 | if (!iF.F) |
3244 | iF = next_input_file(); | 3326 | next_input_file(); |
3245 | rsm = iF; | 3327 | rsm = &iF; |
3246 | } | 3328 | } |
3247 | 3329 | ||
3248 | if (!rsm || !rsm->F) { | 3330 | if (!rsm->F) { |
3249 | setvar_i(intvar[ERRNO], errno); | 3331 | setvar_ERRNO(); |
3250 | setvar_i(res, -1); | 3332 | setvar_i(res, -1); |
3251 | break; | 3333 | break; |
3252 | } | 3334 | } |
@@ -3395,16 +3477,18 @@ static var *evaluate(node *op, var *res) | |||
3395 | */ | 3477 | */ |
3396 | if (rsm->F) | 3478 | if (rsm->F) |
3397 | err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); | 3479 | err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); |
3398 | //TODO: fix this case: | ||
3399 | // $ awk 'BEGIN { print close(""); print ERRNO }' | ||
3400 | // -1 | ||
3401 | // close of redirection that was never opened | ||
3402 | // (we print 0, 0) | ||
3403 | free(rsm->buffer); | 3480 | free(rsm->buffer); |
3404 | hash_remove(fdhash, L.s); | 3481 | hash_remove(fdhash, L.s); |
3482 | } else { | ||
3483 | err = -1; | ||
3484 | /* gawk 'BEGIN { print close(""); print ERRNO }' | ||
3485 | * -1 | ||
3486 | * close of redirection that was never opened | ||
3487 | */ | ||
3488 | errno = ENOENT; | ||
3405 | } | 3489 | } |
3406 | if (err) | 3490 | if (err) |
3407 | setvar_i(intvar[ERRNO], errno); | 3491 | setvar_ERRNO(); |
3408 | R_d = (double)err; | 3492 | R_d = (double)err; |
3409 | break; | 3493 | break; |
3410 | } | 3494 | } |
@@ -3584,8 +3668,6 @@ static var *evaluate(node *op, var *res) | |||
3584 | #undef sreg | 3668 | #undef sreg |
3585 | } | 3669 | } |
3586 | 3670 | ||
3587 | /* -------- main & co. -------- */ | ||
3588 | |||
3589 | static int awk_exit(void) | 3671 | static int awk_exit(void) |
3590 | { | 3672 | { |
3591 | unsigned i; | 3673 | unsigned i; |
@@ -3678,7 +3760,7 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3678 | setvar_s(intvar[FS], opt_F); | 3760 | setvar_s(intvar[FS], opt_F); |
3679 | } | 3761 | } |
3680 | while (list_v) { | 3762 | while (list_v) { |
3681 | if (!is_assignment(llist_pop(&list_v))) | 3763 | if (!try_to_assign(llist_pop(&list_v))) |
3682 | bb_show_usage(); | 3764 | bb_show_usage(); |
3683 | } | 3765 | } |
3684 | 3766 | ||
@@ -3695,6 +3777,8 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3695 | _setmode(fd, _O_TEXT); | 3777 | _setmode(fd, _O_TEXT); |
3696 | #endif | 3778 | #endif |
3697 | s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ | 3779 | s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ |
3780 | if (!s) | ||
3781 | bb_perror_msg_and_die("read error from '%s'", g_progname); | ||
3698 | close(fd); | 3782 | close(fd); |
3699 | parse_program(s); | 3783 | parse_program(s); |
3700 | free(s); | 3784 | free(s); |
@@ -3740,15 +3824,14 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3740 | awk_exit(); | 3824 | awk_exit(); |
3741 | 3825 | ||
3742 | /* input file could already be opened in BEGIN block */ | 3826 | /* input file could already be opened in BEGIN block */ |
3743 | if (!iF) | 3827 | if (!iF.F) |
3744 | iF = next_input_file(); | 3828 | goto next_file; /* no, it wasn't, go try opening */ |
3745 | 3829 | /* Iterate over input files */ | |
3746 | /* passing through input files */ | 3830 | for (;;) { |
3747 | while (iF) { | ||
3748 | nextfile = FALSE; | 3831 | nextfile = FALSE; |
3749 | setvar_i(intvar[FNR], 0); | 3832 | setvar_i(intvar[FNR], 0); |
3750 | 3833 | ||
3751 | while ((i = awk_getline(iF, intvar[F0])) > 0) { | 3834 | while ((i = awk_getline(&iF, intvar[F0])) > 0) { |
3752 | nextrec = FALSE; | 3835 | nextrec = FALSE; |
3753 | incvar(intvar[NR]); | 3836 | incvar(intvar[NR]); |
3754 | incvar(intvar[FNR]); | 3837 | incvar(intvar[FNR]); |
@@ -3757,11 +3840,11 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3757 | if (nextfile) | 3840 | if (nextfile) |
3758 | break; | 3841 | break; |
3759 | } | 3842 | } |
3760 | |||
3761 | if (i < 0) | 3843 | if (i < 0) |
3762 | syntax_error(strerror(errno)); | 3844 | syntax_error(strerror(errno)); |
3763 | 3845 | next_file: | |
3764 | iF = next_input_file(); | 3846 | if (!next_input_file()) |
3847 | break; | ||
3765 | } | 3848 | } |
3766 | 3849 | ||
3767 | awk_exit(); | 3850 | awk_exit(); |
diff --git a/include/dump.h b/include/dump.h index 10fc5d900..c6763a64d 100644 --- a/include/dump.h +++ b/include/dump.h | |||
@@ -33,9 +33,14 @@ typedef struct dumper_t { | |||
33 | int dump_length; /* max bytes to read */ | 33 | int dump_length; /* max bytes to read */ |
34 | smallint dump_vflag; /*enum dump_vflag_t*/ | 34 | smallint dump_vflag; /*enum dump_vflag_t*/ |
35 | FS *fshead; | 35 | FS *fshead; |
36 | #if ENABLE_OD | ||
37 | const char *od_eofstring; | ||
38 | #endif | ||
39 | #if ENABLE_XXD | ||
36 | const char *xxd_eofstring; | 40 | const char *xxd_eofstring; |
37 | off_t address; /* address/offset in stream */ | ||
38 | long long xxd_displayoff; | 41 | long long xxd_displayoff; |
42 | #endif | ||
43 | off_t address; /* address/offset in stream */ | ||
39 | } dumper_t; | 44 | } dumper_t; |
40 | 45 | ||
41 | dumper_t* alloc_dumper(void) FAST_FUNC; | 46 | dumper_t* alloc_dumper(void) FAST_FUNC; |
diff --git a/libbb/dump.c b/libbb/dump.c index d24057325..ffc46f6a7 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -50,8 +50,10 @@ typedef struct priv_dumper_t { | |||
50 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; | 50 | static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; |
51 | 51 | ||
52 | static const char size_conv_str[] ALIGN1 = | 52 | static const char size_conv_str[] ALIGN1 = |
53 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; | 53 | "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\x8""cdiouxXeEfgG"; |
54 | 54 | /* c d i o u x X e E f g G - bytes contain 'bcnt' for the type */ | |
55 | #define SCS_OFS 12 | ||
56 | #define float_convs (size_conv_str + SCS_OFS + sizeof("cdiouxX")-1) | ||
55 | static const char int_convs[] ALIGN1 = "diouxX"; | 57 | static const char int_convs[] ALIGN1 = "diouxX"; |
56 | 58 | ||
57 | dumper_t* FAST_FUNC alloc_dumper(void) | 59 | dumper_t* FAST_FUNC alloc_dumper(void) |
@@ -94,7 +96,7 @@ static NOINLINE int bb_dump_size(FS *fs) | |||
94 | while (isdigit(*++fmt)) | 96 | while (isdigit(*++fmt)) |
95 | continue; | 97 | continue; |
96 | } | 98 | } |
97 | p = strchr(size_conv_str + 12, *fmt); | 99 | p = strchr(size_conv_str + SCS_OFS, *fmt); |
98 | if (!p) { | 100 | if (!p) { |
99 | if (*fmt == 's') { | 101 | if (*fmt == 's') { |
100 | bcnt += prec; | 102 | bcnt += prec; |
@@ -106,7 +108,7 @@ static NOINLINE int bb_dump_size(FS *fs) | |||
106 | } | 108 | } |
107 | } | 109 | } |
108 | } else { | 110 | } else { |
109 | bcnt += p[-12]; | 111 | bcnt += p[-SCS_OFS]; |
110 | } | 112 | } |
111 | } | 113 | } |
112 | cur_size += bcnt * fu->reps; | 114 | cur_size += bcnt * fu->reps; |
@@ -193,6 +195,10 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
193 | 195 | ||
194 | ++p2; | 196 | ++p2; |
195 | ++p1; | 197 | ++p1; |
198 | if (*p1 == 'l') { /* %lld etc */ | ||
199 | ++p2; | ||
200 | ++p1; | ||
201 | } | ||
196 | DO_INT_CONV: | 202 | DO_INT_CONV: |
197 | e = strchr(int_convs, *p1); /* "diouxX"? */ | 203 | e = strchr(int_convs, *p1); /* "diouxX"? */ |
198 | if (!e) | 204 | if (!e) |
@@ -200,13 +206,13 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
200 | pr->flags = F_INT; | 206 | pr->flags = F_INT; |
201 | if (e > int_convs + 1) /* not d or i? */ | 207 | if (e > int_convs + 1) /* not d or i? */ |
202 | pr->flags = F_UINT; | 208 | pr->flags = F_UINT; |
203 | byte_count_str = "\004\002\001"; | 209 | byte_count_str = "\010\004\002\001"; |
204 | goto DO_BYTE_COUNT; | 210 | goto DO_BYTE_COUNT; |
205 | } else | 211 | } else |
206 | if (strchr(int_convs, *p1)) { /* %d etc */ | 212 | if (strchr(int_convs, *p1)) { /* %d etc */ |
207 | goto DO_INT_CONV; | 213 | goto DO_INT_CONV; |
208 | } else | 214 | } else |
209 | if (strchr("eEfgG", *p1)) { /* floating point */ | 215 | if (strchr(float_convs, *p1)) { /* floating point */ |
210 | pr->flags = F_DBL; | 216 | pr->flags = F_DBL; |
211 | byte_count_str = "\010\004"; | 217 | byte_count_str = "\010\004"; |
212 | goto DO_BYTE_COUNT; | 218 | goto DO_BYTE_COUNT; |
@@ -244,7 +250,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
244 | pr->flags = F_P; | 250 | pr->flags = F_P; |
245 | *p1 = 'c'; | 251 | *p1 = 'c'; |
246 | goto DO_BYTE_COUNT_1; | 252 | goto DO_BYTE_COUNT_1; |
247 | case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */ | 253 | case 'u': /* %_u: chars, 'nul', 'esc' etc for nonprintable */ |
248 | pr->flags = F_U; | 254 | pr->flags = F_U; |
249 | /* *p1 = 'c'; set in conv_u */ | 255 | /* *p1 = 'c'; set in conv_u */ |
250 | goto DO_BYTE_COUNT_1; | 256 | goto DO_BYTE_COUNT_1; |
@@ -324,8 +330,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | |||
324 | p2 = NULL; | 330 | p2 = NULL; |
325 | for (p1 = pr->fmt; *p1; ++p1) | 331 | for (p1 = pr->fmt; *p1; ++p1) |
326 | p2 = isspace(*p1) ? p1 : NULL; | 332 | p2 = isspace(*p1) ? p1 : NULL; |
327 | if (p2) | 333 | pr->nospace = p2; |
328 | pr->nospace = p2; | ||
329 | } | 334 | } |
330 | } | 335 | } |
331 | } | 336 | } |
@@ -509,7 +514,7 @@ static void bpad(PR *pr) | |||
509 | 514 | ||
510 | static const char conv_str[] ALIGN1 = | 515 | static const char conv_str[] ALIGN1 = |
511 | "\0" "\\""0""\0" | 516 | "\0" "\\""0""\0" |
512 | "\007""\\""a""\0" /* \a */ | 517 | "\007""\\""a""\0" |
513 | "\b" "\\""b""\0" | 518 | "\b" "\\""b""\0" |
514 | "\f" "\\""f""\0" | 519 | "\f" "\\""f""\0" |
515 | "\n" "\\""n""\0" | 520 | "\n" "\\""n""\0" |
@@ -549,10 +554,12 @@ static void conv_u(PR *pr, unsigned char *p) | |||
549 | static const char list[] ALIGN1 = | 554 | static const char list[] ALIGN1 = |
550 | "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0" | 555 | "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0" |
551 | "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_" | 556 | "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_" |
552 | "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0" | 557 | "dle\0dc1\0dc2\0dc3\0dc4\0nak\0syn\0etb\0" |
553 | "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us"; | 558 | "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us"; |
559 | /* NB: bug: od uses %_u to implement -a, | ||
560 | * but it should use "nl", not "lf", for char #10. | ||
561 | */ | ||
554 | 562 | ||
555 | /* od used nl, not lf */ | ||
556 | if (*p <= 0x1f) { | 563 | if (*p <= 0x1f) { |
557 | *pr->cchar = 's'; | 564 | *pr->cchar = 's'; |
558 | printf(pr->fmt, list + (4 * (int)*p)); | 565 | printf(pr->fmt, list + (4 * (int)*p)); |
@@ -571,7 +578,6 @@ static void conv_u(PR *pr, unsigned char *p) | |||
571 | static NOINLINE void display(priv_dumper_t* dumper) | 578 | static NOINLINE void display(priv_dumper_t* dumper) |
572 | { | 579 | { |
573 | unsigned char *bp; | 580 | unsigned char *bp; |
574 | unsigned char savech = '\0'; | ||
575 | 581 | ||
576 | while ((bp = get(dumper)) != NULL) { | 582 | while ((bp = get(dumper)) != NULL) { |
577 | FS *fs; | 583 | FS *fs; |
@@ -592,24 +598,41 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
592 | PR *pr; | 598 | PR *pr; |
593 | for (pr = fu->nextpr; pr; dumper->pub.address += pr->bcnt, | 599 | for (pr = fu->nextpr; pr; dumper->pub.address += pr->bcnt, |
594 | bp += pr->bcnt, pr = pr->nextpr) { | 600 | bp += pr->bcnt, pr = pr->nextpr) { |
601 | unsigned char savech; | ||
602 | |||
595 | if (dumper->eaddress | 603 | if (dumper->eaddress |
596 | && dumper->pub.address >= dumper->eaddress | 604 | && dumper->pub.address >= dumper->eaddress |
597 | ) { | 605 | ) { |
606 | #if ENABLE_XXD | ||
598 | if (dumper->pub.xxd_eofstring) { | 607 | if (dumper->pub.xxd_eofstring) { |
599 | /* xxd support: requested to not pad incomplete blocks */ | 608 | /* xxd support: requested to not pad incomplete blocks */ |
600 | fputs_stdout(dumper->pub.xxd_eofstring); | 609 | fputs_stdout(dumper->pub.xxd_eofstring); |
601 | return; | 610 | return; |
602 | } | 611 | } |
612 | #endif | ||
613 | #if ENABLE_OD | ||
614 | if (dumper->pub.od_eofstring) { | ||
615 | /* od support: requested to not pad incomplete blocks */ | ||
616 | /* ... but do print final offset */ | ||
617 | fputs_stdout(dumper->pub.od_eofstring); | ||
618 | goto endfu; | ||
619 | } | ||
620 | #endif | ||
603 | if (!(pr->flags & (F_TEXT | F_BPAD))) | 621 | if (!(pr->flags & (F_TEXT | F_BPAD))) |
604 | bpad(pr); | 622 | bpad(pr); |
605 | } | 623 | } |
624 | savech = '\0'; | ||
606 | if (cnt == 1 && pr->nospace) { | 625 | if (cnt == 1 && pr->nospace) { |
607 | savech = *pr->nospace; | 626 | savech = *pr->nospace; |
608 | *pr->nospace = '\0'; | 627 | *pr->nospace = '\0'; |
609 | } | 628 | } |
610 | switch (pr->flags) { | 629 | switch (pr->flags) { |
611 | case F_ADDRESS: | 630 | case F_ADDRESS: |
612 | printf(pr->fmt, (unsigned long long) dumper->pub.address + dumper->pub.xxd_displayoff); | 631 | printf(pr->fmt, (unsigned long long) dumper->pub.address |
632 | #if ENABLE_XXD | ||
633 | + dumper->pub.xxd_displayoff | ||
634 | #endif | ||
635 | ); | ||
613 | break; | 636 | break; |
614 | case F_BPAD: | 637 | case F_BPAD: |
615 | printf(pr->fmt, ""); | 638 | printf(pr->fmt, ""); |
@@ -637,22 +660,32 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
637 | break; | 660 | break; |
638 | } | 661 | } |
639 | case F_INT: { | 662 | case F_INT: { |
640 | int ival; | 663 | union { |
641 | short sval; | 664 | int16_t ival16; |
665 | int32_t ival32; | ||
666 | int64_t ival64; | ||
667 | } u; | ||
668 | int value = (signed char)*bp; | ||
642 | 669 | ||
643 | switch (pr->bcnt) { | 670 | switch (pr->bcnt) { |
644 | case 1: | 671 | case 1: |
645 | printf(pr->fmt, (int) *bp); | ||
646 | break; | 672 | break; |
647 | case 2: | 673 | case 2: |
648 | memcpy(&sval, bp, sizeof(sval)); | 674 | move_from_unaligned16(u.ival16, bp); |
649 | printf(pr->fmt, (int) sval); | 675 | value = u.ival16; |
650 | break; | 676 | break; |
651 | case 4: | 677 | case 4: |
652 | memcpy(&ival, bp, sizeof(ival)); | 678 | move_from_unaligned32(u.ival32, bp); |
653 | printf(pr->fmt, ival); | 679 | value = u.ival32; |
654 | break; | 680 | break; |
681 | case 8: | ||
682 | move_from_unaligned64(u.ival64, bp); | ||
683 | //A hack. Users _must_ use %llX formats to not truncate high bits | ||
684 | printf(pr->fmt, (long long)u.ival64); | ||
685 | goto skip; | ||
655 | } | 686 | } |
687 | printf(pr->fmt, value); | ||
688 | skip: | ||
656 | break; | 689 | break; |
657 | } | 690 | } |
658 | case F_P: | 691 | case F_P: |
@@ -662,32 +695,29 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
662 | printf(pr->fmt, (char *) bp); | 695 | printf(pr->fmt, (char *) bp); |
663 | break; | 696 | break; |
664 | case F_TEXT: | 697 | case F_TEXT: |
665 | printf(pr->fmt); | 698 | fputs_stdout(pr->fmt); |
666 | break; | 699 | break; |
667 | case F_U: | 700 | case F_U: |
668 | conv_u(pr, bp); | 701 | conv_u(pr, bp); |
669 | break; | 702 | break; |
670 | case F_UINT: { | 703 | case F_UINT: { |
671 | unsigned ival; | 704 | unsigned value = (unsigned char)*bp; |
672 | unsigned short sval; | ||
673 | |||
674 | switch (pr->bcnt) { | 705 | switch (pr->bcnt) { |
675 | case 1: | 706 | case 1: |
676 | printf(pr->fmt, (unsigned) *bp); | ||
677 | break; | 707 | break; |
678 | case 2: | 708 | case 2: |
679 | memcpy(&sval, bp, sizeof(sval)); | 709 | move_from_unaligned16(value, bp); |
680 | printf(pr->fmt, (unsigned) sval); | ||
681 | break; | 710 | break; |
682 | case 4: | 711 | case 4: |
683 | memcpy(&ival, bp, sizeof(ival)); | 712 | move_from_unaligned32(value, bp); |
684 | printf(pr->fmt, ival); | ||
685 | break; | 713 | break; |
714 | /* case 8: no users yet */ | ||
686 | } | 715 | } |
716 | printf(pr->fmt, value); | ||
687 | break; | 717 | break; |
688 | } | 718 | } |
689 | } | 719 | } |
690 | if (cnt == 1 && pr->nospace) { | 720 | if (savech) { |
691 | *pr->nospace = savech; | 721 | *pr->nospace = savech; |
692 | } | 722 | } |
693 | } | 723 | } |
@@ -695,7 +725,7 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
695 | } | 725 | } |
696 | } | 726 | } |
697 | } | 727 | } |
698 | 728 | IF_OD(endfu:) | |
699 | if (dumper->endfu) { | 729 | if (dumper->endfu) { |
700 | PR *pr; | 730 | PR *pr; |
701 | /* | 731 | /* |
@@ -711,10 +741,14 @@ static NOINLINE void display(priv_dumper_t* dumper) | |||
711 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { | 741 | for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) { |
712 | switch (pr->flags) { | 742 | switch (pr->flags) { |
713 | case F_ADDRESS: | 743 | case F_ADDRESS: |
714 | printf(pr->fmt, (unsigned long long) dumper->eaddress + dumper->pub.xxd_displayoff); | 744 | printf(pr->fmt, (unsigned long long) dumper->eaddress |
745 | #if ENABLE_XXD | ||
746 | + dumper->pub.xxd_displayoff | ||
747 | #endif | ||
748 | ); | ||
715 | break; | 749 | break; |
716 | case F_TEXT: | 750 | case F_TEXT: |
717 | printf(pr->fmt); | 751 | fputs_stdout(pr->fmt); |
718 | break; | 752 | break; |
719 | } | 753 | } |
720 | } | 754 | } |
diff --git a/networking/tunctl.c b/networking/tunctl.c index 97e6917aa..28571ae7f 100644 --- a/networking/tunctl.c +++ b/networking/tunctl.c | |||
@@ -124,8 +124,7 @@ int tunctl_main(int argc UNUSED_PARAM, char **argv) | |||
124 | if (opts & OPT_b) { | 124 | if (opts & OPT_b) { |
125 | puts(ifr.ifr_name); | 125 | puts(ifr.ifr_name); |
126 | } else { | 126 | } else { |
127 | printf("Set '%s' %spersistent", ifr.ifr_name, ""); | 127 | printf("Set '%s' persistent and owned by uid %ld", ifr.ifr_name, user); |
128 | printf(" and owned by uid %ld", user); | ||
129 | if (group != -1) | 128 | if (group != -1) |
130 | printf(" gid %ld", group); | 129 | printf(" gid %ld", group); |
131 | bb_putchar('\n'); | 130 | bb_putchar('\n'); |
diff --git a/shell/ash_test/ash-misc/elif1.right b/shell/ash_test/ash-misc/elif1.right new file mode 100644 index 000000000..36dc59fed --- /dev/null +++ b/shell/ash_test/ash-misc/elif1.right | |||
@@ -0,0 +1,4 @@ | |||
1 | ELIF1 | ||
2 | ELIF2 | ||
3 | ELIF THEN | ||
4 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/elif1.tests b/shell/ash_test/ash-misc/elif1.tests new file mode 100755 index 000000000..77b8a25ea --- /dev/null +++ b/shell/ash_test/ash-misc/elif1.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | if false; then | ||
2 | : | ||
3 | elif echo 'ELIF1'; echo 'ELIF2'; then | ||
4 | echo "ELIF THEN" | ||
5 | fi | ||
6 | echo "Ok:$?" | ||
diff --git a/shell/ash_test/ash-misc/elif2.right b/shell/ash_test/ash-misc/elif2.right new file mode 100644 index 000000000..8f2851f91 --- /dev/null +++ b/shell/ash_test/ash-misc/elif2.right | |||
@@ -0,0 +1,2 @@ | |||
1 | THEN | ||
2 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/elif2.tests b/shell/ash_test/ash-misc/elif2.tests new file mode 100755 index 000000000..3e5876f05 --- /dev/null +++ b/shell/ash_test/ash-misc/elif2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | if true; then | ||
2 | echo "THEN" | ||
3 | elif echo "ELIF false"; false; then | ||
4 | echo "ELIF THEN" | ||
5 | else | ||
6 | echo "ELSE" | ||
7 | fi | ||
8 | echo "Ok:$?" | ||
diff --git a/shell/hush.c b/shell/hush.c index 810dafd35..cdaa67a3b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1061,6 +1061,7 @@ static int builtin_export(char **argv) FAST_FUNC; | |||
1061 | #if ENABLE_HUSH_READONLY | 1061 | #if ENABLE_HUSH_READONLY |
1062 | static int builtin_readonly(char **argv) FAST_FUNC; | 1062 | static int builtin_readonly(char **argv) FAST_FUNC; |
1063 | #endif | 1063 | #endif |
1064 | static int builtin_false(char **argv) FAST_FUNC; | ||
1064 | #if ENABLE_HUSH_JOB | 1065 | #if ENABLE_HUSH_JOB |
1065 | static int builtin_fg_bg(char **argv) FAST_FUNC; | 1066 | static int builtin_fg_bg(char **argv) FAST_FUNC; |
1066 | static int builtin_jobs(char **argv) FAST_FUNC; | 1067 | static int builtin_jobs(char **argv) FAST_FUNC; |
@@ -1161,6 +1162,7 @@ static const struct built_in_command bltins1[] ALIGN_PTR = { | |||
1161 | #if ENABLE_HUSH_EXPORT | 1162 | #if ENABLE_HUSH_EXPORT |
1162 | BLTIN("export" , builtin_export , "Set environment variables"), | 1163 | BLTIN("export" , builtin_export , "Set environment variables"), |
1163 | #endif | 1164 | #endif |
1165 | BLTIN("false" , builtin_false , NULL), | ||
1164 | #if ENABLE_HUSH_JOB | 1166 | #if ENABLE_HUSH_JOB |
1165 | BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"), | 1167 | BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"), |
1166 | #endif | 1168 | #endif |
@@ -9758,7 +9760,7 @@ static int run_list(struct pipe *pi) | |||
9758 | smallint last_rword; /* ditto */ | 9760 | smallint last_rword; /* ditto */ |
9759 | #endif | 9761 | #endif |
9760 | 9762 | ||
9761 | debug_printf_exec("run_list start lvl %d\n", G.run_list_level); | 9763 | debug_printf_exec("run_list lvl %d start\n", G.run_list_level); |
9762 | debug_enter(); | 9764 | debug_enter(); |
9763 | 9765 | ||
9764 | #if ENABLE_HUSH_LOOPS | 9766 | #if ENABLE_HUSH_LOOPS |
@@ -9817,7 +9819,7 @@ static int run_list(struct pipe *pi) | |||
9817 | break; | 9819 | break; |
9818 | 9820 | ||
9819 | IF_HAS_KEYWORDS(rword = pi->res_word;) | 9821 | IF_HAS_KEYWORDS(rword = pi->res_word;) |
9820 | debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", | 9822 | debug_printf_exec(": rword:%d cond_code:%d last_rword:%d\n", |
9821 | rword, cond_code, last_rword); | 9823 | rword, cond_code, last_rword); |
9822 | 9824 | ||
9823 | sv_errexit_depth = G.errexit_depth; | 9825 | sv_errexit_depth = G.errexit_depth; |
@@ -9851,23 +9853,29 @@ static int run_list(struct pipe *pi) | |||
9851 | } | 9853 | } |
9852 | } | 9854 | } |
9853 | last_followup = pi->followup; | 9855 | last_followup = pi->followup; |
9854 | IF_HAS_KEYWORDS(last_rword = rword;) | ||
9855 | #if ENABLE_HUSH_IF | 9856 | #if ENABLE_HUSH_IF |
9856 | if (cond_code) { | 9857 | if (cond_code != 0) { |
9857 | if (rword == RES_THEN) { | 9858 | if (rword == RES_THEN) { |
9858 | /* if false; then ... fi has exitcode 0! */ | 9859 | /* if false; then ... fi has exitcode 0! */ |
9859 | G.last_exitcode = rcode = EXIT_SUCCESS; | 9860 | G.last_exitcode = rcode = EXIT_SUCCESS; |
9860 | /* "if <false> THEN cmd": skip cmd */ | 9861 | /* "if <false> THEN cmd": skip cmd */ |
9862 | debug_printf_exec("skipped THEN cmd because IF condition was false\n"); | ||
9863 | last_rword = rword; | ||
9861 | continue; | 9864 | continue; |
9862 | } | 9865 | } |
9863 | } else { | 9866 | } else { |
9864 | if (rword == RES_ELSE || rword == RES_ELIF) { | 9867 | if (rword == RES_ELSE |
9868 | || (rword == RES_ELIF && last_rword != RES_ELIF) | ||
9869 | ) { | ||
9865 | /* "if <true> then ... ELSE/ELIF cmd": | 9870 | /* "if <true> then ... ELSE/ELIF cmd": |
9866 | * skip cmd and all following ones */ | 9871 | * skip cmd and all following ones */ |
9872 | debug_printf_exec("skipped ELSE/ELIF branch because IF condition was true\n"); | ||
9867 | break; | 9873 | break; |
9868 | } | 9874 | } |
9875 | //if (rword == RES_THEN): "if <true> THEN cmd", run cmd (fall through) | ||
9869 | } | 9876 | } |
9870 | #endif | 9877 | #endif |
9878 | IF_HAS_KEYWORDS(last_rword = rword;) | ||
9871 | #if ENABLE_HUSH_LOOPS | 9879 | #if ENABLE_HUSH_LOOPS |
9872 | if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ | 9880 | if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ |
9873 | if (!for_lcur) { | 9881 | if (!for_lcur) { |
@@ -9943,7 +9951,7 @@ static int run_list(struct pipe *pi) | |||
9943 | ); | 9951 | ); |
9944 | /* TODO: which FNM_xxx flags to use? */ | 9952 | /* TODO: which FNM_xxx flags to use? */ |
9945 | cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); | 9953 | cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); |
9946 | debug_printf_exec("fnmatch(pattern:'%s',str:'%s'):%d\n", | 9954 | debug_printf_exec("cond_code=fnmatch(pattern:'%s',str:'%s'):%d\n", |
9947 | pattern, case_word, cond_code); | 9955 | pattern, case_word, cond_code); |
9948 | free(pattern); | 9956 | free(pattern); |
9949 | if (cond_code == 0) { | 9957 | if (cond_code == 0) { |
@@ -10069,8 +10077,10 @@ static int run_list(struct pipe *pi) | |||
10069 | 10077 | ||
10070 | /* Analyze how result affects subsequent commands */ | 10078 | /* Analyze how result affects subsequent commands */ |
10071 | #if ENABLE_HUSH_IF | 10079 | #if ENABLE_HUSH_IF |
10072 | if (rword == RES_IF || rword == RES_ELIF) | 10080 | if (rword == RES_IF || rword == RES_ELIF) { |
10081 | debug_printf_exec("cond_code=rcode:%d\n", rcode); | ||
10073 | cond_code = rcode; | 10082 | cond_code = rcode; |
10083 | } | ||
10074 | #endif | 10084 | #endif |
10075 | check_jobs_and_continue: | 10085 | check_jobs_and_continue: |
10076 | checkjobs(NULL, 0 /*(no pid to wait for)*/); | 10086 | checkjobs(NULL, 0 /*(no pid to wait for)*/); |
@@ -10111,7 +10121,7 @@ static int run_list(struct pipe *pi) | |||
10111 | free(case_word); | 10121 | free(case_word); |
10112 | #endif | 10122 | #endif |
10113 | debug_leave(); | 10123 | debug_leave(); |
10114 | debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode); | 10124 | debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level, rcode); |
10115 | return rcode; | 10125 | return rcode; |
10116 | } | 10126 | } |
10117 | 10127 | ||
@@ -10823,6 +10833,11 @@ static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM) | |||
10823 | return 0; | 10833 | return 0; |
10824 | } | 10834 | } |
10825 | 10835 | ||
10836 | static int FAST_FUNC builtin_false(char **argv UNUSED_PARAM) | ||
10837 | { | ||
10838 | return 1; | ||
10839 | } | ||
10840 | |||
10826 | #if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL | 10841 | #if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL |
10827 | static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) | 10842 | static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) |
10828 | { | 10843 | { |
diff --git a/shell/hush_test/hush-misc/elif1.right b/shell/hush_test/hush-misc/elif1.right new file mode 100644 index 000000000..36dc59fed --- /dev/null +++ b/shell/hush_test/hush-misc/elif1.right | |||
@@ -0,0 +1,4 @@ | |||
1 | ELIF1 | ||
2 | ELIF2 | ||
3 | ELIF THEN | ||
4 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/elif1.tests b/shell/hush_test/hush-misc/elif1.tests new file mode 100755 index 000000000..77b8a25ea --- /dev/null +++ b/shell/hush_test/hush-misc/elif1.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | if false; then | ||
2 | : | ||
3 | elif echo 'ELIF1'; echo 'ELIF2'; then | ||
4 | echo "ELIF THEN" | ||
5 | fi | ||
6 | echo "Ok:$?" | ||
diff --git a/shell/hush_test/hush-misc/elif2.right b/shell/hush_test/hush-misc/elif2.right new file mode 100644 index 000000000..8f2851f91 --- /dev/null +++ b/shell/hush_test/hush-misc/elif2.right | |||
@@ -0,0 +1,2 @@ | |||
1 | THEN | ||
2 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/elif2.tests b/shell/hush_test/hush-misc/elif2.tests new file mode 100755 index 000000000..3e5876f05 --- /dev/null +++ b/shell/hush_test/hush-misc/elif2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | if true; then | ||
2 | echo "THEN" | ||
3 | elif echo "ELIF false"; false; then | ||
4 | echo "ELIF THEN" | ||
5 | else | ||
6 | echo "ELSE" | ||
7 | fi | ||
8 | echo "Ok:$?" | ||
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 11beb1b10..0a84dc13e 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -499,4 +499,120 @@ testing 'awk backslash+CRLF eaten with no trace' \ | |||
499 | 'BEGIN { printf "Hello\\\r\n world\\n" }\n' | 499 | 'BEGIN { printf "Hello\\\r\n world\\n" }\n' |
500 | SKIP= | 500 | SKIP= |
501 | 501 | ||
502 | # User-supplied bug (SEGV) example, was causing use-after-realloc | ||
503 | testing 'awk assign while assign' \ | ||
504 | "awk '\$5=\$\$5=\$0'; echo \$?" \ | ||
505 | "\ | ||
506 | ─ process timing ────────────────────────────────────┬─ ─ process timing ────────────────────────────────────┬─ overall results ────┐ results ────┐ | ||
507 | │ run time : │ run time : 0 days, 0 hrs, 0 min, 56 sec │ cycles done : 0 │ days, 0 hrs, 0 min, 56 sec │ cycles done : 0 │ | ||
508 | │ last new find │ last new find : 0 days, 0 hrs, 0 min, 1 sec │ corpus count : 208 │ 0 days, 0 hrs, 0 min, 1 sec │ corpus count : 208 │ | ||
509 | │last saved crash : │last saved crash : none seen yet │saved crashes : 0 │ seen yet │saved crashes : 0 │ | ||
510 | │ last saved hang │ last saved hang : none seen yet │ saved hangs : 0 │ none seen yet │ saved hangs : 0 │ | ||
511 | ├─ cycle progress ─────────────────────┬─ ├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤ coverage┴──────────────────────┤ | ||
512 | │ now processing : │ now processing : 184.1 (88.5%) │ map density : 0.30% / 0.52% │ (88.5%) │ map density : 0.30% / 0.52% │ │ now processing : 184.1 (88.5%) │ map density : 0.30% / 0.52% │ | ||
513 | │ runs timed out │ runs timed out : 0 (0.00%) │ count coverage : 2.18 bits/tuple │ 0 (0.00%) │ count coverage : 2.18 bits/tuple │ | ||
514 | ├─ stage progress ─────────────────────┼─ ├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤ in depth ─────────────────┤ | ||
515 | │ now trying : │ now trying : havoc │ favored items : 43 (20.67%) │ │ favored items : 43 (20.67%) │ | ||
516 | │ stage execs : │ stage execs : 11.2k/131k (8.51%) │ new edges on : 52 (25.00%) │ (8.51%) │ new edges on │ stage execs : 11.2k/131k (8.51%) │ new edges on : 52 (25.00%) │ 52 (25.00%) │ | ||
517 | │ total execs : │ total execs : 179k │ total crashes : 0 (0 saved) │ │ total crashes : 0 (0 saved) │ │ total execs : 179k │ total crashes : 0 (0 saved) │ | ||
518 | │ exec speed : │ exec speed : 3143/sec │ total tmouts : 0 (0 saved) │ │ total tmouts : 0 (0 saved) │ │ exec speed : 3143/sec │ total tmouts : 0 (0 saved) │ | ||
519 | ├─ fuzzing strategy yields ├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤ item geometry ───────┤ | ||
520 | │ bit flips : │ bit flips : 11/648, 4/638, 5/618 │ levels : 4 │ 4/638, 5/618 │ levels : │ bit flips : 11/648, 4/638, 5/618 │ levels : 4 │ │ | ||
521 | │ byte flips : │ byte flips : 0/81, 0/71, 0/52 │ pending : 199 │ 0/71, 0/52 │ pending : 199 │ | ||
522 | │ arithmetics : 11/4494, │ arithmetics : 11/4494, 0/1153, 0/0 │ pend fav : 35 │ 0/0 │ pend fav : 35 │ | ||
523 | │ known ints : 1/448, 0/1986, 0/2288 │ own finds : 207 │ known ints : │ known ints : 1/448, 0/1986, 0/2288 │ own finds : 207 │ 0/1986, 0/2288 │ own finds : 207 │ | ||
524 | │ dictionary : 0/0, │ dictionary : 0/0, 0/0, 0/0, 0/0 │ imported : 0 │ 0/0, 0/0 │ imported : 0 │ | ||
525 | │havoc/splice : 142/146k, 23/7616 │havoc/splice : 142/146k, 23/7616 │ stability : 100.00% │ stability : 100.00% │ | ||
526 | │py/custom/rq : unused, unused, │py/custom/rq : unused, unused, unused, unused ├───────────────────────┘ unused ├───────────────────────┘ | ||
527 | │ trim/eff : 57.02%/26, │ trim/eff : 57.02%/26, 0.00% │ [cpu000:100%] │ [cpu000:100%] | ||
528 | └────────────────────────────────────────────────────┘^C └────────────────────────────────────────────────────┘^C | ||
529 | 0 | ||
530 | " \ | ||
531 | "" \ | ||
532 | "\ | ||
533 | ─ process timing ────────────────────────────────────┬─ overall results ────┐ | ||
534 | │ run time : 0 days, 0 hrs, 0 min, 56 sec │ cycles done : 0 │ | ||
535 | │ last new find : 0 days, 0 hrs, 0 min, 1 sec │ corpus count : 208 │ | ||
536 | │last saved crash : none seen yet │saved crashes : 0 │ | ||
537 | │ last saved hang : none seen yet │ saved hangs : 0 │ | ||
538 | ├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤ | ||
539 | │ now processing : 184.1 (88.5%) │ map density : 0.30% / 0.52% │ | ||
540 | │ runs timed out : 0 (0.00%) │ count coverage : 2.18 bits/tuple │ | ||
541 | ├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤ | ||
542 | │ now trying : havoc │ favored items : 43 (20.67%) │ | ||
543 | │ stage execs : 11.2k/131k (8.51%) │ new edges on : 52 (25.00%) │ | ||
544 | │ total execs : 179k │ total crashes : 0 (0 saved) │ | ||
545 | │ exec speed : 3143/sec │ total tmouts : 0 (0 saved) │ | ||
546 | ├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤ | ||
547 | │ bit flips : 11/648, 4/638, 5/618 │ levels : 4 │ | ||
548 | │ byte flips : 0/81, 0/71, 0/52 │ pending : 199 │ | ||
549 | │ arithmetics : 11/4494, 0/1153, 0/0 │ pend fav : 35 │ | ||
550 | │ known ints : 1/448, 0/1986, 0/2288 │ own finds : 207 │ | ||
551 | │ dictionary : 0/0, 0/0, 0/0, 0/0 │ imported : 0 │ | ||
552 | │havoc/splice : 142/146k, 23/7616 │ stability : 100.00% │ | ||
553 | │py/custom/rq : unused, unused, unused, unused ├───────────────────────┘ | ||
554 | │ trim/eff : 57.02%/26, 0.00% │ [cpu000:100%] | ||
555 | └────────────────────────────────────────────────────┘^C" | ||
556 | |||
557 | # If field separator FS=' ' (default), fields are split only on | ||
558 | # space or tab or linefeed, NOT other whitespace. | ||
559 | testing 'awk does not split on CR (char 13)' \ | ||
560 | "awk '{ \$1=\$0; print }'" \ | ||
561 | 'word1 word2 word3\r word2 word3\r\n' \ | ||
562 | '' 'word1 word2 word3\r' | ||
563 | |||
564 | testing "awk = has higher precedence than == (despite what gawk manpage claims)" \ | ||
565 | "awk 'BEGIN { v=1; print 2==v; print 2==v=2; print v; print v=3==3; print v}'" \ | ||
566 | '0\n1\n2\n1\n3\n' \ | ||
567 | '' '' | ||
568 | |||
569 | sq="'" | ||
570 | testing 'awk gensub backslashes \' \ | ||
571 | 'awk '$sq'BEGIN { s="\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
572 | 's=\\ | ||
573 | \\|\\ | ||
574 | ' '' '' | ||
575 | testing 'awk gensub backslashes \\' \ | ||
576 | 'awk '$sq'BEGIN { s="\\\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
577 | 's=\\\\ | ||
578 | \\|\\ | ||
579 | ' '' '' | ||
580 | # gawk 5.1.1 handles trailing unpaired \ inconsistently. | ||
581 | # If replace string is single \, it is used verbatim, | ||
582 | # but if it is \\\ (three slashes), gawk uses "\<NUL>" (!!!), not "\\" as you would expect. | ||
583 | testing 'awk gensub backslashes \\\' \ | ||
584 | 'awk '$sq'BEGIN { s="\\\\\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
585 | 's=\\\\\\ | ||
586 | \\\\|\\\\ | ||
587 | ' '' '' | ||
588 | testing 'awk gensub backslashes \\\\' \ | ||
589 | 'awk '$sq'BEGIN { s="\\\\\\\\"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
590 | 's=\\\\\\\\ | ||
591 | \\\\|\\\\ | ||
592 | ' '' '' | ||
593 | testing 'awk gensub backslashes \&' \ | ||
594 | 'awk '$sq'BEGIN { s="\\&"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
595 | 's=\\& | ||
596 | &|& | ||
597 | ' '' '' | ||
598 | testing 'awk gensub backslashes \0' \ | ||
599 | 'awk '$sq'BEGIN { s="\\0"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
600 | 's=\\0 | ||
601 | a|a | ||
602 | ' '' '' | ||
603 | testing 'awk gensub backslashes \\0' \ | ||
604 | 'awk '$sq'BEGIN { s="\\\\0"; print "s=" s; print gensub("a", s, "g", "a|a") }'$sq \ | ||
605 | 's=\\\\0 | ||
606 | \\0|\\0 | ||
607 | ' '' '' | ||
608 | |||
609 | # The "b" in "abc" should not match <b* pattern. | ||
610 | # Currently we use REG_STARTEND ("This flag is a BSD extension, not present in POSIX") | ||
611 | # to implement the code to handle this correctly, but if your libc has no REG_STARTEND, | ||
612 | # the alternative code mishandles this case. | ||
613 | testing 'awk gsub erroneous word start match' \ | ||
614 | "awk 'BEGIN { a=\"abc\"; gsub(/\<b*/,\"\",a); print a }'" \ | ||
615 | 'abc\n' \ | ||
616 | '' '' | ||
617 | |||
502 | exit $FAILCOUNT | 618 | exit $FAILCOUNT |
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests index cfb20187e..be0379cfc 100755 --- a/testsuite/hexdump.tests +++ b/testsuite/hexdump.tests | |||
@@ -34,4 +34,52 @@ testing "hexdump thinks last full block can match" \ | |||
34 | '' \ | 34 | '' \ |
35 | '\0\0\0\0\0\0\0\0\0\0\0\0' | 35 | '\0\0\0\0\0\0\0\0\0\0\0\0' |
36 | 36 | ||
37 | testing "hexdump -e %3_u" \ | ||
38 | "hexdump -e '16/1 \" %3_u\" \"\n\"'" \ | ||
39 | "\ | ||
40 | nul soh stx etx eot enq ack bel bs ht lf vt ff cr so si | ||
41 | dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us | ||
42 | p q r s t u v w x y z { | } ~ del | ||
43 | 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f | ||
44 | f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff | ||
45 | " \ | ||
46 | "" \ | ||
47 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
48 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
49 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
50 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
51 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | ||
52 | |||
53 | testing "hexdump -e /1 %d" \ | ||
54 | "hexdump -e '16/1 \" %4d\" \"\n\"'" \ | ||
55 | "\ | ||
56 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
57 | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ||
58 | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | ||
59 | -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 | ||
60 | -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 | ||
61 | " \ | ||
62 | "" \ | ||
63 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
64 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
65 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
66 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
67 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | ||
68 | |||
69 | testing "hexdump -e /2 %d" \ | ||
70 | "hexdump -e '8/2 \" %6d\" \"\n\"'" \ | ||
71 | "\ | ||
72 | 256 770 1284 1798 2312 2826 3340 3854 | ||
73 | 4368 4882 5396 5910 6424 6938 7452 7966 | ||
74 | 29040 29554 30068 30582 31096 31610 32124 32638 | ||
75 | -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 | ||
76 | -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 | ||
77 | " \ | ||
78 | "" \ | ||
79 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
80 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
81 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
82 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
83 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ | ||
84 | |||
37 | exit $FAILCOUNT | 85 | exit $FAILCOUNT |
diff --git a/testsuite/od.tests b/testsuite/od.tests index 0880e0d2f..4f245a7e8 100755 --- a/testsuite/od.tests +++ b/testsuite/od.tests | |||
@@ -6,6 +6,236 @@ | |||
6 | 6 | ||
7 | # testing "test name" "commands" "expected result" "file input" "stdin" | 7 | # testing "test name" "commands" "expected result" "file input" "stdin" |
8 | 8 | ||
9 | input="$(printf '\001\002\003\nABC\xfe')" | ||
10 | |||
11 | little_endian=false | ||
12 | { printf '\0\1' | od -s | grep -q 256; } && little_endian=true | ||
13 | readonly little_endian | ||
14 | |||
15 | $little_endian || SKIP=1 | ||
16 | testing "od (little-endian)" \ | ||
17 | "od" \ | ||
18 | "\ | ||
19 | 0000000 001001 005003 041101 177103 | ||
20 | 0000010 | ||
21 | " \ | ||
22 | "" "$input" | ||
23 | SKIP= | ||
24 | |||
25 | optional !DESKTOP | ||
26 | testing "od -a (!DESKTOP)" \ | ||
27 | "od -a" \ | ||
28 | "\ | ||
29 | 0000000 nul soh stx etx eot enq ack bel bs ht lf vt ff cr so si | ||
30 | 0000020 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us | ||
31 | 0000040 p q r s t u v w x y z { | } ~ del | ||
32 | 0000060 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f | ||
33 | 0000100 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff | ||
34 | 0000120 | ||
35 | " \ | ||
36 | "" \ | ||
37 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
38 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
39 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
40 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
41 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" | ||
42 | SKIP= | ||
43 | # ^^^ a bit incorrect handling of ctrl ("lf" should be "nl") and high bytes. | ||
44 | # vvv this output is correct. | ||
45 | optional DESKTOP | ||
46 | testing "od -a (DESKTOP)" \ | ||
47 | "od -a" \ | ||
48 | "\ | ||
49 | 0000000 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si | ||
50 | 0000020 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us | ||
51 | 0000040 p q r s t u v w x y z { | } ~ del | ||
52 | 0000060 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si | ||
53 | 0000100 p q r s t u v w x y z { | } ~ del | ||
54 | 0000120 | ||
55 | " \ | ||
56 | "" \ | ||
57 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ | ||
58 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ | ||
59 | "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ | ||
60 | "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ | ||
61 | "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" | ||
62 | SKIP= | ||
63 | |||
64 | testing "od -B" \ | ||
65 | "od -B" \ | ||
66 | "\ | ||
67 | 0000000 001001 005003 041101 177103 | ||
68 | 0000010 | ||
69 | " \ | ||
70 | "" "$input" | ||
71 | SKIP= | ||
72 | |||
73 | $little_endian || SKIP=1 | ||
74 | testing "od -o (little-endian)" \ | ||
75 | "od -o" \ | ||
76 | "\ | ||
77 | 0000000 001001 005003 041101 177103 | ||
78 | 0000010 | ||
79 | " \ | ||
80 | "" "$input" | ||
81 | SKIP= | ||
82 | |||
83 | testing "od -b" \ | ||
84 | "od -b" \ | ||
85 | "\ | ||
86 | 0000000 001 002 003 012 101 102 103 376 | ||
87 | 0000010 | ||
88 | " \ | ||
89 | "" "$input" | ||
90 | SKIP= | ||
91 | |||
92 | testing "od -c" \ | ||
93 | "od -c" \ | ||
94 | "\ | ||
95 | 0000000 001 002 003 \\\\n A B C 376 | ||
96 | 0000010 | ||
97 | " \ | ||
98 | "" "$input" | ||
99 | SKIP= | ||
100 | |||
101 | $little_endian || SKIP=1 | ||
102 | testing "od -d (little-endian)" \ | ||
103 | "od -d" \ | ||
104 | "\ | ||
105 | 0000000 513 2563 16961 65091 | ||
106 | 0000010 | ||
107 | " \ | ||
108 | "" "$input" | ||
109 | SKIP= | ||
110 | |||
111 | $little_endian || SKIP=1 | ||
112 | testing "od -D (little-endian)" \ | ||
113 | "od -D" \ | ||
114 | "\ | ||
115 | 0000000 167969281 4265820737 | ||
116 | 0000010 | ||
117 | " \ | ||
118 | "" "$input" | ||
119 | SKIP= | ||
120 | |||
121 | optional !DESKTOP #DESKTOP: unrecognized option: e | ||
122 | $little_endian || SKIP=1 | ||
123 | testing "od -e (!DESKTOP little-endian)" \ | ||
124 | "od -e" \ | ||
125 | "\ | ||
126 | 0000000 -1.61218556514036e+300 | ||
127 | 0000010 | ||
128 | " \ | ||
129 | "" "$input" | ||
130 | SKIP= | ||
131 | |||
132 | optional !DESKTOP #DESKTOP: unrecognized option: F | ||
133 | $little_endian || SKIP=1 | ||
134 | testing "od -F (!DESKTOP little-endian)" \ | ||
135 | "od -F" \ | ||
136 | "\ | ||
137 | 0000000 -1.61218556514036e+300 | ||
138 | 0000010 | ||
139 | " \ | ||
140 | "" "$input" | ||
141 | SKIP= | ||
142 | |||
143 | $little_endian || SKIP=1 | ||
144 | testing "od -f (little-endian)" \ | ||
145 | "od -f" \ | ||
146 | "\ | ||
147 | 0000000 6.3077975e-33 -6.4885867e+37 | ||
148 | 0000010 | ||
149 | " \ | ||
150 | "" "$input" | ||
151 | SKIP= | ||
152 | |||
153 | $little_endian || SKIP=1 | ||
154 | testing "od -H (little-endian)" \ | ||
155 | "od -H" \ | ||
156 | "\ | ||
157 | 0000000 0a030201 fe434241 | ||
158 | 0000010 | ||
159 | " \ | ||
160 | "" "$input" | ||
161 | SKIP= | ||
162 | |||
163 | $little_endian || SKIP=1 | ||
164 | testing "od -X (little-endian)" \ | ||
165 | "od -X" \ | ||
166 | "\ | ||
167 | 0000000 0a030201 fe434241 | ||
168 | 0000010 | ||
169 | " \ | ||
170 | "" "$input" | ||
171 | SKIP= | ||
172 | |||
173 | $little_endian || SKIP=1 | ||
174 | testing "od -h (little-endian)" \ | ||
175 | "od -h" \ | ||
176 | "\ | ||
177 | 0000000 0201 0a03 4241 fe43 | ||
178 | 0000010 | ||
179 | " \ | ||
180 | "" "$input" | ||
181 | SKIP= | ||
182 | |||
183 | $little_endian || SKIP=1 | ||
184 | testing "od -x (little-endian)" \ | ||
185 | "od -x" \ | ||
186 | "\ | ||
187 | 0000000 0201 0a03 4241 fe43 | ||
188 | 0000010 | ||
189 | " \ | ||
190 | "" "$input" | ||
191 | SKIP= | ||
192 | |||
193 | $little_endian || SKIP=1 | ||
194 | testing "od -i (little-endian)" \ | ||
195 | "od -i" \ | ||
196 | "\ | ||
197 | 0000000 167969281 -29146559 | ||
198 | 0000010 | ||
199 | " \ | ||
200 | "" "$input" | ||
201 | SKIP= | ||
202 | |||
203 | $little_endian || SKIP=1 | ||
204 | testing "od -O (little-endian)" \ | ||
205 | "od -O" \ | ||
206 | "\ | ||
207 | 0000000 01200601001 37620641101 | ||
208 | 0000010 | ||
209 | " \ | ||
210 | "" "$input" | ||
211 | SKIP= | ||
212 | |||
213 | # 32-bit? | ||
214 | printf '00000000' | od -l | grep -q '808464432 *808464432' && SKIP=1 #yes, skip | ||
215 | $little_endian || SKIP=1 | ||
216 | testing "od -I (little-endian)" \ | ||
217 | "od -I" \ | ||
218 | "\ | ||
219 | 0000000 -125183517527965183 | ||
220 | 0000010 | ||
221 | " \ | ||
222 | "" "$input" | ||
223 | testing "od -L (little-endian)" \ | ||
224 | "od -L" \ | ||
225 | "\ | ||
226 | 0000000 -125183517527965183 | ||
227 | 0000010 | ||
228 | " \ | ||
229 | "" "$input" | ||
230 | testing "od -l (little-endian)" \ | ||
231 | "od -l" \ | ||
232 | "\ | ||
233 | 0000000 -125183517527965183 | ||
234 | 0000010 | ||
235 | " \ | ||
236 | "" "$input" | ||
237 | SKIP= | ||
238 | |||
9 | optional DESKTOP | 239 | optional DESKTOP |
10 | testing "od -b" \ | 240 | testing "od -b" \ |
11 | "od -b" \ | 241 | "od -b" \ |
diff --git a/testsuite/testing.sh b/testsuite/testing.sh index f5b756947..95bb46dda 100644 --- a/testsuite/testing.sh +++ b/testsuite/testing.sh | |||
@@ -56,11 +56,21 @@ optional() | |||
56 | { | 56 | { |
57 | SKIP= | 57 | SKIP= |
58 | while test "$1"; do | 58 | while test "$1"; do |
59 | case $1 in | ||
60 | "!"*) | ||
61 | case "${OPTIONFLAGS}" in | ||
62 | *:${1#!}:*) SKIP=1; return;; | ||
63 | esac | ||
64 | shift | ||
65 | ;; | ||
66 | *) | ||
59 | case "${OPTIONFLAGS}" in | 67 | case "${OPTIONFLAGS}" in |
60 | *:$1:*) ;; | 68 | *:$1:*) ;; |
61 | *) SKIP=1; return ;; | 69 | *) SKIP=1; return ;; |
62 | esac | 70 | esac |
63 | shift | 71 | shift |
72 | ;; | ||
73 | esac | ||
64 | done | 74 | done |
65 | } | 75 | } |
66 | 76 | ||
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index 307a84803..be4c1964f 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c | |||
@@ -72,14 +72,20 @@ static void bb_dump_addfile(dumper_t *dumper, char *name) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | static const char *const add_strings[] ALIGN_PTR = { | 74 | static const char *const add_strings[] ALIGN_PTR = { |
75 | "\"%07.7_ax \"16/1 \"%03o \"\"\n\"", /* b */ | 75 | "16/1 \" %03o" , /* b */ |
76 | "\"%07.7_ax \"16/1 \"%3_c \"\"\n\"", /* c */ | 76 | "16/1 \" %3_c" , /* c */ |
77 | "\"%07.7_ax \"8/2 \" %05u \"\"\n\"", /* d */ | 77 | "8/2 \" %05u" , /* d */ |
78 | "\"%07.7_ax \"8/2 \" %06o \"\"\n\"", /* o */ | 78 | "8/2 \" %06o" , /* o */ |
79 | "\"%07.7_ax \"8/2 \" %04x \"\"\n\"", /* x */ | 79 | "8/2 \" %04x", /* x */ |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; | 82 | static void add_format(dumper_t *dumper, const char *fmt) |
83 | { | ||
84 | char fmtbuf[sizeof("\"%07_ax\"" "%s\"" "\"\n\"") + 16]; | ||
85 | sprintf(fmtbuf, "\"%%07_ax\"" "%s\"" "\"\n\"", fmt); | ||
86 | bb_dump_add(dumper, "\"%07_Ax\n\""); | ||
87 | bb_dump_add(dumper, fmtbuf); | ||
88 | } | ||
83 | 89 | ||
84 | static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v"; | 90 | static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v"; |
85 | 91 | ||
@@ -104,15 +110,14 @@ int hexdump_main(int argc, char **argv) | |||
104 | if (!p) | 110 | if (!p) |
105 | bb_show_usage(); | 111 | bb_show_usage(); |
106 | if ((p - hexdump_opts) < 5) { | 112 | if ((p - hexdump_opts) < 5) { |
107 | bb_dump_add(dumper, add_first); | 113 | add_format(dumper, add_strings[(int)(p - hexdump_opts)]); |
108 | bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]); | ||
109 | } | 114 | } |
110 | /* Save a little bit of space below by omitting the 'else's. */ | 115 | /* Save a little bit of space below by omitting the 'else's. */ |
111 | if (ch == 'C') { | 116 | if (ch == 'C') { |
112 | hd_applet: | 117 | hd_applet: |
113 | bb_dump_add(dumper, "\"%08.8_Ax\n\""); // final address line after dump | 118 | bb_dump_add(dumper, "\"%08_Ax\n\""); // final address line after dump |
114 | //------------------- "address " 8 * "xx " " " 8 * "xx " | 119 | //------------------- "address " 8 * " xx" " " 8 * " xx" |
115 | bb_dump_add(dumper, "\"%08.8_ax \"8/1 \"%02x \"\" \"8/1 \"%02x \""); | 120 | bb_dump_add(dumper, "\"%08_ax \"8/1 \" %02x\"\" \"8/1 \" %02x\""); |
116 | //------------------- " |ASCII...........|\n" | 121 | //------------------- " |ASCII...........|\n" |
117 | bb_dump_add(dumper, "\" |\"16/1 \"%_p\"\"|\n\""); | 122 | bb_dump_add(dumper, "\" |\"16/1 \"%_p\"\"|\n\""); |
118 | } | 123 | } |
@@ -139,8 +144,7 @@ int hexdump_main(int argc, char **argv) | |||
139 | } | 144 | } |
140 | 145 | ||
141 | if (!dumper->fshead) { | 146 | if (!dumper->fshead) { |
142 | bb_dump_add(dumper, add_first); | 147 | add_format(dumper, "8/2 \" %04x"); |
143 | bb_dump_add(dumper, "\"%07.7_ax \"8/2 \"%04x \"\"\n\""); | ||
144 | } | 148 | } |
145 | 149 | ||
146 | argv += optind; | 150 | argv += optind; |
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 9738a76ad..636cbfeec 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -285,7 +285,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
285 | // output is " 0xXX, 0xXX, 0xXX...", add leading space | 285 | // output is " 0xXX, 0xXX, 0xXX...", add leading space |
286 | bb_dump_add(dumper, "\" \""); | 286 | bb_dump_add(dumper, "\" \""); |
287 | } else | 287 | } else |
288 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | 288 | bb_dump_add(dumper, "\"%08_ax: \""); // "address: " |
289 | } | 289 | } |
290 | 290 | ||
291 | if (bytes < 1 || bytes >= cols) { | 291 | if (bytes < 1 || bytes >= cols) { |