[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: [PATCH 12/12] vi: allow line addresses to have an offset
From: Ron Yorston <rmy () pobox ! com>
Date: 2021-04-15 11:06:51
Message-ID: 60781e4b.Ffp3xuFyLiBzcIW2%rmy () pobox ! com
[Download RAW message or body]
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>
---
editors/vi.c | 118 +++++++++++++++++++++++++++++++--------------------
1 file 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)
//----- The Colon commands -------------------------------------
#if ENABLE_FEATURE_VI_COLON
-static char *get_one_address(char *p, int *addr) // get colon addr, if present
+static char *get_one_address(char *p, int *result) // get colon addr, if present
{
- int st;
+ int st, num, sign, addr, new_addr;
# if ENABLE_FEATURE_VI_YANKMARK || ENABLE_FEATURE_VI_SEARCH
char *q, c;
# endif
IF_FEATURE_VI_SEARCH(int dir;)
- *addr = -1; // assume no addr
- if (*p == '.') { // the current line
- p++;
- *addr = count_lines(text, dot);
- }
+ addr = -1; // assume no addr
+ sign = 0;
+ for (;;) {
+ new_addr = -1;
+ if (isblank(*p)) {
+ p++;
+ } else if (*p == '.') { // the current line
+ p++;
+ new_addr = count_lines(text, dot);
+ }
# if ENABLE_FEATURE_VI_YANKMARK
- else if (*p == '\'') { // is this a mark addr
- p++;
- c = tolower(*p);
- p++;
- q = NULL;
- if (c >= 'a' && c <= 'z') {
- // we have a mark
- c = c - 'a';
- q = mark[(unsigned char) c];
+ else if (*p == '\'') { // is this a mark addr
+ p++;
+ c = tolower(*p);
+ p++;
+ q = NULL;
+ if (c >= 'a' && c <= 'z') {
+ // we have a mark
+ c = c - 'a';
+ q = mark[(unsigned char) c];
+ }
+ if (q == NULL) // is mark valid
+ return NULL;
+ new_addr = count_lines(text, q);
}
- if (q == NULL) // is mark valid
- return NULL;
- *addr = count_lines(text, q);
- }
# endif
# if ENABLE_FEATURE_VI_SEARCH
- else if (*p == '/' || *p == '?') { // a search pattern
- c = *p;
- q = strchrnul(p + 1, c);
- if (p + 1 != q) {
- // save copy of new pattern
- free(last_search_pattern);
- last_search_pattern = xstrndup(p, q - p);
+ else if (*p == '/' || *p == '?') { // a search pattern
+ c = *p;
+ q = strchrnul(p + 1, c);
+ if (p + 1 != q) {
+ // save copy of new pattern
+ free(last_search_pattern);
+ last_search_pattern = xstrndup(p, q - p);
+ }
+ p = q;
+ if (*p == c)
+ p++;
+ if (c == '/') {
+ q = next_line(dot);
+ dir = (FORWARD << 1) | FULL;
+ } else {
+ q = begin_line(dot);
+ dir = ((unsigned)BACK << 1) | FULL;
+ }
+ q = char_search(q, last_search_pattern + 1, dir);
+ if (q == NULL)
+ return NULL;
+ new_addr = count_lines(text, q);
}
- p = q;
- if (*p == c)
+# endif
+ else if (*p == '$') { // the last line in file
p++;
- if (c == '/') {
- q = next_line(dot);
- dir = (FORWARD << 1) | FULL;
+ new_addr = count_lines(text, end - 1);
+ } else if (isdigit(*p)) {
+ sscanf(p, "%d%n", &num, &st);
+ p += st;
+ if (addr < 0) { // specific line number
+ addr = num;
+ } else { // offset from current addr
+ addr += sign >= 0 ? num : -num;
+ }
+ sign = 0;
+ } else if (*p == '-' || *p == '+') {
+ sign = *p++ == '-' ? -1 : 1;
+ if (addr < 0) { // default address is dot
+ addr = count_lines(text, dot);
+ }
} else {
- q = begin_line(dot);
- dir = ((unsigned)BACK << 1) | FULL;
+ addr += sign; // consume unused trailing sign
+ break;
+ }
+ if (new_addr >= 0) {
+ if (addr >= 0) // only one new address per expression
+ return NULL;
+ addr = new_addr;
}
- q = char_search(q, last_search_pattern + 1, dir);
- if (q == NULL)
- return NULL;
- *addr = count_lines(text, q);
- }
-# endif
- else if (*p == '$') { // the last line in file
- p++;
- *addr = count_lines(text, end - 1);
- } else if (isdigit(*p)) { // specific line number
- sscanf(p, "%d%n", addr, &st);
- p += st;
}
+ *result = addr;
return p;
}
--
2.30.2
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic