Fix command expansion in wordsplit
* libmailutils/string/wordsplit.c: Change ordering of expansions so that command expansion occurs first. This fixes nested expansions and command expansions occurring after variable expansions. * libmailutils/tests/wordsplit.at: Add more tests.
Showing
2 changed files
with
224 additions
and
10 deletions
... | @@ -1332,7 +1332,6 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t len, | ... | @@ -1332,7 +1332,6 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t len, |
1332 | struct mu_wordsplit ws; | 1332 | struct mu_wordsplit ws; |
1333 | 1333 | ||
1334 | rc = _wsplt_subsplit (wsp, &ws, str, j, | 1334 | rc = _wsplt_subsplit (wsp, &ws, str, j, |
1335 | MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | | ||
1336 | MU_WRDSF_WS | MU_WRDSF_QUOTE); | 1335 | MU_WRDSF_WS | MU_WRDSF_QUOTE); |
1337 | if (rc) | 1336 | if (rc) |
1338 | { | 1337 | { |
... | @@ -2065,29 +2064,41 @@ mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex) | ... | @@ -2065,29 +2064,41 @@ mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex) |
2065 | } | 2064 | } |
2066 | } | 2065 | } |
2067 | 2066 | ||
2067 | |||
2068 | /* This structure describes a single expansion phase */ | ||
2068 | struct exptab | 2069 | struct exptab |
2069 | { | 2070 | { |
2070 | char *descr; | 2071 | char *descr; /* Textual description (for debugging) */ |
2071 | int flag; | 2072 | int flag; /* MU_WRDSF_ bit that controls this phase */ |
2072 | int opt; | 2073 | int opt; /* Entry-specific options (see EXPOPT_ flags below */ |
2073 | int (*expansion) (struct mu_wordsplit *wsp); | 2074 | int (*expansion) (struct mu_wordsplit *wsp); /* expansion function */ |
2074 | }; | 2075 | }; |
2075 | 2076 | ||
2077 | /* The following options control expansions: */ | ||
2078 | /* Normally the exptab entry is run if its flag bit is set in struct | ||
2079 | wordsplit. The EXPOPT_NEG option negates this test so that expansion | ||
2080 | is performed if its associated flag bit is not set in struct wordsplit. */ | ||
2076 | #define EXPOPT_NEG 0x01 | 2081 | #define EXPOPT_NEG 0x01 |
2082 | /* Coalesce the input list before running the expansion. */ | ||
2077 | #define EXPOPT_COALESCE 0x02 | 2083 | #define EXPOPT_COALESCE 0x02 |
2078 | 2084 | ||
2079 | static struct exptab exptab[] = { | 2085 | static struct exptab exptab[] = { |
2080 | { N_("WS trimming"), MU_WRDSF_WS, 0, mu_wordsplit_trimws }, | 2086 | { N_("WS trimming"), MU_WRDSF_WS, 0, |
2081 | { N_("tilde expansion"), MU_WRDSF_PATHEXPAND, 0, mu_wordsplit_tildexpand }, | 2087 | mu_wordsplit_trimws }, |
2088 | { N_("command substitution"), MU_WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE, | ||
2089 | mu_wordsplit_cmdexp }, | ||
2090 | { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE, | ||
2091 | NULL }, | ||
2092 | { N_("tilde expansion"), MU_WRDSF_PATHEXPAND, 0, | ||
2093 | mu_wordsplit_tildexpand }, | ||
2082 | { N_("variable expansion"), MU_WRDSF_NOVAR, EXPOPT_NEG, | 2094 | { N_("variable expansion"), MU_WRDSF_NOVAR, EXPOPT_NEG, |
2083 | mu_wordsplit_varexp }, | 2095 | mu_wordsplit_varexp }, |
2084 | { N_("quote removal"), 0, EXPOPT_NEG, | 2096 | { N_("quote removal"), 0, EXPOPT_NEG, |
2085 | wsnode_quoteremoval }, | 2097 | wsnode_quoteremoval }, |
2086 | { N_("command substitution"), MU_WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE, | ||
2087 | mu_wordsplit_cmdexp }, | ||
2088 | { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE, | 2098 | { N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE, |
2089 | NULL }, | 2099 | NULL }, |
2090 | { N_("path expansion"), MU_WRDSF_PATHEXPAND, 0, mu_wordsplit_pathexpand }, | 2100 | { N_("path expansion"), MU_WRDSF_PATHEXPAND, 0, |
2101 | mu_wordsplit_pathexpand }, | ||
2091 | { NULL } | 2102 | { NULL } |
2092 | }; | 2103 | }; |
2093 | 2104 | ... | ... |
... | @@ -421,4 +421,207 @@ NF: 1 | ... | @@ -421,4 +421,207 @@ NF: 1 |
421 | [input exhausted | 421 | [input exhausted |
422 | ]) | 422 | ]) |
423 | 423 | ||
424 | dnl Something that doesn't fit into TESTWSP | ||
425 | |||
426 | AT_SETUP([simple command substitution]) | ||
427 | AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-1]) | ||
428 | AT_CHECK([ | ||
429 | mkdir dir | ||
430 | > dir/file | ||
431 | |||
432 | wsp -nocmd <<'EOT' | ||
433 | begin $(find dir) end | ||
434 | EOT | ||
435 | ], | ||
436 | [0], | ||
437 | [NF: 4 | ||
438 | 0: begin | ||
439 | 1: dir | ||
440 | 2: dir/file | ||
441 | 3: end | ||
442 | ]) | ||
443 | AT_CLEANUP | ||
444 | |||
445 | AT_SETUP([quoted command substitution]) | ||
446 | AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-2]) | ||
447 | AT_CHECK([ | ||
448 | mkdir dir | ||
449 | > dir/file | ||
450 | |||
451 | wsp -nocmd <<'EOT' | ||
452 | begin "$(find dir)" end | ||
453 | EOT | ||
454 | ], | ||
455 | [0], | ||
456 | [NF: 3 | ||
457 | 0: begin | ||
458 | 1: "dir dir/file" | ||
459 | 2: end | ||
460 | ]) | ||
461 | AT_CLEANUP | ||
462 | |||
463 | AT_SETUP([coalesced command substitution]) | ||
464 | AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-3]) | ||
465 | AT_CHECK([ | ||
466 | mkdir dir | ||
467 | > dir/file | ||
468 | |||
469 | wsp -nocmd <<'EOT' | ||
470 | begin($(find dir))end | ||
471 | EOT | ||
472 | ], | ||
473 | [0], | ||
474 | [NF: 2 | ||
475 | 0: begin(dir | ||
476 | 1: dir/file)end | ||
477 | ]) | ||
478 | AT_CLEANUP | ||
479 | |||
480 | AT_SETUP([quoted coalesced command substitution]) | ||
481 | AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-4]) | ||
482 | AT_CHECK([ | ||
483 | mkdir dir | ||
484 | > dir/file | ||
485 | |||
486 | wsp -nocmd <<'EOT' | ||
487 | "begin($(find dir))end" | ||
488 | EOT | ||
489 | ], | ||
490 | [0], | ||
491 | [NF: 1 | ||
492 | 0: "begin(dir dir/file)end" | ||
493 | ]) | ||
494 | AT_CLEANUP | ||
495 | |||
496 | AT_SETUP([variable and command substitution]) | ||
497 | AT_KEYWORDS([wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5]) | ||
498 | AT_CHECK([ | ||
499 | mkdir dir | ||
500 | > dir/file | ||
501 | |||
502 | DIR=dir wsp -nocmd -novar<<'EOT' | ||
503 | begin $DIR $(find $DIR) end | ||
504 | EOT | ||
505 | ], | ||
506 | [0], | ||
507 | [NF: 5 | ||
508 | 0: begin | ||
509 | 1: dir | ||
510 | 2: dir | ||
511 | 3: dir/file | ||
512 | 4: end | ||
513 | ]) | ||
514 | AT_CLEANUP | ||
515 | |||
516 | AT_SETUP([variable expansion and command substitution in quotes]) | ||
517 | AT_KEYWORDS([wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6]) | ||
518 | AT_CHECK([ | ||
519 | mkdir dir | ||
520 | > dir/file | ||
521 | |||
522 | DIR=dir BEGIN=begin wsp -nocmd -novar<<'EOT' | ||
523 | "${BEGIN}($(find $DIR))end" | ||
524 | EOT | ||
525 | ], | ||
526 | [0], | ||
527 | [NF: 1 | ||
528 | 0: "begin(dir dir/file)end" | ||
529 | ]) | ||
530 | AT_CLEANUP | ||
531 | |||
532 | AT_SETUP([nested commands]) | ||
533 | AT_KEYWORDS([wordsplit wsp wsp-cmd]) | ||
534 | AT_CHECK([ | ||
535 | AT_DATA([input],[foo | ||
536 | bar | ||
537 | baz | ||
538 | ]) | ||
539 | SUFFIX=put wsp -nocmd -novar <<'EOT' | ||
540 | $(echo output $(cat in$SUFFIX)) | ||
541 | EOT | ||
542 | ], | ||
543 | [0], | ||
544 | [NF: 4 | ||
545 | 0: output | ||
546 | 1: foo | ||
547 | 2: bar | ||
548 | 3: baz | ||
549 | ]) | ||
550 | AT_CLEANUP | ||
551 | |||
552 | AT_SETUP([pathname expansion]) | ||
553 | AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1]) | ||
554 | AT_CHECK([ | ||
555 | mkdir dir | ||
556 | > dir/1.c | ||
557 | > dir/2.c | ||
558 | > dir/3.b | ||
559 | |||
560 | wsp pathexpand<<'EOT' | ||
561 | begin dir/*.c end | ||
562 | EOT | ||
563 | ], | ||
564 | [0], | ||
565 | [NF: 4 | ||
566 | 0: begin | ||
567 | 1: dir/1.c | ||
568 | 2: dir/2.c | ||
569 | 3: end | ||
570 | ]) | ||
571 | AT_CLEANUP | ||
572 | |||
573 | AT_SETUP([pathname expansion: no match]) | ||
574 | AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-2]) | ||
575 | AT_CHECK([ | ||
576 | mkdir dir | ||
577 | > dir/1.c | ||
578 | > dir/2.b | ||
579 | |||
580 | wsp pathexpand<<'EOT' | ||
581 | begin dir/*.d end | ||
582 | EOT | ||
583 | ], | ||
584 | [0], | ||
585 | [NF: 3 | ||
586 | 0: begin | ||
587 | 1: dir/*.d | ||
588 | 2: end | ||
589 | ]) | ||
590 | AT_CLEANUP | ||
591 | |||
592 | AT_SETUP([pathname expansion: nullglob]) | ||
593 | AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-3]) | ||
594 | AT_CHECK([ | ||
595 | mkdir dir | ||
596 | > dir/1.c | ||
597 | > dir/2.b | ||
598 | |||
599 | wsp pathexpand nullglob<<'EOT' | ||
600 | begin dir/*.d end | ||
601 | EOT | ||
602 | ], | ||
603 | [0], | ||
604 | [NF: 2 | ||
605 | 0: begin | ||
606 | 1: end | ||
607 | ]) | ||
608 | AT_CLEANUP | ||
609 | |||
610 | AT_SETUP([pathname expansion: failglob]) | ||
611 | AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-4]) | ||
612 | AT_CHECK([ | ||
613 | mkdir dir | ||
614 | > dir/1.c | ||
615 | > dir/2.b | ||
616 | |||
617 | wsp pathexpand failglob<<'EOT' | ||
618 | begin dir/*.d end | ||
619 | EOT | ||
620 | ], | ||
621 | [0], | ||
622 | [], | ||
623 | [no files match pattern dir/*.d | ||
624 | ]) | ||
625 | AT_CLEANUP | ||
626 | |||
424 | m4_popdef([TESTWSP]) | 627 | m4_popdef([TESTWSP]) | ... | ... |
-
Please register or sign in to post a comment