summaryrefslogtreecommitdiff
path: root/usr.bin/tr/str.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tr/str.c')
-rw-r--r--usr.bin/tr/str.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/usr.bin/tr/str.c b/usr.bin/tr/str.c
index 6b5f1f02d37..26e706d29ba 100644
--- a/usr.bin/tr/str.c
+++ b/usr.bin/tr/str.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: str.c,v 1.12 2012/12/05 23:20:26 deraadt Exp $ */
+/* $OpenBSD: str.c,v 1.13 2021/10/31 21:34:16 cheloha Exp $ */
/* $NetBSD: str.c,v 1.7 1995/08/31 22:13:47 jtc Exp $ */
/*-
@@ -32,6 +32,7 @@
#include <sys/types.h>
+#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
@@ -280,25 +281,34 @@ genseq(s)
* an escape code or a literal character.
*/
static int
-backslash(s)
- STR *s;
+backslash(STR *s)
{
- int ch, cnt, val;
+ size_t i;
+ int ch, val;
- for (cnt = val = 0;;) {
- ch = *++s->str;
- if (!isascii(ch) || !isdigit(ch))
- break;
- val = val * 8 + ch - '0';
- if (++cnt == 3) {
- ++s->str;
+ assert(*s->str == '\\');
+ s->str++;
+
+ /* Empty escapes become plain backslashes. */
+ if (*s->str == '\0') {
+ s->state = EOS;
+ return ('\\');
+ }
+
+ val = 0;
+ for (i = 0; i < 3; i++) {
+ if (s->str[i] < '0' || '7' < s->str[i])
break;
- }
+ val = val * 8 + s->str[i] - '0';
}
- if (cnt)
+ if (i > 0) {
+ if (val > UCHAR_MAX)
+ errx(1, "octal value out of range: %d", val);
+ s->str += i;
return (val);
- if (ch != '\0')
- ++s->str;
+ }
+
+ ch = *s->str++;
switch (ch) {
case 'a': /* escape characters */
return ('\7');
@@ -314,9 +324,6 @@ backslash(s)
return ('\t');
case 'v':
return ('\13');
- case '\0': /* \" -> \ */
- s->state = EOS;
- return ('\\');
default: /* \x" -> x */
return (ch);
}