aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lib.c23
-rw-r--r--lib/lib.h1
-rw-r--r--toys/posix/echo.c46
-rw-r--r--toys/posix/find.c16
4 files changed, 38 insertions, 48 deletions
diff --git a/lib/lib.c b/lib/lib.c
index 364ce07e..4fa358c0 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -436,6 +436,29 @@ int unescape(char c)
return (idx == -1) ? 0 : to[idx];
}
+// parse next character advancing pointer. echo requires leading 0 in octal esc
+int unescape2(char **c, int echo)
+{
+ int idx = *((*c)++), i, off;
+
+ if (idx != '\\' || !**c) return idx;
+ if (**c == 'c') return 31&*(++*c);
+ for (i = 0; i<4; i++) {
+ if (sscanf(*c, (char *[]){"0%3o%n"+!echo, "x%2x%n", "u%4x%n", "U%6x%n"}[i],
+ &idx, &off))
+ {
+ *c += off;
+
+ return idx;
+ }
+ }
+
+ if (-1 == (idx = stridx("\\abeEfnrtv'\"?", **c))) return '\\';
+ ++*c;
+
+ return "\\\a\b\033\033\f\n\r\t\v'\"?"[idx];
+}
+
// If string ends with suffix return pointer to start of suffix in string,
// else NULL
char *strend(char *str, char *suffix)
diff --git a/lib/lib.h b/lib/lib.h
index 3200dc32..60c800ca 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -234,6 +234,7 @@ char *strlower(char *s);
char *strafter(char *haystack, char *needle);
char *chomp(char *s);
int unescape(char c);
+int unescape2(char **c, int echo);
char *strend(char *str, char *suffix);
int strstart(char **a, char *b);
int strcasestart(char **a, char *b);
diff --git a/toys/posix/echo.c b/toys/posix/echo.c
index c78c2c01..b546e94b 100644
--- a/toys/posix/echo.c
+++ b/toys/posix/echo.c
@@ -41,12 +41,10 @@ config ECHO
void echo_main(void)
{
- int i = 0, out;
- char *arg, *c;
+ int i = 0;
+ char *arg, *c, out[8];
- for (;;) {
- arg = toys.optargs[i];
- if (!arg) break;
+ while ((arg = toys.optargs[i])) {
if (i++) putchar(' ');
// Should we output arg verbatim?
@@ -58,40 +56,12 @@ void echo_main(void)
// Handle -e
- for (c = arg;;) {
- if (!(out = *(c++))) break;
+ for (c = arg; *c; ) {
+ unsigned u;
- // handle \escapes
- if (out == '\\' && *c) {
- int slash = *(c++), n = unescape(slash);
-
- if (n) out = n;
- else if (slash=='c') return;
- else if (slash=='0') {
- out = 0;
- while (*c>='0' && *c<='7' && n++<3) out = (out*8)+*(c++)-'0';
- } else if (slash=='x') {
- out = 0;
- while (n++<2) {
- if (*c>='0' && *c<='9') out = (out*16)+*(c++)-'0';
- else {
- int temp = tolower(*c);
- if (temp>='a' && temp<='f') {
- out = (out*16)+temp-'a'+10;
- c++;
- } else {
- if (n==1) {
- --c;
- out = '\\';
- }
- break;
- }
- }
- }
- // Slash in front of unknown character, print literal.
- } else c--;
- }
- putchar(out);
+ if (*c == '\\' && c[1] == 'c') return;
+ if ((u = unescape2(&c, 1))<128) putchar(u);
+ else printf("%.*s", (int)wcrtomb(out, u, 0), out);
}
}
diff --git a/toys/posix/find.c b/toys/posix/find.c
index 3fb97b1c..9b688d46 100644
--- a/toys/posix/find.c
+++ b/toys/posix/find.c
@@ -585,16 +585,12 @@ static int do_find(struct dirtree *new)
if (check) for (fmt = ss[1]; *fmt; fmt++) {
// Print the parts that aren't escapes
if (*fmt == '\\') {
- int slash = *++fmt, n = unescape(slash);
-
- if (n) ch = n;
- else if (slash=='c') break;
- else if (slash=='0') {
- ch = 0;
- while (*fmt>='0' && *fmt<='7' && n++<3) ch=(ch*8)+*(fmt++)-'0';
- --fmt;
- } else error_exit("bad \\%c", *fmt);
- putchar(ch);
+ unsigned u;
+
+ if (fmt[1] == 'c') break;
+ if ((u = unescape2(&fmt, 0))<128) putchar(u);
+ else printf("%.*s", (int)wcrtomb(buf, u, 0), buf);
+ fmt--;
} else if (*fmt != '%') putchar(*fmt);
else if (*++fmt == '%') putchar('%');
else {