Index | Thread | Search

From:
joshua stein <jcs@jcs.org>
Subject:
Re: cups-filters: fix driverless
To:
deraadt@openbsd.org, ports@openbsd.org
Date:
Wed, 18 Feb 2026 20:22:03 -0600

Download raw body.

Thread
On Wed, 18 Feb 2026 at 20:10:05 -0600, joshua stein wrote:
> On Wed, 18 Feb 2026 at 18:22:38 -0700, Theo de Raadt wrote:
> > Can someone write the -e and -E diff for echo like I suggest please?
> 
> this makes cups-filters ippfind happy, running an mkr with it now

oops, try #2:


diff --git bin/echo/echo.1 bin/echo/echo.1
index 7286602d752..cfd0391eb44 100644
--- bin/echo/echo.1
+++ bin/echo/echo.1
@@ -41,7 +41,7 @@
 .Nd write arguments to the standard output
 .Sh SYNOPSIS
 .Nm echo
-.Op Fl n
+.Op Fl Een
 .Op Ar string ...
 .Sh DESCRIPTION
 The
@@ -63,6 +63,41 @@ is treated as part of
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
+.It Fl E
+Disable interpretation of backslash escape sequences (default).
+.It Fl e
+Enable interpretation of the following backslash escape sequences:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It Cm \e\e
+A literal backslash.
+.It Cm \ea
+Alert (BEL).
+.It Cm \eb
+Backspace.
+.It Cm \ec
+Suppress further output, including the trailing newline character.
+.It Cm \ee
+Escape character.
+.It Cm \ef
+Form feed.
+.It Cm \en
+Newline.
+.It Cm \er
+Carriage return.
+.It Cm \et
+Horizontal tab.
+.It Cm \ev
+Vertical tab.
+.It Cm \e0 Ns Ar nnn
+The character whose octal value is
+.Ar nnn
+(zero to three octal digits).
+.It Cm \ex Ns Ar hh
+The character whose hexadecimal value is
+.Ar hh
+(one or two hexadecimal digits).
+.El
 .It Fl n
 Do not print the trailing newline character.
 .El
@@ -79,17 +114,17 @@ utility is compliant with the
 .St -p1003.1-2008
 specification.
 .Pp
-The flag
+The flags
+.Op Fl E ,
+.Op Fl e ,
+and
 .Op Fl n
-conflicts with the behaviour mandated by the
+conflict with the behaviour mandated by the
 X/Open System Interfaces option of the
 .St -p1003.1-2008
 specification,
-which says it should be treated as part of
+which says they should be treated as part of
 .Ar string .
-Additionally,
-.Nm
-does not support any of the backslash character sequences mandated by XSI.
 .Pp
 .Nm
 also exists as a built-in to
diff --git bin/echo/echo.c bin/echo/echo.c
index 52da05c050f..20bd7fb5cb9 100644
--- bin/echo/echo.c
+++ bin/echo/echo.c
@@ -30,29 +30,52 @@
  * SUCH DAMAGE.
  */
 
+#include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <err.h>
 
+int escape(const char *);
+
 int
 main(int argc, char *argv[])
 {
-	int nflag;
+	int nflag = 0, eflag = 0;
+	const char *p;
 
 	if (pledge("stdio", NULL) == -1)
 		err(1, "pledge");
 
 	/* This utility may NOT do getopt(3) option parsing. */
-	if (*++argv && !strcmp(*argv, "-n")) {
-		++argv;
-		nflag = 1;
+	while (*++argv && **argv == '-' && (*argv)[1] != '\0') {
+		for (p = *argv + 1; *p != '\0'; p++)
+			if (*p != 'E' && *p != 'e' && *p != 'n')
+				goto echoargs;
+
+		for (p = *argv + 1; *p != '\0'; p++) {
+			switch (*p) {
+			case 'E':
+				eflag = 0;
+				break;
+			case 'e':
+				eflag = 1;
+				break;
+			case 'n':
+				nflag = 1;
+				break;
+			}
+		}
 	}
-	else
-		nflag = 0;
 
+echoargs:
 	while (*argv) {
-		(void)fputs(*argv, stdout);
+		if (eflag) {
+			if (escape(*argv) != 0)
+				/* \c encountered */
+				return 0;
+		} else
+			(void)fputs(*argv, stdout);
 		if (*++argv)
 			putchar(' ');
 	}
@@ -61,3 +84,86 @@ main(int argc, char *argv[])
 
 	return 0;
 }
+
+/* return -1 on \c to suppress further output */
+int
+escape(const char *s)
+{
+	int ch, n;
+
+	while ((ch = *s++) != '\0') {
+		if (ch != '\\') {
+			putchar(ch);
+			continue;
+		}
+
+		switch ((ch = *s++)) {
+		case '\0':
+			putchar('\\');
+			return 0;
+		case '\\':
+			putchar('\\');
+			break;
+		case 'a':
+			putchar('\a');
+			break;
+		case 'b':
+			putchar('\b');
+			break;
+		case 'c':
+			return -1;
+		case 'e':
+			putchar('\033');
+			break;
+		case 'f':
+			putchar('\f');
+			break;
+		case 'n':
+			putchar('\n');
+			break;
+		case 'r':
+			putchar('\r');
+			break;
+		case 't':
+			putchar('\t');
+			break;
+		case 'v':
+			putchar('\v');
+			break;
+		case '0':
+			/* octal: \0nnn */
+			ch = 0;
+			for (n = 0; n < 3 && *s >= '0' && *s <= '7'; n++)
+				ch = ch * 8 + (*s++ - '0');
+			putchar(ch);
+			break;
+		case 'x':
+			/* hexadecimal: \xhh */
+			if (isxdigit((unsigned char)*s)) {
+				ch = 0;
+				for (n = 0;
+				    n < 2 && isxdigit(*s); n++) {
+					ch *= 16;
+					if (*s >= '0' && *s <= '9')
+						ch += *s - '0';
+					else if (*s >= 'a' && *s <= 'f')
+						ch += *s - 'a' + 10;
+					else
+						ch += *s - 'A' + 10;
+					s++;
+				}
+				putchar(ch);
+			} else {
+				putchar('\\');
+				putchar('x');
+			}
+			break;
+		default:
+			putchar('\\');
+			putchar(ch);
+			break;
+		}
+	}
+
+	return 0;
+}