[git commit branch/1_34_stable] awk: code shrink: avoid duplicate NUL checks and strlen()

Denys Vlasenko vda.linux at googlemail.com
Wed Sep 29 22:15:44 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=5ec12fa657052ceebe02f98571402232ca411c3c
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/1_34_stable

function                                             old     new   delta
awk_printf                                           665     652     -13

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/awk.c | 54 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 33 insertions(+), 21 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index 3594717b1..46bda93b2 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -2345,38 +2345,49 @@ static char *awk_printf(node *n, size_t *len)
 		var *arg;
 		size_t slen;
 
+		/* Find end of the next format spec, or end of line */
 		s = f;
-		while (*f && *f != '%')
+		while (1) {
+			c = *f;
+			if (!c) /* no percent chars found at all */
+				goto nul;
+			if (c == '%') {
+				c = *++f;
+				if (!c) /* we are past % in "....%" */
+					goto nul;
+				break;
+			}
+			f++;
+		}
+		/* we are past % in "....%...", c == char after % */
+		if (c == '%') { /* double % */
+			slen = f - s;
+			s = xstrndup(s, slen);
 			f++;
-		if (*f) {
+			goto tail; /* print "....%" part verbatim */
+		}
+		while (1) {
+			if (isalpha(c))
+				break;
+			if (c == '*')
+				syntax_error("%*x formats are not supported");
 			c = *++f;
-			if (c == '%') { /* double % */
+			if (!c) { /* "....%...." and no letter found after % */
+				/* Example: awk 'BEGIN { printf "^^^%^^^\n"; }' */
+ nul:
 				slen = f - s;
-				s = xstrndup(s, slen);
-				f++;
-				goto tail;
-			}
-			while (*f && !isalpha(*f)) {
-				if (*f == '*')
-					syntax_error("%*x formats are not supported");
-				f++;
+				goto tail; /* print remaining string, exit loop */
 			}
 		}
-		c = *f;
-		if (!c) {
-			/* Tail of fmt with no percent chars,
-			 * or "....%" (percent seen, but no format specifier char found)
-			 */
-			slen = strlen(s);
-			goto tail;
-		}
-		sv = *++f;
-		*f = '\0';
+		/* we are at A in "....%...A..." */
+
 		arg = evaluate(nextarg(&n), TMPVAR);
 
 		/* Result can be arbitrarily long. Example:
 		 *  printf "%99999s", "BOOM"
 		 */
+		sv = *++f;
+		*f = '\0';
 		if (c == 'c') {
 			char cc = is_numeric(arg) ? getvar_i(arg) : *getvar_s(arg);
 			char *r = xasprintf(s, cc ? cc : '^' /* else strlen will be wrong */);
@@ -2395,6 +2406,7 @@ static char *awk_printf(node *n, size_t *len)
 				} else if (strchr("eEfFgGaA", c)) {
 					s = xasprintf(s, d);
 				} else {
+//TODO: GNU Awk 5.0.1: printf "%W" prints "%W", does not error out
 					syntax_error(EMSG_INV_FMT);
 				}
 			}


More information about the busybox-cvs mailing list