diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-07-08 14:38:07 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-07-08 14:38:07 +0200 |
| commit | 8f0533c576964c99e0d9d573942d845122d56863 (patch) | |
| tree | 42d2a794bb701c14281bdb109875a9d953339cee /coreutils/join.c | |
| parent | a058289401f801f89fd375f500c82014e7635205 (diff) | |
| download | busybox-w32-busybox.tar.gz busybox-w32-busybox.tar.bz2 busybox-w32-busybox.zip | |
join: code shrink by making some variables "global"busybox
function old new delta
readfields 442 437 -5
printfields 462 457 -5
join_main 843 760 -83
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-93) Total: -93 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'coreutils/join.c')
| -rw-r--r-- | coreutils/join.c | 108 |
1 files changed, 58 insertions, 50 deletions
diff --git a/coreutils/join.c b/coreutils/join.c index aee944c50..34b4437d3 100644 --- a/coreutils/join.c +++ b/coreutils/join.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | #include "libbb.h" | 34 | #include "libbb.h" |
| 35 | #include "unicode.h" | 35 | #include "unicode.h" |
| 36 | #include "common_bufsiz.h" | ||
| 36 | 37 | ||
| 37 | /* This is a NOEXEC applet. Be very careful! */ | 38 | /* This is a NOEXEC applet. Be very careful! */ |
| 38 | 39 | ||
| @@ -52,8 +53,24 @@ typedef struct { | |||
| 52 | int linecap; /* current capacity of lines array */ | 53 | int linecap; /* current capacity of lines array */ |
| 53 | } FDAT; | 54 | } FDAT; |
| 54 | 55 | ||
| 56 | /* "globals" can be made local to main(), but then passing them | ||
| 57 | down the callchains as parameters requires ~90 bytes of code (on x86). | ||
| 58 | */ | ||
| 59 | struct globals { | ||
| 60 | int *format; // = NULL; | ||
| 61 | const char *empty_str; | ||
| 62 | /* \0 can't be separator, 0 means: "whitespace+" pattern */ | ||
| 63 | char sep; // = 0; | ||
| 64 | } FIX_ALIASING; | ||
| 65 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
| 66 | #define INIT_G() do { \ | ||
| 67 | setup_common_bufsiz(); \ | ||
| 68 | /* we have to zero it out because of NOEXEC */ \ | ||
| 69 | memset(&G, 0, sizeof(G)); \ | ||
| 70 | } while (0) | ||
| 71 | |||
| 55 | /* split s by sep, and put the results into *curr */ | 72 | /* split s by sep, and put the results into *curr */ |
| 56 | static void field_split(char *s, char sep, LINE *curr) | 73 | static void field_split(char *s, LINE *curr) |
| 57 | { | 74 | { |
| 58 | /* compare awk_split from editors/awk.c */ | 75 | /* compare awk_split from editors/awk.c */ |
| 59 | int n; | 76 | int n; |
| @@ -68,8 +85,8 @@ static void field_split(char *s, char sep, LINE *curr) | |||
| 68 | curr->line = s; | 85 | curr->line = s; |
| 69 | 86 | ||
| 70 | n = 0; | 87 | n = 0; |
| 71 | if (sep != '\0') { /* single-character split */ | 88 | if (G.sep != '\0') { /* single-character split */ |
| 72 | while ((s1 = strchr(ps, sep)) != NULL) { | 89 | while ((s1 = strchr(ps, G.sep)) != NULL) { |
| 73 | sl[n] = ps; | 90 | sl[n] = ps; |
| 74 | *s1 = '\0'; | 91 | *s1 = '\0'; |
| 75 | ps = s1 + 1; | 92 | ps = s1 + 1; |
| @@ -123,7 +140,7 @@ static void freelines(FDAT *f) | |||
| 123 | f->field = ""; | 140 | f->field = ""; |
| 124 | } | 141 | } |
| 125 | 142 | ||
| 126 | static void readfields(char sep, FDAT *f) | 143 | static void readfields(FDAT *f) |
| 127 | { | 144 | { |
| 128 | LINE curr = { .line = NULL, .fields = NULL, .fieldcount = 0 }; | 145 | LINE curr = { .line = NULL, .fields = NULL, .fieldcount = 0 }; |
| 129 | char *line; | 146 | char *line; |
| @@ -144,7 +161,7 @@ static void readfields(char sep, FDAT *f) | |||
| 144 | return; | 161 | return; |
| 145 | } | 162 | } |
| 146 | 163 | ||
| 147 | field_split(line, sep, &curr); | 164 | field_split(line, &curr); |
| 148 | } | 165 | } |
| 149 | 166 | ||
| 150 | if (f->idx >= curr.fieldcount) | 167 | if (f->idx >= curr.fieldcount) |
| @@ -171,14 +188,14 @@ static void readfields(char sep, FDAT *f) | |||
| 171 | } | 188 | } |
| 172 | } | 189 | } |
| 173 | 190 | ||
| 174 | static inline const char *fieldorempty(const char *field, const char *empty_str) | 191 | static inline const char *fieldorempty(const char *field) |
| 175 | { | 192 | { |
| 176 | if (*field == '\0') | 193 | if (*field == '\0') |
| 177 | return empty_str; | 194 | return G.empty_str; |
| 178 | return field; | 195 | return field; |
| 179 | } | 196 | } |
| 180 | 197 | ||
| 181 | static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, FDAT *f2) | 198 | static void printfields(FDAT *f1, FDAT *f2) |
| 182 | { | 199 | { |
| 183 | const char *field = (f1 == NULL) ? f2->field : f1->field; | 200 | const char *field = (f1 == NULL) ? f2->field : f1->field; |
| 184 | 201 | ||
| @@ -189,19 +206,19 @@ static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, | |||
| 189 | int format_idx; | 206 | int format_idx; |
| 190 | int *formatcurr; | 207 | int *formatcurr; |
| 191 | bool first; | 208 | bool first; |
| 209 | char sep; | ||
| 192 | 210 | ||
| 193 | LINE *l1; | 211 | LINE *l1; |
| 194 | LINE *l2; | 212 | LINE *l2; |
| 195 | 213 | ||
| 196 | if (sep == '\0') | 214 | sep = (G.sep == '\0') ? ' ' : G.sep; |
| 197 | sep = ' '; | ||
| 198 | 215 | ||
| 199 | for (linef1 = 0; linef1 < (f1 ? f1->linecount : 1); linef1++) { | 216 | for (linef1 = 0; linef1 < (f1 ? f1->linecount : 1); linef1++) { |
| 200 | l1 = f1 ? &f1->lines[linef1] : NULL; | 217 | l1 = f1 ? &f1->lines[linef1] : NULL; |
| 201 | for (linef2 = 0; linef2 < (f2 ? f2->linecount : 1); linef2++) { | 218 | for (linef2 = 0; linef2 < (f2 ? f2->linecount : 1); linef2++) { |
| 202 | l2 = f2 ? &f2->lines[linef2] : NULL; | 219 | l2 = f2 ? &f2->lines[linef2] : NULL; |
| 203 | 220 | ||
| 204 | if (format) { | 221 | if (G.format) { |
| 205 | /* | 222 | /* |
| 206 | Format is a sort of null-terminated array: | 223 | Format is a sort of null-terminated array: |
| 207 | They are indexed by [n] for file number and [n + 1] for field number. | 224 | They are indexed by [n] for file number and [n + 1] for field number. |
| @@ -209,7 +226,7 @@ static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, | |||
| 209 | If file number is neither 1 nor 2 then we have the join field. | 226 | If file number is neither 1 nor 2 then we have the join field. |
| 210 | */ | 227 | */ |
| 211 | first = true; | 228 | first = true; |
| 212 | formatcurr = format; | 229 | formatcurr = G.format; |
| 213 | while (formatcurr[0]) { | 230 | while (formatcurr[0]) { |
| 214 | if (first) | 231 | if (first) |
| 215 | first = false; | 232 | first = false; |
| @@ -221,28 +238,28 @@ static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, | |||
| 221 | 238 | ||
| 222 | if (format_fl == 1) { | 239 | if (format_fl == 1) { |
| 223 | if (l1 != NULL && l1->fieldcount > format_idx) | 240 | if (l1 != NULL && l1->fieldcount > format_idx) |
| 224 | fputs_stdout(fieldorempty(l1->fields[format_idx], empty_str)); | 241 | fputs_stdout(fieldorempty(l1->fields[format_idx])); |
| 225 | else | 242 | else |
| 226 | fputs_stdout(empty_str); | 243 | fputs_stdout(G.empty_str); |
| 227 | } else if (format_fl == 2) { | 244 | } else if (format_fl == 2) { |
| 228 | if (l2 != NULL && l2->fieldcount > format_idx) | 245 | if (l2 != NULL && l2->fieldcount > format_idx) |
| 229 | fputs_stdout(fieldorempty(l2->fields[format_idx], empty_str)); | 246 | fputs_stdout(fieldorempty(l2->fields[format_idx])); |
| 230 | else | 247 | else |
| 231 | fputs_stdout(empty_str); | 248 | fputs_stdout(G.empty_str); |
| 232 | } else | 249 | } else |
| 233 | fputs_stdout(fieldorempty(field, empty_str)); | 250 | fputs_stdout(fieldorempty(field)); |
| 234 | 251 | ||
| 235 | formatcurr += 2; | 252 | formatcurr += 2; |
| 236 | } | 253 | } |
| 237 | } else { | 254 | } else { |
| 238 | fputs_stdout(fieldorempty(field, empty_str)); | 255 | fputs_stdout(fieldorempty(field)); |
| 239 | 256 | ||
| 240 | fn = 0; | 257 | fn = 0; |
| 241 | if (l1 != NULL) | 258 | if (l1 != NULL) |
| 242 | while (l1->fields[fn]) { | 259 | while (l1->fields[fn]) { |
| 243 | if (fn != f1->idx) { | 260 | if (fn != f1->idx) { |
| 244 | bb_putchar(sep); | 261 | bb_putchar(sep); |
| 245 | fputs_stdout(fieldorempty(l1->fields[fn], empty_str)); | 262 | fputs_stdout(fieldorempty(l1->fields[fn])); |
| 246 | } | 263 | } |
| 247 | fn++; | 264 | fn++; |
| 248 | } | 265 | } |
| @@ -252,7 +269,7 @@ static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, | |||
| 252 | while (l2->fields[fn]) { | 269 | while (l2->fields[fn]) { |
| 253 | if (fn != f2->idx) { | 270 | if (fn != f2->idx) { |
| 254 | bb_putchar(sep); | 271 | bb_putchar(sep); |
| 255 | fputs_stdout(fieldorempty(l2->fields[fn], empty_str)); | 272 | fputs_stdout(fieldorempty(l2->fields[fn])); |
| 256 | } | 273 | } |
| 257 | fn++; | 274 | fn++; |
| 258 | } | 275 | } |
| @@ -262,7 +279,7 @@ static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, | |||
| 262 | } | 279 | } |
| 263 | } | 280 | } |
| 264 | 281 | ||
| 265 | static void parsejformat(int **format_p, const char *format_str) | 282 | static void parsejformat(const char *format_str) |
| 266 | { | 283 | { |
| 267 | int *format; | 284 | int *format; |
| 268 | int field_idx; | 285 | int field_idx; |
| @@ -278,7 +295,7 @@ static void parsejformat(int **format_p, const char *format_str) | |||
| 278 | which ends up being (strlen + 1) / 2 | 295 | which ends up being (strlen + 1) / 2 |
| 279 | and then we need to have two for each entry plus one for the terminator. | 296 | and then we need to have two for each entry plus one for the terminator. |
| 280 | ( (strlen+1) / 2 * 2 is optimized out in the alloc) */ | 297 | ( (strlen+1) / 2 * 2 is optimized out in the alloc) */ |
| 281 | *format_p = format = xzalloc(sizeof(format[0]) * ((strlen(format_str) + 1) + 1)); | 298 | G.format = format = xzalloc(sizeof(format[0]) * ((strlen(format_str) + 1) + 1)); |
| 282 | 299 | ||
| 283 | /* default split: skip the initial whitespace and then any run | 300 | /* default split: skip the initial whitespace and then any run |
| 284 | of non-whitespace characters is a field */ | 301 | of non-whitespace characters is a field */ |
| @@ -328,25 +345,17 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 328 | bool print2unpaired; // = false; | 345 | bool print2unpaired; // = false; |
| 329 | bool printpaired; | 346 | bool printpaired; |
| 330 | 347 | ||
| 331 | int *format; // = NULL; | ||
| 332 | |||
| 333 | FDAT f1; // = { }; | 348 | FDAT f1; // = { }; |
| 334 | FDAT f2; // = { }; | 349 | FDAT f2; // = { }; |
| 335 | |||
| 336 | /* We can't use \0 as a real separator, so this stands in for the whitespace+ pattern */ | ||
| 337 | char sep; // = 0; | ||
| 338 | } L; | 350 | } L; |
| 339 | #define unpaired_list L.unpaired_list | 351 | #define unpaired_list L.unpaired_list |
| 340 | #define format_str L.format_str | 352 | #define format_str L.format_str |
| 341 | #define print1unpaired L.print1unpaired | 353 | #define print1unpaired L.print1unpaired |
| 342 | #define print2unpaired L.print2unpaired | 354 | #define print2unpaired L.print2unpaired |
| 343 | #define printpaired L.printpaired | 355 | #define printpaired L.printpaired |
| 344 | #define format L.format | ||
| 345 | #define f1 L.f1 | 356 | #define f1 L.f1 |
| 346 | #define f2 L.f2 | 357 | #define f2 L.f2 |
| 347 | #define sep L.sep | ||
| 348 | 358 | ||
| 349 | const char *empty_str; | ||
| 350 | char *separator; | 359 | char *separator; |
| 351 | uint32_t opts; | 360 | uint32_t opts; |
| 352 | /* Must match getopt32 call */ | 361 | /* Must match getopt32 call */ |
| @@ -360,10 +369,9 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 360 | FLAG_FIELD_2 = (1 << 6), | 369 | FLAG_FIELD_2 = (1 << 6), |
| 361 | }; | 370 | }; |
| 362 | 371 | ||
| 372 | INIT_G(); | ||
| 373 | G.empty_str = ""; | ||
| 363 | memset(&L, 0, sizeof(L)); | 374 | memset(&L, 0, sizeof(L)); |
| 364 | |||
| 365 | empty_str = ""; | ||
| 366 | |||
| 367 | init_unicode(); | 375 | init_unicode(); |
| 368 | 376 | ||
| 369 | opts = getopt32(argv, | 377 | opts = getopt32(argv, |
| @@ -375,7 +383,7 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 375 | "\0""=2:a--v:v--a", | 383 | "\0""=2:a--v:v--a", |
| 376 | &unpaired_list, | 384 | &unpaired_list, |
| 377 | &unpaired_list, | 385 | &unpaired_list, |
| 378 | &empty_str, | 386 | &G.empty_str, |
| 379 | &format_str, | 387 | &format_str, |
| 380 | &separator, | 388 | &separator, |
| 381 | &f1.idx, | 389 | &f1.idx, |
| @@ -407,11 +415,11 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 407 | if (separator[0] && separator[1]) | 415 | if (separator[0] && separator[1]) |
| 408 | bb_simple_error_msg_and_die("separators are single characters"); | 416 | bb_simple_error_msg_and_die("separators are single characters"); |
| 409 | 417 | ||
| 410 | sep = *separator; | 418 | G.sep = *separator; |
| 411 | } | 419 | } |
| 412 | 420 | ||
| 413 | if (opts & FLAG_LIST_OUTPUT) | 421 | if (opts & FLAG_LIST_OUTPUT) |
| 414 | parsejformat(&format, format_str); | 422 | parsejformat(format_str); |
| 415 | 423 | ||
| 416 | f1.fp = xfopen_stdin(argv[0]); | 424 | f1.fp = xfopen_stdin(argv[0]); |
| 417 | f2.fp = xfopen_stdin(argv[1]); | 425 | f2.fp = xfopen_stdin(argv[1]); |
| @@ -478,42 +486,42 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 478 | 486 | ||
| 479 | */ | 487 | */ |
| 480 | 488 | ||
| 481 | readfields(sep, &f1); | 489 | readfields(&f1); |
| 482 | readfields(sep, &f2); | 490 | readfields(&f2); |
| 483 | 491 | ||
| 484 | while (f1.linecount != 0 && f2.linecount != 0) { | 492 | while (f1.linecount != 0 && f2.linecount != 0) { |
| 485 | int res = strcmp(f1.field, f2.field); | 493 | int res = strcmp(f1.field, f2.field); |
| 486 | 494 | ||
| 487 | if (res == 0) { | 495 | if (res == 0) { |
| 488 | if (printpaired) | 496 | if (printpaired) |
| 489 | printfields(format, empty_str, sep, &f1, &f2); | 497 | printfields(&f1, &f2); |
| 490 | 498 | ||
| 491 | readfields(sep, &f1); | 499 | readfields(&f1); |
| 492 | readfields(sep, &f2); | 500 | readfields(&f2); |
| 493 | } else if (res < 0) { | 501 | } else if (res < 0) { |
| 494 | if (print1unpaired) | 502 | if (print1unpaired) |
| 495 | printfields(format, empty_str, sep, &f1, NULL); | 503 | printfields(&f1, NULL); |
| 496 | 504 | ||
| 497 | readfields(sep, &f1); | 505 | readfields(&f1); |
| 498 | } else { | 506 | } else { |
| 499 | if (print2unpaired) | 507 | if (print2unpaired) |
| 500 | printfields(format, empty_str, sep, NULL, &f2); | 508 | printfields(NULL, &f2); |
| 501 | 509 | ||
| 502 | readfields(sep, &f2); | 510 | readfields(&f2); |
| 503 | } | 511 | } |
| 504 | } | 512 | } |
| 505 | 513 | ||
| 506 | if (print1unpaired) { | 514 | if (print1unpaired) { |
| 507 | while (f1.linecount != 0) { | 515 | while (f1.linecount != 0) { |
| 508 | printfields(format, empty_str, sep, &f1, NULL); | 516 | printfields(&f1, NULL); |
| 509 | readfields(sep, &f1); | 517 | readfields(&f1); |
| 510 | } | 518 | } |
| 511 | } | 519 | } |
| 512 | 520 | ||
| 513 | if (print2unpaired) { | 521 | if (print2unpaired) { |
| 514 | while (f2.linecount != 0) { | 522 | while (f2.linecount != 0) { |
| 515 | printfields(format, empty_str, sep, NULL, &f2); | 523 | printfields(NULL, &f2); |
| 516 | readfields(sep, &f2); | 524 | readfields(&f2); |
| 517 | } | 525 | } |
| 518 | } | 526 | } |
| 519 | 527 | ||
| @@ -528,7 +536,7 @@ int join_main(int argc UNUSED_PARAM, char **argv) | |||
| 528 | free(f2.lines); | 536 | free(f2.lines); |
| 529 | } | 537 | } |
| 530 | 538 | ||
| 531 | free(format); | 539 | free(G.format); |
| 532 | 540 | ||
| 533 | fclose_if_not_stdin(f1.fp); | 541 | fclose_if_not_stdin(f1.fp); |
| 534 | fclose_if_not_stdin(f2.fp); | 542 | fclose_if_not_stdin(f2.fp); |
