diff options
Diffstat (limited to 'editors')
-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 a0a046272..2c1048a4c 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -2524,26 +2524,38 @@ static char *char_search(char *p, const char *pat, int dir_and_range) | |||
2524 | 2524 | ||
2525 | //----- The Colon commands ------------------------------------- | 2525 | //----- The Colon commands ------------------------------------- |
2526 | #if ENABLE_FEATURE_VI_COLON | 2526 | #if ENABLE_FEATURE_VI_COLON |
2527 | static char *get_one_address(char *p, int *result) // get colon addr, if present | 2527 | // Evaluate colon address expression. Returns a pointer to the |
2528 | // next character or NULL on error. If 'result' contains a valid | ||
2529 | // address 'valid' is TRUE. | ||
2530 | static char *get_one_address(char *p, int *result, int *valid) | ||
2528 | { | 2531 | { |
2529 | int st, num, sign, addr, new_addr; | 2532 | int num, sign, addr, got_addr; |
2530 | # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH | 2533 | # if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH |
2531 | char *q, c; | 2534 | char *q, c; |
2532 | # endif | 2535 | # endif |
2533 | IF_FEATURE_VI_SEARCH(int dir;) | 2536 | IF_FEATURE_VI_SEARCH(int dir;) |
2534 | 2537 | ||
2535 | addr = -1; // assume no addr | 2538 | got_addr = FALSE; |
2539 | addr = count_lines(text, dot); // default to current line | ||
2536 | sign = 0; | 2540 | sign = 0; |
2537 | for (;;) { | 2541 | for (;;) { |
2538 | new_addr = -1; | ||
2539 | if (isblank(*p)) { | 2542 | if (isblank(*p)) { |
2543 | if (got_addr) { | ||
2544 | addr += sign; | ||
2545 | sign = 0; | ||
2546 | } | ||
2547 | p++; | ||
2548 | } else if (!got_addr && *p == '.') { // the current line | ||
2540 | p++; | 2549 | p++; |
2541 | } else if (*p == '.') { // the current line | 2550 | //addr = count_lines(text, dot); |
2551 | got_addr = TRUE; | ||
2552 | } else if (!got_addr && *p == '$') { // the last line in file | ||
2542 | p++; | 2553 | p++; |
2543 | new_addr = count_lines(text, dot); | 2554 | addr = count_lines(text, end - 1); |
2555 | got_addr = TRUE; | ||
2544 | } | 2556 | } |
2545 | # if ENABLE_FEATURE_VI_YANKMARK | 2557 | # if ENABLE_FEATURE_VI_YANKMARK |
2546 | else if (*p == '\'') { // is this a mark addr | 2558 | else if (!got_addr && *p == '\'') { // is this a mark addr |
2547 | p++; | 2559 | p++; |
2548 | c = tolower(*p); | 2560 | c = tolower(*p); |
2549 | p++; | 2561 | p++; |
@@ -2553,13 +2565,16 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2553 | c = c - 'a'; | 2565 | c = c - 'a'; |
2554 | q = mark[(unsigned char) c]; | 2566 | q = mark[(unsigned char) c]; |
2555 | } | 2567 | } |
2556 | if (q == NULL) // is mark valid | 2568 | if (q == NULL) { // is mark valid |
2569 | status_line_bold("Mark not set"); | ||
2557 | return NULL; | 2570 | return NULL; |
2558 | new_addr = count_lines(text, q); | 2571 | } |
2572 | addr = count_lines(text, q); | ||
2573 | got_addr = TRUE; | ||
2559 | } | 2574 | } |
2560 | # endif | 2575 | # endif |
2561 | # if ENABLE_FEATURE_VI_SEARCH | 2576 | # if ENABLE_FEATURE_VI_SEARCH |
2562 | else if (*p == '/' || *p == '?') { // a search pattern | 2577 | else if (!got_addr && (*p == '/' || *p == '?')) { // a search pattern |
2563 | c = *p; | 2578 | c = *p; |
2564 | q = strchrnul(p + 1, c); | 2579 | q = strchrnul(p + 1, c); |
2565 | if (p + 1 != q) { | 2580 | if (p + 1 != q) { |
@@ -2582,40 +2597,41 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2582 | // no match, continue from other end of file | 2597 | // no match, continue from other end of file |
2583 | q = char_search(dir > 0 ? text : end - 1, | 2598 | q = char_search(dir > 0 ? text : end - 1, |
2584 | last_search_pattern + 1, dir); | 2599 | last_search_pattern + 1, dir); |
2585 | if (q == NULL) | 2600 | if (q == NULL) { |
2601 | status_line_bold("Pattern not found"); | ||
2586 | return NULL; | 2602 | return NULL; |
2603 | } | ||
2587 | } | 2604 | } |
2588 | new_addr = count_lines(text, q); | 2605 | addr = count_lines(text, q); |
2606 | got_addr = TRUE; | ||
2589 | } | 2607 | } |
2590 | # endif | 2608 | # endif |
2591 | else if (*p == '$') { // the last line in file | 2609 | else if (isdigit(*p)) { |
2592 | p++; | 2610 | num = 0; |
2593 | new_addr = count_lines(text, end - 1); | 2611 | while (isdigit(*p)) |
2594 | } else if (isdigit(*p)) { | 2612 | num = num * 10 + *p++ -'0'; |
2595 | sscanf(p, "%d%n", &num, &st); | 2613 | if (!got_addr) { // specific line number |
2596 | p += st; | ||
2597 | if (addr < 0) { // specific line number | ||
2598 | addr = num; | 2614 | addr = num; |
2615 | got_addr = TRUE; | ||
2599 | } else { // offset from current addr | 2616 | } else { // offset from current addr |
2600 | addr += sign >= 0 ? num : -num; | 2617 | addr += sign >= 0 ? num : -num; |
2601 | } | 2618 | } |
2602 | sign = 0; | 2619 | sign = 0; |
2603 | } else if (*p == '-' || *p == '+') { | 2620 | } else if (*p == '-' || *p == '+') { |
2604 | sign = *p++ == '-' ? -1 : 1; | 2621 | if (!got_addr) { // default address is dot |
2605 | if (addr < 0) { // default address is dot | 2622 | //addr = count_lines(text, dot); |
2606 | addr = count_lines(text, dot); | 2623 | got_addr = TRUE; |
2624 | } else { | ||
2625 | addr += sign; | ||
2607 | } | 2626 | } |
2627 | sign = *p++ == '-' ? -1 : 1; | ||
2608 | } else { | 2628 | } else { |
2609 | addr += sign; // consume unused trailing sign | 2629 | addr += sign; // consume unused trailing sign |
2610 | break; | 2630 | break; |
2611 | } | 2631 | } |
2612 | if (new_addr >= 0) { | ||
2613 | if (addr >= 0) // only one new address per expression | ||
2614 | return NULL; | ||
2615 | addr = new_addr; | ||
2616 | } | ||
2617 | } | 2632 | } |
2618 | *result = addr; | 2633 | *result = addr; |
2634 | *valid = got_addr; | ||
2619 | return p; | 2635 | return p; |
2620 | } | 2636 | } |
2621 | 2637 | ||
@@ -2624,34 +2640,40 @@ static char *get_one_address(char *p, int *result) // get colon addr, if present | |||
2624 | 2640 | ||
2625 | // Read line addresses for a colon command. The user can enter as | 2641 | // Read line addresses for a colon command. The user can enter as |
2626 | // many as they like but only the last two will be used. | 2642 | // many as they like but only the last two will be used. |
2627 | static char *get_address(char *p, int *b, int *e) | 2643 | static char *get_address(char *p, int *b, int *e, unsigned int *got) |
2628 | { | 2644 | { |
2629 | int state = GET_ADDRESS; | 2645 | int state = GET_ADDRESS; |
2646 | int valid; | ||
2647 | int addr; | ||
2630 | char *save_dot = dot; | 2648 | char *save_dot = dot; |
2631 | 2649 | ||
2632 | //----- get the address' i.e., 1,3 'a,'b ----- | 2650 | //----- get the address' i.e., 1,3 'a,'b ----- |
2633 | for (;;) { | 2651 | for (;;) { |
2634 | if (isblank(*p)) { | 2652 | if (isblank(*p)) { |
2635 | p++; | 2653 | p++; |
2636 | } else if (*p == '%' && state == GET_ADDRESS) { // alias for 1,$ | 2654 | } else if (state == GET_ADDRESS && *p == '%') { // alias for 1,$ |
2637 | p++; | 2655 | p++; |
2638 | *b = 1; | 2656 | *b = 1; |
2639 | *e = count_lines(text, end-1); | 2657 | *e = count_lines(text, end-1); |
2658 | *got = 3; | ||
2659 | state = GET_SEPARATOR; | ||
2660 | } else if (state == GET_ADDRESS) { | ||
2661 | valid = FALSE; | ||
2662 | p = get_one_address(p, &addr, &valid); | ||
2663 | // Quit on error or if the address is invalid and isn't of | ||
2664 | // the form ',$' or '1,' (in which case it defaults to dot). | ||
2665 | if (p == NULL || !(valid || *p == ',' || *p == ';' || *got & 1)) | ||
2666 | break; | ||
2667 | *b = *e; | ||
2668 | *e = addr; | ||
2669 | *got = (*got << 1) | 1; | ||
2640 | state = GET_SEPARATOR; | 2670 | state = GET_SEPARATOR; |
2641 | } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { | 2671 | } else if (state == GET_SEPARATOR && (*p == ',' || *p == ';')) { |
2642 | if (*p == ';') | 2672 | if (*p == ';') |
2643 | dot = find_line(*e); | 2673 | dot = find_line(*e); |
2644 | p++; | 2674 | p++; |
2645 | *b = *e; | ||
2646 | state = GET_ADDRESS; | 2675 | state = GET_ADDRESS; |
2647 | } else if (state == GET_ADDRESS) { | ||
2648 | p = get_one_address(p, e); | ||
2649 | if (p == NULL) | ||
2650 | break; | ||
2651 | state = GET_SEPARATOR; | ||
2652 | } else { | 2676 | } else { |
2653 | if (state == GET_SEPARATOR && *b >= 0 && *e < 0) | ||
2654 | *e = count_lines(text, dot); | ||
2655 | break; | 2677 | break; |
2656 | } | 2678 | } |
2657 | } | 2679 | } |
@@ -2865,9 +2887,14 @@ static void colon(char *buf) | |||
2865 | not_implemented(p); | 2887 | not_implemented(p); |
2866 | #else | 2888 | #else |
2867 | 2889 | ||
2890 | // check how many addresses we got | ||
2891 | # define GOT_ADDRESS (got & 1) | ||
2892 | # define GOT_RANGE ((got & 3) == 3) | ||
2893 | |||
2868 | char c, *buf1, *q, *r; | 2894 | char c, *buf1, *q, *r; |
2869 | char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; | 2895 | char *fn, cmd[MAX_INPUT_LEN], *cmdend, *args, *exp = NULL; |
2870 | int i, l, li, b, e; | 2896 | int i, l, li, b, e; |
2897 | unsigned int got; | ||
2871 | int useforce; | 2898 | int useforce; |
2872 | 2899 | ||
2873 | // :3154 // if (-e line 3154) goto it else stay put | 2900 | // :3154 // if (-e line 3154) goto it else stay put |
@@ -2894,14 +2921,13 @@ static void colon(char *buf) | |||
2894 | 2921 | ||
2895 | li = i = 0; | 2922 | li = i = 0; |
2896 | b = e = -1; | 2923 | b = e = -1; |
2924 | got = 0; | ||
2897 | li = count_lines(text, end - 1); | 2925 | li = count_lines(text, end - 1); |
2898 | fn = current_filename; | 2926 | fn = current_filename; |
2899 | 2927 | ||
2900 | // look for optional address(es) :. :1 :1,9 :'q,'a :% | 2928 | // look for optional address(es) :. :1 :1,9 :'q,'a :% |
2901 | buf1 = buf; | 2929 | buf = get_address(buf, &b, &e, &got); |
2902 | buf = get_address(buf, &b, &e); | ||
2903 | if (buf == NULL) { | 2930 | if (buf == NULL) { |
2904 | status_line_bold("Bad address: %s", buf1); | ||
2905 | goto ret; | 2931 | goto ret; |
2906 | } | 2932 | } |
2907 | 2933 | ||
@@ -2924,13 +2950,17 @@ static void colon(char *buf) | |||
2924 | } | 2950 | } |
2925 | // assume the command will want a range, certain commands | 2951 | // assume the command will want a range, certain commands |
2926 | // (read, substitute) need to adjust these assumptions | 2952 | // (read, substitute) need to adjust these assumptions |
2927 | if (e < 0) { | 2953 | if (!GOT_ADDRESS) { |
2928 | q = text; // no addr, use 1,$ for the range | 2954 | q = text; // no addr, use 1,$ for the range |
2929 | r = end - 1; | 2955 | r = end - 1; |
2930 | } else { | 2956 | } else { |
2931 | // at least one addr was given, get its details | 2957 | // at least one addr was given, get its details |
2958 | if (e < 0 || e > li) { | ||
2959 | status_line_bold("Invalid range"); | ||
2960 | goto ret; | ||
2961 | } | ||
2932 | q = r = find_line(e); | 2962 | q = r = find_line(e); |
2933 | if (b < 0) { | 2963 | if (!GOT_RANGE) { |
2934 | // if there is only one addr, then it's the line | 2964 | // if there is only one addr, then it's the line |
2935 | // number of the single line the user wants. | 2965 | // number of the single line the user wants. |
2936 | // Reset the end pointer to the end of that line. | 2966 | // Reset the end pointer to the end of that line. |
@@ -2939,6 +2969,10 @@ static void colon(char *buf) | |||
2939 | } else { | 2969 | } else { |
2940 | // we were given two addrs. change the | 2970 | // we were given two addrs. change the |
2941 | // start pointer to the addr given by user. | 2971 | // start pointer to the addr given by user. |
2972 | if (b < 0 || b > li || b > e) { | ||
2973 | status_line_bold("Invalid range"); | ||
2974 | goto ret; | ||
2975 | } | ||
2942 | q = find_line(b); // what line is #b | 2976 | q = find_line(b); // what line is #b |
2943 | r = end_line(r); | 2977 | r = end_line(r); |
2944 | li = e - b + 1; | 2978 | li = e - b + 1; |
@@ -2969,12 +3003,12 @@ static void colon(char *buf) | |||
2969 | } | 3003 | } |
2970 | # endif | 3004 | # endif |
2971 | else if (cmd[0] == '=' && !cmd[1]) { // where is the address | 3005 | else if (cmd[0] == '=' && !cmd[1]) { // where is the address |
2972 | if (e < 0) { // no addr given- use defaults | 3006 | if (!GOT_ADDRESS) { // no addr given- use defaults |
2973 | e = count_lines(text, dot); | 3007 | e = count_lines(text, dot); |
2974 | } | 3008 | } |
2975 | status_line("%d", e); | 3009 | status_line("%d", e); |
2976 | } else if (strncmp(cmd, "delete", i) == 0) { // delete lines | 3010 | } else if (strncmp(cmd, "delete", i) == 0) { // delete lines |
2977 | if (e < 0) { // no addr given- use defaults | 3011 | if (!GOT_ADDRESS) { // no addr given- use defaults |
2978 | q = begin_line(dot); // assume .,. for the range | 3012 | q = begin_line(dot); // assume .,. for the range |
2979 | r = end_line(dot); | 3013 | r = end_line(dot); |
2980 | } | 3014 | } |
@@ -3046,7 +3080,7 @@ static void colon(char *buf) | |||
3046 | rawmode(); | 3080 | rawmode(); |
3047 | Hit_Return(); | 3081 | Hit_Return(); |
3048 | } else if (strncmp(cmd, "list", i) == 0) { // literal print line | 3082 | } else if (strncmp(cmd, "list", i) == 0) { // literal print line |
3049 | if (e < 0) { // no addr given- use defaults | 3083 | if (!GOT_ADDRESS) { // no addr given- use defaults |
3050 | q = begin_line(dot); // assume .,. for the range | 3084 | q = begin_line(dot); // assume .,. for the range |
3051 | r = end_line(dot); | 3085 | r = end_line(dot); |
3052 | } | 3086 | } |
@@ -3129,7 +3163,7 @@ static void colon(char *buf) | |||
3129 | if (e == 0) { // user said ":0r foo" | 3163 | if (e == 0) { // user said ":0r foo" |
3130 | q = text; | 3164 | q = text; |
3131 | } else { // read after given line or current line if none given | 3165 | } else { // read after given line or current line if none given |
3132 | q = next_line(e > 0 ? find_line(e) : dot); | 3166 | q = next_line(GOT_ADDRESS ? find_line(e) : dot); |
3133 | // read after last line | 3167 | // read after last line |
3134 | if (q == end-1) | 3168 | if (q == end-1) |
3135 | ++q; | 3169 | ++q; |
@@ -3250,11 +3284,11 @@ static void colon(char *buf) | |||
3250 | len_F = strlen(F); | 3284 | len_F = strlen(F); |
3251 | } | 3285 | } |
3252 | 3286 | ||
3253 | if (e < 0) { // no addr given | 3287 | if (!GOT_ADDRESS) { // no addr given |
3254 | q = begin_line(dot); // start with cur line | 3288 | q = begin_line(dot); // start with cur line |
3255 | r = end_line(dot); | 3289 | r = end_line(dot); |
3256 | b = e = count_lines(text, q); // cur line number | 3290 | b = e = count_lines(text, q); // cur line number |
3257 | } else if (b < 0) { // one addr given | 3291 | } else if (!GOT_RANGE) { // one addr given |
3258 | b = e; | 3292 | b = e; |
3259 | } | 3293 | } |
3260 | 3294 | ||
@@ -3425,7 +3459,7 @@ static void colon(char *buf) | |||
3425 | } | 3459 | } |
3426 | # if ENABLE_FEATURE_VI_YANKMARK | 3460 | # if ENABLE_FEATURE_VI_YANKMARK |
3427 | } else if (strncmp(cmd, "yank", i) == 0) { // yank lines | 3461 | } else if (strncmp(cmd, "yank", i) == 0) { // yank lines |
3428 | if (b < 0) { // no addr given- use defaults | 3462 | if (!GOT_ADDRESS) { // no addr given- use defaults |
3429 | q = begin_line(dot); // assume .,. for the range | 3463 | q = begin_line(dot); // assume .,. for the range |
3430 | r = end_line(dot); | 3464 | r = end_line(dot); |
3431 | } | 3465 | } |