diff --git a/editors/vi.c b/editors/vi.c index caf01acd3..77c42641e 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2473,37 +2473,43 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present return p; } -# define GET_FIRST 0 -# define GET_SECOND 1 -# define GOT_FIRST 2 -# define GOT_SECOND 3 -# define GOT 2 +# define GET_ADDRESS 0 +# define GET_SEPARATOR 1 -static char *get_address(char *p, int *b, int *e) // get two colon addrs, 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) { - int state = GET_FIRST; + int state = GET_ADDRESS; + char *save_dot = dot; //----- get the address' i.e., 1,3 'a,'b ----- for (;;) { if (isblank(*p)) { p++; - } else if (*p == '%' && state == GET_FIRST) { // alias for 1,$ + } else if (*p == '%' && state == GET_ADDRESS) { // alias for 1,$ p++; *b = 1; *e = count_lines(text, end-1); - state = GOT_SECOND; - } else if (*p == ',' && state == GOT_FIRST) { + state = GET_SEPARATOR; + } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { + if (*p == ';') + dot = find_line(*e); p++; - state = GET_SECOND; - } else if (state == GET_FIRST || state == GET_SECOND) { - p = get_one_address(p, state == GET_FIRST ? b : e); + *b = *e; + state = GET_ADDRESS; + } else if (state == GET_ADDRESS) { + p = get_one_address(p, e); if (p == NULL) break; - state |= GOT; + state = GET_SEPARATOR; } else { + if (state == GET_SEPARATOR && *e < 0) + *e = count_lines(text, dot); break; } } + dot = save_dot; return p; } @@ -2637,8 +2643,6 @@ static void colon(char *buf) li = i = 0; b = e = -1; - q = text; // assume 1,$ for the range - r = end - 1; li = count_lines(text, end - 1); fn = current_filename; @@ -2673,27 +2677,33 @@ static void colon(char *buf) useforce = TRUE; *buf1 = '\0'; // get rid of ! } - if (b >= 0) { - // if there is only one addr, then the addr - // is the line number of the single line the - // user wants. So, reset the end - // pointer to point at end of the "b" line - q = find_line(b); // what line is #b - r = end_line(q); - li = 1; - } - if (e >= 0) { - // we were given two addrs. change the - // end pointer to the addr given by user. - r = find_line(e); // what line is #e - r = end_line(r); - li = e - b + 1; + // assume the command will want a range, certain commands + // (read, substitute) need to adjust these assumptions + if (e < 0) { + q = text; // no addr, use 1,$ for the range + r = end - 1; + } else { + // at least one addr was given, get its details + q = r = find_line(e); + if (b < 0) { + // 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. + r = end_line(q); + li = 1; + } else { + // we were given two addrs. change the + // start pointer to the addr given by user. + q = find_line(b); // what line is #b + r = end_line(r); + li = e - b + 1; + } } // ------------ now look for the command ------------ i = strlen(cmd); if (i == 0) { // :123CR goto line #123 - if (b >= 0) { - dot = find_line(b); // what line is #b + if (e >= 0) { + dot = find_line(e); // what line is #e dot_skip_over_ws(); } } @@ -2711,12 +2721,12 @@ static void colon(char *buf) } # endif else if (cmd[0] == '=' && !cmd[1]) { // where is the address - if (b < 0) { // no addr given- use defaults - b = e = count_lines(text, dot); + if (e < 0) { // no addr given- use defaults + e = count_lines(text, dot); } - status_line("%d", b); + status_line("%d", e); } else if (strncmp(cmd, "delete", i) == 0) { // delete lines - if (b < 0) { // no addr given- use defaults + if (e < 0) { // no addr given- use defaults q = begin_line(dot); // assume .,. for the range r = end_line(dot); } @@ -2767,7 +2777,7 @@ static void colon(char *buf) li, (int)(end - text) ); } else if (strncmp(cmd, "file", i) == 0) { // what File is this - if (b != -1 || e != -1) { + if (e >= 0) { status_line_bold("No address allowed on this command"); goto ret; } @@ -2787,7 +2797,7 @@ static void colon(char *buf) rawmode(); Hit_Return(); } else if (strncmp(cmd, "list", i) == 0) { // literal print line - if (b < 0) { // no addr given- use defaults + if (e < 0) { // no addr given- use defaults q = begin_line(dot); // assume .,. for the range r = end_line(dot); } @@ -2861,12 +2871,12 @@ static void colon(char *buf) status_line_bold("No filename given"); goto ret; } - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume "dot" - } - // read after current line- unless user said ":0r foo" - if (b != 0) { - q = next_line(q); + if (e < 0) { // no addr given- read after current line + q = begin_line(dot); + } else if (e == 0) { // user said ":0r foo" + q = text; + } else { // addr given- read after that line + q = next_line(find_line(e)); // read after last line if (q == end-1) ++q; @@ -2969,13 +2979,13 @@ static void colon(char *buf) } len_R = strlen(R); - q = begin_line(q); - if (b < 0) { // maybe :s/foo/bar/ + if (e < 0) { // no addr given q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number + r = end_line(dot); + b = e = count_lines(text, q); // cur line number + } else if (b < 0) { // one addr given + b = e; } - if (e < 0) - e = b; // maybe :.s/foo/bar/ for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 char *ls = q; // orig line start