aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-04-15 12:06:51 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2021-04-15 13:09:12 +0200
commitf2277268384d47fbcaba081f19cebc68de819836 (patch)
treeadee727cf5f81119c1d93bd1e1c9981d095fd985
parent47f78913f7576596d44c602a015735cb9c49f4f0 (diff)
downloadbusybox-w32-f2277268384d47fbcaba081f19cebc68de819836.tar.gz
busybox-w32-f2277268384d47fbcaba081f19cebc68de819836.tar.bz2
busybox-w32-f2277268384d47fbcaba081f19cebc68de819836.zip
vi: allow line addresses to have an offset
Line addresses in colon commands can be defined using an expression that includes '+' or '-' operators. The implementation follows traditional vi: - The first term in the expression defines an address. It can be an absolute line number, '.', '$', a search or a marker. - The second and subsequent terms must be non-negative integers. - If the first term is missing '.' is assumed. If the operator is missing addition is assumed. If the final term in missing an offset of 1 is assumed. Thus the following are valid addresses: .+1 .+ + .1 .-1 .- - The following are not valid (though they are in vim): .+$ .$ 2+. function old new delta colon 3701 3844 +143 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/0 up/down: 143/0) Total: 143 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/vi.c118
1 files changed, 72 insertions, 46 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 0866e0fa9..6dd951421 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2342,67 +2342,93 @@ static char *char_search(char *p, const char *pat, int dir_and_range)
2342 2342
2343//----- The Colon commands ------------------------------------- 2343//----- The Colon commands -------------------------------------
2344#if ENABLE_FEATURE_VI_COLON 2344#if ENABLE_FEATURE_VI_COLON
2345static char *get_one_address(char *p, int *addr) // get colon addr, if present 2345static char *get_one_address(char *p, int *result) // get colon addr, if present
2346{ 2346{
2347 int st; 2347 int st, num, sign, addr, new_addr;
2348# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH 2348# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH
2349 char *q, c; 2349 char *q, c;
2350# endif 2350# endif
2351 IF_FEATURE_VI_SEARCH(int dir;) 2351 IF_FEATURE_VI_SEARCH(int dir;)
2352 2352
2353 *addr = -1; // assume no addr 2353 addr = -1; // assume no addr
2354 if (*p == '.') { // the current line 2354 sign = 0;
2355 p++; 2355 for (;;) {
2356 *addr = count_lines(text, dot); 2356 new_addr = -1;
2357 } 2357 if (isblank(*p)) {
2358 p++;
2359 } else if (*p == '.') { // the current line
2360 p++;
2361 new_addr = count_lines(text, dot);
2362 }
2358# if ENABLE_FEATURE_VI_YANKMARK 2363# if ENABLE_FEATURE_VI_YANKMARK
2359 else if (*p == '\'') { // is this a mark addr 2364 else if (*p == '\'') { // is this a mark addr
2360 p++; 2365 p++;
2361 c = tolower(*p); 2366 c = tolower(*p);
2362 p++; 2367 p++;
2363 q = NULL; 2368 q = NULL;
2364 if (c >= 'a' && c <= 'z') { 2369 if (c >= 'a' && c <= 'z') {
2365 // we have a mark 2370 // we have a mark
2366 c = c - 'a'; 2371 c = c - 'a';
2367 q = mark[(unsigned char) c]; 2372 q = mark[(unsigned char) c];
2373 }
2374 if (q == NULL) // is mark valid
2375 return NULL;
2376 new_addr = count_lines(text, q);
2368 } 2377 }
2369 if (q == NULL) // is mark valid
2370 return NULL;
2371 *addr = count_lines(text, q);
2372 }
2373# endif 2378# endif
2374# if ENABLE_FEATURE_VI_SEARCH 2379# if ENABLE_FEATURE_VI_SEARCH
2375 else if (*p == '/' || *p == '?') { // a search pattern 2380 else if (*p == '/' || *p == '?') { // a search pattern
2376 c = *p; 2381 c = *p;
2377 q = strchrnul(p + 1, c); 2382 q = strchrnul(p + 1, c);
2378 if (p + 1 != q) { 2383 if (p + 1 != q) {
2379 // save copy of new pattern 2384 // save copy of new pattern
2380 free(last_search_pattern); 2385 free(last_search_pattern);
2381 last_search_pattern = xstrndup(p, q - p); 2386 last_search_pattern = xstrndup(p, q - p);
2387 }
2388 p = q;
2389 if (*p == c)
2390 p++;
2391 if (c == '/') {
2392 q = next_line(dot);
2393 dir = (FORWARD << 1) | FULL;
2394 } else {
2395 q = begin_line(dot);
2396 dir = ((unsigned)BACK << 1) | FULL;
2397 }
2398 q = char_search(q, last_search_pattern + 1, dir);
2399 if (q == NULL)
2400 return NULL;
2401 new_addr = count_lines(text, q);
2382 } 2402 }
2383 p = q; 2403# endif
2384 if (*p == c) 2404 else if (*p == '$') { // the last line in file
2385 p++; 2405 p++;
2386 if (c == '/') { 2406 new_addr = count_lines(text, end - 1);
2387 q = next_line(dot); 2407 } else if (isdigit(*p)) {
2388 dir = (FORWARD << 1) | FULL; 2408 sscanf(p, "%d%n", &num, &st);
2409 p += st;
2410 if (addr < 0) { // specific line number
2411 addr = num;
2412 } else { // offset from current addr
2413 addr += sign >= 0 ? num : -num;
2414 }
2415 sign = 0;
2416 } else if (*p == '-' || *p == '+') {
2417 sign = *p++ == '-' ? -1 : 1;
2418 if (addr < 0) { // default address is dot
2419 addr = count_lines(text, dot);
2420 }
2389 } else { 2421 } else {
2390 q = begin_line(dot); 2422 addr += sign; // consume unused trailing sign
2391 dir = ((unsigned)BACK << 1) | FULL; 2423 break;
2424 }
2425 if (new_addr >= 0) {
2426 if (addr >= 0) // only one new address per expression
2427 return NULL;
2428 addr = new_addr;
2392 } 2429 }
2393 q = char_search(q, last_search_pattern + 1, dir);
2394 if (q == NULL)
2395 return NULL;
2396 *addr = count_lines(text, q);
2397 }
2398# endif
2399 else if (*p == '$') { // the last line in file
2400 p++;
2401 *addr = count_lines(text, end - 1);
2402 } else if (isdigit(*p)) { // specific line number
2403 sscanf(p, "%d%n", addr, &st);
2404 p += st;
2405 } 2430 }
2431 *result = addr;
2406 return p; 2432 return p;
2407} 2433}
2408 2434