aboutsummaryrefslogtreecommitdiff
path: root/coreutils/join.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2026-07-08 14:38:07 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2026-07-08 14:38:07 +0200
commit8f0533c576964c99e0d9d573942d845122d56863 (patch)
tree42d2a794bb701c14281bdb109875a9d953339cee /coreutils/join.c
parenta058289401f801f89fd375f500c82014e7635205 (diff)
downloadbusybox-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.c108
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 */
59struct 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 */
56static void field_split(char *s, char sep, LINE *curr) 73static 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
126static void readfields(char sep, FDAT *f) 143static 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
174static inline const char *fieldorempty(const char *field, const char *empty_str) 191static 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
181static void printfields(int *format, const char *empty_str, char sep, FDAT *f1, FDAT *f2) 198static 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
265static void parsejformat(int **format_p, const char *format_str) 282static 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);