vi: further changes to colon addresses
No binary (build failed)
—
(log yok)
| @@ -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); | |
| } | |