aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/vi.c132
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
2461static 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.
2464static 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.
2561static char *get_address(char *p, int *b, int *e) 2577static 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 }