Commit Graph

1016 Commits

Author SHA1 Message Date
Denys Vlasenko
a5d7b0f4f4 awk: fix detection of VAR=VAL arguments
1NAME=VAL is not it, neither is VA.R=VAL

function                                             old     new   delta
next_input_file                                      216     214      -2
is_assignment                                        115      91     -24
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-26)             Total: -26 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 23:07:21 +02:00
Denys Vlasenko
4d902ea9de awk: fix beavior of "exit" without parameter
function                                             old     new   delta
evaluate                                            3336    3339      +3
awk_exit                                              93      94      +1
awk_main                                             829     827      -2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 4/-2)                Total: 2 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 22:28:51 +02:00
Denys Vlasenko
8bb03da906 awk: rand() could return 1.0, fix this - should be in [0,1)
While at it, make it finer-grained (63 bits of randomness)

function                                             old     new   delta
evaluate                                            3303    3336     +33
.rodata                                           104107  104111      +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 37/0)               Total: 37 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 19:38:03 +02:00
Denys Vlasenko
37ae8cdc6e awk: beautify builtins table, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 18:55:00 +02:00
Denys Vlasenko
47d9133896 awk: enforce simple builtins' argument number
function                                             old     new   delta
evaluate                                            3215    3303     +88
.rodata                                           104036  104107     +71
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 159/0)             Total: 159 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 18:28:12 +02:00
Denys Vlasenko
786ca197ad awk: make builtin definitions more understandable, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 17:32:08 +02:00
Denys Vlasenko
640212ae0e awk: do not special-case "delete"
Rework of the previous fix:
Can use operation attributes to disable arg evaluation instead of special-casing.

function                                             old     new   delta
.rodata                                           104032  104036      +4
evaluate                                            3223    3215      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 4/-8)               Total: -4 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 15:21:36 +02:00
Denys Vlasenko
ef5463cf16 awk: shuffle globals for smaller offsets
function                                             old     new   delta
awk_main                                             832     829      -3
evaluate                                            3229    3223      -6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-9)               Total: -9 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 14:53:52 +02:00
Denys Vlasenko
966cafcc77 awk: use "static" tmpvars in main and exit
function                                             old     new   delta
awk_exit                                             103      93     -10
awk_main                                             850     832     -18
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-28)             Total: -28 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 14:33:13 +02:00
Denys Vlasenko
1193c68fa7 awk: when parsing length(), simplify eating of LPAREN
function                                             old     new   delta
parse_expr                                           945     948      +3

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 14:29:01 +02:00
Denys Vlasenko
40573556f2 awk: shuffle functions to reduce forward declarations, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-02 14:27:40 +02:00
Denys Vlasenko
8b4c429025 awk: use static tmpvars instead of nvalloc(1)ed ones
ptest() was using this idea already.

As far as I can see, this is safe. Ttestsuite passes.

One downside is that a temporary from e.g. printf invocation
won't be freed until the next printf call.

function                                             old     new   delta
awk_printf                                           481     468     -13
as_regex                                             137     111     -26
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-39)             Total: -39 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-01 17:50:26 +02:00
Denys Vlasenko
1573487e21 awk: rename temp variables, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-07-01 16:17:33 +02:00
Denys Vlasenko
d7354df169 awk: evaluate all, even superfluous function args
function                                             old     new   delta
evaluate                                            3128    3135      +7

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-30 12:52:51 +02:00
Denys Vlasenko
ca9278ee58 awk: rewrite "print" logic a bit to make it clearer
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-30 12:42:39 +02:00
Denys Vlasenko
d150710169 awk: allow empty fuinctions with no arguments, disallow function redefinitions
function                                             old     new   delta
.rodata                                           103681  103700     +19
parse_program                                        303     307      +4
evaluate                                            3145    3141      -4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 23/-4)              Total: 19 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-30 12:23:51 +02:00
Denys Vlasenko
86fc2872b3 awk: replace incorrect use of union in undefined function check (no code changes)
...which reveals that it's buggy: it thinks "func f(){}" is an undefined function!

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-30 12:12:20 +02:00
Denys Vlasenko
6cf6f1eaee awk: remove custom pool allocator for temporary awk variables
It seems to be designed to reduce overhead of malloc's auxiliary data,
by allocating at least 64 variables as a block.
With "struct var" being about 20-32 bytes long (32/64 bits),
malloc overhead for one temporary indeed is high, ~33% more memory used
than needed.

function                                             old     new   delta
evaluate                                            3137    3145      +8
modprobe_main                                        798     803      +5
exec_builtin                                        1414    1419      +5
awk_printf                                           476     481      +5
as_regex                                             132     137      +5
EMSG_INTERNAL_ERROR                                   15       -     -15
nvfree                                               169     116     -53
nvalloc                                              145       -    -145
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 5/1 up/down: 28/-213)          Total: -185 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-30 08:01:29 +02:00
Denys Vlasenko
3aff3b9cb8 awk: assorted optimizations
hash_find(): do not caclculate hash twice. Do not divide - can use
cheap multiply-by-8 shift.

nextword(): do not repeatedly increment in-memory value, do it in register,
then store final result.

