Re: usr.bin/mail: cmd3.c:bangexp(): "borked"?, and BSD fails POSIX compat

From: Steffen Nurpmeso <steffen_at_sdaoden.eu>
Date: Tue, 02 May 2023 22:24:41 UTC
Steffen Nurpmeso wrote in
 <20230502214014._zIz6%steffen@sdaoden.eu>:
 |Hallo, and sorry for the cross-post, but so all in one (maybe) go.
 |
 |This is about a niche "feature" of mail, the shell command "bang"
 |(! / ~! in compose mode):
 ...
 |POSIX now says / will say
 |
 |  If the bang variable is set, each unescaped occurrence of '!' in
 |  command shall be replaced with the command executed by the
 |  previous ! command or ˜! command escape.
 |
 |thus
 |
 |  - All commands entered for ! and ~! shall be stored.
 |
 |  - If "bang" is set, an unquoted ! shall be replaced by that
 |    storage.
 ...
 |It will fail to properly "bang" a second time[.]

Eh, forget this please.  Of course not, one simply inserts the old
string without expansion.
Since vim(1) offers the same "bang"ing, and merges \! to ! (source
comment speaks of vi-compat) i keep it.  (It actually requires
'\!' or \\! ro avoid its expansion in ":echo BLA".)

Ciao.



        static struct str last_bang;

        struct n_string xbang, *bang;
        char c;
        char const *cp_orig;
        boole bangit, changed;
        NYD_IN;

        bangit = ok_blook(bang);
        changed = FAL0;
        cp_orig = cp;

        for(bang = n_string_creat(&xbang); (c = *cp++) != '\0';){
                if(bangit && c == '!'){
                        changed = TRU1;
                        if(last_bang.l > 0)
                                bang = n_string_push_buf(bang, last_bang.s, last_bang.l);
                }else{
                        if(c == '\\' && *cp == '!'){
                                changed = TRU1;
                                ++cp;
                                c = '!';
                        }
                        bang = n_string_push_c(bang, c);
                }
        }

        if(last_bang.s != NIL)
                su_FREE(last_bang.s);

        last_bang.s = n_string_cp(bang);
        last_bang.l = bang->s_len;
        bang = n_string_drop_ownership(bang);
        n_string_gut(bang);

        if(bangit){
                cp = last_bang.s;
                if(changed && (n_psonce & n_PSO_INTERACTIVE))
                        fprintf(n_stdout, "!%s\n", cp);
        }else
                cp = cp_orig;

        NYD_OU;
        return cp;

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
|~~
|..and in spring, hear David Leonard sing..
|
|The black bear,          The black bear,
|blithely holds his own   holds himself at leisure
|beating it, up and down  tossing over his ups and downs with pleasure
|~~
|Farewell, dear collar bear