aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
Diffstat (limited to 'editors')
-rw-r--r--editors/vi.c132
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
2527static 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.
2530static 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.
2627static char *get_address(char *p, int *b, int *e) 2643static 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 }