hashwalk_init(): do not strlen() twice.

function                                             old     new   delta
hash_search3                                           -      49     +49
hash_find                                            259     281     +22
nextword                                              19      16      -3
evaluate                                            3141    3137      -4
hash_search                                           54      28     -26
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/3 up/down: 71/-33)             Total: 38 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 19:07:36 +02:00
Denys Vlasenko
b3c91a127f awk: free unused parsing structures after parse is done
function                                             old     new   delta
hash_clear                                             -      90     +90
awk_main                                             827     849     +22
clear_array                                           90       -     -90
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/0 up/down: 112/-90)            Total: 22 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 19:06:59 +02:00
Denys Vlasenko
21fbee2e87 awk: document which hashes are used at what state (parse/execute)
We can free them after they are no longer needed.
(Currently, being a NOEXEC applet is much larger waste of memory
for the case of long-running awk script).

function                                             old     new   delta
awk_main                                             831     827      -4

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 14:33:04 +02:00
Denys Vlasenko
6872c193a9 awk: fix parsing of expressions such as "v (a)"
function                                             old     new   delta
next_token                                           812     825     +13

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 12:16:36 +02:00
Denys Vlasenko
686287b5da awk: deindent a block, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 03:47:46 +02:00
Denys Vlasenko
216d3d8ad9 awk: code shrink
function                                             old     new   delta
parse_expr                                           948     945      -3
chain_expr                                            65      62      -3
chain_group                                          655     649      -6
parse_program                                        310     303      -7
rollback_token                                        10       -     -10
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 0/4 up/down: 0/-29)             Total: -29 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 03:44:56 +02:00
Denys Vlasenko
4f27503a1e awk: get rid of "move name one char back" trick in next_token()
function                                             old     new   delta
next_token                                           791     812     +21
awk_main                                             886     831     -55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 21/-55)            Total: -34 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 03:27:07 +02:00
Denys Vlasenko
f414fb4411 awk: when parsing TC_FUNCTION token, eat its opening '('
...like we do for array references.

function                                             old     new   delta
parse_expr                                           938     948     +10
next_token                                           788     791      +3
parse_program                                        313     310      -3
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 13/-3)              Total: 10 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 03:02:21 +02:00
Denys Vlasenko
cb6061a4e9 awk: g_buf[] does not need a separate allocation
function                                             old     new   delta
exec_builtin                                        1400    1414     +14
evaluate                                            3132    3141      +9
getvar_s                                             121     125      +4
awk_main                                             902     886     -16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 27/-16)             Total: 11 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 02:43:02 +02:00
Denys Vlasenko
926420795b awk: simplify parsing of function declaration
function                                             old     new   delta
parse_program                                        328     313     -15

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 02:37:10 +02:00
Denys Vlasenko
9782cb7774 awk: rename TC_SEQSTART/END to L/RPAREN, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 01:50:47 +02:00
Denys Vlasenko
a493441ca5 awk: deindent code block, no code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 01:30:49 +02:00
Denys Vlasenko
adcd9a6f34 awk: use TS_foo for combined token classes. No code changes
Confusion with "simple" classes was the cause of a bug fixed by previous commit

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 01:23:37 +02:00
Denys Vlasenko
832cb4fcb9 awk: make ltclass ("last token class") local to next_token()
function                                             old     new   delta
next_token                                           784     790      +6
next_input_file                                      219     216      -3
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 6/-3)                Total: 3 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 01:09:08 +02:00
Denys Vlasenko
af0172369e awk: remove redundant check
function                                             old     new   delta
next_token                                           785     784      -1
parse_program                                        337     328      -9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-10)             Total: -10 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-29 01:03:42 +02:00
Ron Yorston
5dbbd0a6f5 vi: stored search pattern applies to ':s'
The same stored search pattern applies to both search ('/') and
search/replace (':s') operations.

A search/replace operation with an empty "find" string (':s//abc/')
should use the last stored search pattern, if available, and issue an
error message if there is none.

If the "find" string is not empty it should replace the stored search
pattern.

function                                             old     new   delta
colon                                               3952    4024     +72
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 72/0)               Total: 72 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-27 13:36:49 +02:00
Denys Vlasenko
78645d8371 awk: move locals deeper into scopes where they are used, no logic changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-25 19:41:05 +02:00
Denys Vlasenko
8c5da0323b awk: more efficient -f FILE, document what "some trick in next_token" is
function                                             old     new   delta
awk_main                                             890     898      +8

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-25 19:38:27 +02:00
S Harris
5c89e5a04e vi: fix read outside of text buffer during insert
Signed-off-by: S Harris <S.E.Harris@kent.ac.uk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-23 19:15:07 +02:00
Ron Yorston
51358757c7 vi: fix backward search with GNU regex
With FEATURE_VI_REGEX_SEARCH enabled backward searches don't work.
This is problematic on distros that enable regexes, such as Tiny
Core Linux and Fedora.

When calling GNU re_search() with a negative range parameter
(indicating a backward search) the start offset must be set to
the end of the area being searched.

The return value of re_search() is the offset of the matched pattern
from the start of the area being searched.  For a successful search
(positive return value) char_search() can return the pointer to
the start of the area plus the offset.

FEATURE_VI_REGEX_SEARCH isn't enabled by default but when it is:

function                                             old     new   delta
char_search                                          256     247      -9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-9)               Total: -9 bytes

Signed-off-by: Andrey Dobrovolsky <andrey.dobrovolsky.odessa@gmail.com>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-21 15:37:28 +02:00
Denys Vlasenko
ac4786ba00 qwk: make code clearer, no actual code changes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-20 22:52:29 +02:00
Denys Vlasenko
fd217c1cbf awk: after preinc/dec, only allow variable, field ref, array ref, or another preinc/dec
Accepting nonsense like "--4", and even "-- -4" is confusing.

function                                             old     new   delta
parse_expr                                           917     938     +21

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-18 16:35:27 +02:00
Ron Yorston
038d400709 vi: reject change command when motion fails
If the motion command used to define the range of a change, yank or
delete fails the whole command should be rejected.  BusyBox vi already
handled failed searches in these circumstances.  Add some more cases:

- non-existent mark: d'x

- movement beyond end of file: c99999+ or 99999<<

This is implemented using a global variable which is set when a command
error is detected.  Unlike the case of motion within a line it's
insufficient to check that the motion command doesn't move the cursor:
this fails to process 'LyL' correctly, for example, as the second 'L'
doesn't move the cursor.

function                                             old     new   delta
indicate_error                                        75      82      +7
find_range                                           686     692      +6
do_cmd                                              4851    4852      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 14/0)               Total: 14 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Ron Yorston
ac04eb3657 vi: up/down motion beyond end of file should fail
In traditional vi and vim line motion commands ('+'/'-'/'j'/'k')
fail if the movement would exceed the bounds of the file.  BusyBox vi
allowed such commands to succeed, leaving the cursor on the first or
last character of the file.

Make BusyBox vi work like vi/vim.

For the 'G'/'H'/'L' commands traditional vi treats an out of bounds
result as an error, vim doesn't.  BusyBox vi behaves like vim, both
before and after this patch.

function                                             old     new   delta
do_cmd                                              4785    4851     +66
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 66/0)               Total: 66 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Ron Yorston
f1d21b7434 vi: keep autoindent if line isn't empty
When ESC is entered to leave insert mode any autoindent should only
be removed if there's no content beyond the indent.  This may be the
case if a line has been split by entering insert mode and then
entering a CR.

Add a check to ensure there's only a newline after the indent.

function                                             old     new   delta
char_insert                                          912     929     +17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0)               Total: 17 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 23:53:03 +02:00
Denys Vlasenko
a885ce1af0 awk: fix use-after-free in "$BIGNUM1 $BIGGERNUM2" concat op
Second reference to a field reallocs/moves Fields[] array, but first ref
still tries to use the element where it was before move.

function                                             old     new   delta
fsrealloc                                             94     106     +12

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-16 09:21:40 +02:00
Ron Yorston
52c4b7ac3b vi: initialise tabstop once not for each file
The default tabstop value should be set during early start up,
not reset for each new file.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-14 20:58:17 +02:00
Ron Yorston
f7ed0e8ae0 vi: ':r' should insert text after current line
When no line number is specified ':read' should place the inserted
text after the current line, not before.

This used to be correct but was broken when commit 0c42a6b07
(vi: fix empty line range regression) revealed a bug in commit
7a8ceb4eb (vi: changes to line addresses for colon commands).

function                                             old     new   delta
colon                                               3960    3952      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8)               Total: -8 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-14 20:58:17 +02:00
Denys Vlasenko
e2b9215868 *: --help tweaks
function                                             old     new   delta
packed_usage                                       33589   33552     -37

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-14 20:47:20 +02:00
Denys Vlasenko
6b6826f0b8 *: --help tweaks
function                                             old     new   delta
.rodata                                           103190  103189      -1
packed_usage                                       33590   33566     -24
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-25)             Total: -25 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-13 01:08:48 +02:00
Ron Yorston
9659a8db1d vi: remove autoindent from otherwise empty lines
Lines that have no content apart from automatic indentation should
be treated as empty when the user hits return or ESC.

The implementation uses the global variable 'indentcol'.  Usually
this is zero.  It can also be -1 to indicate an 'O' (open above)
command, replacing the overloading of the tabstop option bit.

A value greater than zero indicates that the current line has
been autoindented to the given column (or that the autoindent has
been adjusted with ctrl-D).  Any other change to the line resets
'indentcol' to zero.

Replace strspn() with ident_len().  The latter handles the unlikely
case that it's called on the last line of a file which doesn't have
a terminating newline.

function                                             old     new   delta
char_insert                                          741     912    +171
indent_len                                             -      42     +42
do_cmd                                              4781    4785      +4
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 217/0)             Total: 217 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:29:34 +02:00
Ron Yorston
16e2fa9049 vi: make autoindent respect expandtab setting
Autoindent took a copy of the indent from a neighbouring line, which
may not have respected the expandtab setting.

Determine the target column and construct a suitable indent.  This
will consist entirely of spaces if expandtab is enabled or an
efficient combination of tabs and spaces otherwise.

function                                             old     new   delta
char_insert                                          719     741     +22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 22/0)               Total: 22 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:16:36 +02:00
Ron Yorston
d95f89ec57 vi: make cursor positioning more vi compatible
Commit 24effc7a3 (vi: cursor positioning after whole-line 'y')
tried to save a few bytes by treating whole-line deletion the
same as whole-line yank.  If the deletion removed the last lines
of the file the cursor was left beyond the end of the file.
Revert the part of the commit related to whole-line deletion.

Position the cursor on the first non-whitespace character of the
line when whole lines are 'put'.

function                                             old     new   delta
do_cmd                                              4759    4781     +22
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 22/0)               Total: 22 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-06-02 06:16:36 +02:00
Ron Yorston
8e71f2aab8 vi: :wq/:x should warn if there are more files to edit
':wq' or ':x' should issue a warning if there are more files to edit,
unless they're followed by '!'.

function                                             old     new   delta
colon                                               3911    3960     +49
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 49/0)               Total: 49 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-04 14:51:48 +02:00
Ron Yorston
24effc7a3f vi: cursor positioning after whole-line 'y'
The 'y' command to yank text should leave the cursor at the start
of the range.  This mostly works correctly in BusyBox vi but not
for whole-line yanks with backward motion, e.g. '2yk' to yank two
lines backwards.  In this case the cursor is left at the end of the
range.

Fix this by returning the actual range from find_range().  Cursor
positioning following whole-line deletion is inconsistent between
vim and traditional vi.  For BusyBox vi chose the option that uses
least code without being exactly compatible with either.

Also, find_range() preserved the value of 'dot', the current cursor
position.  Since this isn't used by either caller of find_range()
we can save a few bytes by not bothering.

function                                             old     new   delta
do_cmd                                              4730    4759     +29
find_range                                           749     686     -63
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 29/-63)            Total: -34 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-04 14:51:48 +02:00
Denys Vlasenko
74e1f321c1 vi: trivial code shrink
function                                             old     new   delta
get_input_line                                       178     176      -2

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-05-01 14:00:09 +02:00
Ron Yorston
0c42a6b072 vi: fix empty line range regression
Commit 7a8ceb4eb (vi: changes to line addresses for colon commands)
was supposed to address the issue:

  When the last address is empty it should refer to the current line.

This was intended to allow ranges of the form '1,' with an empty
last address.  It should have been expressed as:

  When the last address is empty *and the second last isn't* it
  should refer to the current line.

Otherwise a command like ':w' only writes the current line resulting
in serious loss of data.

function                                             old     new   delta
colon                                               3906    3911      +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0)                 Total: 5 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-30 01:40:27 +02:00
Ron Yorston
acd3079fd1 vi: expand '%' and '#' in colon commands
Track the current and alternate filenames.  The placeholders '%'
and '#' can be used in arguments to colon commands to represent
the current and alternate filenames respectively.  Backslash can
be used to allow literal '%' and '#' characters to be entered.

This feature is controlled by the configuration option
FEATURE_VI_COLON_EXPAND.

function                                             old     new   delta
expand_args                                            -     198    +198
colon                                               3751    3927    +176
update_filename                                        -      70     +70
init_filename                                          -      48     +48
.rodata                                           105218  105239     +21
get_one_char                                         115     124      +9
edit_file                                            835     838      +3
do_cmd                                              4724    4727      +3
init_text_buffer                                     190     172     -18
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 5/1 up/down: 528/-18)           Total: 510 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
852ffbee34 vi: fix buffer overrun; code shrink
It was possible for get_input_line() to store its NUL terminator
one character beyond the end of its buffer.

Code shrink in colon():

- Certain colon commands can be matched exactly, as any shorter
  string would be matched earlier, e.g. ':wq' versus ':write'.

- Command matching is now case sensitive so there's no need to
  check for 'N' or 'Q' suffixes.

- Rewrite how commands and arguments are split.

function                                             old     new   delta
colon                                               3848    3751     -97
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-97)             Total: -97 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
dadd909746 vi: improvements to ':read' command
Improvements to ':read':

- When a file is read into the current buffer the cursor should be
  placed on the first line read.

- If invoked without supplying a filename the current filename should
  be used.  This is similar to how ':edit' works.

- The code for ':edit' included an explicit check that the current
  filename was non-empty.  Both vim and traditional vi accept non-empty
  filenames, only issuing an error message when an attempt to use such
  a name fails.

- Allow undo of a file read.

function                                             old     new   delta
file_insert                                          367     382     +15
colon                                               3841    3848      +7
.rodata                                           105236  105218     -18
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 22/-18)              Total: 4 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
e6bc8a29a9 vi: preserve state when switching file
When a new file is opened from an existing editing session the
following details should be preserved:

- the last command used;
- the last character searched for on a line.

function                                             old     new   delta
edit_file                                            849     835     -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-14)             Total: -14 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
b9aaa375a3 vi: 'ZZ' should warn if there are more files to edit
When 'ZZ' was used to save the current file and more files were
available to edit BusyBox vi immediately moved on to the next file.
The correct behaviour is to issue a warning.

function                                             old     new   delta
do_cmd                                              4673    4724     +51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 51/0)               Total: 51 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
09172582da vi: saving unnamed file in readonly mode
Suppose vi is started with the command 'vi -R', that is, in readonly
mode with no filename.  Attempting to save the file with 'ZZ' or ':w'
results in the message:

   '(null)' is read only

Skip the code which prints this if no filename was provided, thus
falling through to file_write() which gives the more helpful message
'No current filename'.

function                                             old     new   delta
colon                                               3867    3874      +7
do_cmd                                              4668    4673      +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 12/0)               Total: 12 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
3b9233f05f vi: adjust conditional compilation of modifying_cmds
Since commit 74d565ff1 (vi: make context marks more like vi) the
list of commands that modify the text is no longer required when
FEATURE_VI_YANKMARK is enabled, only FEATURE_VI_DOT_CMD.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
7a8ceb4eb2 vi: changes to line addresses for colon commands
Make line addresses behave more like vi:

- Vi allows the user to enter an arbitrary number of addresses,
  though only the last two are used.  This simplifies get_address()
  by reducing the amount of state that needs to be carried.

- When a command requires a single address the last one entered is
  used.

- If addresses are separated by a ';' instead of a ',' the current
  line is updated to the left address.  This may be useful when a
  search is used to specify a range, e.g. ':/first/;/last/d'.

- When the last address is empty it should refer to the current line.

function                                             old     new   delta
colon                                               3855    3834     -21
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-21)             Total: -21 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-28 11:29:33 +02:00
Ron Yorston
f277c9eebb vi: make de-indentation with ctrl-D more like vim
Commit ac6495f6f (vi: allow ctrl-D to reduce indentation) treated
ctrl-D during autoindent as a backspace.  This was adequate for
indentation using tabs but doesn't work well with the expandtab
option.  In the latter case it's necessary to backspace over all
the spaces.

Make ctrl-D work correctly when spaces are present in the indent.

Also, make it behave more like vim:

- ctrl-D is independent of autoindent;
- indentation is reduced even when the cursor isn't positioned at
  the end of the indent.

function                                             old     new   delta
char_insert                                          679     717     +38
get_column                                             -      37     +37
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 75/0)               Total: 75 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-20 11:21:43 +02:00
Ron Yorston
310ef23280 vi: add expandtab option
This implements the vim option expandtab in BusyBox vi.  From
vim help:

  In Insert mode: Use the appropriate number of spaces to insert a
  <Tab>.  Spaces are used in indents with the '>' and '<' commands and
  when 'autoindent' is on.  To insert a real tab when 'expandtab' is
  on, use CTRL-V<Tab>.

This implementation doesn't change how BusyBox vi handles autoindent:
it continues to copy the indentation from a neighbouring line.  If
that line has tabs in its indentation so too will the new line.

function                                             old     new   delta
char_insert                                          563     679    +116
next_column                                            -      48     +48
.rodata                                           105211  105236     +25
colon                                               3844    3855     +11
refresh                                             1000     982     -18
move_to_col                                           83      59     -24
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/2 up/down: 200/-42)           Total: 158 bytes

Signed-off-by: Peter D <urmum69@snopyta.org>
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-20 11:21:43 +02:00
Denys Vlasenko
b65e7f629e vi: move undo_queue_state in globals to other byte-sized members
function                                             old     new   delta
vi_main                                              278     275      -3
undo_queue_commit                                     62      56      -6
undo_push                                            374     362     -12
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-21)             Total: -21 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 23:18:40 +02:00
Ron Yorston
f227726838 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>
2021-04-15 13:09:12 +02:00
Ron Yorston
47f78913f7 vi: allow backward search to specify line address
It should be possible to use a backward search as a line address
in colon commands.

function                                             old     new   delta
colon                                               3661    3701     +40
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 40/0)               Total: 40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d488def0e4 vi: detect and warn about invalid line addresses
BusyBox vi didn't have proper handling for invalid markers or
unsuccessful searches in colon line addresses.  This could result
in the wrong lines being affected by a change.

Detect when an invalid address is specified, propagate an error
indicator up the call chain and issue a warning.

function                                             old     new   delta
colon                                               3604    3661     +57
.rodata                                           105195  105211     +16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 73/0)               Total: 73 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
5d1bb58b13 vi: code shrink colon line addresses
Remove some unnecessary code in get_one_address() and rewrite
get_address().

function                                             old     new   delta
colon                                               3325    3604    +279
get_one_address                                      342       -    -342
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 279/-342)          Total: -63 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
74d565ff1f vi: make context marks more like vi
The context marks that are automatically updated and can be used
with the "''" command didn't behave the same as in vi.  Marks
were only being set for certain editing commands when they should
have been set on successful movement commands.

Make BusyBox vi behave more like vi.

function                                             old     new   delta
.rodata                                           105179  105194     +15
do_cmd                                              4723    4668     -55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 15/-55)            Total: -40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
47c3eaa22f vi: correct autoindent for 'O' command
Opening a line above the current line with the 'O' command should
use the current, not previous, line to determine how much to
autoindent.

function                                             old     new   delta
char_insert                                          531     563     +32
do_cmd                                              4746    4723     -23
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 32/-23)              Total: 9 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
ac6495f6fb vi: allow ctrl-D to reduce indentation
When whitespace has been automatically added to a new line due to
autoindent entering ctrl-D should reduce the level of indentation.

Implement an approximation of this by treating ctrl-D as backspace.
For the common case of indentation using tabs this is good enough.
My attempt at a full implementation was three times bigger.

function                                             old     new   delta
char_insert                                          476     531     +55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 55/0)               Total: 55 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d6e653d667 vi: don't move cursor when yanking whole lines
When whole lines are yanked using 'yy' or 'Y' vi doesn't change the
cursor position.  Make BusyBox vi do the same.

function                                             old     new   delta
do_cmd                                              4776    4786     +10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 10/0)               Total: 10 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
38ae0f3e3e vi: reset command count when specifying '0' range
Since commit a54450248 (vi: allow the '.' command to have a
repetition count) using '0' to specify a range doesn't work with
a non-zero repeat count, e.g. '1d0'.  Users wouldn't normally try
to do that but the '.' command does.

Add a special case in get_motion_char() to handle this.

function                                             old     new   delta
find_range                                           737     746      +9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 9/0)                 Total: 9 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
033fa3d5c6 vi: code shrink motion by paragraph
Use a hand-coded loop to search for paragraph boundaries instead
of calling char_search().  We were using a loop anyway to skip
consecutive newlines.

function                                             old     new   delta
do_cmd                                              4792    4752     -40
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-40)             Total: -40 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
d9d19896a9 vi: position cursor on last column of tab
Vi places the cursor on the last column of a tab character whereas
BusyBox vi puts it on the first.  This is disconcerting for
experienced vi users and makes it impossible to distinguish
visually between an empty line and one containing just a tab.

It wasn't always this way.  Prior to commit e3cbfb91d (vi: introduce
FEATURE_VI_8BIT) BusyBox vi also put the cursor on the last column.
However there were problems with cursor positioning when text was
inserted before a tab.  Commit eaabf0675 (vi: multiple fixes by
Natanael Copa) includes a partial attempt to fix this.  (The code is
still present but it's never executed.  Clever compilers optimise it
away.)

Revert the changes of commit e3cbfb91d and fix the insert problem
for all tabs, not just the first.

To quote Natanael:  "Costs a few bytes but its worth it imho".

function                                             old     new   delta
refresh                                              974    1000     +26
move_to_col                                           81      83      +2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 28/0)               Total: 28 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Ron Yorston
9b2a3895ee vi: correctly record deleted characters
The undo queue didn't record deleted characters properly.  For
example, insert some text, backspace over a couple of characters
then exit insert mode.  At this point undo will restore two nulls
instead of the deleted characters.

The fix is in undo_push():  record the state of the UNDO_USE_SPOS
flag and clear it before using 'u_type'.

Also, update the comments to reflect the fact that UNDO_QUEUED_FLAG
isn't actually used.

function                                             old     new   delta
undo_push                                            443     435      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-8)               Total: -8 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-15 13:09:12 +02:00
Alison Winters
7b5cbfd6d6 vi: allow writing to another file if this one is readonly
Version 2. Same change but rebased after Ron's improvements. Fixes bug
where if you open a read only file, you can't save it as a different
filename.

function                                             old     new   delta
colon                                               3160    3162      +2

Signed-off-by: Alison Winters <alisonatwork@outlook.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-13 19:30:16 +02:00
Ron Yorston
f4a9908b4c vi: improvements to reporting of changes
Traditional vi is mostly silent about the results of yank, delete,
change, undo or substitution commands.  Vim reports some details
about undo and substitution.  BusyBox vi is positively verbose in
comparison.

Make some improvements to BusyBox vi:

- Add vim-like reporting of changes caused by substitutions, of
  the form '64 substitutions on 53 lines'.  This replaces a fairly
  useless report of the result of the last change made.

- Ensure that the report about put operations correctly reflects the
  newly introduced repetition count.

- Commit 25d2592640 tried to limit status updates for delete and
  yank operations by detecting whether the register had changed.
  This didn't always work because the previously allocated memory
  could be reused for the new register contents.  Fix this by
  delaying freeing the old register until after the new one has
  been allocated.

- Add a configuration option to control verbose status reporting.
  This is on by default.  Turning it off make BusyBox vi as taciturn
  as traditional vi and saves 435 bytes.

function                                             old     new   delta
colon                                               3212    3292     +80
yank_status                                            -      74     +74
static.text_yank                                      99      86     -13
string_insert                                        130      76     -54
do_cmd                                              4842    4776     -66
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/3 up/down: 154/-133)           Total: 21 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:56 +02:00
Ron Yorston
99fb5f2144 vi: issue a warning on failure to find a character
When a search for a character within a line fails issue a warning.

function                                             old     new   delta
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0)                 Total: 0 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:56 +02:00
Ron Yorston
6220b4d531 vi: make the substitute command more like vi
Make the ':s/find/replace/g' command behave more like vi:

- the final delimiter is optional if no flag is specified;

- the cursor is moved to the first visible character of the last
  line where a substitution was made;

- a warning is displayed if no substitution was made.

function                                             old     new   delta
colon                                               3156    3212     +56
.rodata                                           105133  105142      +9
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 65/0)               Total: 65 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
951c6ded3a vi: make put commands more like vi
Make the put commands 'p' and 'P' behave more like vi:

- allow a repetition count to be specified;

- when the text being inserted doesn't include a newline the cursor
  should be positioned at the end of the inserted text.

function                                             old     new   delta
do_cmd                                              4765    4842     +77
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 77/0)               Total: 77 bytes

v2: Don't break build when FEATURE_VI_UNDO is disabled.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
a54450248b vi: allow the '.' command to have a repetition count
The '.' command repeats the last text change.  When it has a
repetition count replay the change the number of times requested.
Update the stored count if it changes.  For example,

   3dw     deletes 3 words
   .       deletes another 3 words
   2.      deletes 2 words and changes the stored count
   .       deletes 2 words

function                                             old     new   delta
do_cmd                                              4746    4781     +35
.rodata                                           105133  105138      +5
edit_file                                            887     849     -38
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 40/-38)              Total: 2 bytes

v2: Change implementation to include repetition count in string.
    Otherwise repeating 'r' doesn't work properly.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
fe76569daa vi: allow 'r' command to be aborted, repeated
Make the 'r' command behave more like vi:

- abort the command if ESC is entered after the 'r';

- allow a repeat count to be entered before the 'r';

- if the repeat count exceeds the space available on the line don't
  change any characters and issue an alert.

function                                             old     new   delta
do_cmd                                              4679    4746     +67
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 67/0)               Total: 67 bytes

v2: Don't break build when FEATURE_VI_UNDO is disabled.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
b18c7bf702 vi: improvements to undo
The left shift operator ('<') didn't support undo at all; right
shift ('>') required changes to be undone separately for each line.
Allow both types of shift to be undone as a single operation.

Also, neither traditional vi nor vim yank the lines being shifted by
the '<' and '>' commands, so remove that call to yank_delete();

When a repetition count was specified for the '~', 'x', 'X' or 's'
commands the changes had to be undone one character at a time.
Allow undo as a single operation (though the delete and change
parts of the 's' command still have to be undone separately).

function                                             old     new   delta
undo_push_insert                                      37      40      +3
do_cmd                                              4695    4663     -32
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 3/-32)             Total: -29 bytes

v2: Don't break build when FEATURE_VI_UNDO is  disabled.  Don't reset
    'undo_del' too early in '~' handling code.  Code shrink '~'.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
e577afca7c vi: more fixes to range selection by word
An example in my vi book presents different ways to fix the spelling
of the last word in a line:

   ... anyweigh.

With the cursor on the 'e' the command 'cway' should do the job.
Since commit 776b56d77, though, 'cw' incorrectly includes the full
stop in the range if we're on the last line of the file.

(Prior to commit 776b56d77 BusyBox vi got 'cw' right in this case but
'cW' wrong:  it *didn't* delete the full stop.)

Reinstate some of the bloat removed by the earlier commit to fix this.

Also, commit 7b4c2276a (vi: fix word operations across line boundaries)
incorrectly ignores whitespace after a single character word.  Adjust
the condition to avoid this.

function                                             old     new   delta
find_range                                           707     737     +30
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 30/0)               Total: 30 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
b7b1119d9f vi: improvements to range selection
Rewrite find_range(), pushing quite a bit of code from do_cmd()
down into it.

- The commands 'y', 'd', 'c', '<' and '>' can be given twice to
  specify a whole-line range.  BusyBox vi actually accepted any
  second character from that group, e.g. 'dc' or '<y', with the
  latter being accepted even if yank was disabled.  Require the
  two characters to match.

- '<' and '>' commands followed by ESC incorrectly issued an alert.

- Allow search commands and a marker (specified as "y'a", for example)
  to define a range for those operators that support it.

function                                             old     new   delta
find_range                                           518     707    +189
.rodata                                           105119  105133     +14
get_motion_char                                       68       -     -68
do_cmd                                              4860    4695    -165
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 2/1 up/down: 203/-233)          Total: -30 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
7ce0e75c1f vi: code shrink search commands
Changes to search commands ('/', '?', 'n' and 'N'):

- Rewrite to be smaller and (possibly) clearer.

- Issue a warning when a repeat search is requested without a
  previous search having been made.

Vim and BusyBox vi support a repetition count for searches though
the original vi doesn't.  If the count exceeds the number of
occurrences of the search string the search may loop through the
file multiple times.

function                                             old     new   delta
.rodata                                           105135  105119     -16
do_cmd                                              4898    4860     -38
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-54)             Total: -54 bytes

Signed-off-by; Ron Yorston <rmy@pobox.com>

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-11 00:18:55 +02:00
Ron Yorston
9f017d9db0 vi: changes to option handling
Since commit 70ee23399 (vi: code shrink) the ':set' command is
unable to process multiple options on a line.  Fix this by
temporarily null-terminating each option.

Change the default setting for all options to off to match vim.
Actually, 'flash' isn't an option in vim, only traditional vi,
where it's on by default.  In vim the corresponding option is
'visualbell' which defaults to off.  POSIX doesn't have either
of these.

