diff options
author | Ron Yorston <rmy@pobox.com> | 2021-04-15 12:06:51 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-04-15 13:09:12 +0200 |
commit | f2277268384d47fbcaba081f19cebc68de819836 (patch) | |
tree | adee727cf5f81119c1d93bd1e1c9981d095fd985 | |
parent | 47f78913f7576596d44c602a015735cb9c49f4f0 (diff) | |
download | busybox-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.c | 118 |
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 |
2345 | static char *get_one_address(char *p, int *addr) // get colon addr, if present | 2345 | static 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 | ||