[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: [PATCH 1/1] vi: further changes to colon addresses
From:       Denys Vlasenko <vda.linux () googlemail ! com>
Date:       2021-08-29 18:19:29
Message-ID: CAK1hOcNt6awDztrbYWOn_pyQg0KFwf6GuLb1Z9N=ZyPKK5tuKw () mail ! gmail ! com
[Download RAW message or body]

Applied, thank you.

On Sun, Aug 29, 2021 at 3:56 PM Ron Yorston <rmy@pobox.com> wrote:
> 
> Improved error messages:
> 
> - specify when a search fails or a mark isn't set;
> - warn when line addresses are out of range or when a range of
> lines is reversed.
> 
> Addresses are limited to the number of lines in the file so a
> command like ':2000000000' (go to the two billionth line) no
> longer causes a long pause.
> 
> Improved vi compatibility of '+' and '-' operators that aren't
> followed immediately by a number:
> 
> > 4+++=       7
> > 3-2=        1
> > 3 - 2=      4 (yes, really!)
> 
> In a command like ':,$' the empty address before the separator now
> correctly refers to the current line.  (The similar case ':1,' was
> already being handled.)
> 
> And all with a tidy reduction in bloat (32-bit build):
> 
> function                                             old     new   delta
> colon                                               4029    4069     +40
> .rodata                                            99348   99253     -95
> ------------------------------------------------------------------------------
> (add/remove: 0/0 grow/shrink: 1/1 up/down: 40/-95)            Total: -55 bytes
> 
> Signed-off-by: Ron Yorston <rmy@pobox.com>
> ---
> editors/vi.c | 132 ++++++++++++++++++++++++++++++++-------------------
> 1 file changed, 83 insertions(+), 49 deletions(-)
> 
> diff --git a/editors/vi.c b/editors/vi.c
> index e4ba2b2b0..3dbe5b471 100644
> --- a/editors/vi.c
> +++ b/editors/vi.c
> @@ -2458,26 +2458,38 @@ static char *char_search(char *p, const char *pat, int \
> dir_and_range) 
> //----- The Colon commands -------------------------------------
> #if ENABLE_FEATURE_VI_COLON
> -static char *get_one_address(char *p, int *result)     // get colon addr, if \
> present +// Evaluate colon address expression.  Returns a pointer to the
> +// next character or NULL on error.  If 'result' contains a valid
> +// address 'valid' is TRUE.
> +static char *get_one_address(char *p, int *result, int *valid)
> {
> -       int st, num, sign, addr, new_addr;
> +       int num, sign, addr, got_addr;
> # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH
> char *q, c;
> # endif
> IF_FEATURE_VI_SEARCH(int dir;)
> 
> -       addr = -1;                      // assume no addr
> +       got_addr = FALSE;
> +       addr = count_lines(text, dot);  // default to current line
> sign = 0;
> for (;;) {
> -               new_addr = -1;
> if (isblank(*p)) {
> +                       if (got_addr) {
> +                               addr += sign;
> +                               sign = 0;
> +                       }
> +                       p++;
> +               } else if (!got_addr && *p == '.') {    // the current line
> p++;
> -               } else if (*p == '.') { // the current line
> +                       //addr = count_lines(text, dot);
> +                       got_addr = TRUE;
> +               } else if (!got_addr && *p == '$') {    // the last line in file
> p++;
> -                       new_addr = count_lines(text, dot);
> +                       addr = count_lines(text, end - 1);
> +                       got_addr = TRUE;
> }
> # if ENABLE_FEATURE_VI_YANKMARK
> -               else if (*p == '\'') {  // is this a mark addr
> +               else if (!got_addr && *p == '\'') {     // is this a mark addr
> p++;
> c = tolower(*p);
> p++;
> @@ -2487,13 +2499,16 @@ static char *get_one_address(char *p, int *result)      // \
> get colon addr, if present c = c - 'a';
> q = mark[(unsigned char) c];
> }
> -                       if (q == NULL)  // is mark valid
> +                       if (q == NULL) {        // is mark valid
> +                               status_line_bold("Mark not set");
> return NULL;
> -                       new_addr = count_lines(text, q);
> +                       }
> +                       addr = count_lines(text, q);
> +                       got_addr = TRUE;
> }
> # endif
> # if ENABLE_FEATURE_VI_SEARCH
> -               else if (*p == '/' || *p == '?') {      // a search pattern
> +               else if (!got_addr && (*p == '/' || *p == '?')) {       // a search \
> pattern c = *p;
> q = strchrnul(p + 1, c);
> if (p + 1 != q) {
> @@ -2516,40 +2531,41 @@ static char *get_one_address(char *p, int *result)      // \
> get colon addr, if present // no match, continue from other end of file
> q = char_search(dir > 0 ? text : end - 1,
> last_search_pattern + 1, dir);
> -                               if (q == NULL)
> +                               if (q == NULL) {
> +                                       status_line_bold("Pattern not found");
> return NULL;
> +                               }
> }
> -                       new_addr = count_lines(text, q);
> +                       addr = count_lines(text, q);
> +                       got_addr = TRUE;
> }
> # endif
> -               else if (*p == '$') {   // the last line in file
> -                       p++;
> -                       new_addr = count_lines(text, end - 1);
> -               } else if (isdigit(*p)) {
> -                       sscanf(p, "%d%n", &num, &st);
> -                       p += st;
> -                       if (addr < 0) { // specific line number
> +               else if (isdigit(*p)) {
> +                       num = 0;
> +                       while (isdigit(*p))
> +                               num = num * 10 + *p++ -'0';
> +                       if (!got_addr) {        // specific line number
> addr = num;
> +                               got_addr = TRUE;
> } else {        // offset from current addr
> addr += sign >= 0 ? num : -num;
> }
> sign = 0;
> } else if (*p == '-' || *p == '+') {
> -                       sign = *p++ == '-' ? -1 : 1;
> -                       if (addr < 0) { // default address is dot
> -                               addr = count_lines(text, dot);
> +                       if (!got_addr) {        // default address is dot
> +                               //addr = count_lines(text, dot);
> +                               got_addr = TRUE;
> +                       } else {
> +                               addr += sign;
> }
> +                       sign = *p++ == '-' ? -1 : 1;
> } else {
> addr += sign;   // consume unused trailing sign
> break;
> }
> -               if (new_addr >= 0) {
> -                       if (addr >= 0)  // only one new address per expression
> -                               return NULL;
> -                       addr = new_addr;
> -               }
> }
> *result = addr;
> +       *valid = got_addr;
> return p;
> }
> 
> @@ -2558,34 +2574,40 @@ static char *get_one_address(char *p, int *result)      // \
> get colon addr, if present 
> // Read line addresses for a colon command.  The user can enter as
> // many as they like but only the last two will be used.
> -static char *get_address(char *p, int *b, int *e)
> +static char *get_address(char *p, int *b, int *e, unsigned int *got)
> {
> int state = GET_ADDRESS;
> +       int valid;
> +       int addr;
> char *save_dot = dot;
> 
> //----- get the address' i.e., 1,3   'a,'b  -----
> for (;;) {
> if (isblank(*p)) {
> p++;
> -               } else if (*p == '%' && state == GET_ADDRESS) { // alias for 1,$
> +               } else if (state == GET_ADDRESS && *p == '%') { // alias for 1,$
> p++;
> *b = 1;
> *e = count_lines(text, end-1);
> +                       *got = 3;
> +                       state = GET_SEPARATOR;
> +               } else if (state == GET_ADDRESS) {
> +                       valid = FALSE;
> +                       p = get_one_address(p, &addr, &valid);
> +                       // Quit on error or if the address is invalid and isn't of
> +                       // the form ',$' or '1,' (in which case it defaults to \
> dot). +                       if (p == NULL || !(valid || *p == ',' || *p == ';' || \
> *got & 1)) +                               break;
> +                       *b = *e;
> +                       *e = addr;
> +                       *got = (*got << 1) | 1;
> state = GET_SEPARATOR;
> } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) {
> if (*p == ';')
> dot = find_line(*e);
> p++;
> -                       *b = *e;
> state = GET_ADDRESS;
> -               } else if (state == GET_ADDRESS) {
> -                       p = get_one_address(p, e);
> -                       if (p == NULL)
> -                               break;
> -                       state = GET_SEPARATOR;
> } else {
> -                       if (state == GET_SEPARATOR && *b >= 0 && *e < 0)
> -                               *e = count_lines(text, dot);
> break;
> }
> }
> @@ -2799,9 +2821,14 @@ static void colon(char *buf)
> not_implemented(p);
> #else
> 
> +// check how many addresses we got
> +# define GOT_ADDRESS (got & 1)
> +# define GOT_RANGE ((got & 3) == 3)
> +
> char c, *buf1, *q, *r;
> char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL;
> int i, l, li, b, e;
> +       unsigned int got;
> int useforce;
> 
> // :3154        // if (-e line 3154) goto it  else stay put
> @@ -2828,14 +2855,13 @@ static void colon(char *buf)
> 
> li = i = 0;
> b = e = -1;
> +       got = 0;
> li = count_lines(text, end - 1);
> fn = current_filename;
> 
> // look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
> -       buf1 = buf;
> -       buf = get_address(buf, &b, &e);
> +       buf = get_address(buf, &b, &e, &got);
> if (buf == NULL) {
> -               status_line_bold("Bad address: %s", buf1);
> goto ret;
> }
> 
> @@ -2858,13 +2884,17 @@ static void colon(char *buf)
> }
> // assume the command will want a range, certain commands
> // (read, substitute) need to adjust these assumptions
> -       if (e < 0) {
> +       if (!GOT_ADDRESS) {
> q = text;                       // no addr, use 1,$ for the range
> r = end - 1;
> } else {
> // at least one addr was given, get its details
> +               if (e < 0 || e > li) {
> +                       status_line_bold("Invalid range");
> +                       goto ret;
> +               }
> q = r = find_line(e);
> -               if (b < 0) {
> +               if (!GOT_RANGE) {
> // if there is only one addr, then it's the line
> // number of the single line the user wants.
> // Reset the end pointer to the end of that line.
> @@ -2873,6 +2903,10 @@ static void colon(char *buf)
> } else {
> // we were given two addrs.  change the
> // start pointer to the addr given by user.
> +                       if (b < 0 || b > li || b > e) {
> +                               status_line_bold("Invalid range");
> +                               goto ret;
> +                       }
> q = find_line(b);       // what line is #b
> r = end_line(r);
> li = e - b + 1;
> @@ -2903,12 +2937,12 @@ static void colon(char *buf)
> }
> # endif
> else if (cmd[0] == '=' && !cmd[1]) {    // where is the address
> -               if (e < 0) {    // no addr given- use defaults
> +               if (!GOT_ADDRESS) {     // no addr given- use defaults
> e = count_lines(text, dot);
> }
> status_line("%d", e);
> } else if (strncmp(cmd, "delete", i) == 0) {    // delete lines
> -               if (e < 0) {    // no addr given- use defaults
> +               if (!GOT_ADDRESS) {     // no addr given- use defaults
> q = begin_line(dot);    // assume .,. for the range
> r = end_line(dot);
> }
> @@ -2980,7 +3014,7 @@ static void colon(char *buf)
> rawmode();
> Hit_Return();
> } else if (strncmp(cmd, "list", i) == 0) {      // literal print line
> -               if (e < 0) {    // no addr given- use defaults
> +               if (!GOT_ADDRESS) {     // no addr given- use defaults
> q = begin_line(dot);    // assume .,. for the range
> r = end_line(dot);
> }
> @@ -3063,7 +3097,7 @@ static void colon(char *buf)
> if (e == 0) {   // user said ":0r foo"
> q = text;
> } else {        // read after given line or current line if none given
> -                       q = next_line(e > 0 ? find_line(e) : dot);
> +                       q = next_line(GOT_ADDRESS ? find_line(e) : dot);
> // read after last line
> if (q == end-1)
> ++q;
> @@ -3184,11 +3218,11 @@ static void colon(char *buf)
> len_F = strlen(F);
> }
> 
> -               if (e < 0) {    // no addr given
> +               if (!GOT_ADDRESS) {     // no addr given
> q = begin_line(dot);      // start with cur line
> r = end_line(dot);
> b = e = count_lines(text, q); // cur line number
> -               } else if (b < 0) {     // one addr given
> +               } else if (!GOT_RANGE) {        // one addr given
> b = e;
> }
> 
> @@ -3359,7 +3393,7 @@ static void colon(char *buf)
> }
> # if ENABLE_FEATURE_VI_YANKMARK
> } else if (strncmp(cmd, "yank", i) == 0) {      // yank lines
> -               if (b < 0) {    // no addr given- use defaults
> +               if (!GOT_ADDRESS) {     // no addr given- use defaults
> q = begin_line(dot);    // assume .,. for the range
> r = end_line(dot);
> }
> --
> 2.31.1
> 
> _______________________________________________
> busybox mailing list
> busybox@busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic