Re: shopt

2024-10-09 Thread Ron Yorston
Jiří Prchal  wrote:
>Hi, a simple question: is there shopt? Can't find it.

No.  BusyBox ash has _some_ features from bash, but shopt isn't
one of them.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: reject unknown long options

2024-09-23 Thread Ron Yorston
Commit 64f70cc755 (Add --login support) added code in options()
to handle the bash-compatible '--login' option.  In doing so it
committed BusyBox ash to silently accepting all other long
options.

Restore compatibility with other ash variants by rejecting unknown
long options.

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shell/ash.c b/shell/ash.c
index bbd730770..0a145d31b 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -11502,11 +11502,11 @@ options(int *login_sh)
if (val && (c == '-')) { /* long options */
if (strcmp(p, "login") == 0) {
*login_sh = 1;
+   break;
}
 /* TODO: --noprofile: e.g. if I want to run emergency shell from sulogin,
  * I want minimal/no shell init scripts - but it insists on running it as 
"-ash"...
  */
-   break;
}
}
if (c == 'o') {
-- 
2.46.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] lineedit: use stdout for shell history builtin

2024-07-27 Thread Ron Yorston
Commit fd47f0567 (lineedit: print prompt and editing operations
to stderr) changed various print statements to output to stderr.
The change in show_history() caused the shell history builtin to
send its output to stderr.

Revert that part of the commit.

function old new   delta
show_history  47  42  -5
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-5)   Total: -5 bytes

Signed-off-by: Ron Yorston 
---
 libbb/lineedit.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 543a3f11c..3e06a4bc5 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1463,7 +1463,7 @@ void FAST_FUNC show_history(const line_input_t *st)
if (!st)
return;
for (i = 0; i < st->cnt_history; i++)
-   fprintf(stderr, "%4d %s\n", i, st->history[i]);
+   printf("%4d %s\n", i, st->history[i]);
 }
 
 # if ENABLE_FEATURE_EDITING_SAVEHISTORY
-- 
2.45.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ed: fix line insertion before current line. Closes 15081

2024-07-18 Thread Ron Yorston
When text is inserted by insertLine() the lines following the
insertion are moved down and the insertion point is made the new
current line.  To avoid too much scanning of the linked list of
lines setCurNum() may use the position of the old current line to
determine the location of the new current line.

If the insertion point is before the old current line in the file
the latter will have been moved down, so its line pointer needs to
be adjusted.

function old new   delta
insertLine   162 180 +18
--
(add/remove: 0/0 grow/shrink: 1/0 up/down: 18/0)   Total: 18 bytes

Signed-off-by: Ron Yorston 
---
 editors/ed.c   |  2 ++
 testsuite/ed.tests | 21 +
 2 files changed, 23 insertions(+)
 create mode 100755 testsuite/ed.tests

diff --git a/editors/ed.c b/editors/ed.c
index 8ec23d07f..a02634ec7 100644
--- a/editors/ed.c
+++ b/editors/ed.c
@@ -345,6 +345,8 @@ static int insertLine(int num, const char *data, int len)
lp->prev->next = newLp;
lp->prev = newLp;
 
+   if (num <= curNum)
+   curLine = curLine->prev;
lastNum++;
dirty = TRUE;
return setCurNum(num);
diff --git a/testsuite/ed.tests b/testsuite/ed.tests
new file mode 100755
index 0..475fdc244
--- /dev/null
+++ b/testsuite/ed.tests
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+. ./testing.sh
+
+# testing "test name" "command" "expected result" "file input" "stdin"
+
+testing "ed insert text before current line" \
+   "ed input" "8\n1\ntext\n2\n3\n4\n13\n" "1\n2\n3\n4\n" '2i
+text
+.
+,p
+w
+q
+'
+
+testing "ed read text before current line" \
+   "ed input" "8\n8\n1\n2\n1\n2\n3\n4\n3\n4\n16\n" "1\n2\n3\n4\n" '2r input
+,p
+w
+q
+'
-- 
2.45.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: fix parsing of alias expansion + bash features

2024-05-02 Thread Ron Yorston
An alias expansion immediately followed by '<' and a newline is
parsed incorrectly:

   ~ $ alias x='echo yo'
   ~ $ x<
   yo
   ~ $
   sh: syntax error: unexpected newline

The echo is executed and an error is printed on the next command
submission.  In dash the echo isn't executed and the error is
reported immediately:

   $ alias x='echo yo'
   $ x<
   dash: 3: Syntax error: newline unexpected
   $

The difference between BusyBox and dash is that BusyBox supports
bash-style process substitution and output redirection.  These
require checking for '<(', '>(' and '&>' in readtoken1().

In the case above, when the end of the alias is found, the '<' and
the following newline are both read to check for '<('.  Since
there's no match both characters are pushed back.

The next input is obtained by reading the expansion of the alias.
Once this string is exhausted the next call to __pgetc() calls
preadbuffer() which pops the string, reverts to the previous input
and recursively calls __pgetc().  This request is satisified from
the pungetc buffer.  But the first __pgetc() doesn't know this:
it sees the character has come from preadbuffer() so it (incorrectly)
updates the pungetc buffer.

Resolve the issue by moving the code to pop the string and fetch
the next character up from preadbuffer() into __pgetc().

function old new   delta
pgetc 28 589+561
__pgetc  607   --607
----------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 561/-607)  Total: -46 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 4ca4c6c56..5df0ba625 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -10934,11 +10934,6 @@ preadbuffer(void)
char *q;
int more;
 
-   if (unlikely(g_parsefile->strpush)) {
-   popstring();
-   return __pgetc();
-   }
-
if (g_parsefile->buf == NULL) {
pgetc_debug("preadbuffer PEOF1");
return PEOF;
@@ -11053,8 +11048,13 @@ static int __pgetc(void)
 
if (--g_parsefile->left_in_line >= 0)
c = (unsigned char)*g_parsefile->next_to_pgetc++;
-   else
+   else {
+   if (unlikely(g_parsefile->strpush)) {
+   popstring();
+   return __pgetc();
+   }
c = preadbuffer();
+   }
 
g_parsefile->lastc[1] = g_parsefile->lastc[0];
g_parsefile->lastc[0] = c;
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH v2] fixdep: add fstat error handling

2024-04-30 Thread Ron Yorston
Sam James  wrote:
>David Leonard  writes:
>> I worry that the fprintf() may destroy the errno which perror() uses,
>> so you could get a random error message.
>> Perhaps remove the fprintf(s) completely? Because the context should be
>> clear enough from the filename alone that perror displays.
>
>Ah, a great point. Any preference between just stripping the fprintfs vs
>a better argument to perror, as we do in some places (but not very
>consistently)?

Or:

   fprintf(stderr, "fixdep: fstat %s %s\n", depfile, strerror(errno));

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 2/2] libbb: send usage messages to correct stream

2024-04-09 Thread Ron Yorston
POSIX generally requires normal output to go to stdout and
diagnostic (i.e. error) output to go to stderr.

When usage messages for BusyBox applets are specifically requested
by the user (e.g. 'find --help') they should go to stdout; when
they're emitted due to an error they should go to stderr.

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

Signed-off-by: Avi Halachmi 
Signed-off-by: Ron Yorston 
---
 libbb/appletlib.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index ad373ae1c..d2e5900b5 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -127,17 +127,19 @@ static const char packed_usage[] ALIGN1 = { PACKED_USAGE 
};
 void FAST_FUNC bb_show_usage(void)
 {
if (ENABLE_SHOW_USAGE) {
+   ssize_t FAST_FUNC (*full_write_fn)(const char *) =
+   xfunc_error_retval ? full_write2_str : 
full_write1_str;
 #ifdef SINGLE_APPLET_STR
/* Imagine that this applet is "true". Dont link in printf! */
const char *usage_string = unpack_usage_messages();
 
if (usage_string) {
if (*usage_string == '\b') {
-   full_write2_str("No help available\n");
+   full_write_fn("No help available\n");
} else {
-   full_write2_str("Usage: "SINGLE_APPLET_STR" ");
-   full_write2_str(usage_string);
-   full_write2_str("\n");
+   full_write_fn("Usage: "SINGLE_APPLET_STR" ");
+   full_write_fn(usage_string);
+   full_write_fn("\n");
}
if (ENABLE_FEATURE_CLEAN_UP)
dealloc_usage_messages((char*)usage_string);
@@ -153,19 +155,19 @@ void FAST_FUNC bb_show_usage(void)
while (*p++) continue;
ap--;
}
-   full_write2_str(bb_banner);
-   full_write2_str(" multi-call binary.\n"); /* common string */
+   full_write_fn(bb_banner);
+   full_write_fn(" multi-call binary.\n"); /* common string */
if (*p == '\b')
-   full_write2_str("\nNo help available\n");
+   full_write_fn("\nNo help available\n");
else {
-   full_write2_str("\nUsage: ");
-   full_write2_str(applet_name);
+   full_write_fn("\nUsage: ");
+   full_write_fn(applet_name);
if (p[0]) {
if (p[0] != '\n')
-   full_write2_str(" ");
-   full_write2_str(p);
+   full_write_fn(" ");
+   full_write_fn(p);
}
-   full_write2_str("\n");
+   full_write_fn("\n");
}
if (ENABLE_FEATURE_CLEAN_UP)
dealloc_usage_messages((char*)usage_string);
@@ -268,8 +270,10 @@ void lbb_prepare(const char *applet
 && !(ENABLE_TRUE && strcmp(applet_name, "true") == 0)
 && !(ENABLE_FALSE && strcmp(applet_name, "false") == 0)
 && !(ENABLE_ECHO && strcmp(applet_name, "echo") == 0)
-   )
+   ) {
+   xfunc_error_retval = 0;
bb_show_usage();
+   }
}
 #endif
 }
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 1/2] libbb: use full_write1_str() to shrink busybox_main()

2024-04-09 Thread Ron Yorston
There are two calls to dup2() in busybox_main().  These were
introduced to coerce full_write2_str() into writing to stdout.

The relevant commits were: 21278dff7 (busybox: do not print help
to fd 2, print it to fd 1) and 5a7c72015 (busybox --list option.
+140 bytes. Rob wanted it.)

Later, in commit 729ecb87b (bbconfig: make it independent from
printf functions), the function full_write1_str() was added.

Using this in busybox_main() allows us to drop the dup2() calls.

function old new   delta
run_applet_and_exit  796 760 -36
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-36) Total: -36 bytes

Signed-off-by: Ron Yorston 
---
 libbb/appletlib.c | 24 +++-
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d9cc48423..ad373ae1c 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -776,10 +776,9 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
  help:
output_width = get_terminal_width(2);
 
-   dup2(1, 2);
-   full_write2_str(bb_banner); /* reuse const string */
-   full_write2_str(" multi-call binary.\n"); /* reuse */
-   full_write2_str(
+   full_write1_str(bb_banner); /* reuse const string */
+   full_write1_str(" multi-call binary.\n"); /* reuse */
+   full_write1_str(
"BusyBox is copyrighted by many authors between 
1998-2015.\n"
"Licensed under GPLv2. See source distribution for 
detailed\n"
"copyright notices.\n"
@@ -817,20 +816,20 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
while (*a) {
int len2 = strlen(a) + 2;
if (col >= (int)output_width - len2) {
-   full_write2_str(",\n");
+   full_write1_str(",\n");
col = 0;
}
if (col == 0) {
col = 6;
-   full_write2_str("\t");
+   full_write1_str("\t");
} else {
-   full_write2_str(", ");
+   full_write1_str(", ");
}
-   full_write2_str(a);
+   full_write1_str(a);
col += len2;
a += len2 - 1;
}
-   full_write2_str("\n");
+   full_write1_str("\n");
return 0;
}
 
@@ -850,14 +849,13 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
if (is_prefixed_with(argv[1], "--list")) {
unsigned i = 0;
const char *a = applet_names;
-   dup2(1, 2);
while (*a) {
 #  if ENABLE_FEATURE_INSTALLER
if (argv[1][6]) /* --list-full? */
-   
full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
+   
full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
 #  endif
-   full_write2_str(a);
-   full_write2_str("\n");
+   full_write1_str(a);
+   full_write1_str("\n");
i++;
while (*a++ != '\0')
continue;
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] timeout: allow fractional seconds in timeout values

2024-04-08 Thread Ron Yorston
The 'timeout' applet uses parse_duration_str() to obtain its
timeout values.  The default configuration enables float durations.

However, the applet silently ignores fractional seconds.  This
results in unexpected behaviour:

   $ timeout 5.99 sleep 5.1; echo $?
   Terminated
   143

When float durations are enabled ensure that any fractional seconds
are taken into account.

function old new   delta
timeout_wait  44  92 +48
timeout_main 383 365 -18
--
(add/remove: 0/0 grow/shrink: 1/1 up/down: 48/-18) Total: 30 bytes

Signed-off-by: Ron Yorston 
---
 coreutils/timeout.c | 13 +
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 18aa9ebeb..84299a0a5 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -47,11 +47,16 @@
 
 #include "libbb.h"
 
-static NOINLINE int timeout_wait(int timeout, pid_t pid)
+static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
 {
/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
while (1) {
-   sleep1();
+#if ENABLE_FLOAT_DURATION
+   if (timeout < 1)
+   sleep_for_duration(timeout);
+   else
+#endif
+   sleep1();
if (--timeout <= 0)
break;
if (kill(pid, 0)) {
@@ -68,8 +73,8 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
int signo;
int status;
int parent = 0;
-   int timeout;
-   int kill_timeout;
+   duration_t timeout;
+   duration_t kill_timeout;
pid_t pid;
 #if !BB_MMU
char *sv1, *sv2;
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: move hashvar() calls into findvar()

2024-04-06 Thread Ron Yorston
dash has accepted a patch to remove the first argument of findvar().
It's commit e85e972 (var: move hashvar() calls into findvar()).

Apply the same change to BusyBox ash.

function old new   delta
findvar   35  40  +5
mklocal  268 261  -7
exportcmd164 157  -7
setvareq 319 310  -9
lookupvar150 141  -9
--
(add/remove: 0/0 grow/shrink: 1/4 up/down: 5/-32) Total: -27 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 17 -
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 4ca4c6c56..8195bfca3 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2328,9 +2328,11 @@ initvar(void)
 }
 
 static struct var **
-findvar(struct var **vpp, const char *name)
+findvar(const char *name)
 {
-   for (; *vpp; vpp = &(*vpp)->next) {
+   struct var **vpp;
+
+   for (vpp = hashvar(name); *vpp; vpp = &(*vpp)->next) {
if (varcmp((*vpp)->var_text, name) == 0) {
break;
}
@@ -2346,7 +2348,7 @@ lookupvar(const char *name)
 {
struct var *v;
 
-   v = *findvar(hashvar(name), name);
+   v = *findvar(name);
if (v) {
 #if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
/*
@@ -2413,9 +2415,8 @@ setvareq(char *s, int flags)
 {
struct var *vp, **vpp;
 
-   vpp = hashvar(s);
flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
-   vpp = findvar(vpp, s);
+   vpp = findvar(s);
vp = *vpp;
if (vp) {
if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
@@ -9967,7 +9968,6 @@ static void
 mklocal(char *name, int flags)
 {
struct localvar *lvp;
-   struct var **vpp;
struct var *vp;
char *eq = strchr(name, '=');
 
@@ -9996,8 +9996,7 @@ mklocal(char *name, int flags)
lvp->text = memcpy(p, optlist, sizeof(optlist));
vp = NULL;
} else {
-   vpp = hashvar(name);
-   vp = *findvar(vpp, name);
+   vp = *findvar(name);
if (vp == NULL) {
/* variable did not exist yet */
if (eq)
@@ -14138,7 +14137,7 @@ exportcmd(int argc UNUSED_PARAM, char **argv)
if (p != NULL) {
p++;
} else {
-   vp = *findvar(hashvar(name), name);
+   vp = *findvar(name);
if (vp) {
vp->flags = ((vp->flags | flag) 
& flag_off);
continue;
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] md5/shaXsum: accept uppercase hex strings

2024-04-03 Thread Ron Yorston
The coreutils versions of md5sum and the like accept uppercase hex
strings from checksum files specified with the '-c' option.

Use a case-insensitive comparison so BusyBox does the same.

Signed-off-by: Ron Yorston 
---
 coreutils/md5_sha1_sum.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index f6a21237d..978d328f1 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -320,7 +320,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
 
hash_value = hash_file(in_buf, filename_ptr, 
sha3_width);
 
-   if (hash_value && (strcmp((char*)hash_value, 
line) == 0)) {
+   if (hash_value && 
(strcasecmp((char*)hash_value, line) == 0)) {
if (!(flags & FLAG_SILENT))
printf("%s: OK\n", 
filename_ptr);
} else {
-- 
2.44.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] awk: fix segfault when compiled by clang

2024-01-25 Thread Ron Yorston
Rob Landley wrote:
>Out of morbid curiosity, why did this message a week ago wind up delivered to 
>me
>through the mailing list (I confirmed I was not personally cc'd on it), but not
>wind up in the mailing list web archive?

Dunno.  I did notice the mailing list archive was unavailable at the
time I sent the message.  Presumably it was encountering difficulties
which resulted in it becoming forgetful.

It is archived elsewhere:

   https://marc.info/?l=busybox&r=1&b=202401&w=2

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] awk: fix segfault when compiled by clang

2024-01-19 Thread Ron Yorston
A 32-bit build of BusyBox using clang segfaulted in the test
"awk assign while assign".  Specifically, on line 7 of the test
input where the adjustment of the L.v pointer when the Fields
array was reallocated

L.v += Fields - old_Fields_ptr;

was out by 4 bytes.

Rearrange to code so both gcc and clang generate code that works.

Signed-off-by: Ron Yorston 
---
 editors/awk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/editors/awk.c b/editors/awk.c
index aa485c782..0981c6735 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -3006,7 +3006,7 @@ static var *evaluate(node *op, var *res)
if (old_Fields_ptr) {
//if (old_Fields_ptr != Fields)
//  debug_printf_eval("L.v moved\n");
-   L.v += Fields - old_Fields_ptr;
+   L.v = Fields + (L.v - old_Fields_ptr);
}
if (opinfo & OF_STR2) {
R.s = getvar_s(R.v);
-- 
2.43.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] - vi: Append a newline to opened files that don't already end in one

2024-01-10 Thread Ron Yorston
There was another, similar patch for this issue last year:

   http://lists.busybox.net/pipermail/busybox/2023-April/090272.html

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] Remove FAST_FUNC from variadic functions

2024-01-02 Thread Ron Yorston
The GCC documentation points out that the stdcall attribute doesn't
apply to functions which take a variable number of arguments.  GCC
is silent about this during compilation but clang complains noisily.

Remove FAST_FUNC from all variadic functions.  This has no effect
whatsoever on the binary resulting from a default 32-bit build.

Signed-off-by: Ron Yorston 
---
 include/libbb.h   | 24 
 libbb/getopt32.c  |  4 ++--
 libbb/herror_msg.c|  4 ++--
 libbb/perror_msg.c|  4 ++--
 libbb/verror_msg.c|  6 +++---
 libbb/xfuncs_printf.c |  6 +++---
 6 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index ef5d04713..6ef090a0e 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -926,7 +926,7 @@ int bb_putchar(int ch) FAST_FUNC;
 /* Note: does not use stdio, writes to fd 2 directly */
 int bb_putchar_stderr(char ch) FAST_FUNC;
 int fputs_stdout(const char *s) FAST_FUNC;
-char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 
2))) FAST_FUNC RETURNS_MALLOC;
+char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 
2))) RETURNS_MALLOC;
 char *auto_string(char *str) FAST_FUNC;
 // gcc-4.1.1 still isn't good enough at optimizing it
 // (+200 bytes compared to macro)
@@ -1350,12 +1350,12 @@ char* single_argv(char **argv) FAST_FUNC;
 char **skip_dash_dash(char **argv) FAST_FUNC;
 extern const char *const bb_argv_dash[]; /* { "-", NULL } */
 extern uint32_t option_mask32;
-uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC;
+uint32_t getopt32(char **argv, const char *applet_opts, ...);
 # define No_argument "\0"
 # define Required_argument "\001"
 # define Optional_argument "\002"
 #if ENABLE_LONG_OPTS
-uint32_t getopt32long(char **argv, const char *optstring, const char 
*longopts, ...) FAST_FUNC;
+uint32_t getopt32long(char **argv, const char *optstring, const char 
*longopts, ...);
 #else
 #define getopt32long(argv,optstring,longopts,...) \
getopt32(argv,optstring,##__VA_ARGS__)
@@ -1430,17 +1430,17 @@ extern uint8_t xfunc_error_retval;
 extern void (*die_func)(void);
 void xfunc_die(void) NORETURN FAST_FUNC;
 void bb_show_usage(void) NORETURN FAST_FUNC;
-void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) 
FAST_FUNC;
+void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
 void bb_simple_error_msg(const char *s) FAST_FUNC;
-void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format 
(printf, 1, 2))) FAST_FUNC;
+void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format 
(printf, 1, 2)));
 void bb_simple_error_msg_and_die(const char *s) NORETURN FAST_FUNC;
-void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) 
FAST_FUNC;
+void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
 void bb_simple_perror_msg(const char *s) FAST_FUNC;
-void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, 
format (printf, 1, 2))) FAST_FUNC;
+void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, 
format (printf, 1, 2)));
 void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC;
-void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) 
FAST_FUNC;
+void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
 void bb_simple_herror_msg(const char *s) FAST_FUNC;
-void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, 
format (printf, 1, 2))) FAST_FUNC;
+void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, 
format (printf, 1, 2)));
 void bb_simple_herror_msg_and_die(const char *s) NORETURN FAST_FUNC;
 void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC;
 void bb_perror_nomsg(void) FAST_FUNC;
@@ -1456,7 +1456,7 @@ void bb_logenv_override(void) FAST_FUNC;
 typedef smalluint exitcode_t;
 
 #if ENABLE_FEATURE_SYSLOG_INFO
-void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) 
FAST_FUNC;
+void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2)));
 void bb_simple_info_msg(const char *s) FAST_FUNC;
 void bb_vinfo_msg(const char *s, va_list p) FAST_FUNC;
 #else
@@ -1832,8 +1832,8 @@ int get_termios_and_make_raw(int fd, struct termios 
*newterm, struct termios *ol
 int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC;
 
 /* NB: "unsigned request" is crucial! "int request" will break some arches! */
-int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) 
__attribute__ ((format (printf, 4, 5))) FAST_FUNC;
-int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char 
*fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC;
+int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) 
__attribute__ ((format (printf, 4, 5)));
+int ioctl_or

[PATCH] Makefile.flags: suppress clang warnings when cross-compiling

2024-01-02 Thread Ron Yorston
Extend the changes introduced by commit b4ef2e3467 (Makefile.flags:
suppress some clang-9 warnings) so they also cover the case where
clang is used as a cross-compiler.

Signed-off-by: Ron Yorston 
---
 Makefile.flags | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Makefile.flags b/Makefile.flags
index e4cd658fd..97cb4dca2 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -48,7 +48,7 @@ endif
 # gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action()
 CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition)
 
-ifneq ($(CC),clang)
+ifneq ($(lastword $(subst -, ,$(CC))),clang)
 # "clang-9: warning: optimization flag '-finline-limit=0' is not supported
 CFLAGS += $(call cc-option,-finline-limit=0,)
 endif
@@ -66,7 +66,7 @@ CFLAGS += $(call cc-option,-static-libgcc,)
 endif
 
 CFLAGS += $(call cc-option,-falign-functions=1,)
-ifneq ($(CC),clang)
+ifneq ($(lastword $(subst -, ,$(CC))),clang)
 # "clang-9: warning: optimization flag '-falign-jumps=1' is not supported" 
(and same for other two)
 CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,)
 endif
@@ -79,7 +79,7 @@ CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
 CFLAGS += $(call cc-option,-fno-builtin-printf,)
 
 # clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs
-ifeq ($(CC),clang)
+ifeq ($(lastword $(subst -, ,$(CC))),clang)
 CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand)
 endif
 
-- 
2.43.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: ash: is %builtin in PATH still expected to work?

2023-10-21 Thread Ron Yorston
There was a discussion on the dash mailing list earlier this year:

   https://www.spinics.net/lists/dash/msg02429.html

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] shell: avoid segfault on ${0::0/0~09J}. Closes 15216

2023-08-28 Thread Ron Yorston
Radoslav Kolev  wrote:
>On 12/29/22 3:45 PM, Ron Yorston wrote:
>> Both ash and hush segfault when asked to evaluate ${0::0/0~09J}.
>
>is there some problem with this patch or another reason it's not applied 
>yet? Or it just slipped trough the cracks? If so please consider 
>applying it.

Denys applied a different fix in commit d417193cf.

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] tsort: avoid use-after-free

2023-08-22 Thread Ron Yorston
When the input data contained a cycle it was possible for tsort to
attempt to access freed nodes.  This sometimes resulted in the
test case 'echo a b b a | tsort' crashing.

Don't free nodes when they're removed from the graph.

function old new   delta
tsort_main   621 596 -25
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-25) Total: -25 bytes

Signed-off-by: Ron Yorston 
---
 coreutils/tsort.c | 20 +---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/coreutils/tsort.c b/coreutils/tsort.c
index a451ed2ff..3e7aa48f4 100644
--- a/coreutils/tsort.c
+++ b/coreutils/tsort.c
@@ -101,6 +101,10 @@ int tsort_main(int argc UNUSED_PARAM, char **argv)
ssize_t len;
struct node *a;
int cycles;
+   unsigned i;
+#if ENABLE_FEATURE_CLEAN_UP
+   unsigned max_len;
+#endif
 
INIT_G();
 
@@ -152,9 +156,11 @@ int tsort_main(int argc UNUSED_PARAM, char **argv)
 *   - if any nodes are left, they form cycles.
 */
cycles = 0;
+#if ENABLE_FEATURE_CLEAN_UP
+   max_len = G.nodes_len;
+#endif
while (G.nodes_len) {
struct node *n;
-   unsigned i;
 
/* Search for first node with no incoming edges */
for (i = 0; i < G.nodes_len; i++) {
@@ -173,16 +179,24 @@ int tsort_main(int argc UNUSED_PARAM, char **argv)
/* Remove the node (need no longer maintain sort) */
n = G.nodes[i];
G.nodes[i] = G.nodes[--G.nodes_len];
+#if ENABLE_FEATURE_CLEAN_UP
+   /* Keep reference to removed node so it can be freed */
+   G.nodes[G.nodes_len] = n;
+#endif
 
/* And remove its outgoing edges */
for (i = 0; i < n->out_count; i++)
n->out[i]->in_count--;
-   free(n->out);
 
puts(n->name);
-   free(n);
+   }
+#if ENABLE_FEATURE_CLEAN_UP
+   for (i = 0; i < max_len; i++)
+   free(G.nodes[i].out);
+   free(G.nodes[i]);
}
free(G.nodes);
+#endif
 
fflush_stdout_and_exit(cycles ? 1 : 0);
 }
-- 
2.41.0

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: ash builtin sleep behavior

2023-07-22 Thread Ron Yorston
Igor,

There have been a number of problems with the sleep built-in.

It was recently disabled by this commit:

   
https://git.busybox.net/busybox/commit/?id=5e0411a7fb510b9aecda0a850c76bdd62c50efa4

>ash: disable sleep as builtin, closes 15619
>Has a few annoying problems:
>* sleepcmd() -> sleep_main(), the parsing of bad arguments exits the shell.
>* sleep_for_duration() in sleep_main() has to be interruptible for
>  ^C traps to work, which may be a problem for other users
>  of sleep_for_duration().
>* BUT, if sleep_for_duration() is interruptible, then SIGCHLD interrupts it
>  as well (try "/bin/sleep 1 & sleep 10").
>* sleep_main() must not allocate anything as ^C in ash longjmp's.
>  (currently, allocations are only on error paths, in message printing).

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] tr: display usage for incorrect arguments

2023-04-16 Thread Ron Yorston
tr must have one or two non-option arguments.  Display the usage
message if any other number is present.

function old new   delta
.rodata   108389  108392  +3
--
(add/remove: 0/0 grow/shrink: 1/0 up/down: 3/0) Total: 3 bytes

Signed-off-by: Ron Yorston 
---
 coreutils/tr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/coreutils/tr.c b/coreutils/tr.c
index 1e402dfdb..7fe7f89d5 100644
--- a/coreutils/tr.c
+++ b/coreutils/tr.c
@@ -299,7 +299,7 @@ int tr_main(int argc UNUSED_PARAM, char **argv)
 */
 
/* '+': stop at first non-option */
-   opts = getopt32(argv, "^+" "Ccds" "\0" "-1");
+   opts = getopt32(argv, "^+" "Ccds" "\0" "-1:?2");
argv += optind;
 
str1_length = expand(*argv++, &str1);
-- 
2.39.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 1/1] ash,hush: tab completion of functions and aliases

2023-04-13 Thread Ron Yorston
Since commit 9e2a5668f (ash,hush: allow builtins to be tab-completed,
closes 7532) ash and hush have supported tab completion of builtins.

Other shells, bash and ksh for example, also support tab completion
of functions and aliases.

Add such support to ash and hush.

function old new   delta
ash_command_name   -  98 +98
hush_command_name  -  71 +71
ash_builtin_name  17   - -17
hush_builtin_name 38   - -38
--
(add/remove: 2/2 grow/shrink: 0/0 up/down: 169/-55)   Total: 114 bytes

Signed-off-by: Ron Yorston 
Signed-off-by: Avi Halachmi 
---
 shell/ash.c  | 30 ++
 shell/hush.c | 11 +--
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index d4ee4c93e..055f5ff73 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9732,7 +9732,7 @@ evalpipe(union node *n, int flags)
 
 /* setinteractive needs this forward reference */
 #if ENABLE_FEATURE_TAB_COMPLETION
-static const char *get_builtin_name(int i) FAST_FUNC;
+static const char *ash_command_name(int i) FAST_FUNC;
 #endif
 
 /*
@@ -9769,7 +9769,7 @@ setinteractive(int on)
if (!line_input_state) {
line_input_state = new_line_input_t(FOR_SHELL | 
WITH_PATH_LOOKUP);
 # if ENABLE_FEATURE_TAB_COMPLETION
-   line_input_state->get_exe_name = get_builtin_name;
+   line_input_state->get_exe_name = ash_command_name;
 # endif
 # if EDITING_HAS_sh_get_var
line_input_state->sh_get_var = lookupvar;
@@ -10284,9 +10284,31 @@ find_builtin(const char *name)
 
 #if ENABLE_FEATURE_TAB_COMPLETION
 static const char * FAST_FUNC
-get_builtin_name(int i)
+ash_command_name(int i)
 {
-   return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 
1 : NULL;
+   int n;
+
+   if (/*i >= 0 &&*/ i < ARRAY_SIZE(builtintab))
+   return builtintab[i].name + 1;
+   i -= ARRAY_SIZE(builtintab);
+
+   for (n = 0; n < CMDTABLESIZE; n++) {
+   for (struct tblentry *cmdp = cmdtable[n]; cmdp; cmdp = 
cmdp->next) {
+   if (cmdp->cmdtype == CMDFUNCTION && i-- <= 0)
+   return cmdp->cmdname;
+   }
+   }
+
+# if ENABLE_ASH_ALIAS
+   for (n = 0; n < ATABSIZE; n++) {
+   for(struct alias *ap = atab[n]; ap; ap = ap->next) {
+   if (i-- <= 0)
+   return ap->name;
+   }
+   }
+#endif
+
+   return NULL;
 }
 #endif
 
diff --git a/shell/hush.c b/shell/hush.c
index 202c0993a..9439c2cca 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8220,7 +8220,7 @@ static const struct built_in_command *find_builtin(const 
char *name)
 }
 
 #if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION
-static const char * FAST_FUNC get_builtin_name(int i)
+static const char * FAST_FUNC hush_command_name(int i)
 {
if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
return bltins1[i].b_cmd;
@@ -8229,6 +8229,13 @@ static const char * FAST_FUNC get_builtin_name(int i)
if (i < ARRAY_SIZE(bltins2)) {
return bltins2[i].b_cmd;
}
+# if ENABLE_HUSH_FUNCTIONS
+   i -= ARRAY_SIZE(bltins2);
+   for (struct function *funcp = G.top_func; funcp; funcp = funcp->next) {
+   if (i-- <= 0)
+   return funcp->name;
+   }
+# endif
return NULL;
 }
 #endif
@@ -10716,7 +10723,7 @@ int hush_main(int argc, char **argv)
 # if ENABLE_FEATURE_EDITING
G.line_input_state = new_line_input_t(FOR_SHELL);
 #  if ENABLE_FEATURE_TAB_COMPLETION
-   G.line_input_state->get_exe_name = get_builtin_name;
+   G.line_input_state->get_exe_name = hush_command_name;
 #  endif
 #  if EDITING_HAS_sh_get_var
G.line_input_state->sh_get_var = get_local_var_value;
-- 
2.39.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 0/1] ash,hush: tab completion of functions and aliases

2023-04-13 Thread Ron Yorston
There follows a patch to add tab completion of functions and aliases
to ash and hush.  (hush doesn't support aliases, but that's a different
issue.)

A couple of things:

- The code makes repeated passes over the command and alias tables.
  We don't think this will be a problem in most cases.  We do have
  an alternative patch which only requires a single pass but it's
  more intrusive and bigger (200 vs 114 bytes).  It can be made
  available if there's interest.

- bloatcheck doesn't give an accurate result for this patch.  It was
  confused by there being two functions called get_builtin_name.  The 
  report in the patch was generated by splitting the change into two
  parts:  one to change the names and a second to add the new code.

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: sleep as an ash builtin

2023-04-10 Thread Ron Yorston
Denys Vlasenko wrote:
>Fixed. Please try current git.

Thanks, Denys.  Works now.

But...

   /* Without this, bare "sleep" in ash shows _ash_ --help */
   if (ENABLE_ASH_SLEEP && applet_name[0] != 's') {
  bb_simple_error_msg("sleep: missing operand");
  return EXIT_FAILURE;
   }

'ash' can be configured to run as 'sh'.  Which begins with 's'.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


sleep as an ash builtin

2023-04-03 Thread Ron Yorston
Another thing about sleep as an ash builtin:

   $ trap 'echo yo' INT
   $ echo $EPOCHSECONDS; sleep 10; echo $EPOCHSECONDS
   1680553805
   ^C^C^C^C^Cyo
   1680553815
   $ 

No matter how urgently I press Ctrl-C the sleep runs its full course.

Ron

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: improve trap and jobs builtins in child shells

2023-03-30 Thread Ron Yorston
The trap and jobs builtins can be used to report information about
traps and jobs.  This works when they're called from the current
shell but in a child shell the required information is usually
cleared.  Special hacks allow:

- trap to work with command substitution;
- jobs to work with command substitution or in a pipeline.

Neither works with process substitution.

- Relax the test for the trap hack so it also supports pipelines.

- Pass the command to be evaluated to forkshell() in evalbackcmd()
  so trap and jobs both work with process substitution.

function old new   delta
forkchild629 640 +11
argstr  15021496  -6
--
(add/remove: 0/0 grow/shrink: 1/1 up/down: 11/-6)   Total: 5 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c| 13 +++--
 shell/ash_test/ash-signals/usage.right | 12 
 shell/ash_test/ash-signals/usage.tests | 12 
 3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 559566b58..40b921be1 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5190,8 +5190,7 @@ forkchild(struct job *jp, union node *n, int mode)
 
closescript();
 
-   if (mode == FORK_NOJOB  /* is it `xxx` ? */
-&& n && n->type == NCMD/* is it single cmd? */
+   if (n && n->type == NCMD/* is it single cmd? */
/* && n->ncmd.args->type == NARG - always true? */
 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
@@ -5285,10 +5284,12 @@ forkchild(struct job *jp, union node *n, int mode)
) {
TRACE(("Job hack\n"));
/* "jobs": we do not want to clear job list for it,
-* instead we remove only _its_ own_ job from job list.
+* instead we remove only _its_ own_ job from job list
+* (if it has one).
 * This makes "jobs  | cat" more useful.
 */
-   freejob(curjob);
+   if (jp)
+   freejob(curjob);
return;
}
 #endif
@@ -6607,9 +6608,9 @@ evalbackcmd(union node *n, struct backcmd *result
 
if (pipe(pip) < 0)
ash_msg_and_raise_perror("can't create pipe");
-   /* process substitution uses NULL job/node, like openhere() */
+   /* process substitution uses NULL job, like openhere() */
jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL;
-   if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) {
+   if (forkshell(jp, n, FORK_NOJOB) == 0) {
/* child */
FORCE_INT_ON;
close(pip[ip]);
diff --git a/shell/ash_test/ash-signals/usage.right 
b/shell/ash_test/ash-signals/usage.right
index c0dbd6c3c..df1ed2dd7 100644
--- a/shell/ash_test/ash-signals/usage.right
+++ b/shell/ash_test/ash-signals/usage.right
@@ -6,6 +6,18 @@ trap -- 'a' INT
 trap -- 'a' USR1
 trap -- 'a' USR2
 ___
+trap -- 'a' EXIT trap -- 'a' INT trap -- 'a' USR1 trap -- 'a' USR2
+___
+trap -- 'a' EXIT
+trap -- 'a' INT
+trap -- 'a' USR1
+trap -- 'a' USR2
+___
+trap -- 'a' EXIT
+trap -- 'a' INT
+trap -- 'a' USR1
+trap -- 'a' USR2
+___
 ___
 trap -- 'a' USR1
 trap -- 'a' USR2
diff --git a/shell/ash_test/ash-signals/usage.tests 
b/shell/ash_test/ash-signals/usage.tests
index d29c6e74a..34e24cceb 100755
--- a/shell/ash_test/ash-signals/usage.tests
+++ b/shell/ash_test/ash-signals/usage.tests
@@ -10,6 +10,18 @@ trap "a" EXIT INT USR1 USR2
 echo ___
 trap
 
+# show them by command substitution
+echo ___
+echo $(trap)
+
+# show them by pipe
+echo ___
+trap | cat
+
+# show them by process substitution
+echo ___
+cat <(trap)
+
 # clear one
 echo ___
 trap 0 INT
-- 
2.39.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: make EPOCH variables work if RANDOM is disabled

2023-03-26 Thread Ron Yorston
Commit 1d37186fe2 (ash: add bash-compatible EPOCH variables) added
support for the EPOCHSECONDS and EPOCHREALTIME variables.

These variables are dynamic and therefore require the VDYNAMIC flag
to be non-zero.  However, this is only the case if support for the
RANDOM variable is enabled.

Give VDYNAMIC a non-zero value if either EPOCH variables or RANDOM
are enabled.

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shell/ash.c b/shell/ash.c
index 5f8c8ea19..559566b58 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2087,7 +2087,7 @@ struct localvar {
 #define VNOFUNC 0x40/* don't call the callback function */
 #define VNOSET  0x80/* do not set variable - just readonly test */
 #define VNOSAVE 0x100   /* when text is on the heap before setvareq */
-#if ENABLE_ASH_RANDOM_SUPPORT
+#if ENABLE_ASH_RANDOM_SUPPORT || BASH_EPOCH_VARS
 # define VDYNAMIC   0x200   /* dynamic variable */
 #else
 # define VDYNAMIC   0
-- 
2.39.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] lineedit: fix matching of directories when searching PATH

2023-03-24 Thread Ron Yorston
Commit 8baa643a3 (lineedit: match local directories when searching
PATH) included subdirectories of the current directory in the search
when tab-completing commands.

Unfortunately a short time later commit 1d180cd74 (lineedit: use
strncmp instead of is_prefixed_with (we know the length)) broke
this feature by returning an incorrect length for the array of paths.

Fix the length and reinstate matching of subdirectories.

Signed-off-by: Ron Yorston 
---
 libbb/lineedit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b942f540a..625884adf 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -825,8 +825,8 @@ static unsigned path_parse(char ***p)
res[npth++] = tmp;
}
/* special case: "match subdirectories of the current directory" */
-   /*res[npth++] = NULL; - filled by xzalloc() */
-   return npth;
+   /*res[npth] = NULL; - filled by xzalloc() */
+   return npth + 1;
 }
 
 /* Complete command, directory or file name.
-- 
2.39.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] fixdep: avoid underflow when end of entry doesn't coincide with EOF

2023-02-23 Thread Ron Yorston
Bernhard Reutner-Fischer wrote:
>Or, of course, just sit down and do a sweeping update
>to the current kconfig and bring forward the necessary busybox specific
>bits. Maybe someone volunteers to have a look?

Xabier Oneca posted an RFC patch set in 2021:

   http://lists.busybox.net/pipermail/busybox/2021-May/089589.html

I reviewed it in 2022 when it popped up in my inbox for some reason:

   http://lists.busybox.net/pipermail/busybox/2022-April/089597.html

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] build system: fix linking on Red Hat systems

2022-12-31 Thread Ron Yorston
Commit 77216c368 (Fix non-Linux builds) made linking with libresolv
conditional on the output of 'gcc -dumpmachine' containing 'gnu'.

This broke builds on Red Hat systems (Fedora, RHEL) and derivatives
(CentOS, Rocky).  Such systems report a machine type of the form
'x86_64-redhat-linux'.

Check for 'linux' as well as 'gnu'.

Signed-off-by: Ron Yorston 
---
 Makefile.flags | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Makefile.flags b/Makefile.flags
index 50137a78e..e484ab6c7 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -186,6 +186,8 @@ endif
 ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y)
 ifneq (,$(findstring gnu,$(shell $(CC) $(CFLAGS) -dumpmachine)))
 LDLIBS += resolv
+else ifneq (,$(findstring linux,$(shell $(CC) $(CFLAGS) -dumpmachine)))
+LDLIBS += resolv
 endif
 endif
 
-- 
2.38.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] shell: avoid segfault on ${0::0/0~09J}. Closes 15216

2022-12-29 Thread Ron Yorston
Both ash and hush segfault when asked to evaluate ${0::0/0~09J}.

The stack for integer values in the arithmetic code was too small:
'09J' results in three integers.  The leading zero starts an octal
number but '9' isn't an octal digit so '0', '9' and the variable
'Z' are placed on the stack.

Signed-off-by: Ron Yorston 
---
 shell/math.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/shell/math.c b/shell/math.c
index 76d22c9bd..83ef85c0c 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -588,7 +588,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
/* The proof that there can be no more than strlen(startbuf)/2+1
 * integers in any given correct or incorrect expression
 * is left as an exercise to the reader. */
-   var_or_num_t *const numstack = alloca((expr_len / 2) * 
sizeof(numstack[0]));
+   /* Counterexample: 09J results in three integers. */
+   var_or_num_t *const numstack = alloca((expr_len - 2) * 
sizeof(numstack[0]));
var_or_num_t *numstackptr = numstack;
/* Stack of operator tokens */
operator *const stack = alloca(expr_len * sizeof(stack[0]));
-- 
2.38.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] Fix non-Linux builds

2022-10-16 Thread Ron Yorston
Maling list thread prior to commit e3b1a1fd2:

   http://lists.busybox.net/pipermail/busybox/2011-February/074954.html

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] Fix non-Linux builds

2022-10-16 Thread Ron Yorston
Samuel Thibault wrote:
>Ron Yorston, le dim. 16 oct. 2022 08:36:21 +0100, a ecrit:
>> PLATFORM_LINUX was removed a couple of years ago by commit 5c69ad0ec
>> (build system: drop PLATFORM_LINUX).
>> 
>> It had very little effect back then, now it has none.
>
>Ah, so how would it have to be done nowadays?

I suppose it would mean going back to the situation prior to these
commits:

  4d06b3145  build system: no longer prompt for PLATFORM_LINUX option
  e3b1a1fd2  Replace "depends on PLATFORM_LINUX" with "select PLATFORM_LINUX"

where PLATFORM_LINUX was a user-selectable option and applets that were
deemed Linux specific depended on it.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] Fix non-Linux builds

2022-10-16 Thread Ron Yorston
PLATFORM_LINUX was removed a couple of years ago by commit 5c69ad0ec
(build system: drop PLATFORM_LINUX).

It had very little effect back then, now it has none.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] ash: make 'sleep' a builtin

2022-10-13 Thread Ron Yorston
shawnlandden wrote:
>The builtin is exiting ash in two cases:
>
>1.If no argument is given (also does not print usage of sleep, but ash---look 
>at how printf handles his)
>2.If xatou() interpretation of the number fails. This is a bit more involved 
>to fix, which is why I didn't send my patch for #1.

3. 'sleep' can be configured as both an applet and a shell builtin.
   In that case FEATURE_FANCY_SLEEP can be enabled.  This offers further
   opportunities for the builtin to call xfunc_die() and is even more
   involved to fix.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] xxd: avoid use of uninitialised variable

2022-09-28 Thread Ron Yorston
If xxd is run with '-r' but no '-s' the value of opt_s passed to
reverse() is uninitialised.

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

Signed-off-by: Ron Yorston 
---
 util-linux/hexdump_xxd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c
index 6629407de..049ed4395 100644
--- a/util-linux/hexdump_xxd.c
+++ b/util-linux/hexdump_xxd.c
@@ -229,7 +229,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
 {
char buf[80];
dumper_t *dumper;
-   char *opt_l, *opt_s, *opt_o;
+   char *opt_l, *opt_s = NULL, *opt_o;
unsigned bytes = 2;
unsigned cols = 0;
unsigned opt;
-- 
2.37.3

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: special treatment for aliases of test

2022-08-25 Thread Ron Yorston
Commit 5a9d2b6e0 (libbb: make '--help' handling more consistent)
broke the command "[ --help ]".  This should check that the string
is non-empty, not display help.

function old new   delta
show_usage_if_dash_dash_help  69  74  +5
--
(add/remove: 0/0 grow/shrink: 1/0 up/down: 5/0) Total: 5 bytes

Signed-off-by: Ron Yorston 
Reported-by: Harald van Dijk 
---
 applets/applet_tables.c | 4 
 libbb/appletlib.c   | 8 +++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 66ef7e4ac..923cb2a22 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -147,6 +147,10 @@ int main(int argc, char **argv)
for (i = 0; i < NUM_APPLETS; i++) {
if (str_isalnum_(applets[i].name))
printf("#define APPLET_NO_%s %d\n", applets[i].name, i);
+   else if (strcmp(applets[i].name, "[") == 0)
+   printf("#define APPLET_NO_test1 %d\n", i);
+   else if (strcmp(applets[i].name, "[[") == 0)
+   printf("#define APPLET_NO_test2 %d\n", i);
}
printf("\n");
 
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 9b9d7dbd6..a9901aa72 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -923,12 +923,18 @@ void FAST_FUNC show_usage_if_dash_dash_help(int 
applet_no, char **argv)
/* Special case. POSIX says "test --help"
 * should be no different from e.g. "test --foo".
 * Thus for "test", we skip --help check.
-* "true", "false", "echo" are also special.
+* "[", "[[", "true", "false", "echo" are also special.
 */
if (1
 #  if defined APPLET_NO_test
 && applet_no != APPLET_NO_test
 #  endif
+#  if defined APPLET_NO_test1
+&& applet_no != APPLET_NO_test1
+#  endif
+#  if defined APPLET_NO_test2
+&& applet_no != APPLET_NO_test2
+#  endif
 #  if defined APPLET_NO_true
 && applet_no != APPLET_NO_true
 #  endif
-- 
2.37.2

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] lineedit: get PWD from ash

2022-06-28 Thread Ron Yorston
The line editing code and ash disagree when the current directory
is changed to a symbolic link:

   ~ $ mkdir real
   ~ $ ln -s real link
   ~ $ cd link
   ~/real $ pwd
   /home/rmyf36/link

Note the prompt says we're in ~/real.  Bash does:

   [rmy@random ~]$ cd link
   [rmy@random link]$ pwd
   /home/rmyf36/link

Ash uses the name supplied by the user while the line editing code
calls getcwd(3).  The discrepancy can be avoided by fetching the
value of PWD from ash.

Hush (incorrectly?) calls getcwd(3) when the directory is changed
so there's no disagreement with the line editing code.

function old new   delta
parse_and_put_prompt 921 904 -17

Signed-off-by: Ron Yorston 
---
 libbb/lineedit.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b685399f9..27b5ef30e 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2035,7 +2035,13 @@ static void parse_and_put_prompt(const char *prmt_ptr)
case 'W': /* basename of cur dir */
if (!cwd_buf) {
const char *home;
+#if ENABLE_SHELL_ASH
+   cwd_buf = state->sh_get_var ?
+   
xstrdup(state->sh_get_var("PWD")) :
+   
xrealloc_getcwd_or_warn(NULL);
+#else
cwd_buf = 
xrealloc_getcwd_or_warn(NULL);
+#endif
if (!cwd_buf)
cwd_buf = (char 
*)bb_msg_unknown;
else if ((home = 
get_homedir_or_NULL()) != NULL && home[0]) {
-- 
2.36.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: make '--help' handling more consistent

2022-05-01 Thread Ron Yorston
Running an applet with '--help' as its only argument is treated
as a special case.  If additional arguments follow '--help' the
behaviour is inconsistent:

- applets which call single_argv() print help and do nothing else;

- applets which call getopt() report "unrecognized option '--help'"
  and print help anyway;

- expr says "expr: syntax error" and doesn't print help;

- printenv silently ignores '--help', prints any other variables
  and doesn't print help;

- realpath says "--help: No such file or directory", prints the path
  of any other files and doesn't print help.

If the first argument is '--help' ignore any other arguments and print
help.  This is more consistent and most likely what the user wanted.

See also commit 6bdfbc4cb (libbb: fix '--help' handling in
FEATURE_SH_NOFORK=y).

function old new   delta
show_usage_if_dash_dash_help  75  69  -6
------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-6)   Total: -6 bytes

Signed-off-by: Ron Yorston 
---
 libbb/appletlib.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 841b3b873..d56b5b409 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -258,7 +258,6 @@ void lbb_prepare(const char *applet
/* Redundant for busybox (run_applet_and_exit covers that case)
 * but needed for "individual applet" mode */
if (argv[1]
-&& !argv[2]
 && strcmp(argv[1], "--help") == 0
 && !is_prefixed_with(applet, "busybox")
) {
@@ -940,8 +939,8 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no, 
char **argv)
 && applet_no != APPLET_NO_echo
 #  endif
) {
-   if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) {
-   /* Make "foo --help" exit with 0: */
+   if (argv[1] && strcmp(argv[1], "--help") == 0) {
+   /* Make "foo --help [...]" exit with 0: */
xfunc_error_retval = 0;
bb_show_usage();
}
-- 
2.35.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: avoid some redirection oddities

2022-04-26 Thread Ron Yorston
A user reports:

   I know this code is wrong but it shouldn't cause the shell to exit:
   echo text >&
   This instead cause the creation of a file:
   echo text >&99

   I think it would be better if they report Bad file descriptor

The first case happens because save_fd_on_redirect() causes an exit
when dup_CLOEXEC() returns any error other than EBADF.  Despite its
name dup_CLOEXEC() actually uses fcntl(2) which returns EINVAL when
the file descriptor is greater than the maximum allowed.

The second case is due to any numeric string longer than nine digits
being treated as a file name rather than a number.  Bash doesn't
do this.

Treat a numeric string of any length as a number and limit the
range of valid file descriptors to the maximum determined by
calling getrlimit(2).

function old new   delta
fixredir   - 174+174
readtoken1  30593069 +10
.rodata99930   99916 -14
isdigit_str9  45   - -45
expredir 225 177 -48
parsefname   206 157 -49
--
(add/remove: 1/1 grow/shrink: 1/3 up/down: 184/-156)   Total: 28 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index ef4a47afe..31ad03e47 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -535,10 +535,9 @@ static void trace_vprintf(const char *fmt, va_list va);
 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 
 static int
-isdigit_str9(const char *str)
+isdigit_str(const char *str)
 {
-   int maxlen = 9 + 1; /* max 9 digits: 9 */
-   while (--maxlen && isdigit(*str))
+   while (isdigit(*str))
str++;
return (*str == '\0');
 }
@@ -9635,7 +9634,7 @@ expredir(union node *n)
if (fn.list == NULL)
ash_msg_and_raise_error("redir error");
 #if BASH_REDIR_OUTPUT
-   if (!isdigit_str9(fn.list->text)) {
+   if (!isdigit_str(fn.list->text)) {
/* >&file, not >&fd */
if (redir->nfile.fd != 1) /* 123>&file 
- BAD */
ash_msg_and_raise_error("redir 
error");
@@ -11945,19 +11944,21 @@ static void
 fixredir(union node *n, const char *text, int err)
 {
int fd;
+   struct rlimit limit;
 
TRACE(("Fix redir %s %d\n", text, err));
if (!err)
n->ndup.vname = NULL;
 
+   getrlimit(RLIMIT_NOFILE, &limit);
fd = bb_strtou(text, NULL, 10);
-   if (!errno && fd >= 0)
+   if (!errno && fd >= 0 && fd < limit.rlim_cur - 1)
n->ndup.dupfd = fd;
else if (LONE_DASH(text))
n->ndup.dupfd = -1;
else {
if (err)
-   raise_error_syntax("bad fd number");
+   raise_error_syntax(strerror(EBADF));
n->ndup.vname = makename();
}
 }
@@ -12640,7 +12641,7 @@ readtoken1(int c, int syntax, char *eofmark, int 
striptabs)
if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + 
'>'))
 && quotef == 0
) {
-   if (isdigit_str9(out)) {
+   if (isdigit_str(out)) {
PARSEREDIR(); /* passed as params: out, c */
lasttoken = TREDIR;
return lasttoken;
-- 
2.35.1
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH v9] seedrng: import SeedRNG utility for kernel RNG seed files

2022-04-21 Thread Ron Yorston
Jason A. Donenfeld wrote:
>Oh interesting. I wonder what's different about your
>config/compiler... I guess that means we can change the menuconfig
>entry to say (1.8k) instead.

My understanding is that the applet sizes reported in config are
to be generated by running the make_single_applets.sh and
size_single_applets.sh scripts.

Bloatcheck tells us the incremental cost of the patch versus a fully
configured build whereas the scripts report the cost of creating a
single-applet binary relative to the minimum possible single-applet
binary.  The latter cost will be (roughly) the size reported by
bloatcheck plus any dependent code it pulls in beyond that required
by the minimal applet.

For current git on my system I get "seedrng (8.3 kb)".

The comments in size_single_applets.sh say that a 32-bit build should
be used:

   # CONFIG_STATIC is not set
   CONFIG_CROSS_COMPILER_PREFIX=""
   CONFIG_EXTRA_CFLAGS="-m32"
   CONFIG_EXTRA_LDFLAGS="-m32"

However, this configuration failed to link due to problems with the
recent hardware accelerated SHA1/SHA256 code.  So I edited the config
to include:

   # CONFIG_SHA1_HWACCEL is not set
   # CONFIG_SHA256_HWACCEL is not set

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: restore special handling of nomsg errors

2022-04-21 Thread Ron Yorston
The functions bb_perror_nomsg() and bb_perror_nomsg_and_die() are
used to print error messages where no specific information is
available.  For example:

   $ busybox mktemp -p /
   mktemp: (null): Permission denied

mktemp(3) doesn't tell us the name of the file it tried to create.

However, printing '(null)' is a regression introduced by commit
6937487be (libbb: reduce the overhead of single parameter bb_error_msg()
calls).  Restore the previous behaviour by reverting the changes to
the two functions mentioned:

   $ busybox mktemp -p /
   mktemp: Permission denied

function old new   delta
bb_perror_nomsg_and_die7  14  +7
bb_perror_nomsg7  14  +7
--
(add/remove: 0/0 grow/shrink: 2/0 up/down: 14/0)   Total: 14 bytes

Signed-off-by: Ron Yorston 
---
 libbb/perror_nomsg.c | 4 ++--
 libbb/perror_nomsg_and_die.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libbb/perror_nomsg.c b/libbb/perror_nomsg.c
index d7d53de44..a2a11cc8e 100644
--- a/libbb/perror_nomsg.c
+++ b/libbb/perror_nomsg.c
@@ -12,11 +12,11 @@
  * instead of including libbb.h */
 //#include "libbb.h"
 #include "platform.h"
-extern void bb_simple_perror_msg(const char *s) FAST_FUNC;
+extern void bb_perror_msg(const char *s, ...) FAST_FUNC;
 
 /* suppress gcc "no previous prototype" warning */
 void FAST_FUNC bb_perror_nomsg(void);
 void FAST_FUNC bb_perror_nomsg(void)
 {
-   bb_simple_perror_msg(0);
+   bb_perror_msg(0);
 }
diff --git a/libbb/perror_nomsg_and_die.c b/libbb/perror_nomsg_and_die.c
index bea5f25a5..543ff5178 100644
--- a/libbb/perror_nomsg_and_die.c
+++ b/libbb/perror_nomsg_and_die.c
@@ -12,11 +12,11 @@
  * instead of including libbb.h */
 //#include "libbb.h"
 #include "platform.h"
-extern void bb_simple_perror_msg_and_die(const char *s) FAST_FUNC;
+extern void bb_perror_msg_and_die(const char *s, ...) FAST_FUNC;
 
 /* suppress gcc "no previous prototype" warning */
 void FAST_FUNC bb_perror_nomsg_and_die(void);
 void FAST_FUNC bb_perror_nomsg_and_die(void)
 {
-   bb_simple_perror_msg_and_die(0);
+   bb_perror_msg_and_die(0);
 }
-- 
2.35.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: fix backspace over tab in commands

2022-04-20 Thread Ron Yorston
Colon and search commands are entered on the status line.  Since
the cursor position wasn't being tracked backspacing over a tab
resulted in a mismatch between the actual and apparent content
of the command.

function old new   delta
get_input_line   178 180  +2
--
(add/remove: 0/0 grow/shrink: 1/0 up/down: 2/0) Total: 2 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/editors/vi.c b/editors/vi.c
index 4257c0fdc..6fa0a4e18 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -1217,10 +1217,11 @@ static char *get_input_line(const char *prompt)
break;  // this is end of input
if (isbackspace(c)) {
// user wants to erase prev char
-   write1("\b \b"); // erase char on screen
buf[--i] = '\0';
+   go_bottom_and_clear_to_eol();
if (i <= 0) // user backs up before b-o-l, exit
break;
+   write1(buf);
} else if (c > 0 && c < 256) { // exclude Unicode
// (TODO: need to handle Unicode)
buf[i] = c;
-- 
2.35.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [RFC PATCH SET] build system: update kconfig to bring new features and fixes

2022-04-15 Thread Ron Yorston
It's probably worth pointing out the patches are nearly a year old.
I started from BusyBox commit 972e29881, otherwise there were problems
applying them.

Not to make it too easy for myself, though, I was working on the BusyBox
port to Microsoft Windows which I maintain[1].  Naturally this has many
tweaks to the build system.

The first three patches went in just fine.  The last two required careful
shepherding but got there in the end.  Cross compiling for Windows on
Linux worked fine, as did a POSIX build on Linux.  I haven't tried a
native compilation on Windows yet.

On the whole, this was less troublesome than I expected.

Cheers,

Ron
---
[1] https://frippery.org/busybox
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] Added miscutil/tree.c

2022-04-12 Thread Ron Yorston
Roger Knecht wrote:
>+//usage:#define tree_trivial_usage NOUSAGE_STR
>+//usage:#define tree_full_usage ""
>+
>+//usage:#define find_trivial_usage
>+//usage:   "[PATH]"
>+//usage:#define find_full_usage "\n\n"
>+//usage:   "Print files and directories in a tree structure."
>+//usage:   "Defaults: PATH is current directory\n"

This redefines the help text for the 'find' applet (and invalidates
the bloatcheck results).

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH v2] ash,hush: use HOME for tab completion and prompts

2022-03-24 Thread Ron Yorston
ash and hush correctly use the value of HOME for tilde expansion.
However the line editing code in libbb obtains the user's home
directory by calling getpwuid().  Thus tildes in tab completion
and prompts may be interpreted differently than in tilde expansion.

When the line editing code is invoked from a shell make it use the
shell's interpretation of tilde.  This is similar to how GNU readline
and bash collaborate.

function old new   delta
get_homedir_or_NULL   29  72 +43
optschanged  119 126  +7
hush_main   12041211  +7
--
(add/remove: 0/0 grow/shrink: 3/0 up/down: 57/0)   Total: 57 bytes

v2: Always check for HOME before trying the password database:  this
is what GNU readline does.

Signed-off-by: Ron Yorston 
---
 include/libbb.h  | 11 +++
 libbb/lineedit.c | 12 +++-
 shell/ash.c  |  7 +++
 shell/hush.c |  5 ++---
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 6aeec249d..abbc9ac59 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1924,6 +1924,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC;
 #  define MAX_HISTORY 0
 # endif
 typedef const char *get_exe_name_t(int i) FAST_FUNC;
+typedef const char *sh_get_var_t(const char *name) FAST_FUNC;
 typedef struct line_input_t {
int flags;
int timeout;
@@ -1937,9 +1938,8 @@ typedef struct line_input_t {
 #  if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
/* function to fetch additional application-specific names to match */
get_exe_name_t *get_exe_name;
-#   define EDITING_HAS_get_exe_name 1
-#  else
-#   define EDITING_HAS_get_exe_name 0
+   /* function to fetch value of shell variable */
+   sh_get_var_t *sh_get_var;
 #  endif
 # endif
 # if MAX_HISTORY
@@ -1993,11 +1993,6 @@ int read_line_input(const char* prompt, char* command, 
int maxsize) FAST_FUNC;
read_line_input(prompt, command, maxsize)
 #endif
 
-#ifndef EDITING_HAS_get_exe_name
-# define EDITING_HAS_get_exe_name 0
-#endif
-
-
 #ifndef COMM_LEN
 # ifdef TASK_COMM_LEN
 enum { COMM_LEN = TASK_COMM_LEN };
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 82624757e..fd9377327 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -259,6 +259,16 @@ static const char *get_username_str(void)
 
 static NOINLINE const char *get_homedir_or_NULL(void)
 {
+   const char *home;
+
+#if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
+   home = state->sh_get_var ? state->sh_get_var("HOME") : getenv("HOME");
+#else
+   home = getenv("HOME");
+#endif
+   if (home != NULL && home[0] != '\0')
+   return home;
+
if (!got_user_strings)
get_user_strings();
return home_pwd_buf;
@@ -861,7 +871,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char 
*command, int type)
continue;
}
 # endif
-# if EDITING_HAS_get_exe_name
+# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
if (state->get_exe_name) {
i = 0;
for (;;) {
diff --git a/shell/ash.c b/shell/ash.c
index ef4a47afe..d29de37b7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9720,7 +9720,7 @@ evalpipe(union node *n, int flags)
 }
 
 /* setinteractive needs this forward reference */
-#if EDITING_HAS_get_exe_name
+#if ENABLE_FEATURE_EDITING
 static const char *get_builtin_name(int i) FAST_FUNC;
 #endif
 
@@ -9757,9 +9757,8 @@ setinteractive(int on)
 #if ENABLE_FEATURE_EDITING
if (!line_input_state) {
line_input_state = new_line_input_t(FOR_SHELL | 
WITH_PATH_LOOKUP);
-# if EDITING_HAS_get_exe_name
line_input_state->get_exe_name = get_builtin_name;
-# endif
+   line_input_state->sh_get_var = lookupvar;
}
 #endif
}
@@ -10262,7 +10261,7 @@ find_builtin(const char *name)
return bp;
 }
 
-#if EDITING_HAS_get_exe_name
+#if ENABLE_FEATURE_EDITING
 static const char * FAST_FUNC
 get_builtin_name(int i)
 {
diff --git a/shell/hush.c b/shell/hush.c
index ae81f0da5..051b123e7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8188,7 +8188,7 @@ static const struct built_in_command *find_builtin(const 
char *name)
return find_builtin_helper(name, bltins2, 
&bltins2[ARRAY_SIZE(bltins2)]);
 }
 
-#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
+#if ENABLE_HUSH_JOB && ENABLE_FEATURE_EDITING
 static const char * FAST_FUNC get_builtin_name(int i)
 {
if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
@@ -10668,9 +10668,8 @@ int hush_main(int argc, char **argv)
 
 # if ENABLE_FEATUR

[PATCH] ash,hush: use HOME for tab completion and prompts

2022-03-22 Thread Ron Yorston
ash and hush correctly use the value of HOME for tilde expansion.
However the line editing code in libbb obtains the user's home
directory by calling getpwuid().  Thus tildes in tab completion
and prompts may be interpreted differently than in tilde expansion.

When the line editing code is invoked from a shell make it use the
shell's interpretation of tilde.  This is similar to how GNU readline
and bash collaborate.

function old new   delta
get_homedir_or_NULL   29  56 +27
optschanged  119 126  +7
hush_main   12041211  +7
--
(add/remove: 0/0 grow/shrink: 3/0 up/down: 41/0)   Total: 41 bytes

Signed-off-by: Ron Yorston 
---
 include/libbb.h  | 11 +++
 libbb/lineedit.c | 10 +-
 shell/ash.c  |  7 +++
 shell/hush.c |  5 ++---
 4 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 6aeec249d..abbc9ac59 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1924,6 +1924,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC;
 #  define MAX_HISTORY 0
 # endif
 typedef const char *get_exe_name_t(int i) FAST_FUNC;
+typedef const char *sh_get_var_t(const char *name) FAST_FUNC;
 typedef struct line_input_t {
int flags;
int timeout;
@@ -1937,9 +1938,8 @@ typedef struct line_input_t {
 #  if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
/* function to fetch additional application-specific names to match */
get_exe_name_t *get_exe_name;
-#   define EDITING_HAS_get_exe_name 1
-#  else
-#   define EDITING_HAS_get_exe_name 0
+   /* function to fetch value of shell variable */
+   sh_get_var_t *sh_get_var;
 #  endif
 # endif
 # if MAX_HISTORY
@@ -1993,11 +1993,6 @@ int read_line_input(const char* prompt, char* command, 
int maxsize) FAST_FUNC;
read_line_input(prompt, command, maxsize)
 #endif
 
-#ifndef EDITING_HAS_get_exe_name
-# define EDITING_HAS_get_exe_name 0
-#endif
-
-
 #ifndef COMM_LEN
 # ifdef TASK_COMM_LEN
 enum { COMM_LEN = TASK_COMM_LEN };
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 82624757e..2d991faa2 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -261,6 +261,14 @@ static NOINLINE const char *get_homedir_or_NULL(void)
 {
if (!got_user_strings)
get_user_strings();
+#if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
+   if (state->sh_get_var) {
+   const char *home = state->sh_get_var("HOME");
+   if (home != NULL && home[0] != '\0') {
+   return home;
+   }
+   }
+#endif
return home_pwd_buf;
 }
 #endif
@@ -861,7 +869,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char 
*command, int type)
continue;
}
 # endif
-# if EDITING_HAS_get_exe_name
+# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
if (state->get_exe_name) {
i = 0;
for (;;) {
diff --git a/shell/ash.c b/shell/ash.c
index ef4a47afe..d29de37b7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9720,7 +9720,7 @@ evalpipe(union node *n, int flags)
 }
 
 /* setinteractive needs this forward reference */
-#if EDITING_HAS_get_exe_name
+#if ENABLE_FEATURE_EDITING
 static const char *get_builtin_name(int i) FAST_FUNC;
 #endif
 
@@ -9757,9 +9757,8 @@ setinteractive(int on)
 #if ENABLE_FEATURE_EDITING
if (!line_input_state) {
line_input_state = new_line_input_t(FOR_SHELL | 
WITH_PATH_LOOKUP);
-# if EDITING_HAS_get_exe_name
line_input_state->get_exe_name = get_builtin_name;
-# endif
+   line_input_state->sh_get_var = lookupvar;
}
 #endif
}
@@ -10262,7 +10261,7 @@ find_builtin(const char *name)
return bp;
 }
 
-#if EDITING_HAS_get_exe_name
+#if ENABLE_FEATURE_EDITING
 static const char * FAST_FUNC
 get_builtin_name(int i)
 {
diff --git a/shell/hush.c b/shell/hush.c
index ae81f0da5..051b123e7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8188,7 +8188,7 @@ static const struct built_in_command *find_builtin(const 
char *name)
return find_builtin_helper(name, bltins2, 
&bltins2[ARRAY_SIZE(bltins2)]);
 }
 
-#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
+#if ENABLE_HUSH_JOB && ENABLE_FEATURE_EDITING
 static const char * FAST_FUNC get_builtin_name(int i)
 {
if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
@@ -10668,9 +10668,8 @@ int hush_main(int argc, char **argv)
 
 # if ENABLE_FEATURE_EDITING
G.line_input_state = new_line_input_t(FOR_SHELL);
-#  if EDITING_HAS_get_exe_name
G.line_input_state->

[PATCH 2/2] vi: handle autoindent in 'cc' command

2022-03-18 Thread Ron Yorston
When the 'cc' command is invoked with autoindent enabled it
should use the indent of the first line being changed.

The size of the indent has to be established before char_insert()
is called as the lines being changed are deleted.  Introduce a
new global variable, newindent, to handle this.  The indentcol
global is now effectively a static variable in char_insert().

function old new   delta
do_cmd  42474308 +61
vi_main  416 422  +6
char_insert  891 875 -16
--
(add/remove: 0/0 grow/shrink: 2/1 up/down: 67/-16) Total: 51 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 71 ++--
 1 file changed, 47 insertions(+), 24 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index e63ca60d4..6edff0b5a 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -380,7 +380,9 @@ struct globals {
char *last_search_pattern; // last pattern from a '/' or '?' search
 #endif
 #if ENABLE_FEATURE_VI_SETOPTS
-   int indentcol;  // column of recently autoindent, 0 or -1
+   int char_insert__indentcol; // column of recent autoindent 
or 0
+   int newindent;  // autoindent value for 'O'/'cc' commands
+   // or -1 to use indent from 
previous line
 #endif
smallint cmd_error;
 
@@ -507,7 +509,8 @@ struct globals {
 #define ioq_start   (G.ioq_start  )
 #define dotcnt  (G.dotcnt )
 #define last_search_pattern (G.last_search_pattern)
-#define indentcol   (G.indentcol  )
+#define char_insert__indentcol  (G.char_insert__indentcol)
+#define newindent   (G.newindent  )
 #define cmd_error   (G.cmd_error  )
 
 #define edit_file__cur_line (G.edit_file__cur_line)
@@ -540,10 +543,11 @@ struct globals {
 
 #define INIT_G() do { \
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
-   last_modified_count = -1; \
+   last_modified_count--; \
/* "" but has space for 2 chars: */ \
IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \
tabstop = 8; \
+   IF_FEATURE_VI_SETOPTS(newindent--;) \
 } while (0)
 
 #if ENABLE_FEATURE_VI_CRASHME
@@ -2112,6 +2116,7 @@ static size_t indent_len(char *p)
 static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
 {
 #if ENABLE_FEATURE_VI_SETOPTS
+# define indentcol char_insert__indentcol
size_t len;
int col, ntab, nspc;
 #endif
@@ -2140,7 +2145,8 @@ static char *char_insert(char *p, char c, int undo) // 
insert the char c at 'p'
 #if ENABLE_FEATURE_VI_SETOPTS
if (autoindent) {
len = indent_len(bol);
-   if (len && get_column(bol + len) == indentcol && 
bol[len] == '\n') {
+   col = get_column(bol + len);
+   if (len && col == indentcol && bol[len] == '\n') {
// remove autoindent from otherwise empty line
text_hole_delete(bol, bol + len - 1, undo);
p = bol;
@@ -2209,26 +2215,30 @@ static char *char_insert(char *p, char c, int undo) // 
insert the char c at 'p'
showmatching(p - 1);
}
if (autoindent && c == '\n') {  // auto indent the new line
-   // use indent of current/previous line
-   bol = indentcol < 0 ? p : prev_line(p);
-   len = indent_len(bol);
-   col = get_column(bol + len);
-
-   if (len && col == indentcol) {
-   // previous line was empty except for autoindent
-   // move the indent to the current line
-   memmove(bol + 1, bol, len);
-   *bol = '\n';
-   return p;
+   if (newindent < 0) {
+   // use indent of previous line
+   bol = prev_line(p);
+   len = indent_len(bol);
+   col = get_column(bol + len);
+
+   if (len && col == indentcol) {
+   // previous line was empty except for 
autoindent
+   // move the indent to the current line
+   mem

[PATCH 1/2] vi: fix regression in autoindent handling

2022-03-18 Thread Ron Yorston
Suppose autoindent is enabled and we have a line with an initial
tab where we want to split the words onto separate lines:

split the words

One way to do this is with the sequence 'f r;r', but in
BusyBox vi the result is:

split

he
words

This is a regression introduced by commit 9659a8db1 (vi: remove
autoindent from otherwise empty lines).  The amount of indentation
is being recorded when the 'r' command inserts a newline but
isn't subsequently reset.  A fix is to only record the indent
when in insert or replace mode.  Proper handling of the 'o' and
'O' commands then requires them to switch to insert mode before
calling char_insert() to insert a newline.

function old new   delta
char_insert  884 891  +7
do_cmd  42434247  +4
--
(add/remove: 0/0 grow/shrink: 2/0 up/down: 11/0)           Total: 11 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/editors/vi.c b/editors/vi.c
index 4257c0fdc..e63ca60d4 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2226,7 +2226,10 @@ static char *char_insert(char *p, char c, int undo) // 
insert the char c at 'p'
p--;// open above, indent before newly 
inserted NL
 
if (len) {
-   indentcol = col;
+   // only record indent if in insert/replace mode 
or for
+   // the 'o'/'O' commands, which are switched to 
insert
+   // mode early.
+   indentcol = cmd_mode != 0 ? col : 0;
if (expandtab) {
ntab = 0;
nspc = col;
@@ -4264,6 +4267,9 @@ static void do_cmd(int c)
case 'o':   // o- open an empty line below
dot_end();
  dc3:
+#if ENABLE_FEATURE_VI_SETOPTS
+   cmd_mode = 1;   // switch to insert mode early
+#endif
dot = char_insert(dot, '\n', ALLOW_UNDO);
if (c == 'O' && !autoindent) {
// done in char_insert() for 'O'+autoindent
-- 
2.35.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 0/2] vi: autoindent fixes

2022-03-18 Thread Ron Yorston
Still dogfooding BusyBox vi I happened upon a regression in autoindent.
While investigating that I also found that the 'cc' command didn't
handle autoindent properly.

Fixes follow.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: improved handling of backspace in replace mode

2022-03-03 Thread Ron Yorston
In replace mode ('R' command) the backspace character should get
special treatment:

- backspace only goes back to the start of the replacement;
- backspacing over replaced characters restores the original text.

Prior to this commit BusyBox vi deleted the characters both before
and after the cursor in replace mode.

function old new   delta
undo_pop   - 235+235
char_insert  858 884 +26
indicate_error81  84  +3
find_range   654 657  +3
static.text_yank  77  79  +2
do_cmd  44864243-243
--
(add/remove: 1/0 grow/shrink: 4/1 up/down: 269/-243)   Total: 26 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 24 ++--
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index d37cd48a3..4257c0fdc 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -224,6 +224,7 @@
 
 #endif
 
+#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 
127)
 
 enum {
MAX_TABSTOP = 32, // sanity limit
@@ -342,6 +343,7 @@ struct globals {
int last_modified_count; // = -1;
int cmdline_filecnt; // how many file names on cmd line
int cmdcnt;  // repetition count
+   char *rstart;// start of text in Replace mode
unsigned rows, columns;  // the terminal screen is this size
 #if ENABLE_FEATURE_VI_ASK_TERMINAL
int get_rowcol_error;
@@ -474,6 +476,7 @@ struct globals {
 #define last_modified_count (G.last_modified_count)
 #define cmdline_filecnt (G.cmdline_filecnt)
 #define cmdcnt  (G.cmdcnt )
+#define rstart  (G.rstart )
 #define rows(G.rows   )
 #define columns (G.columns)
 #define crow(G.crow   )
@@ -1212,7 +1215,7 @@ static char *get_input_line(const char *prompt)
c = get_one_char();
if (c == '\n' || c == '\r' || c == 27)
break;  // this is end of input
-   if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) {
+   if (isbackspace(c)) {
// user wants to erase prev char
write1("\b \b"); // erase char on screen
buf[--i] = '\0';
@@ -2174,8 +2177,16 @@ static char *char_insert(char *p, char c, int undo) // 
insert the char c at 'p'
p += 1 + stupid_insert(p, ' ');
}
 #endif
-   } else if (c == term_orig.c_cc[VERASE] || c == 8 || c == 127) { // Is 
this a BS
-   if (p > text) {
+   } else if (isbackspace(c)) {
+   if (cmd_mode == 2) {
+   // special treatment for backspace in Replace mode
+   if (p > rstart) {
+   p--;
+#if ENABLE_FEATURE_VI_UNDO
+   undo_pop();
+#endif
+   }
+   } else if (p > text) {
p--;
p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED);  // 
shrink buffer 1 char
}
@@ -3703,9 +3714,9 @@ static void do_cmd(int c)
undo_queue_commit();
} else {
if (1 <= c || Isprint(c)) {
-   if (c != 27)
-   dot = yank_delete(dot, dot, PARTIAL, 
YANKDEL, ALLOW_UNDO);  // delete char
-   dot = char_insert(dot, c, ALLOW_UNDO_CHAIN);
// insert new char
+   if (c != 27 && !isbackspace(c))
+   dot = yank_delete(dot, dot, PARTIAL, 
YANKDEL, ALLOW_UNDO);
+   dot = char_insert(dot, c, ALLOW_UNDO_CHAIN);
}
goto dc1;
}
@@ -4264,6 +4275,7 @@ static void do_cmd(int c)
  dc5:
cmd_mode = 2;
undo_queue_commit();
+   rstart = dot;
break;
case KEYCODE_DELETE:
if (dot < end - 1)
-- 
2.35.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] cpio: code shrink

2022-02-10 Thread Ron Yorston
Use a generic llist_t to store the names of hardlinked files.

function old new   delta
cpio_o  11401122 -18

Signed-off-by: Ron Yorston 
---
 archival/cpio.c | 18 --
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/archival/cpio.c b/archival/cpio.c
index 7149782d7..836609fc3 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -223,13 +223,9 @@ static off_t cpio_pad4(off_t size)
  * It's ok to exit instead of return. */
 static NOINLINE int cpio_o(void)
 {
-   struct name_s {
-   struct name_s *next;
-   char name[1];
-   };
struct inodes_s {
struct inodes_s *next;
-   struct name_s *names;
+   llist_t *names;
struct stat st;
 #if ENABLE_FEATURE_CPIO_RENUMBER_INODES
ino_t mapped_inode;
@@ -277,7 +273,6 @@ static NOINLINE int cpio_o(void)
 
/* Store hardlinks for later processing, dont output 
them */
if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
-   struct name_s *n;
struct inodes_s *l;
 
/* Do we have this hardlink remembered? */
@@ -302,11 +297,7 @@ static NOINLINE int cpio_o(void)
l = l->next;
}
/* Add new name to "l->names" list */
-   n = xmalloc(sizeof(*n) + strlen(name));
-   strcpy(n->name, name);
-   n->next = l->names;
-   l->names = n;
-
+   llist_add_to(&l->names, xstrdup(name));
free(line);
continue;
}
@@ -320,8 +311,7 @@ static NOINLINE int cpio_o(void)
if (links) {
/* Output hardlink's data */
st = links->st;
-   name = links->names->name;
-   links->names = links->names->next;
+   name = llist_pop(&links->names);
 #if ENABLE_FEATURE_CPIO_RENUMBER_INODES
if (links->mapped_inode)
st.st_ino = links->mapped_inode;
@@ -332,7 +322,7 @@ static NOINLINE int cpio_o(void)
links = links->next;
else
st.st_size = 0;
-   /* NB: we leak links->names and/or links,
+   /* NB: we leak links->names->name and/or links,
 * this is intended (we exit soon anyway) */
} else {
/* If no (more) hardlinks to output,
-- 
2.34.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] printf: allow 0 as a flag and allow multiple flags

2021-12-19 Thread Ron Yorston
David Laight wrote:
>Or:
>   tmp = strspn(f, "-+ #0");
>   direc_length += tmp - f;
>   f = tmp;

Yes, that seems to work too, and it saves 28 bytes.  Though since
strspn() returns the length of the initial segment it needs to be:

   size_t tmp;
   ...
   tmp = strspn(f, "-+ #0"); 
   direc_length += tmp; 
   f += tmp;

>Except that I'd have thought it would need to remember which flags are set.

They're retained in the format string which is pointed to by direc_start.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] printf: allow 0 as a flag and allow multiple flags

2021-12-16 Thread Ron Yorston
The '%' character in a format specification may be followed by
one or more flags from the list "+- #0".  BusyBox printf didn't
support the '0' flag or allow multiple flags to be provided.
As a result the formats '%0*d' and '%0 d' were considered to be
invalid.

The lack of support for '0' was pointed out by Andrew Snyder on the
musl mailing list:

   https://www.openwall.com/lists/musl/2021/12/14/2

function old new   delta
printf_main  860 891 +31
.rodata99281   99282  +1
--
(add/remove: 0/0 grow/shrink: 2/0 up/down: 32/0)   Total: 32 bytes

Signed-off-by: Ron Yorston 
---
 coreutils/printf.c |  8 +---
 testsuite/printf.tests | 10 ++
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/coreutils/printf.c b/coreutils/printf.c
index dd94c8ade..e5cf5f942 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -313,9 +313,11 @@ static char **print_formatted(char *f, char **argv, int 
*conv_err)
}
break;
}
-   if (*f && strchr("-+ #", *f)) {
-   ++f;
-   ++direc_length;
+   if (*f) {
+   while (strchr("-+ #0", *f)) {
+   ++f;
+   ++direc_length;
+   }
}
if (*f == '*') {
++f;
diff --git a/testsuite/printf.tests b/testsuite/printf.tests
index 050edef71..728bbf4bf 100755
--- a/testsuite/printf.tests
+++ b/testsuite/printf.tests
@@ -143,4 +143,14 @@ testing "printf aborts on %r" \
"printf: %r: invalid format\n""1\n" \
"" ""
 
+testing "printf treats leading 0 as flag" \
+   "${bb}printf '%0*d\n' 2 1 2>&1; echo \$?" \
+   "01\n""0\n" \
+   "" ""
+
+testing "printf handles multiple flags" \
+   "${bb}printf '%0 d\n' 2 2>&1; echo \$?" \
+   " 2\n""0\n" \
+   "" ""
+
 exit $FAILCOUNT
-- 
2.33.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] wget: implement --post-file

2021-10-01 Thread Ron Yorston
Denys wrote:
>>  #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_WGET_LONG_OPTIONS
>> free(G.extra_headers);
>> +   free(G.post_data);
>> +   free(G.post_file);
>
>
>This is wrong, isn't it? G.post_file is not malloced.
>G.post_data is not always allocated.

Yes, it's wrong.  Sorry.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] wget: implement --post-file

2021-09-28 Thread Ron Yorston
Add the --post-file option to send form data from a file.  As with
--post-data it's up to the user to ensure that the data is encoded
as appropriate:  all wget does is stuff the provided data into
the request.

The --post-data and --post-file options are mutually exclusive and
only one instance of either may be given.

Additionally:

- update the usage message to include missing details of the --post-data
  and --header options;

- free POST data if FEATURE_CLEAN_UP is enabled.

function old new   delta
packed_usage   34158   34214 +56
wget_main   27622805 +43
.rodata99225   99240 +15
static.wget_longopts 266 278 +12
--
(add/remove: 0/0 grow/shrink: 4/0 up/down: 126/0) Total: 126 bytes

Signed-off-by: Ron Yorston 
---
 networking/wget.c | 28 +---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/networking/wget.c b/networking/wget.c
index 6a9604421..ae24aa524 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -135,7 +135,8 @@
 
 //usage:#define wget_trivial_usage
 //usage:   IF_FEATURE_WGET_LONG_OPTIONS(
-//usage:   "[-cqS] [--spider] [-O FILE] [-o LOGFILE] [--header 'HEADER: 
VALUE'] [-Y on/off]\n"
+//usage:   "[-cqS] [--spider] [-O FILE] [-o LOGFILE] [--header STR]\n"
+//usage:   "   [--post-data STR | --post-file FILE] [-Y on/off]\n"
 /* Since we ignore these opts, we don't show them in --help */
 /* //usage:"   [--no-cache] [--passive-ftp] [-t TRIES]" */
 /* //usage:"   [-nv] [-nc] [-nH] [-np]" */
@@ -148,6 +149,9 @@
 //usage:   "Retrieve files via HTTP or FTP\n"
 //usage:   IF_FEATURE_WGET_LONG_OPTIONS(
 //usage: "\n   --spiderOnly check URL existence: $? is 0 if 
exists"
+//usage: "\n   --header STRAdd STR (of form 'header: value') to 
headers"
+//usage: "\n   --post-data STR Send STR using POST method"
+//usage: "\n   --post-file FILESend FILE using POST method"
 //usage:   IF_FEATURE_WGET_OPENSSL(
 //usage: "\n   --no-check-certificate  Don't validate the server's 
certificate"
 //usage:   )
@@ -244,6 +248,7 @@ struct globals {
char *dir_prefix;
 #if ENABLE_FEATURE_WGET_LONG_OPTIONS
char *post_data;
+   char *post_file;
char *extra_headers;
unsigned char user_headers; /* Headers mentioned by the user */
 #endif
@@ -292,10 +297,13 @@ enum {
WGET_OPT_POST_DATA  = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
WGET_OPT_SPIDER = (1 << 13) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
WGET_OPT_NO_CHECK_CERT = (1 << 14) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
+   WGET_OPT_POST_FILE  = (1 << 15) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
/* hijack this bit for other than opts purposes: */
WGET_NO_FTRUNCATE   = (1 << 31)
 };
 
+#define WGET_OPT_POST (WGET_OPT_POST_DATA | WGET_OPT_POST_FILE)
+
 enum {
PROGRESS_START = -1,
PROGRESS_END   = 0,
@@ -1213,7 +1221,7 @@ static void download_one_url(const char *url)
target.path);
} else {
SENDFMT(sfp, "%s /%s HTTP/1.1\r\n",
-   (option_mask32 & WGET_OPT_POST_DATA) ? "POST" : 
"GET",
+   (option_mask32 & WGET_OPT_POST) ? "POST" : 
"GET",
target.path);
}
if (!USR_HEADER_HOST)
@@ -1246,7 +1254,13 @@ static void download_one_url(const char *url)
fputs(G.extra_headers, sfp);
}
 
-   if (option_mask32 & WGET_OPT_POST_DATA) {
+   if (option_mask32 & WGET_OPT_POST_FILE) {
+   int fd = xopen_stdin(G.post_file);
+   G.post_data = xmalloc_read(fd, NULL);
+   close(fd);
+   }
+
+   if (G.post_data) {
SENDFMT(sfp,
"Content-Type: 
application/x-www-form-urlencoded\r\n"
"Content-Length: %u\r\n"
@@ -1489,6 +1503,7 @@ IF_DESKTOP(   "tries\0"Required_argument 
"t")
"post-data\0"Required_argument "\xfe"
"spider\0"   No_argument   "\xfd"
"no-check-certificate\0" No_argument   "\xfc"
+  

[PATCH] cal: implement -m

2021-09-21 Thread Ron Yorston
Some people prefer the week to start on Monday.  Add the '-m'
option to support this.

function old new   delta
cal_main 926 966 +40
day_array316 337 +21
packed_usage   34151   34158  +7
.rodata99224   99225  +1
--
(add/remove: 0/0 grow/shrink: 4/0 up/down: 69/0)   Total: 69 bytes

Signed-off-by: Ron Yorston 
---
 util-linux/cal.c | 38 +-
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/util-linux/cal.c b/util-linux/cal.c
index 006bc817b..6ba6ebf98 100644
--- a/util-linux/cal.c
+++ b/util-linux/cal.c
@@ -27,10 +27,11 @@
 /* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */
 
 //usage:#define cal_trivial_usage
-//usage:   "[-jy] [[MONTH] YEAR]"
+//usage:   "[-jmy] [[MONTH] YEAR]"
 //usage:#define cal_full_usage "\n\n"
 //usage:   "Display a calendar\n"
 //usage: "\n   -j  Use julian dates"
+//usage: "\n   -m  Week starts on Monday"
 //usage: "\n   -y  Display the entire year"
 
 #include "libbb.h"
@@ -38,6 +39,8 @@
 
 /* We often use "unsigned" instead of "int", it's easier to div on most CPUs */
 
+#defineSUNDAY  0
+#defineMONDAY  1
 #defineTHURSDAY4   /* for reformation */
 #defineSATURDAY6   /* 1 Jan 1 was a 
Saturday */
 
@@ -81,7 +84,7 @@ static int leap_year(unsigned yr)
((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
 
 static void center(char *, unsigned, unsigned);
-static void day_array(unsigned, unsigned, unsigned *);
+static void day_array(unsigned, unsigned, unsigned, unsigned *);
 static void trim_trailing_spaces_and_print(char *);
 
 static void blank_string(char *buf, size_t buflen);
@@ -93,12 +96,18 @@ static char *build_row(char *p, unsigned *dp);
 #defineJ_WEEK_LEN  (WEEK_LEN + 7)
 #defineHEAD_SEP2   /* spaces between day headings 
*/
 
+enum {
+   OPT_JULIAN = (1 << 0),
+   OPT_MONDAY = (1 << 1),
+   OPT_YEAR   = (1 << 2),
+};
+
 int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int cal_main(int argc UNUSED_PARAM, char **argv)
 {
struct tm zero_tm;
time_t now;
-   unsigned month, year, flags, i;
+   unsigned month, year, flags, i, weekstart;
char *month_names[12];
/* normal heading: */
/* "Su Mo Tu We Th Fr Sa" */
@@ -110,10 +119,11 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
 
init_unicode();
 
-   flags = getopt32(argv, "jy");
-   /* This sets julian = flags & 1: */
-   option_mask32 &= 1;
+   flags = getopt32(argv, "jmy");
+   /* This sets julian = flags & OPT_JULIAN: */
+   option_mask32 &= OPT_JULIAN;
month = 0;
+   weekstart = (flags & OPT_MONDAY) ? MONDAY : SUNDAY;
argv += optind;
 
if (!argv[0]) {
@@ -122,7 +132,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
time(&now);
ptm = localtime(&now);
year = ptm->tm_year + 1900;
-   if (!(flags & 2)) { /* no -y */
+   if (!(flags & OPT_YEAR)) { /* no -y */
month = ptm->tm_mon + 1;
}
} else {
@@ -130,7 +140,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
if (argv[2]) {
bb_show_usage();
}
-   if (!(flags & 2)) { /* no -y */
+   if (!(flags & OPT_YEAR)) { /* no -y */
month = xatou_range(*argv, 1, 12);
}
argv++;
@@ -148,7 +158,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
month_names[i] = xstrdup(buf);
 
if (i < 7) {
-   zero_tm.tm_wday = i;
+   zero_tm.tm_wday = (i + weekstart) % 7;
/* abbreviated weekday name according to locale */
strftime(buf, sizeof(buf), "%a", &zero_tm);
 #if ENABLE_UNICODE_SUPPORT
@@ -173,7 +183,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
unsigned *dp = days;
char lineout[30];
 
-   day_array(month, year, dp);
+   day_array(month, year, weekstart, dp);
len = spr

[PATCH v2] libbb: code shrink parse_datestr (again)

2021-09-18 Thread Ron Yorston
Commit 9fe1548bb (date,touch: allow timezone offsets in dates)
mentioned the similarity between '@' format dates and those with
timezone offsets.  It didn't notice that as a result there's
common code which can be shared.

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

v2: A different version of gcc complained about the label appearing
before a declaration.  Make it happy.

Signed-off-by: Ron Yorston 
---
 libbb/time.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/libbb/time.c b/libbb/time.c
index 41a69c754..48c16e5f1 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -13,6 +13,7 @@
 int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
 {
char end = '\0';
+   time_t t;
 #if ENABLE_DESKTOP
 /*
  * strptime is BIG: ~1k in uclibc, ~10k in glibc
@@ -47,9 +48,6 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
if (endp && *endp == '\0') {
 #if ENABLE_FEATURE_TIMEZONE
if (strchr(fmt, 'z')) {
-   time_t t;
-   struct tm *utm;
-
/* we have timezone offset: obtain Unix time_t 
*/
ptm->tm_sec -= ptm->tm_gmtoff;
ptm->tm_isdst = 0;
@@ -57,11 +55,7 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
if (t == (time_t)-1)
break;
/* convert Unix time_t to struct tm in user's 
locale */
-   utm = localtime(&t);
-   if (!utm)
-   break;
-   *ptm = *utm;
-   return 0;
+   goto localise;
}
 #endif
return 1;
@@ -141,13 +135,14 @@ int FAST_FUNC parse_datestr(const char *date_str, struct 
tm *ptm)
} else
 #endif /* ENABLE_DESKTOP */
if (date_str[0] == '@') {
-   time_t t;
if (sizeof(t) <= sizeof(long))
t = bb_strtol(date_str + 1, NULL, 10);
else /* time_t is 64 bits but longs are smaller */
t = bb_strtoll(date_str + 1, NULL, 10);
if (!errno) {
-   struct tm *lt = localtime(&t);
+   struct tm *lt;
+ IF_FEATURE_TIMEZONE(localise:)
+   lt = localtime(&t);
if (lt) {
*ptm = *lt;
return 0;
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: code shrink parse_datestr (again)

2021-09-18 Thread Ron Yorston
Commit 9fe1548bb (date,touch: allow timezone offsets in dates)
mentioned the similarity between '@' format dates and those with
timezone offsets.  It didn't notice that as a result there's
common code which can be shared.

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

Signed-off-by: Ron Yorston 
---
 libbb/time.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/libbb/time.c b/libbb/time.c
index 41a69c754..8010c0caa 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -13,6 +13,7 @@
 int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
 {
char end = '\0';
+   time_t t;
 #if ENABLE_DESKTOP
 /*
  * strptime is BIG: ~1k in uclibc, ~10k in glibc
@@ -47,9 +48,6 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
if (endp && *endp == '\0') {
 #if ENABLE_FEATURE_TIMEZONE
if (strchr(fmt, 'z')) {
-   time_t t;
-   struct tm *utm;
-
/* we have timezone offset: obtain Unix time_t 
*/
ptm->tm_sec -= ptm->tm_gmtoff;
ptm->tm_isdst = 0;
@@ -57,11 +55,7 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
if (t == (time_t)-1)
break;
/* convert Unix time_t to struct tm in user's 
locale */
-   utm = localtime(&t);
-   if (!utm)
-   break;
-   *ptm = *utm;
-   return 0;
+   goto localise;
}
 #endif
return 1;
@@ -141,12 +135,12 @@ int FAST_FUNC parse_datestr(const char *date_str, struct 
tm *ptm)
} else
 #endif /* ENABLE_DESKTOP */
if (date_str[0] == '@') {
-   time_t t;
if (sizeof(t) <= sizeof(long))
t = bb_strtol(date_str + 1, NULL, 10);
else /* time_t is 64 bits but longs are smaller */
t = bb_strtoll(date_str + 1, NULL, 10);
if (!errno) {
+ IF_FEATURE_TIMEZONE(localise:)
struct tm *lt = localtime(&t);
if (lt) {
*ptm = *lt;
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: ensure mode_string is NUL terminated

2021-09-17 Thread Ron Yorston
If the mode_string array is no longer static we can't rely on
it being NUL terminated.

function old new   delta
bb_mode_string   145 156 +11
--
(add/remove: 0/0 grow/shrink: 1/0 up/down: 11/0)   Total: 11 bytes

Signed-off-by: Ron Yorston 
---
 libbb/mode_string.c | 10 ++
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 2b829016f..39a655d35 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -66,10 +66,7 @@ char* FAST_FUNC bb_mode_string(char buf[12], mode_t mode)
i += 4;
} while (i < 12);
 
-   /* Note: We don't bother with nul termination because bss initialization
-* should have taken care of that for us.  If the user scribbled in buf
-* memory, they deserve whatever happens.  But we'll at least assert. */
-   assert(buf[10] == 0);
+   buf[10] = '\0';
 
return buf;
 }
@@ -107,10 +104,7 @@ char* FAST_FUNC bb_mode_string(char buf[12], mode_t mode)
}
} while (i < 3);
 
-   /* Note: We don't bother with nul termination because bss initialization
-* should have taken care of that for us.  If the user scribbled in buf
-* memory, they deserve whatever happens.  But we'll at least assert. */
-   assert(buf[10] == 0);
+   buf[10] = '\0';
 
return buf;
 }
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] date,touch: allow timezone offsets in dates

2021-09-16 Thread Ron Yorston
Allow ISO 8601 style dates to include a timezone offset.  Like
the '@' format these dates aren't relative to the user's current
timezone and shouldn't be subject to DST adjustment.

- The implementation uses the strptime() '%z' format specifier.
  This an extension which may not be available so the use of
  timezones is a configuration option.

- The 'touch' applet has been updated to respect whether DST
  adjustment is required, matching 'date'.

function old new   delta
parse_datestr624 730+106
static.fmt_str   106 136 +30
touch_main   388 392  +4
date_main818 819  +1
--
(add/remove: 0/0 grow/shrink: 4/0 up/down: 141/0)     Total: 141 bytes

Signed-off-by: Ron Yorston 
---
 coreutils/date.c |  7 ---
 coreutils/touch.c|  6 --
 include/libbb.h  |  2 +-
 libbb/Config.src | 11 +++
 libbb/time.c | 32 
 testsuite/date/date-timezone | 32 
 6 files changed, 80 insertions(+), 10 deletions(-)
 create mode 100644 testsuite/date/date-timezone

diff --git a/coreutils/date.c b/coreutils/date.c
index 7061f1719..abcc37c33 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -266,6 +266,7 @@ int date_main(int argc UNUSED_PARAM, char **argv)
 
/* If date string is given, update tm_time, and maybe set date */
if (date_str != NULL) {
+   int check_dst = 1;
/* Zero out fields - take her back to midnight! */
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
@@ -276,12 +277,12 @@ int date_main(int argc UNUSED_PARAM, char **argv)
if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
bb_error_msg_and_die(bb_msg_invalid_date, 
date_str);
} else {
-   parse_datestr(date_str, &tm_time);
+   check_dst = parse_datestr(date_str, &tm_time);
}
 
/* Correct any day of week and day of year etc. fields */
-   /* Be sure to recheck dst (but not if date is time_t format) */
-   if (date_str[0] != '@')
+   /* Be sure to recheck dst (but not if date is UTC) */
+   if (check_dst)
tm_time.tm_isdst = -1;
ts.tv_sec = validate_tm_time(date_str, &tm_time);
ts.tv_nsec = 0;
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 78100ba1d..7e13a27be 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -140,15 +140,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
if (opts & (OPT_d|OPT_t)) {
struct tm tm_time;
time_t t;
+   int check_dst;
 
//memset(&tm_time, 0, sizeof(tm_time));
/* Better than memset: makes "HH:MM" dates meaningful */
time(&t);
localtime_r(&t, &tm_time);
-   parse_datestr(date_str, &tm_time);
+   check_dst = parse_datestr(date_str, &tm_time);
 
/* Correct any day of week and day of year etc. fields */
-   tm_time.tm_isdst = -1;  /* Be sure to recheck dst */
+   if (check_dst)
+   tm_time.tm_isdst = -1;  /* recheck dst unless date is 
UTC */
t = validate_tm_time(date_str, &tm_time);
 
timebuf[1].tv_sec = timebuf[0].tv_sec = t;
diff --git a/include/libbb.h b/include/libbb.h
index 7d6ab4a93..1ec8d2d3b 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -690,7 +690,7 @@ struct BUG_too_small {
 };
 
 
-void parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC;
+int parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC;
 time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC;
 char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
 char *strftime_MMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
diff --git a/libbb/Config.src b/libbb/Config.src
index f97de8ef7..58c5fad50 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -395,3 +395,14 @@ config FEATURE_HWIB
default y
help
Support for printing infiniband addresses in network applets.
+
+config FEATURE_TIMEZONE
+   bool "Allow timezone in dates"
+   default y
+   depends on DESKTOP
+   help
+   Permit the use of timezones when parsing user-provided data
+   strings, e.g. '1996-04-09 12:45:00 -0500'.
+
+   This requires s

[PATCH] libbb: code shrink parse_datestr

2021-09-14 Thread Ron Yorston
The default build uses strptime() in parse_datestr() to support the
'month_name d HH:MM:SS ' format of GNU date.  If we've linked
with strptime() there's an advantage is using it for other formats
too.

There's no change to the non-default, non-DESKTOP build.

function old new   delta
fmt_str- 106+106
.rodata99216   99145 -71
parse_datestr948 624-324
--
(add/remove: 1/0 grow/shrink: 0/2 up/down: 106/-395) Total: -289 bytes

Signed-off-by: Ron Yorston 
---
 libbb/time.c | 49 ++---
 1 file changed, 38 insertions(+), 11 deletions(-)

diff --git a/libbb/time.c b/libbb/time.c
index cf5f2e5c8..1a00953b2 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -8,16 +8,50 @@
  */
 #include "libbb.h"
 
+#if ENABLE_DESKTOP
+/*
+ * strptime is BIG: ~1k in uclibc, ~10k in glibc
+ * We need it for 'month_name d HH:MM:SS ', supported by GNU date,
+ * but if we've linked it we might as well use it for everything.
+ */
+static const char fmt_str[] ALIGN1 =
+   "%R" "\0"   /* HH:MM */
+   "%T" "\0"   /* HH:MM:SS */
+   "%m.%d-%R" "\0" /* mm.dd-HH:MM */
+   "%m.%d-%T" "\0" /* mm.dd-HH:MM:SS */
+   "%Y.%m.%d-%R" "\0"  /* .mm.dd-HH:MM */
+   "%Y.%m.%d-%T" "\0"  /* .mm.dd-HH:MM:SS */
+   "%b %d %T %Y" "\0"  /* month_name d HH:MM:SS  */
+   "%Y-%m-%d %R" "\0"  /* -mm-dd HH:MM */
+   "%Y-%m-%d %T" "\0"  /* -mm-dd HH:MM:SS */
+   "%Y-%m-%d %H" "\0"  /* -mm-dd HH */
+   "%Y-%m-%d" "\0" /* -mm-dd */
+   /* extra NUL */;
+#endif
+
 void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
 {
char end = '\0';
+#if ENABLE_DESKTOP
+   struct tm save;
+   const char *fmt;
+   char *endp;
+
+   save = *ptm;
+   fmt = fmt_str;
+   while (*fmt) {
+   if ((endp = strptime(date_str, fmt, ptm)) != NULL && *endp == 
'\0')
+   return;
+   *ptm = save;
+   while (*++fmt)
+   ;
+   ++fmt;
+   }
+#else
const char *last_colon = strrchr(date_str, ':');
 
if (last_colon != NULL) {
/* Parse input and assign appropriately to ptm */
-#if ENABLE_DESKTOP
-   const char *endp;
-#endif
 
/* HH:MM */
if (sscanf(date_str, "%u:%u%c",
@@ -50,14 +84,6 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
ptm->tm_year -= 1900; /* Adjust years */
ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
} else
-#if ENABLE_DESKTOP  /* strptime is BIG: ~1k in uclibc, ~10k in glibc */
-   /* month_name d HH:MM:SS . Supported by GNU date */
-   if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL
-&& *endp == '\0'
-   ) {
-   return; /* don't fall through to end == ":" check */
-   } else
-#endif
{
bb_error_msg_and_die(bb_msg_invalid_date, date_str);
}
@@ -89,6 +115,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm 
*ptm)
ptm->tm_year -= 1900; /* Adjust years */
ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
} else
+#endif /* ENABLE_DESKTOP */
if (date_str[0] == '@') {
time_t t;
if (sizeof(t) <= sizeof(long))
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] getopt: code shrink

2021-09-12 Thread Ron Yorston
function old new   delta
.rodata99277   99290 +13
normalize177 142 -35
getopt_main  675 622 -53
--
(add/remove: 0/0 grow/shrink: 1/2 up/down: 13/-88)Total: -75 bytes

Signed-off-by: Ron Yorston 
---
 util-linux/getopt.c | 45 +
 1 file changed, 17 insertions(+), 28 deletions(-)

diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index 1fa402429..c6d5dfc76 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -156,46 +156,29 @@ enum {
 static const char *normalize(const char *arg)
 {
char *bufptr;
-#if ENABLE_FEATURE_CLEAN_UP
-   static char *BUFFER = NULL;
-   free(BUFFER);
-#else
char *BUFFER;
-#endif
 
-   if (!quote) { /* Just copy arg */
-   BUFFER = xstrdup(arg);
-   return BUFFER;
+   if (!quote) { /* Just return arg */
+   return arg;
}
 
/* Each character in arg may take up to four characters in the result:
   For a quote we need a closing quote, a backslash, a quote and an
   opening quote! We need also the global opening and closing quote,
   and one extra character for '\0'. */
-   BUFFER = xmalloc(strlen(arg)*4 + 3);
+   BUFFER = auto_string(xmalloc(strlen(arg)*4 + 3));
 
bufptr = BUFFER;
*bufptr ++= '\'';
 
while (*arg) {
-   if (*arg == '\'') {
-   /* Quote: replace it with: '\'' */
-   *bufptr ++= '\'';
-   *bufptr ++= '\\';
-   *bufptr ++= '\'';
-   *bufptr ++= '\'';
-   } else if (shell_TCSH && *arg == '!') {
-   /* Exclamation mark: replace it with: \! */
-   *bufptr ++= '\'';
-   *bufptr ++= '\\';
-   *bufptr ++= '!';
-   *bufptr ++= '\'';
-   } else if (shell_TCSH && *arg == '\n') {
+   if (shell_TCSH && *arg == '\n') {
/* Newline: replace it with: \n */
*bufptr ++= '\\';
*bufptr ++= 'n';
-   } else if (shell_TCSH && isspace(*arg)) {
-   /* Non-newline whitespace: replace it with \ */
+   } else if ((shell_TCSH && (*arg == '!' || isspace(*arg))) ||
+   *arg == '\'') {
+   /* Quote exclamation marks, non-NL whitespace and 
quotes */
*bufptr ++= '\'';
*bufptr ++= '\\';
*bufptr ++= *arg;
@@ -327,12 +310,18 @@ static struct option *add_long_options(struct option 
*long_options, char *option
 
 static void set_shell(const char *new_shell)
 {
-   if (strcmp(new_shell, "bash") == 0 || strcmp(new_shell, "sh") == 0)
-   return;
-   if (strcmp(new_shell, "tcsh") == 0 || strcmp(new_shell, "csh") == 0)
+   switch (index_in_strings("bash\0sh\0tcsh\0csh\0", new_shell)) {
+   case 0:
+   case 1:
+   break;
+   case 2:
+   case 3:
option_mask32 |= SHELL_IS_TCSH;
-   else
+   break;
+   default:
bb_error_msg("unknown shell '%s', assuming bash", new_shell);
+   break;
+   }
 }
 
 
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 2/3] ash: stopped jobs should only prevent exit from interactive shell

2021-09-12 Thread Ron Yorston
When the user tries to exit an interactive shell with stopped jobs
present the shell issues a warning and only exits if the user
insists by trying to exit again.

This shouldn't apply to non-interactive shells.

Reported-by: Roberto A. Foglietta 
Signed-off-by: Ron Yorston 
---
 shell/ash.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shell/ash.c b/shell/ash.c
index 99b89409e..62e1a4c7e 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5449,7 +5449,7 @@ stoppedjobs(void)
int retval;
 
retval = 0;
-   if (job_warning)
+   if (!iflag || job_warning)
goto out;
jp = curjob;
if (jp && jp->state == JOBSTOPPED) {
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 1/3] ash: fix ignoreeof option

2021-09-12 Thread Ron Yorston
The ignoreeof option should prevent an interactive shell from
exiting on EOF.  This hasn't worked in BusyBox ash since commit
727752d2d (ash: better fix for ash -c 'echo 5&' and ash -c 'sleep 5&'
with testcase).

Commit 3b4d04b77e (ash: input: Allow two consecutive calls to pungetc)
pulled in improved support for multiple calls to pungetc from dash,
thus rendering much of commit 727752d2d obsolete.  Removing this old
code fixes the problem with ignoreeof.

function old new   delta
__pgetc  605 587 -18
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-18) Total: -18 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 22 +++---
 1 file changed, 3 insertions(+), 19 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index ba116d83a..99b89409e 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -10822,9 +10822,7 @@ preadfd(void)
  * Refill the input buffer and return the next input character:
  *
  * 1) If a string was pushed back on the input, pop it;
- * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
- *or we are reading from a string so we can't refill the buffer,
- *return EOF.
+ * 2) If we are reading from a string we can't refill the buffer, return EOF.
  * 3) If there is more stuff in this buffer, use it else call read to fill it.
  * 4) Process input up to the next newline, deleting nul characters.
  */
@@ -10841,21 +10839,9 @@ preadbuffer(void)
popstring();
return __pgetc();
}
-   /* on both branches above g_parsefile->left_in_line < 0.
-* "pgetc" needs refilling.
-*/
 
-   /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
-* pungetc() may increment it a few times.
-* Assuming it won't increment it to less than -90.
-*/
-   if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
+   if (g_parsefile->buf == NULL) {
pgetc_debug("preadbuffer PEOF1");
-   /* even in failure keep left_in_line and next_to_pgetc
-* in lock step, for correct multi-layer pungetc.
-* left_in_line was decremented before preadbuffer(),
-* must inc next_to_pgetc: */
-   g_parsefile->next_to_pgetc++;
return PEOF;
}
 
@@ -10865,10 +10851,8 @@ preadbuffer(void)
  again:
more = preadfd();
if (more <= 0) {
-   /* don't try reading again */
-   g_parsefile->left_in_line = -99;
+   g_parsefile->left_in_buffer = g_parsefile->left_in_line 
= 0;
pgetc_debug("preadbuffer PEOF2");
-   g_parsefile->next_to_pgetc++;
return PEOF;
}
}
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 0/3] ash: ignoreeof and interactive vs. non-interactive shells

2021-09-12 Thread Ron Yorston
I was holding back my fix for ignoreeof (broken since 2008!) to see
what upstream dash thought about my changes to EOF handling.

However, it's required to address the problem with stopped jobs
preventing non-interactive shells from exiting, so here it is.

I've also pulled in a patch from Harald van Dijk's ash derivative
which handles a similar situation with non-interactive shells when
ignoreeof is set.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: A stopped job make ash ignores exit

2021-09-12 Thread Ron Yorston
Roberto wrote:
> IMHO this line
>
>> +   if (iflag || job_warning)
>> goto out;
>
> should be modified in this way
>
>> +   if (!iflag || job_warning)
>> goto out;
>
> Non-interactive shells should not care about stopped jobs but
>interactive shells do as you said.
>
> Is that right?

It is.  My bad.

Actually, things are a bit more complicated.  I had a patch queued for
submission which has an impact on this.  I foresee a series of patches.

Give me a moment...

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: A stopped job make ash ignores exit

2021-09-12 Thread Ron Yorston
Roberto A. Foglietta wrote:
> I found a case in which IMHO the ash does not behave as expected by a shell.
> When there is a stopped job the exit command is ignored but it should not.
> At least bash does not ignore the exit if a stopped job exists.

Warning about stopped jobs is OK in an interactive shell.  Bash does
that too.  The difference is that BusyBox ash (and dash) issues the
warning in a non-interactive shell, which it probably shouldn't do.

Possible alternative fix below.

Ron
---

diff --git a/shell/ash.c b/shell/ash.c
index 3524d046e..d163ec8e3 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5451,7 +5451,7 @@ stoppedjobs(void)
int retval;
 
retval = 0;
-   if (job_warning)
+   if (iflag || job_warning)
goto out;
jp = curjob;
if (jp && jp->state == JOBSTOPPED) {
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] awk: fix read beyond end of buffer

2021-09-09 Thread Ron Yorston
Commit 7d06d6e18 (awk: fix printf %%) can cause awk printf to read
beyond the end of a strduped buffer:

  2349  while (*f && *f != '%')
  2350  f++;
  2351  c = *++f;

If the loop terminates because a NUL character is detected the
character after the NUL is read.  This can result in failures
depending on the value of that character.

function old new   delta
awk_printf   736 706 -30

Signed-off-by: Ron Yorston 
---
 editors/awk.c | 24 +---
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index f7b8ef0d3..3594717b1 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -2348,17 +2348,19 @@ static char *awk_printf(node *n, size_t *len)
s = f;
while (*f && *f != '%')
f++;
-   c = *++f;
-   if (c == '%') { /* double % */
-   slen = f - s;
-   s = xstrndup(s, slen);
-   f++;
-   goto tail;
-   }
-   while (*f && !isalpha(*f)) {
-   if (*f == '*')
-   syntax_error("%*x formats are not supported");
-   f++;
+   if (*f) {
+   c = *++f;
+   if (c == '%') { /* double % */
+   slen = f - s;
+   s = xstrndup(s, slen);
+   f++;
+   goto tail;
+   }
+   while (*f && !isalpha(*f)) {
+   if (*f == '*')
+   syntax_error("%*x formats are not 
supported");
+   f++;
+   }
}
c = *f;
if (!c) {
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: regressions in process substitution

2021-08-30 Thread Ron Yorston
Stacy Harper reports that this script:

   test() { . /tmp/bb_test; }
   echo "export TEST=foo" >/tmp/bb_test
   test 2>/dev/null
   echo "$TEST"

correctly prints 'foo' in BusyBox 1.33 but hangs in 1.34.

Bisection suggested the problem was caused by commit a1b0d3856 (ash: add
process substitution in bash-compatibility mode).  Removing the call to
unwindredir() in cmdloop() introduced in that commit makes the script
work again.

Additionally, these examples of process substitution:

   while true; do cat <(echo hi); done
   f() { while true; do cat <(echo hi); done }
   f

result in running out of file descriptors.  This is a regression from
v5 of the process substitution patch caused by changes to evalcommand()
not being transferred to v6.

function old new   delta
static.pushredir   -  99 +99
evalcommand 17291750 +21
exitreset 69  86 +17
cmdloop  372 365  -7
unwindredir   28   - -28
pushredir112   --112
--
(add/remove: 1/2 grow/shrink: 2/1 up/down: 137/-147)      Total: -10 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index b5947147a..53c140930 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -10278,6 +10278,9 @@ evalcommand(union node *cmd, int flags)
 
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
+#if BASH_PROCESS_SUBST
+   redir_stop = redirlist;
+#endif
file_stop = g_parsefile;
back_exitstatus = 0;
 
@@ -10356,7 +10359,11 @@ evalcommand(union node *cmd, int flags)
lastarg = nargv[-1];
 
expredir(cmd->ncmd.redirect);
+#if !BASH_PROCESS_SUBST
redir_stop = pushredir(cmd->ncmd.redirect);
+#else
+   pushredir(cmd->ncmd.redirect);
+#endif
preverrout_fd = 2;
if (BASH_XTRACEFD && xflag) {
/* NB: bash closes fd == $BASH_XTRACEFD when it is changed.
@@ -13476,9 +13483,6 @@ cmdloop(int top)
 #if JOBS
if (doing_jobctl)
showjobs(SHOW_CHANGED|SHOW_STDERR);
-#endif
-#if BASH_PROCESS_SUBST
-   unwindredir(NULL);
 #endif
inter = 0;
if (iflag && top) {
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: /bin/sh hang in some circonstance

2021-08-30 Thread Ron Yorston
Stacy Harper wrote:

>Shell will hang on this simple script :

Yes, I can reproduce it.

>I already bisected git and it looks that the first commit that
>got the issue is :
>
>a1b0d3856d9a0419cb74bf4c87525265871b5868
>
>ash: add process substitution in bash-compatibility mode

One of mine.  It's being too aggressive in closing redirections.
But I've also spotted another issue:  it's running out of file
descriptors with process substitutions in a loop.  Which is what
the aggressive closing was supposed to avoid.

I'm investigating...

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 1/1] vi: further changes to colon addresses

2021-08-29 Thread Ron Yorston
Improved error messages:

- specify when a search fails or a mark isn't set;
- warn when line addresses are out of range or when a range of
  lines is reversed.

Addresses are limited to the number of lines in the file so a
command like ':20' (go to the two billionth line) no
longer causes a long pause.

Improved vi compatibility of '+' and '-' operators that aren't
followed immediately by a number:

   :4+++=   7
   :3-2=1
   :3 - 2=  4 (yes, really!)

In a command like ':,$' the empty address before the separator now
correctly refers to the current line.  (The similar case ':1,' was
already being handled.)

And all with a tidy reduction in bloat (32-bit build):

function old new   delta
colon   40294069 +40
.rodata99348   99253 -95
--
(add/remove: 0/0 grow/shrink: 1/1 up/down: 40/-95)Total: -55 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 132 ---
 1 file 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)
 
 //- The Colon commands -
 #if ENABLE_FEATURE_VI_COLON
-static char *get_one_address(char *p, int *result) // get colon addr, if 
present
+// Evaluate colon address expression.  Returns a pointer to the
+// next character or NULL on error.  If 'result' contains a valid
+// address 'valid' is TRUE.
+static char *get_one_address(char *p, int *result, int *valid)
 {
-   int st, num, sign, addr, new_addr;
+   int num, sign, addr, got_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
+   got_addr = FALSE;
+   addr = count_lines(text, dot);  // default to current line
sign = 0;
for (;;) {
-   new_addr = -1;
if (isblank(*p)) {
+   if (got_addr) {
+   addr += sign;
+   sign = 0;
+   }
+   p++;
+   } else if (!got_addr && *p == '.') {// the current line
p++;
-   } else if (*p == '.') { // the current line
+   //addr = count_lines(text, dot);
+   got_addr = TRUE;
+   } else if (!got_addr && *p == '$') {// the last line in file
p++;
-   new_addr = count_lines(text, dot);
+   addr = count_lines(text, end - 1);
+   got_addr = TRUE;
}
 # if ENABLE_FEATURE_VI_YANKMARK
-   else if (*p == '\'') {  // is this a mark addr
+   else if (!got_addr && *p == '\'') { // is this a mark addr
p++;
c = tolower(*p);
p++;
@@ -2487,13 +2499,16 @@ static char *get_one_address(char *p, int *result)  
// get colon addr, if present
c = c - 'a';
q = mark[(unsigned char) c];
}
-   if (q == NULL)  // is mark valid
+   if (q == NULL) {// is mark valid
+   status_line_bold("Mark not set");
return NULL;
-   new_addr = count_lines(text, q);
+   }
+   addr = count_lines(text, q);
+   got_addr = TRUE;
}
 # endif
 # if ENABLE_FEATURE_VI_SEARCH
-   else if (*p == '/' || *p == '?') {  // a search pattern
+   else if (!got_addr && (*p == '/' || *p == '?')) {   // a 
search pattern
c = *p;
q = strchrnul(p + 1, c);
if (p + 1 != q) {
@@ -2516,40 +2531,41 @@ static char *get_one_address(char *p, int *result)  
// get colon addr, if present
// no match, continue from other end of file
q = char_search(dir > 0 ? text : end - 1,

last_search_pattern + 

[PATCH 0/1] vi: further changes to colon addresses

2021-08-29 Thread Ron Yorston
In the original vi source from the second BSD there's a comment:

 * If you are tricky you can use this routine and the = command
 * to do simple addition and subtraction of cardinals less
 * than the number of lines in the file.

Thus:

   vi README
   - README 1/204 0%
   :1+2+3=
   6
   :1 2 3=
   6 (who needs operators?)
   :1+2000-1999=
   2 (the limit only applies to the final result)

But I was disappointed that BusyBox vi couldn't handle negative
intermediate values:

   :1-1999+2000=
   2001

The following patch fixes that problem so now we get:

   :1-1999+2000=
   2

It also limits the range of the result to the number of lines in
the file, which it wasn't actually doing before.

Anyway, in making these changes I was surprised at the reduction in
bloat achieved.  It turned out that the code in get_one_address()
was previously using a chain of ifs that all tested the value of the
current character in the buffer:

   if (isblank(*p)) {
   ...
   } else if (*p == '.') {
   ...
   } else if (*p == '\'') {

The compiler spotted this and generated a big jump table:

jmp *.L608(,%rax,8) #
.section.rodata.colon,"a",@progbits
.align 8
.align 4
.L608:
.quad   .L613
.quad   .L606
.quad   .L606
.quad   .L612
...

(It's in .rodata.colon because get_one_address() and get_address()
are inlined into colon().)

My modified code was too complicated for the compiler to handle so it
reverted to something more straightforward instead.  The reduction in
bloat was due to the loss of the jump table.  The same effect can be
obtained by disabling the relevant optimisation ("full redundancy
elimination (FRE) on trees") around the code in question:

   #pragma GCC optimize "no-tree-fre"
   //- The Colon commands -
   #if ENABLE_FEATURE_VI_COLON
   static char *get_one_address(char *p, int *result)
   ...
colon_s_fail:
status_line(":s expression missing delimiters");
   # endif
   #endif /* FEATURE_VI_COLON */
   }
   #pragma GCC reset_options

In a 64-bit build this gives:

function old new   delta
colon   41154066 -49
.rodata   108442  108266-176
--
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-225)   Total: -225 bytes

The jump table has 22 8-byte pointers and, apparently, the code to *use*
the jump table is bigger than the non-optimised code.

The -Os flag doesn't save us from this fate.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] tar,smemcap: silence compiler warning

2021-08-22 Thread Ron Yorston
gcc 11.2.1 complains that the tar header checksum might overflow
the checksum field.  It won't and using an unsigned int for the
calculation seems to convince the compiler too.

Signed-off-by: Ron Yorston 
---
 archival/chksum_and_xwrite_tar_header.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/archival/chksum_and_xwrite_tar_header.c 
b/archival/chksum_and_xwrite_tar_header.c
index 25934f898..f2d46b9ef 100644
--- a/archival/chksum_and_xwrite_tar_header.c
+++ b/archival/chksum_and_xwrite_tar_header.c
@@ -15,7 +15,7 @@ void FAST_FUNC chksum_and_xwrite_tar_header(int fd, struct 
tar_header_t *hp)
 * (Sun and HP-UX gets it wrong... more details in
 * GNU tar source) */
const unsigned char *cp;
-   int chksum, size;
+   unsigned int chksum, size;
 
strcpy(hp->magic, "ustar  ");
 
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: code shrink print_literal()

2021-08-21 Thread Ron Yorston
Simplify the function print_literal() which is used to format a
string that may contain unprintable characters or control
characters.

- Unprintable characters were being displayed in normal text rather
  than the bold used for the rest of the message.  This doesn't seem
  particularly helpful and it upsets the calculation of the width
  of the message in show_status_line().  Use '?' rather than '.' for
  unprintable characters.

- Newlines in the string were displayed as both '^J' and '$', which
  is somewhat redundant.

function old new   delta
not_implemented  199 108 -91
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-91)         Total: -91 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 19 ++-
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 126780175..9877fa19f 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -1376,21 +1376,14 @@ static void print_literal(char *buf, const char *s)
char *d;
unsigned char c;
 
-   buf[0] = '\0';
if (!s[0])
s = "(NULL)";
 
d = buf;
for (; *s; s++) {
-   int c_is_no_print;
-
c = *s;
-   c_is_no_print = (c & 0x80) && !Isprint(c);
-   if (c_is_no_print) {
-   strcpy(d, ESC_NORM_TEXT);
-   d += sizeof(ESC_NORM_TEXT)-1;
-   c = '.';
-   }
+   if ((c & 0x80) && !Isprint(c))
+   c = '?';
if (c < ' ' || c == 0x7f) {
*d++ = '^';
c |= '@'; // 0x40
@@ -1399,14 +1392,6 @@ static void print_literal(char *buf, const char *s)
}
*d++ = c;
*d = '\0';
-   if (c_is_no_print) {
-   strcpy(d, ESC_BOLD_TEXT);
-   d += sizeof(ESC_BOLD_TEXT)-1;
-   }
-   if (*s == '\n') {
-   *d++ = '$';
-   *d = '\0';
-   }
if (d - buf > MAX_INPUT_LEN - 10) // paranoia
break;
}
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: searches in colon commands should wrap

2021-08-21 Thread Ron Yorston
The '/' and '?' search commands wrap to the other end of the buffer
if the search target isn't found.  When searches are used to specify
addresses in colon commands they should do the same.

(In traditional vi and vim this behaviour is controlled by the
'wrapscan' option.  BusyBox vi doesn't have this option and always
uses the default behaviour.)

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

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 3e1bd0820..126780175 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2526,8 +2526,13 @@ static char *get_one_address(char *p, int *result)   
// get colon addr, if present
dir = ((unsigned)BACK << 1) | FULL;
}
q = char_search(q, last_search_pattern + 1, dir);
-   if (q == NULL)
-   return NULL;
+   if (q == NULL) {
+   // no match, continue from other end of file
+   q = char_search(dir > 0 ? text : end - 1,
+   
last_search_pattern + 1, dir);
+   if (q == NULL)
+   return NULL;
+   }
new_addr = count_lines(text, q);
}
 # endif
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] rev: correct output for long input lines

2021-08-21 Thread Ron Yorston
The input buffer is initialised to a reasonable size and extended
if necessary.  When this happened the offset into the buffer wasn't
reset to zero so subsequent lines were appended to the long line.

Fix this and add some tests.

function old new   delta
rev_main 377 368  -9
--
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-9)   Total: -9 bytes

Signed-off-by: Ron Yorston 
---
 testsuite/rev.tests | 46 +
 util-linux/rev.c|  1 +
 2 files changed, 47 insertions(+)
 create mode 100755 testsuite/rev.tests

diff --git a/testsuite/rev.tests b/testsuite/rev.tests
new file mode 100755
index 0..dd65dcd3b
--- /dev/null
+++ b/testsuite/rev.tests
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Copyright 2021 by Ron Yorston
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+. ./testing.sh
+
+# testing "test name" "commands" "expected result" "file input" "stdin"
+
+testing "rev works" \
+   "rev input" \
+"\
+1 enil
+
+3 enil
+" \
+   "line 1\n\nline 3\n" \
+   ""
+
+testing "rev file with missing newline" \
+   "rev input" \
+"\
+1 enil
+
+3 enil" \
+   "line 1\n\nline 3" \
+   ""
+
+testing "rev file with NUL character" \
+   "rev input" \
+"\
+nil
+3 enil
+" \
+   "lin\000e 1\n\nline 3\n" \
+   ""
+
+testing "rev file with long line" \
+   "rev input" \
+"\
++--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---
+cba
+" \
+   
"---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--+\nabc\n"
 \
+   ""
+
+exit $FAILCOUNT
diff --git a/util-linux/rev.c b/util-linux/rev.c
index d439b4da8..63b005c67 100644
--- a/util-linux/rev.c
+++ b/util-linux/rev.c
@@ -109,6 +109,7 @@ int rev_main(int argc UNUSED_PARAM, char **argv)
strrev(buf, strlen(buf));
 #endif
fputs_stdout(buf);
+   pos = 0;
}
fclose(fp);
} while (*argv);
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: don't right shift empty lines

2021-08-20 Thread Ron Yorston
The right shift command ('>') shouldn't affect empty lines.

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

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 3e1bd0820..6f8a87b70 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -4089,8 +4089,8 @@ static void do_cmd(int c)
 #endif
}
}
-   } else /* if (c == '>') */ {
-   // shift right -- add tab or tabstop spaces
+   } else if (/* c == '>' && */ p != end_line(p)) {
+   // shift right -- add tab or tabstop spaces on 
non-empty lines
char_insert(p, '\t', allow_undo);
}
 #if ENABLE_FEATURE_VI_UNDO
-- 
2.31.1


___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 2/2] vi: support ~/.exrc

2021-08-19 Thread Ron Yorston
Run initialisation commands from ~/.exrc.  As with EXINIT these
commands are processed before the first file is loaded.

Commands starting with double quotes are ignored.  This is how
comments are often included in .exrc.

function old new   delta
vi_main  268 406+138
colon   40334071 +38
.rodata   108411  108442 +31
packed_usage   34128   34118 -10
--
(add/remove: 0/0 grow/shrink: 3/1 up/down: 207/-10)   Total: 197 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 40 
 1 file changed, 32 insertions(+), 8 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index cc4f6bde7..fd8e0d48e 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -7,7 +7,7 @@
  */
 //
 //Things To Do:
-// $HOME/.exrc  and  ./.exrc
+// ./.exrc
 // add magic to search /foo.*bar
 // add :help command
 // :map macros
@@ -185,7 +185,7 @@
 //usage:#define vi_full_usage "\n\n"
 //usage:   "Edit FILE\n"
 //usage:   IF_FEATURE_VI_COLON(
-//usage: "\n   -c CMD  Initial command to run ($EXINIT also available)"
+//usage: "\n   -c CMD  Initial command to run ($EXINIT and ~/.exrc 
also available)"
 //usage:   )
 //usage:   IF_FEATURE_VI_READONLY(
 //usage: "\n   -R  Read-only"
@@ -2829,10 +2829,12 @@ static void colon(char *buf)
// :!  // run  then return
//
 
-   if (!buf[0])
-   goto ret;
-   if (*buf == ':')
-   buf++;  // move past the ':'
+   while (*buf == ':')
+   buf++;  // move past leading colons
+   while (isblank(*buf))
+   buf++;  // move past leading blanks
+   if (!buf[0] || buf[0] == '"')
+   goto ret;   // ignore empty lines or those starting 
with '"'
 
li = i = 0;
b = e = -1;
@@ -4923,14 +4925,36 @@ int vi_main(int argc, char **argv)
cmdline_filecnt = argc - optind;
 
//  1-  process EXINIT variable from environment
-   //  2-  if EXINIT is unset process $HOME/.exrc file (not implemented 
yet)
+   //  2-  if EXINIT is unset process $HOME/.exrc file
//  3-  process command line args
 #if ENABLE_FEATURE_VI_COLON
{
const char *exinit = getenv("EXINIT");
+   char *cmds = NULL;
 
if (exinit) {
-   char *cmds = xstrdup(exinit);
+   cmds = xstrdup(exinit);
+   } else {
+   const char *home = getenv("HOME");
+
+   if (home && *home) {
+   char *exrc = concat_path_file(home, ".exrc");
+   struct stat st;
+
+   // .exrc must belong to and only be writable by 
user
+   if (stat(exrc, &st) == 0) {
+   if (st.st_uid == getuid() &&
+   (st.st_mode & 
(S_IWGRP|S_IWOTH)) == 0) {
+   cmds = 
xmalloc_open_read_close(exrc, NULL);
+   } else {
+   status_line_bold(".exrc: 
permission denied");
+   }
+   }
+   free(exrc);
+   }
+   }
+
+   if (cmds) {
init_text_buffer(NULL);
run_cmds(cmds);
free(cmds);
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH 1/2] vi: changes to handling of -c and EXINIT

2021-08-19 Thread Ron Yorston
Rewrite handling of command line arguments so any number of -c
commands will be processed.  Previously only two -c commands
were allowed (or one if EXINIT was set).

Process commands from EXINIT before the first file is read into
memory, as specified by POSIX.

function old new   delta
run_cmds   -  77 +77
.rodata   108410  108411  +1
vi_main  305 268 -37
edit_file816 764 -52
--
(add/remove: 1/0 grow/shrink: 1/2 up/down: 78/-89)Total: -11 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 123 +++
 1 file changed, 65 insertions(+), 58 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 3e1bd0820..cc4f6bde7 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -201,6 +201,7 @@
 
 // the CRASHME code is unmaintained, and doesn't currently build
 #define ENABLE_FEATURE_VI_CRASHME 0
+#define IF_FEATURE_VI_CRASHME(...)
 
 
 #if ENABLE_LOCALE_SUPPORT
@@ -403,7 +404,7 @@ struct globals {
int cindex;   // saved character index for up/down motion
smallint keep_index;  // retain saved character index
 #if ENABLE_FEATURE_VI_COLON
-   char *initial_cmds[3];  // currently 2 entries, NULL terminated
+   llist_t *initial_cmds;
 #endif
// Should be just enough to hold a key sequence,
// but CRASHME mode uses it as generated command buffer too
@@ -4708,6 +4709,21 @@ static void crash_test()
 }
 #endif
 
+#if ENABLE_FEATURE_VI_COLON
+static void run_cmds(char *p)
+{
+   while (p) {
+   char *q = p;
+   p = strchr(q, '\n');
+   if (p)
+   while (*p == '\n')
+   *p++ = '\0';
+   if (strlen(q) < MAX_INPUT_LEN)
+   colon(q);
+   }
+}
+#endif
+
 static void edit_file(char *fn)
 {
 #if ENABLE_FEATURE_VI_YANKMARK
@@ -4778,25 +4794,8 @@ static void edit_file(char *fn)
 #endif
 
 #if ENABLE_FEATURE_VI_COLON
-   {
-   char *p, *q;
-   int n = 0;
-
-   while ((p = initial_cmds[n]) != NULL) {
-   do {
-   q = p;
-   p = strchr(q, '\n');
-   if (p)
-   while (*p == '\n')
-   *p++ = '\0';
-   if (*q)
-   colon(q);
-   } while (p);
-   free(initial_cmds[n]);
-   initial_cmds[n] = NULL;
-   n++;
-   }
-   }
+   while (initial_cmds)
+   run_cmds((char *)llist_pop(&initial_cmds));
 #endif
redraw(FALSE);  // dont force every col re-draw
//--This is the main Vi cmd handling loop ---
@@ -4859,10 +4858,29 @@ static void edit_file(char *fn)
 #undef cur_line
 }
 
+#define VI_OPTSTR \
+   IF_FEATURE_VI_CRASHME("C") \
+   IF_FEATURE_VI_COLON("c:*") \
+   "Hh" \
+   IF_FEATURE_VI_READONLY("R")
+
+enum {
+   IF_FEATURE_VI_CRASHME(OPTBIT_C,)
+   IF_FEATURE_VI_COLON(OPTBIT_c,)
+   OPTBIT_H,
+   OPTBIT_h,
+   IF_FEATURE_VI_READONLY(OPTBIT_R,)
+   OPT_C = IF_FEATURE_VI_CRASHME(  (1 << OPTBIT_C)) + 0,
+   OPT_c = IF_FEATURE_VI_COLON((1 << OPTBIT_c)) + 0,
+   OPT_H = 1 << OPTBIT_H,
+   OPT_h = 1 << OPTBIT_h,
+   OPT_R = IF_FEATURE_VI_READONLY( (1 << OPTBIT_R)) + 0,
+};
+
 int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int vi_main(int argc, char **argv)
 {
-   int c;
+   int opts;
 
INIT_G();
 
@@ -4886,50 +4904,39 @@ int vi_main(int argc, char **argv)
 
// 0: all of our options are disabled by default in vim
//vi_setops = 0;
-   //  1-  process EXINIT variable from environment
-   //  2-  if EXINIT is unset process $HOME/.exrc file (not inplemented 
yet)
-   //  3-  process command line args
-#if ENABLE_FEATURE_VI_COLON
-   {
-   char *p = getenv("EXINIT");
-   if (p && *p)
-   initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
-   }
-#endif
-   while ((c = getopt(argc, argv,
-#if ENABLE_FEATURE_VI_CRASHME
-   "C"
-#endif
-   "RHh" IF_FEATURE_VI_COLON("c:"))) != -1) {
-   switch (c) {
+   opts = getopt32(argv, VI_OPTSTR 

[PATCH 0/2] vi: initialisation commands

2021-08-19 Thread Ron Yorston
Here are some modifications to how BusyBox vi handles initialisation
commands:  -c, EXINIT and .exrc.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: six patches from tinycore linux

2021-08-12 Thread Ron Yorston
Roberto A. Foglietta wrote:
>Who is in charge of evaluating patch application?

The 'About BusyBox' page on the website says:

  BusyBox is maintained by Denys Vlasenko [vda.li...@googlemail.com]

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: six patches from tinycore linux

2021-08-12 Thread Ron Yorston
Roberto A. Foglietta wrote:
>Hi Ron,
>
> what's about the other five?

Well, I can see that they haven't been applied.  But other than that
I have no particular insight.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: six patches from tinycore linux

2021-08-10 Thread Ron Yorston
Hi Roberto,

>busybox-1.31.1-vi.backward_search.patch

This one has been applied as commit 51358757c7 (vi: fix backward search
with GNU regex).

Cheers,

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] cp: fix build failure with long options disabled

2021-08-10 Thread Ron Yorston
When long options were disabled cp failed to compile with:

coreutils/cp.c:130:9: error: empty enum is invalid
  130 | };
  | ^

Rearrange the conditional compilation to suit.

Signed-off-by: Ron Yorston 
---
 coreutils/cp.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/coreutils/cp.c b/coreutils/cp.c
index 50ca1ccea..ee40af50b 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -121,14 +121,12 @@ int cp_main(int argc, char **argv)
int d_flags;
int flags;
int status;
-   enum {
 #if ENABLE_FEATURE_CP_LONG_OPTIONS
+   enum {
/*OPT_rmdest  = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTBITS */
OPT_parents = 1 << (FILEUTILS_CP_OPTBITS+1),
OPT_reflink = 1 << (FILEUTILS_CP_OPTBITS+2),
-#endif
};
-#if ENABLE_FEATURE_CP_LONG_OPTIONS
 # if ENABLE_FEATURE_CP_REFLINK
char *reflink = NULL;
 # endif
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH 1/1] rev: handle cases where lines are too long for buffer

2021-08-09 Thread Ron Yorston
Or how about this?

Ron
---
 util-linux/rev.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/util-linux/rev.c b/util-linux/rev.c
index d439b4da8..63b005c67 100644
--- a/util-linux/rev.c
+++ b/util-linux/rev.c
@@ -109,6 +109,7 @@ int rev_main(int argc UNUSED_PARAM, char **argv)
strrev(buf, strlen(buf));
 #endif
fputs_stdout(buf);
+   pos = 0;
}
fclose(fp);
} while (*argv);
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH v2] shuf: speed-up when limited output is requested

2021-08-07 Thread Ron Yorston
A user noted that the following command was slower than they
expected:

   busybox shuf -i "15-$(date +%s)" -n 5

At time of writing the range contains 128 million values.  On my
system this takes 7.7s whereas 'shuf' from coreutils takes a
handful of milliseconds.

Optimise BusyBox 'shuf' for cases where -n is specified by stopping
shuffling once the required number of lines have been processed.
On my system the time for the example is reduced to 0.4s.

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

v2: Code shrink.  Since outlines <= numlines:
- the loop in shuffle_lines() only needs to test the value of
  outlines;
- shuffle_lines() can be called unconditionally.
Update timing to allow for the 13 million seconds elapsed since v1.

Signed-off-by: Ron Yorston 
---
 coreutils/shuf.c | 27 ++-
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/coreutils/shuf.c b/coreutils/shuf.c
index fdbd3e9b2..50dfa249d 100644
--- a/coreutils/shuf.c
+++ b/coreutils/shuf.c
@@ -39,8 +39,10 @@
 
 /*
  * Use the Fisher-Yates shuffle algorithm on an array of lines.
+ * If the required number of output lines is less than the total
+ * we can stop shuffling early.
  */
-static void shuffle_lines(char **lines, unsigned numlines)
+static void shuffle_lines(char **lines, unsigned numlines, unsigned outlines)
 {
unsigned i;
unsigned r;
@@ -48,7 +50,7 @@ static void shuffle_lines(char **lines, unsigned numlines)
 
srand(monotonic_us());
 
-   for (i = numlines-1; i > 0; i--) {
+   for (i = numlines-1; outlines > 0; i--, outlines--) {
r = rand();
/* RAND_MAX can be as small as 32767 */
if (i > RAND_MAX)
@@ -67,7 +69,7 @@ int shuf_main(int argc, char **argv)
char *opt_i_str, *opt_n_str, *opt_o_str;
unsigned i;
char **lines;
-   unsigned numlines;
+   unsigned numlines, outlines;
char eol;
 
opts = getopt32(argv, "^"
@@ -128,24 +130,23 @@ int shuf_main(int argc, char **argv)
fclose_if_not_stdin(fp);
}
 
-   if (numlines != 0)
-   shuffle_lines(lines, numlines);
+   outlines = numlines;
+   if (opts & OPT_n) {
+   outlines = xatou(opt_n_str);
+   if (outlines > numlines)
+   outlines = numlines;
+   }
+
+   shuffle_lines(lines, numlines, outlines);
 
if (opts & OPT_o)
xmove_fd(xopen(opt_o_str, O_WRONLY|O_CREAT|O_TRUNC), 
STDOUT_FILENO);
 
-   if (opts & OPT_n) {
-   unsigned maxlines;
-   maxlines = xatou(opt_n_str);
-   if (numlines > maxlines)
-   numlines = maxlines;
-   }
-
eol = '\n';
if (opts & OPT_z)
eol = '\0';
 
-   for (i = 0; i < numlines; i++) {
+   for (i = numlines-outlines; i < numlines; i++) {
if (opts & OPT_i)
printf("%u%c", (unsigned)(uintptr_t)lines[i], eol);
else
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] libbb: better coreutils compatibility for realpath

2021-07-31 Thread Ron Yorston
Add some tests which coreutils realpath pass but BusyBox realpath
fails (bar one).  Adjust xmalloc_realpath_coreutils() so the tests
pass:

- Expand symbolic links before testing whether the last path component
  exists.

- When the link target is a relative path canonicalize it by passing
  it through xmalloc_realpath_coreutils() as already happens for
  absolute paths.

- Ignore trailing slashes when finding the last path component and
  correctly handle the case where the only slash is at the start of
  the path.  This requires ignoring superfluous leading slashes.

- Undo all changes to the path so error messages from the caller show
  the original filename.

function old new   delta
xmalloc_realpath_coreutils   214 313 +99

Signed-off-by: Ron Yorston 
---
 include/libbb.h  |  2 +-
 libbb/xreadlink.c| 75 
 testsuite/realpath.tests | 45 
 3 files changed, 91 insertions(+), 31 deletions(-)
 create mode 100755 testsuite/realpath.tests

diff --git a/include/libbb.h b/include/libbb.h
index 7d6ab4a93..3c9ed792e 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -561,7 +561,7 @@ DIR *xopendir(const char *path) FAST_FUNC;
 DIR *warn_opendir(const char *path) FAST_FUNC;
 
 char *xmalloc_realpath(const char *path) FAST_FUNC RETURNS_MALLOC;
-char *xmalloc_realpath_coreutils(const char *path) FAST_FUNC RETURNS_MALLOC;
+char *xmalloc_realpath_coreutils(char *path) FAST_FUNC RETURNS_MALLOC;
 char *xmalloc_readlink(const char *path) FAST_FUNC RETURNS_MALLOC;
 char *xmalloc_readlink_or_warn(const char *path) FAST_FUNC RETURNS_MALLOC;
 /* !RETURNS_MALLOC: it's a realloc-like function */
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index a18dd0748..2682f6975 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -123,7 +123,7 @@ char* FAST_FUNC xmalloc_realpath(const char *path)
 #endif
 }
 
-char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
+char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
 {
char *buf;
 
@@ -137,32 +137,19 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char 
*path)
 * (the directory must exist).
 */
if (!buf && errno == ENOENT) {
-   char *last_slash = strrchr(path, '/');
-   if (last_slash) {
-   *last_slash++ = '\0';
-   buf = xmalloc_realpath(path);
-   if (buf) {
-   unsigned len = strlen(buf);
-   buf = xrealloc(buf, len + strlen(last_slash) + 
2);
-   buf[len++] = '/';
-   strcpy(buf + len, last_slash);
-   }
-   } else {
-   char *target = xmalloc_readlink(path);
-   if (target) {
-   char *cwd;
-   if (target[0] == '/') {
-   /*
-* $ ln -s /bin/qwe symlink  # note: 
/bin is a link to /usr/bin
-* $ readlink -f symlink
-* /usr/bin/qwe/target_does_not_exist
-* $ realpath symlink
-* /usr/bin/qwe/target_does_not_exist
-*/
-   buf = 
xmalloc_realpath_coreutils(target);
-   free(target);
-   return buf;
-   }
+   char *target, c, *last_slash;
+   size_t i;
+
+   target = xmalloc_readlink(path);
+   if (target) {
+   /*
+* $ ln -s /bin/qwe symlink  # note: /bin is a link to 
/usr/bin
+* $ readlink -f symlink
+* /usr/bin/qwe
+* $ realpath symlink
+* /usr/bin/qwe
+*/
+   if (target[0] != '/') {
/*
 * $ ln -s target_does_not_exist symlink
 * $ readlink -f symlink
@@ -170,13 +157,41 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char 
*path)
 * $ realpath symlink
 * /CURDIR/target_does_not_exist
 */
-   cwd = xrealloc_getcwd_or_warn(NULL);
-   buf = concat_path_file(cwd, target);
+   char *cwd = xrealloc_getcwd_or_warn(NULL);
+   char *tmp = concat_p

Re: [PATCH] ash: improve speed of variable pattern substitution

2021-07-23 Thread Ron Yorston
I see that Denys has applied a smaller and tidier alternative to
my attempt at a patch.  I note:

- The speed up is still only applied if a non-default build option
  is selected so there's no change in the size of a default build.

- The slower search is used if any special characters are present in
  the pattern even if they're escaped.  Thus ${x//\*/|}, for example,
  will continue to be slow.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] ash: improve speed of variable pattern substitution

2021-07-21 Thread Ron Yorston
Bash pattern substitution of variables (${var/find/replace}) was
found to take time O(N^2) (or worse).  Performance can be improved
considerably if the 'find' string doesn't contain any wildcard
characters.

Detect if this is the case, remove the backslashes added to
the pattern to protect literal references to wildcards and call
a simpler replacement function to search for the pattern.

Like a similar optimisation for patterns that end with '*' this
implementation is controlled by the ASH_OPTIMIZE_FOR_SIZE option.
Since this is enabled in the default configuration there's no
effect on the size of the binary.

When ASH_OPTIMIZE_FOR_SIZE is disabled:

function old new   delta
subevalvar  15411708+167
hasmeta- 128+128
expandarg   1099 987-112
--
(add/remove: 1/0 grow/shrink: 1/1 up/down: 295/-112)  Total: 183 bytes

Signed-off-by: Ron Yorston 
---
 shell/ash.c | 54 +++--
 1 file changed, 52 insertions(+), 2 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 2eac6e113..18d60baf2 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7024,6 +7024,27 @@ scanright(char *startp, char *rmesc, char *rmescend,
return NULL;
 }
 
+#if BASH_PATTERN_SUBST && !ENABLE_ASH_OPTIMIZE_FOR_SIZE
+static int hasmeta(const char *p);
+
+/*
+ * Like scanright() but for patterns that don't require the use of fnmatch().
+ */
+static char *
+scannoglob(char *startp, char *rmesc, char *pattern, size_t len)
+{
+   int match = strncmp(rmesc, pattern, len) == 0;
+   //bb_error_msg("strncmp(s:'%s',pattern:'%s',len:%lu):%d", rmesc, 
pattern, len, match);
+   if (match) {
+   while (len--)
+   if (*startp++ == CTLESC)
+   startp++;
+   return startp;
+   }
+   return NULL;
+}
+#endif
+
 static void varunset(const char *, const char *, const char *, int) NORETURN;
 static void
 varunset(const char *end, const char *var, const char *umsg, int varflags)
@@ -7260,6 +7281,12 @@ subevalvar(char *start, char *str, int strloc,
if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
int len;
char *idx, *end;
+# if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
+   int isglob;
+   size_t patlen;
+# else
+   const int isglob = 1;
+# endif
 
if (!repl) {
//bb_error_msg("str9:'%s' slash_pos:%d", str, 
slash_pos);
@@ -7275,12 +7302,35 @@ subevalvar(char *start, char *str, int strloc,
if (str[0] == '\0')
goto out1;
 
+# if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
+   isglob = hasmeta(str);
+   if (!isglob) {
+   /* If the pattern doesn't have any special characters 
remove
+* the backslash escapes that were added by 
rmescapes(). */
+   char *s, *t;
+   s = t = str;
+   while (*t) {
+   if (*t == '\\')
+   if (*++t == '\0')
+   break;
+   *s++ = *t++;
+   }
+   *s = '\0';
+   patlen = strlen(str);
+   }
+# endif
+
len = 0;
idx = startp;
end = str - 1;
while (idx <= end) {
  try_to_match:
-   loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
+   if (isglob)
+   loc = scanright(idx, rmesc, rmescend, str, 
quotes, 1);
+# if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
+   else
+   loc = scannoglob(idx, rmesc, str, patlen);
+# endif
//bb_error_msg("scanright('%s'):'%s'", str, loc);
if (!loc) {
/* No match, advance */
@@ -7300,7 +7350,7 @@ subevalvar(char *start, char *str, int strloc,
len++;
rmesc++;
/* continue; - prone to quadratic behavior, 
smarter code: */
-   if (str[0] == '*') {
+   if (isglob && str[0] == '*') {
/* Pattern is "*foo". If "*foo" does 
not match "long_string",
   

Re: ash ${str/find/repl} performance

2021-07-21 Thread Ron Yorston
I wrote:
>It would be possible to use a more efficient approach when the pattern
>is known to have no special characters.  But that would require more
>code.

To quantify this I made a patch which handles the special case of
patterns that don't require globbing.  The feature is controlled by
the ASH_OPTIMIZE_FOR_SIZE configuration option so it isn't enabled
in the default build (where ASH_OPTIMIZE_FOR_SIZE is enabled).
When it is enabled it adds 183 bytes.

Benchmarks with the feature enabled follow.  This command uses a
bracket expression so globbing is required:

hyperfine -L n 10,15,20,30 -S ./ash -w 2 -r 10 -s basic '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -{n});
for i in $(seq 1 20); do echo "${x//[:]/|}"; done'

Benchmark #1: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done
  Time (mean ± σ):  36.9 ms ±   0.6 ms[User: 36.3 ms, System: 1.1 ms]
  Range (min … max):36.2 ms …  38.4 ms10 runs
 
Benchmark #2: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done
  Time (mean ± σ): 104.6 ms ±   1.4 ms[User: 104.0 ms, System: 1.0 ms]
  Range (min … max):   103.1 ms … 107.6 ms10 runs
 
Benchmark #3: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done
  Time (mean ± σ): 241.3 ms ±   2.7 ms[User: 240.5 ms, System: 1.1 ms]
  Range (min … max):   238.2 ms … 246.7 ms10 runs
 
Benchmark #4: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done
  Time (mean ± σ): 697.1 ms ±   4.0 ms[User: 695.6 ms, System: 1.0 ms]
  Range (min … max):   691.8 ms … 701.8 ms10 runs

Summary
  '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done' ran
2.84 ± 0.06 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done'
6.54 ± 0.14 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done'
   18.90 ± 0.35 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30);
for i in $(seq 1 20); do echo "${x//[:]/|}"; done'

The elapsed times and the increase in time with variable length are
similar to the results reported previously.

This command uses a literal search string:

hyperfine -L n 10,15,20,30 -S ./ash -w 2 -r 10 -s basic '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -{n});
for i in $(seq 1 1000); do echo "${x//:/|}"; done'

Benchmark #1: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10);
for i in $(seq 1 1000); do echo "${x//:/|}"; done
  Time (mean ± σ):   9.0 ms ±   0.6 ms[User: 8.4 ms, System: 1.2 ms]
  Range (min … max): 8.5 ms …  10.5 ms10 runs
 
Benchmark #2: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15);
for i in $(seq 1 1000); do echo "${x//:/|}"; done
  Time (mean ± σ):  12.5 ms ±   0.1 ms[User: 11.6 ms, System: 1.5 ms]
  Range (min … max):12.4 ms …  12.7 ms10 runs
 
Benchmark #3: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20);
for i in $(seq 1 1000); do echo "${x//:/|}"; done
  Time (mean ± σ):  17.9 ms ±   1.1 ms[User: 17.6 ms, System: 0.9 ms]
  Range (min … max):17.0 ms …  19.5 ms10 runs
 
Benchmark #4: 
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30);
for i in $(seq 1 1000); do echo "${x//:/|}"; done
  Time (mean ± σ):  27.2 ms ±   0.9 ms[User: 26.7 ms, System: 1.1 ms]
  Range (min … max):26.0 ms …  28.4 ms10 runs

Summary
  '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10);
for i in $(seq 1 1000); do echo "${x//:/|}"; done' ran
1.39 ± 0.09 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15);
for i in $(seq 1 1000); do echo "${x//:/|}"; done'
1.99 ± 0.18 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20);
for i in $(seq 1 1000); do echo "${x//:/|}"; done'
3.03 ± 0.22 times faster than '
x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30);
for i in $(seq 1 1000); do echo "${x//:/|}"; done'

The elapsed times are much shorter:  I had to increase the number of
iterations from 20 to 1000 to get reliable measurements.  The increase
in time with variable length is linear.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: ash ${str/find/repl} performance

2021-07-20 Thread Ron Yorston
Alin Mr wrote:

>It seems that bash-like pattern substitution is surprisingly slow.

The relevant code is scanright() and the code around its first call in
subevalvar().  It assumes the search string might contain special
characters.  So for x="root:x:0:0:root:/root:/bin/bash" and ${x//:/|}
it uses fnmatch() to match the pattern against each of these in turn:

   root:x:0:0:root:/root:/bin/bash
   root:x:0:0:root:/root:/bin/bas
   root:x:0:0:root:/root:/bin/ba
   root:x:0:0:root:/root:/bin/b
   ...
   r

When that doesn't work it moves on to:

   oot:x:0:0:root:/root:/bin/bash
   oot:x:0:0:root:/root:/bin/bas
   oot:x:0:0:root:/root:/bin/ba
   oot:x:0:0:root:/root:/bin/b
   ...
   o

Eventually it'll find a match with:

   :x:0:0:root:/root:/bin/bash
   :x:0:0:root:/root:/bin/bas
   :x:0:0:root:/root:/bin/ba
   :x:0:0:root:/root:/bin/b
   ...
   :

After making the replacement it then carries on to find the next match.

It would be possible to use a more efficient approach when the pattern
is known to have no special characters.  But that would require more
code.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: Why busybox ash do not support $[ ] for math?

2021-07-18 Thread Ron Yorston
Roberto A. Foglietta wrote:
> why busybox ash do not support $[ ] for math?
> Possibly because original ash does not support it but bash only?
> Have you ever thought about adding this feature or $(( )) is enough?

The $[...] form of arithmetic expansion has been deprecated since
bash 2.0.  It isn't mentioned in the current reference manual and
the Bash Hackers Wiki recommends not using it.

Only the $((...)) form is supported in POSIX.

All things considered, $[...] doesn't seem to be a very attractive
candidate for inclusion in BusyBox ash.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] vi: fix regex search compilation error

2021-07-14 Thread Ron Yorston
Bernhard Reutner-Fischer wrote:
>ah oh in the old code we double increment (only) if the first was a
>backslash _not_ followed by a nul.
>hmz. So is there a more elegant way to express that which i don't see
>right now?

I suspect the inelegance is inherent.  Here's the current code:

1while (*s) {
2   if (*s == c)
3  return (char *)s;
4   if (*s == '\\')
5  if (*++s == '\0')
6 break;
7   s++;
8}

It has the advantage that all the special magic is in lines 4-6.
If you ignore them it's just a standard strchr().

1while (*s) {
2   if (*s == c)
3  return (char *)s;
4   if (*s++ == '\\')
5  if (*s++ == '\0')
6 break;
7}

This is more uniform but adds 6 bytes of bloat.

1while (*s) {
2   if (*s == c)
3  return (char *)s;
4   if (*s++ == '\\')
5  if (*s != '\0')
6 s++;
7}

This makes it clearer that we only skip the character following the
backslash if it's not NUL and it avoids the break.  5 bytes of bloat.

Dietmar's suggestion is indeed equivalent and adds no bloat.  But,
in my opinion, needs more effort to understand.

If the current code is unclear maybe it needs a comment:

  // skip char after backslash, unless it's NUL

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] vi: fix regex search compilation error

2021-07-13 Thread Ron Yorston
Bernhard Reutner-Fischer wrote:
>If i'm not mistaken, the s++ is fully redundant here although it seems
>that my gcc-11 does not optimize it like if we manually spell it out
>like in the attached?

I don't think it's possible to avoid two increments.  When a backslash
is detected we want to move past it and the following character.

Consider:

   strchr_backslash("\\/abc/def", '/');

The original code and Denys' rewrite return a pointer to "/def"; your
suggestion returns a pointer to "/abc/def".

>Must be marked noinline to avoid inlining it twice it seems?!
>If that double inlining really happens then the implied code growth
>even for -Os is a different bug..

Hmm, yes, that's rather an odd thing for the compiler to do.

Ron
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: fix regex search compilation error

2021-07-13 Thread Ron Yorston
Building with FEATURE_VI_REGEX_SEARCH enabled fails.

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/editors/vi.c b/editors/vi.c
index 5c601c759..a4b958734 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2684,7 +2684,7 @@ static char *expand_args(char *args)
 static char *strchr_backslash(const char *s, int c)
 {
while (*s) {
-   if (*s == c) {
+   if (*s == c)
return (char *)s;
if (*s == '\\')
if (*++s == '\0')
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: [PATCH] vi: fix undo when ':s' replacement string is empty

2021-07-13 Thread Ron Yorston
Denys Vlasenko wrote:
>I missed this one, and then this part was rewritten in
>"allow regular expressions in ':s' commands".
>Sorry about the mess.

No worries.  Looks OK at first glance, though only time and continued
dogfooding of BusyBox vi will tell.

I think we may have ended up with a superfluous line.  Unless it was
intentional...

Ron
---
 editors/vi.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/editors/vi.c b/editors/vi.c
index c6bb74cfb..ce5740e49 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3243,7 +3243,6 @@ static void colon(char *buf)
TEST_UNDO2 ? 
ALLOW_UNDO_CHAIN: ALLOW_UNDO);
found += bias;
ls += bias;
-   dot = ls;
//q += bias; - recalculated anyway
}
 #  if ENABLE_FEATURE_VI_REGEX_SEARCH
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: allow delimiter in ':s' to be escaped

2021-07-10 Thread Ron Yorston
When regular expressions are allowed in search commands it becomes
possible to escape the delimiter in search/replace commands.  For
example, this command will replace '/abc' with '/abc/':

   :s/\/abc/\/abc\//g

The code to split the command into 'find' and 'replace' strings
should allow for this possibility.

VI_REGEX_SEARCH isn't enabled by default.  When it is:

function old new   delta
strchr_backslash   -  38 +38
colon   43784373  -5
--
(add/remove: 1/0 grow/shrink: 0/1 up/down: 38/-5)          Total: 33 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index f830368c2..ce5740e49 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2680,6 +2680,19 @@ static char *expand_args(char *args)
 #if ENABLE_FEATURE_VI_REGEX_SEARCH
 # define MAX_SUBPATTERN 10 // subpatterns \0 .. \9
 
+// Like strchr() but skipping backslash-escaped characters
+static char *strchr_backslash(const char *s, int c)
+{
+   for (; *s; ++s) {
+   if (*s == c) {
+   return (char *)s;
+   } else if (*s == '\\' && *++s == '\0') {
+   break;
+   }
+   }
+   return NULL;
+}
+
 // If the return value is not NULL the caller should free R
 static char *regex_search(char *q, regex_t *preg, const char *Rorig,
size_t *len_F, size_t *len_R, char **R)
@@ -2728,6 +2741,8 @@ static char *regex_search(char *q, regex_t *preg, const 
char *Rorig,
 
return found;
 }
+#else /* !ENABLE_FEATURE_VI_REGEX_SEARCH */
+# define strchr_backslash(s, c) strchr(s, c)
 #endif /* ENABLE_FEATURE_VI_REGEX_SEARCH */
 
 // buf must be no longer than MAX_INPUT_LEN!
@@ -3151,12 +3166,12 @@ static void colon(char *buf)
// replace the cmd line delimiters "/" with NULs
c = buf[1]; // what is the delimiter
F = buf + 2;// start of "find"
-   R = strchr(F, c);   // middle delimiter
+   R = strchr_backslash(F, c); // middle delimiter
if (!R)
goto colon_s_fail;
len_F = R - F;
*R++ = '\0';// terminate "find"
-   flags = strchr(R, c);
+   flags = strchr_backslash(R, c);
if (flags) {
*flags++ = '\0';// terminate "replace"
gflag = *flags;
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: awk error as of git / today

2021-07-09 Thread Ron Yorston
Steffen Nurpmeso wrote:
>  $ AWK="/home/steffen/usr-kent-linux-x86_64/bin/busybox awk" \
>dash mdocmx.sh mdocmx.1|wc -l
>  27

Commit 08ca313d7 (awk: simplify tests for operation class) replaced
tests for operation classes with simple equality tests.

It seems this doesn't work for combinations of print and redirection.
In that case this code:

   case OC_PRINT:
   case OC_PRINTF:
  debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
  n = chain_node(t_info);
  n->l.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_OUTRDR | TC_RBRACE);
  if (t_tclass & TC_OUTRDR) {
 n->info |= t_info;
 n->r.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_RBRACE);
  }
  if (t_tclass & TC_RBRACE)
 rollback_token();
  break;

combines the print and redirection bits.

Reverting the part of the commit that handles OC_PRINT appears to
fix the problem.  No guarantees, though.

Ron
---
 editors/awk.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index cd135ef64..4dc4d47aa 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -462,8 +462,7 @@ static const uint32_t tokeninfo[] ALIGN4 = {
0,
0, /* \n */
ST_IF,ST_DO,ST_FOR,  OC_BREAK,
-#define TI_PRINT OC_PRINT
-   OC_CONTINUE,  OC_DELETE|Rx, TI_PRINT,
+   OC_CONTINUE,  OC_DELETE|Rx, OC_PRINT,
OC_PRINTF,OC_NEXT,  OC_NEXTFILE,
OC_RETURN|Vx, OC_EXIT|Nx,
ST_WHILE,
@@ -2929,7 +2928,7 @@ static var *evaluate(node *op, var *res)
F = rsm->F;
}
 
-   if (opinfo == TI_PRINT) {
+   if ((opinfo & OPCLSMASK) == OC_PRINT) {
if (!op1) {
fputs(getvar_s(intvar[F0]), F);
} else {
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[PATCH] vi: allow 'gg' to specify a range

2021-07-07 Thread Ron Yorston
Commit 7b93e317c (vi: enable 'dG' command. Closes 11801) allowed
'G' to be used as a range specifier for change/yank/delete
operations.

Add similar support for 'gg'.  This requires setting the 'cmd_error'
flag if 'g' is followed by any character other than another 'g'.

function old new   delta
do_cmd  48524860  +8
.rodata   108179  108180  +1
--
(add/remove: 0/0 grow/shrink: 2/0 up/down: 9/0) Total: 9 bytes

Signed-off-by: Ron Yorston 
---
 editors/vi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/editors/vi.c b/editors/vi.c
index f779507fc..f830368c2 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3539,7 +3539,7 @@ static int find_range(char **start, char **stop, int cmd)
// for non-change operations WS after NL is not part of word
if (cmd != 'c' && dot != t && *dot != '\n')
dot = t;
-   } else if (strchr("GHL+-jk'\r\n", c)) {
+   } else if (strchr("GHL+-gjk'\r\n", c)) {
// these operate on whole lines
buftype = WHOLE;
do_cmd(c);  // execute movement cmd
@@ -4129,6 +4129,7 @@ static void do_cmd(int c)
buf[1] = (c1 >= 0 ? c1 : '*');
buf[2] = '\0';
not_implemented(buf);
+   cmd_error = TRUE;
break;
}
if (cmdcnt == 0)
-- 
2.31.1

___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


  1   2   3   4   5   6   >