diff options
-rw-r--r-- | editors/vi.c | 132 |
1 files 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) | |||
2458 | 2458 | ||
2459 | //----- The Colon commands ------------------------------------- | 2459 | //----- The Colon commands ------------------------------------- |
2460 | #if ENABLE_FEATURE_VI_COLON | 2460 | #if ENABLE_FEATURE_VI_COLON |
2461 | static char *get_one_address(char *p, int *result) // get colon addr, if present | 2461 | // Evaluate colon address expression. Returns a pointer to the |
2462 | // next character or NULL on error. If 'result' contains a valid | ||
2463 | // address 'valid' is TRUE. | ||
2464 | static char *get_one_address(char *p, int *result, int *valid) | ||
2462 | { | 2465 | { |
2463 | int st, num, sign, addr, new_addr; | 2466 | int num, sign, addr, got_addr; |
2464 | # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH | 2467 | # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH |
2465 | char *q, c; | 2468 | char *q, c; |
2466 | # endif | 2469 | # endif |
2467 | IF_FEATURE_VI_SEARCH(int dir;) | 2470 | IF_FEATURE_VI_SEARCH(int dir;) |
2468 | 2471 | ||
2469 | addr = -1; // assume no addr | 2472 | got_addr = FALSE; |
2473 | addr = count_lines(text, dot); // default to current line | ||
2470 | sign = 0; | 2474 | sign = 0; |
2471 | for (;;) { | 2475 | for (;;) { |
2472 | new_addr = -1; | ||
2473 | if (isblank(*p)) { | 2476 | if (isblank(*p)) { |
2477 | if (got_addr) { | ||
2478 | addr += sign; | ||
2479 | sign = 0; | ||
2480 | } | ||
2481 | p++; | ||
2482 | } else if (!got_addr && *p == '.') { // the current line | ||
2474 | p++; | 2483 | p++; |
2475 | } else if (*p == '.') { // the current line | 2484 | //addr = count_lines(text, dot); |
2485 | got_addr = TRUE; | ||
2486 | } else if (!got_addr && *p == '$') { // the last line in file | ||
2476 | p++; | 2487 | p++; |
2477 | new_addr = count_lines(text, dot); | 2488 | addr = count_lines(text, end - 1); |
2489 | got_addr = TRUE; | ||
2478 | } | 2490 | } |
2479 | # if ENABLE_FEATURE_VI_YANKMARK | 2491 | # if ENABLE_FEATURE_VI_YANKMARK |
2480 | else if (*p == '\'') { // is this a mark addr | 2492 | else if (!got_addr && *p == '\'') { // is this a mark addr |
2481 | p++; | 2493 | p++; |
2482 | c = tolower(*p); | 2494 | c = tolower(*p); |
2483 | p++; | 2495 | p++; |
@@ -2487,13 +2499,16 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2487 | c = c - 'a'; | 2499 | c = c - 'a'; |
2488 | q = mark[(unsigned char) c]; | 2500 | q = mark[(unsigned char) c]; |
2489 | } | 2501 | } |
2490 | if (q == NULL) // is mark valid | 2502 | if (q == NULL) { // is mark valid |
2503 | status_line_bold("Mark not set"); | ||
2491 | return NULL; | 2504 | return NULL; |
2492 | new_addr = count_lines(text, q); | 2505 | } |
2506 | addr = count_lines(text, q); | ||
2507 | got_addr = TRUE; | ||
2493 | } | 2508 | } |
2494 | # endif | 2509 | # endif |
2495 | # if ENABLE_FEATURE_VI_SEARCH | 2510 | # if ENABLE_FEATURE_VI_SEARCH |
2496 | else if (*p == '/' || *p == '?') { // a search pattern | 2511 | else if (!got_addr && (*p == '/' || *p == '?')) { // a search pattern |
2497 | c = *p; | 2512 | c = *p; |
2498 | q = strchrnul(p + 1, c); | 2513 | q = strchrnul(p + 1, c); |
2499 | if (p + 1 != q) { | 2514 | if (p + 1 != q) { |
@@ -2516,40 +2531,41 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2516 | // no match, continue from other end of file | 2531 | // no match, continue from other end of file |
2517 | q = char_search(dir > 0 ? text : end - 1, | 2532 | q = char_search(dir > 0 ? text : end - 1, |
2518 | last_search_pattern + 1, dir); | 2533 | last_search_pattern + 1, dir); |
2519 | if (q == NULL) | 2534 | if (q == NULL) { |
2535 | status_line_bold("Pattern not found"); | ||
2520 | return NULL; | 2536 | return NULL; |
2537 | } | ||
2521 | } | 2538 | } |
2522 | new_addr = count_lines(text, q); | 2539 | addr = count_lines(text, q); |
2540 | got_addr = TRUE; | ||
2523 | } | 2541 | } |
2524 | # endif | 2542 | # endif |
2525 | else if (*p == '$') { // the last line in file | 2543 | else if (isdigit(*p)) { |
2526 | p++; | 2544 | num = 0; |
2527 | new_addr = count_lines(text, end - 1); | 2545 | while (isdigit(*p)) |
2528 | } else if (isdigit(*p)) { | 2546 | num = num * 10 + *p++ -'0'; |
2529 | sscanf(p, "%d%n", &num, &st); | 2547 | if (!got_addr) { // specific line number |
2530 | p += st; | ||
2531 | if (addr < 0) { // specific line number | ||
2532 | addr = num; | 2548 | addr = num; |
2549 | got_addr = TRUE; | ||
2533 | } else { // offset from current addr | 2550 | } else { // offset from current addr |
2534 | addr += sign >= 0 ? num : -num; | 2551 | addr += sign >= 0 ? num : -num; |
2535 | } | 2552 | } |
2536 | sign = 0; | 2553 | sign = 0; |
2537 | } else if (*p == '-' || *p == '+') { | 2554 | } else if (*p == '-' || *p == '+') { |
2538 | sign = *p++ == '-' ? -1 : 1; | 2555 | if (!got_addr) { // default address is dot |
2539 | if (addr < 0) { // default address is dot | 2556 | //addr = count_lines(text, dot); |
2540 | addr = count_lines(text, dot); | 2557 | got_addr = TRUE; |
2558 | } else { | ||
2559 | addr += sign; | ||
2541 | } | 2560 | } |
2561 | sign = *p++ == '-' ? -1 : 1; | ||
2542 | } else { | 2562 | } else { |
2543 | addr += sign; // consume unused trailing sign | 2563 | addr += sign; // consume unused trailing sign |
2544 | break; | 2564 | break; |
2545 | } | 2565 | } |
2546 | if (new_addr >= 0) { | ||
2547 | if (addr >= 0) // only one new address per expression | ||
2548 | return NULL; | ||
2549 | addr = new_addr; | ||
2550 | } | ||
2551 | } | 2566 | } |
2552 | *result = addr; | 2567 | *result = addr; |
2568 | *valid = got_addr; | ||
2553 | return p; | 2569 | return p; |
2554 | } | 2570 | } |
2555 | 2571 | ||
@@ -2558,34 +2574,40 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2558 | 2574 | ||
2559 | // Read line addresses for a colon command. The user can enter as | 2575 | // Read line addresses for a colon command. The user can enter as |
2560 | // many as they like but only the last two will be used. | 2576 | // many as they like but only the last two will be used. |
2561 | static char *get_address(char *p, int *b, int *e) | 2577 | static char *get_address(char *p, int *b, int *e, unsigned int *got) |
2562 | { | 2578 | { |
2563 | int state = GET_ADDRESS; | 2579 | int state = GET_ADDRESS; |
2580 | int valid; | ||
2581 | int addr; | ||
2564 | char *save_dot = dot; | 2582 | char *save_dot = dot; |
2565 | 2583 | ||
2566 | //----- get the address' i.e., 1,3 'a,'b ----- | 2584 | //----- get the address' i.e., 1,3 'a,'b ----- |
2567 | for (;;) { | 2585 | for (;;) { |
2568 | if (isblank(*p)) { | 2586 | if (isblank(*p)) { |
2569 | p++; | 2587 | p++; |
2570 | } else if (*p == '%' && state == GET_ADDRESS) { // alias for 1,$ | 2588 | } else if (state == GET_ADDRESS && *p == '%') { // alias for 1,$ |
2571 | p++; | 2589 | p++; |
2572 | *b = 1; | 2590 | *b = 1; |
2573 | *e = count_lines(text, end-1); | 2591 | *e = count_lines(text, end-1); |
2592 | *got = 3; | ||
2593 | state = GET_SEPARATOR; | ||
2594 | } else if (state == GET_ADDRESS) { | ||
2595 | valid = FALSE; | ||
2596 | p = get_one_address(p, &addr, &valid); | ||
2597 | // Quit on error or if the address is invalid and isn't of | ||
2598 | // the form ',$' or '1,' (in which case it defaults to dot). | ||
2599 | if (p == NULL || !(valid || *p == ',' || *p == ';' || *got & 1)) | ||
2600 | break; | ||
2601 | *b = *e; | ||
2602 | *e = addr; | ||
2603 | *got = (*got << 1) | 1; | ||
2574 | state = GET_SEPARATOR; | 2604 | state = GET_SEPARATOR; |
2575 | } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { | 2605 | } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { |
2576 | if (*p == ';') | 2606 | if (*p == ';') |
2577 | dot = find_line(*e); | 2607 | dot = find_line(*e); |
2578 | p++; | 2608 | p++; |
2579 | *b = *e; | ||
2580 | state = GET_ADDRESS; | 2609 | state = GET_ADDRESS; |
2581 | } else if (state == GET_ADDRESS) { | ||
2582 | p = get_one_address(p, e); | ||
2583 | if (p == NULL) | ||
2584 | break; | ||
2585 | state = GET_SEPARATOR; | ||
2586 | } else { | 2610 | } else { |
2587 | if (state == GET_SEPARATOR && *b >= 0 && *e < 0) | ||
2588 | *e = count_lines(text, dot); | ||
2589 | break; | 2611 | break; |
2590 | } | 2612 | } |
2591 | } | 2613 | } |
@@ -2799,9 +2821,14 @@ static void colon(char *buf) | |||
2799 | not_implemented(p); | 2821 | not_implemented(p); |
2800 | #else | 2822 | #else |
2801 | 2823 | ||
2824 | // check how many addresses we got | ||
2825 | # define GOT_ADDRESS (got & 1) | ||
2826 | # define GOT_RANGE ((got & 3) == 3) | ||
2827 | |||
2802 | char c, *buf1, *q, *r; | 2828 | char c, *buf1, *q, *r; |
2803 | char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; | 2829 | char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; |
2804 | int i, l, li, b, e; | 2830 | int i, l, li, b, e; |
2831 | unsigned int got; | ||
2805 | int useforce; | 2832 | int useforce; |
2806 | 2833 | ||
2807 | // :3154 // if (-e line 3154) goto it else stay put | 2834 | // :3154 // if (-e line 3154) goto it else stay put |
@@ -2828,14 +2855,13 @@ static void colon(char *buf) | |||
2828 | 2855 | ||
2829 | li = i = 0; | 2856 | li = i = 0; |
2830 | b = e = -1; | 2857 | b = e = -1; |
2858 | got = 0; | ||
2831 | li = count_lines(text, end - 1); | 2859 | li = count_lines(text, end - 1); |
2832 | fn = current_filename; | 2860 | fn = current_filename; |
2833 | 2861 | ||
2834 | // look for optional address(es) :. :1 :1,9 :'q,'a :% | 2862 | // look for optional address(es) :. :1 :1,9 :'q,'a :% |
2835 | buf1 = buf; | 2863 | buf = get_address(buf, &b, &e, &got); |
2836 | buf = get_address(buf, &b, &e); | ||
2837 | if (buf == NULL) { | 2864 | if (buf == NULL) { |
2838 | status_line_bold("Bad address: %s", buf1); | ||
2839 | goto ret; | 2865 | goto ret; |
2840 | } | 2866 | } |
2841 | 2867 | ||
@@ -2858,13 +2884,17 @@ static void colon(char *buf) | |||
2858 | } | 2884 | } |
2859 | // assume the command will want a range, certain commands | 2885 | // assume the command will want a range, certain commands |
2860 | // (read, substitute) need to adjust these assumptions | 2886 | // (read, substitute) need to adjust these assumptions |
2861 | if (e < 0) { | 2887 | if (!GOT_ADDRESS) { |
2862 | q = text; // no addr, use 1,$ for the range | 2888 | q = text; // no addr, use 1,$ for the range |
2863 | r = end - 1; | 2889 | r = end - 1; |
2864 | } else { | 2890 | } else { |
2865 | // at least one addr was given, get its details | 2891 | // at least one addr was given, get its details |
2892 | if (e < 0 || e > li) { | ||
2893 | status_line_bold("Invalid range"); | ||
2894 | goto ret; | ||
2895 | } | ||
2866 | q = r = find_line(e); | 2896 | q = r = find_line(e); |
2867 | if (b < 0) { | 2897 | if (!GOT_RANGE) { |
2868 | // if there is only one addr, then it's the line | 2898 | // if there is only one addr, then it's the line |
2869 | // number of the single line the user wants. | 2899 | // number of the single line the user wants. |
2870 | // Reset the end pointer to the end of that line. | 2900 | // Reset the end pointer to the end of that line. |
@@ -2873,6 +2903,10 @@ static void colon(char *buf) | |||
2873 | } else { | 2903 | } else { |
2874 | // we were given two addrs. change the | 2904 | // we were given two addrs. change the |
2875 | // start pointer to the addr given by user. | 2905 | // start pointer to the addr given by user. |
2906 | if (b < 0 || b > li || b > e) { | ||
2907 | status_line_bold("Invalid range"); | ||
2908 | goto ret; | ||
2909 | } | ||
2876 | q = find_line(b); // what line is #b | 2910 | q = find_line(b); // what line is #b |
2877 | r = end_line(r); | 2911 | r = end_line(r); |
2878 | li = e - b + 1; | 2912 | li = e - b + 1; |
@@ -2903,12 +2937,12 @@ static void colon(char *buf) | |||
2903 | } | 2937 | } |
2904 | # endif | 2938 | # endif |
2905 | else if (cmd[0] == '=' && !cmd[1]) { // where is the address | 2939 | else if (cmd[0] == '=' && !cmd[1]) { // where is the address |
2906 | if (e < 0) { // no addr given- use defaults | 2940 | if (!GOT_ADDRESS) { // no addr given- use defaults |
2907 | e = count_lines(text, dot); | 2941 | e = count_lines(text, dot); |
2908 | } | 2942 | } |
2909 | status_line("%d", e); | 2943 | status_line("%d", e); |
2910 | } else if (strncmp(cmd, "delete", i) == 0) { // delete lines | 2944 | } else if (strncmp(cmd, "delete", i) == 0) { // delete lines |
2911 | if (e < 0) { // no addr given- use defaults | 2945 | if (!GOT_ADDRESS) { // no addr given- use defaults |
2912 | q = begin_line(dot); // assume .,. for the range | 2946 | q = begin_line(dot); // assume .,. for the range |
2913 | r = end_line(dot); | 2947 | r = end_line(dot); |
2914 | } | 2948 | } |
@@ -2980,7 +3014,7 @@ static void colon(char *buf) | |||
2980 | rawmode(); | 3014 | rawmode(); |
2981 | Hit_Return(); | 3015 | Hit_Return(); |
2982 | } else if (strncmp(cmd, "list", i) == 0) { // literal print line | 3016 | } else if (strncmp(cmd, "list", i) == 0) { // literal print line |
2983 | if (e < 0) { // no addr given- use defaults | 3017 | if (!GOT_ADDRESS) { // no addr given- use defaults |
2984 | q = begin_line(dot); // assume .,. for the range | 3018 | q = begin_line(dot); // assume .,. for the range |
2985 | r = end_line(dot); | 3019 | r = end_line(dot); |
2986 | } | 3020 | } |
@@ -3063,7 +3097,7 @@ static void colon(char *buf) | |||
3063 | if (e == 0) { // user said ":0r foo" | 3097 | if (e == 0) { // user said ":0r foo" |
3064 | q = text; | 3098 | q = text; |
3065 | } else { // read after given line or current line if none given | 3099 | } else { // read after given line or current line if none given |
3066 | q = next_line(e > 0 ? find_line(e) : dot); | 3100 | q = next_line(GOT_ADDRESS ? find_line(e) : dot); |
3067 | // read after last line | 3101 | // read after last line |
3068 | if (q == end-1) | 3102 | if (q == end-1) |
3069 | ++q; | 3103 | ++q; |
@@ -3184,11 +3218,11 @@ static void colon(char *buf) | |||
3184 | len_F = strlen(F); | 3218 | len_F = strlen(F); |
3185 | } | 3219 | } |
3186 | 3220 | ||
3187 | if (e < 0) { // no addr given | 3221 | if (!GOT_ADDRESS) { // no addr given |
3188 | q = begin_line(dot); // start with cur line | 3222 | q = begin_line(dot); // start with cur line |
3189 | r = end_line(dot); | 3223 | r = end_line(dot); |
3190 | b = e = count_lines(text, q); // cur line number | 3224 | b = e = count_lines(text, q); // cur line number |
3191 | } else if (b < 0) { // one addr given | 3225 | } else if (!GOT_RANGE) { // one addr given |
3192 | b = e; | 3226 | b = e; |
3193 | } | 3227 | } |
3194 | 3228 | ||
@@ -3359,7 +3393,7 @@ static void colon(char *buf) | |||
3359 | } | 3393 | } |
3360 | # if ENABLE_FEATURE_VI_YANKMARK | 3394 | # if ENABLE_FEATURE_VI_YANKMARK |
3361 | } else if (strncmp(cmd, "yank", i) == 0) { // yank lines | 3395 | } else if (strncmp(cmd, "yank", i) == 0) { // yank lines |
3362 | if (b < 0) { // no addr given- use defaults | 3396 | if (!GOT_ADDRESS) { // no addr given- use defaults |
3363 | q = begin_line(dot); // assume .,. for the range | 3397 | q = begin_line(dot); // assume .,. for the range |
3364 | r = end_line(dot); | 3398 | r = end_line(dot); |
3365 | } | 3399 | } |