Applied, thank you.
On Sun, Aug 29, 2021 at 3:56 PM Ron Yorston <[email protected]> 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 <[email protected]> > --- > 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 > [email protected] > http://lists.busybox.net/mailman/listinfo/busybox _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