Allow the abbreviation 'ts' for the 'tabstop' option.

Issue an error message if:

- an option is not implemented
- an option that takes a value has no '=' or has a 'no' prefix
- a boolean option has a '='

function                                             old     new   delta
colon                                               2944    3003     +59
.rodata                                           103171  103189     +18
vi_main                                              274     270      -4
setops                                                73       -     -73
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 2/1 up/down: 77/-77)              Total: 0 bytes

v2: Try harder to detect invalid options.  Thanks to Peter D for pointing
    this out.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-04-08 12:50:01 +02:00
Ron Yorston
24198f652f vi: deal with invalid movements in shift commands
Since commit 25d259264 (vi: make buffer handling more vi-like)
find_range() can return early when an invalid movement is
specified.

The call to find_range() in the code that handles shift commands
('<' and '>') doesn't check for this condition.  Previously this
only resulted in the current line being shifted but it can now
result in a segfault.

Check for an invalid movement and notify the user without taking
any further action.

function                                             old     new   delta
do_cmd                                              4890    4898      +8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0)                 Total: 8 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-30 14:51:27 +02:00
Ron Yorston
a25b4c2c42 vi: code shrink
- In the '+' and '-' commands the call to dot_skip_over_ws() is
  only needed for the final line processed so it can be moved out
  of the while loop.

- Marking sync_cursor() NOINLINE doesn't seem to offer the same
  advantages it did in 2009 (commit adf922ec2).

function                                             old     new   delta
refresh                                              694     974    +280
do_cmd                                              4900    4887     -13
sync_cursor                                          336       -    -336
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/1 up/down: 280/-349)          Total: -69 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
d56da68057 vi: improve operations involving paragraph movement
Movement by paragraph doesn't always involve whole lines.  If the
cursor is positioned in the middle of a line deleting to either end
of the paragraph will result in one partial line and zero or more
full lines.

Adjust the end of ranges delimited by paragraph movement to more
closely match what vi does.

function                                             old     new   delta
find_range                                           467     518     +51
at_eof                                                 -      49     +49
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 100/0)             Total: 100 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
8b571bd7b5 vi: improve motion by paragraph
When moving by paragraph ('{' and '}'):

- Treat multiple empty lines as a single paragraph separator.

- When no paragraph separator is found move to the start or end of
  the file depending on the direction of motion.

function                                             old     new   delta
do_cmd                                              4821    4900     +79
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 79/0)               Total: 79 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
d3b74826c5 vi: allow repetition count for paragraph motion
The paragraph motion commands '{' and '}' should accept a count.

function                                             old     new   delta
do_cmd                                              5054    5071     +17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 17/0)               Total: 17 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
1e84daf054 vi: allow motion count for change/delete/yank/shift
The motion that determines the range of a change, delete, yank
or shift operation can have its own count.  Thus the commands
'5dd' and 'd5d' are equivalent:  both delete 5 lines.

When the command itself also has a count the two values are
multiplied.  Thus the command '2d3w' deletes 6 words and '2D3G'
deletes from the current line to line 6.

(When dealing with structured data it might make sense to think in
units of 3 words so '2d3w' is deleting 2 such units.  It doesn't
seem quite as sensible to express 'delete from current line to line 6'
as '2D3G' but vi permits it.)

function                                             old     new   delta
get_motion_char                                        -      68     +68
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/0 up/down: 68/0)               Total: 68 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
d4c46037a6 vi: support more commands for range selection
Add 'F', 'T' and '|' as commands that can be used to specify a
range for change/delete/yank operations.

function                                             old     new   delta
.rodata                                           105129  105135      +6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 6/0)                 Total: 6 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
15f4ac3ca9 vi: improvements to character search within line
- Use a common routine to handle all commands to search for a
  character in a line.

- When searching for the nth occurrence of a character don't move
  the cursor if fewer than n occurrences are present.

- Add support for the 'T' command, search backwards for character
  after next occurrence of given character.

function                                             old     new   delta
do_cmd                                              4861    4805     -56
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-56)             Total: -56 bytes

v2: Add parentheses to avoid searches continuing past end of line.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
50a2db7dff vi: remember cursor column during vertical motion
When the 'j'/'k' commands or up/down arrow keys are used to move
the cursor vertically 'vi' remembers the original cursor column
and positions the cursor there if possible.  Also, if the '$'
command has been used to position the cursor at the end of a line
vertical movements keep the cursor at the end of the line.

Make BusyBox 'vi' do the same.

function                                             old     new   delta
refresh                                              674     694     +20
do_cmd                                              4853    4861      +8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 28/0)               Total: 28 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00
Ron Yorston
18871c3f2b vi: 'G'/'M' commands move to first visible character
The 'G' command with no target (meaning 'go to last line') should
position the cursor on the first visible character of the line, as
it already does in other cases.

The 'M' command  should position the cursor on the first visible
character (as 'H' and 'L' already do).

function                                             old     new   delta
do_cmd                                              4842    4853     +11
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 11/0)               Total: 11 bytes

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2021-03-29 12:16:21 +02:00