-/* $OpenBSD: compile.c,v 1.43 2017/12/08 18:41:59 martijn Exp $ */
+/* $OpenBSD: compile.c,v 1.44 2017/12/11 13:25:57 martijn Exp $ */
/*-
* Copyright (c) 1992 Diomidis Spinellis.
static char *compile_addr(char *, struct s_addr *);
static char *compile_ccl(char **, char *);
-static char *compile_delimited(char *, char *, int);
+static char *compile_delimited(char *, char *);
static char *compile_flags(char *, struct s_subst *);
static char *compile_re(char *, regex_t **);
static char *compile_subst(char *, struct s_subst *);
* with the processed string.
*/
static char *
-compile_delimited(char *p, char *d, int is_tr)
+compile_delimited(char *p, char *d)
{
char c;
p += 2;
continue;
} else if (*p == '\\' && p[1] == '\\') {
- if (is_tr)
- p++;
- else
- *d++ = *p++;
+ *d++ = *p++;
} else if (*p == c) {
*d = '\0';
return (p + 1);
char *re;
re = xmalloc(strlen(p) + 1); /* strlen(re) <= strlen(p) */
- p = compile_delimited(p, re, 0);
+ p = compile_delimited(p, re);
if (p && strlen(re) == 0) {
*repp = NULL;
free(re);
* Compile a translation set of strings into a lookup table.
*/
static char *
-compile_tr(char *p, char **transtab)
+compile_tr(char *old, char **transtab)
{
int i;
- char *lt, *op, *np;
- char *old = NULL, *new = NULL;
-
- if (*p == '\0' || *p == '\\')
- error(COMPILE,
-"transform pattern can not be delimited by newline or backslash");
- old = xmalloc(strlen(p) + 1);
- p = compile_delimited(p, old, 1);
- if (p == NULL) {
- error(COMPILE, "unterminated transform source string");
- goto bad;
- }
- new = xmalloc(strlen(p) + 1);
- p = compile_delimited(--p, new, 1);
- if (p == NULL) {
- error(COMPILE, "unterminated transform target string");
- goto bad;
- }
- EATSPACE();
- if (strlen(new) != strlen(old)) {
- error(COMPILE, "transform strings are not the same length");
- goto bad;
- }
+ char delimiter, check[UCHAR_MAX];
+ char *new, *end;
+
+ memset(check, 0, sizeof(check));
+ delimiter = *old;
+ if (delimiter == '\\')
+ error(COMPILE, "\\ can not be used as a string delimiter");
+ else if (delimiter == '\n' || delimiter == '\0')
+ error(COMPILE, "newline can not be used as a string delimiter");
+
+ new = old++;
+ do {
+ if ((new = strchr(new + 1, delimiter)) == NULL)
+ error(COMPILE, "unterminated transform source string");
+ } while (*(new - 1) == '\\' && *(new -2) != '\\');
+ *new = '\0';
+ end = new++;
+ do {
+ if ((end = strchr(end + 1, delimiter)) == NULL)
+ error(COMPILE, "unterminated transform target string");
+ } while (*(end -1) == '\\' && *(end -2) != '\\');
+ *end = '\0';
+
/* We assume characters are 8 bits */
- lt = xmalloc(UCHAR_MAX + 1);
+ *transtab = xmalloc(UCHAR_MAX + 1);
for (i = 0; i <= UCHAR_MAX; i++)
- lt[i] = (char)i;
- for (op = old, np = new; *op; op++, np++)
- lt[(u_char)*op] = *np;
- *transtab = lt;
- free(old);
- free(new);
- return (p);
-bad:
- free(old);
- free(new);
- return (NULL);
+ (*transtab)[i] = (char)i;
+
+ while (*old != '\0' && *new != '\0') {
+ if (*old == '\\') {
+ old++;
+ if (*old == 'n')
+ *old = '\n';
+ else if (*old != delimiter && *old != '\\')
+ error(COMPILE, "Unexpected character after "
+ "backslash");
+
+ }
+ if (*new == '\\') {
+ new++;
+ if (*new == 'n')
+ *new = '\n';
+ else if (*new != delimiter && *new != '\\')
+ error(COMPILE, "Unexpected character after "
+ "backslash");
+ }
+ if (check[*old] == 1)
+ error(COMPILE, "Repeated character in source string");
+ check[*old] = 1;
+ (*transtab)[*old++] = *new++;
+ }
+ if (*old != '\0' || *new != '\0')
+ error(COMPILE, "transform strings are not the same length");
+ return end + 1;
}
/*
-.\" $OpenBSD: sed.1,v 1.52 2017/12/08 18:41:59 martijn Exp $
+.\" $OpenBSD: sed.1,v 1.53 2017/12/11 13:25:57 martijn Exp $
.\"
.\" Copyright (c) 1992, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" from: @(#)sed.1 8.2 (Berkeley) 12/30/93
.\"
-.Dd $Mdocdate: December 8 2017 $
+.Dd $Mdocdate: December 11 2017 $
.Dt SED 1
.Os
.Sh NAME
.Ar string2 .
Any character other than a backslash or newline can be used instead of
a slash to delimit the strings.
+.Pp
Within
.Ar string1
and
.Ar string2 ,
-a backslash followed by any character other than a newline is that literal
-character, and a backslash followed by an
+a backslash followed by another backslash
+is replaced by a single backslash,
+a backslash followed by an
+.Sq n
+is replaced by a newline character,
+and a backslash followed by the delimiting character
+is replaced by that character,
+causing it to be treated literally,
+with the exception of the
.Sq n
-is replaced by a newline character.
+character,
+which will still be treated like a newline character.
+It is an error for a backslash to not be followed by another backslash,
+.Sq n ,
+or the delimiting character,
+or for
+.Ar string1
+to contain repeating characters.
.It [0addr] Ns Ic \&: Ns Ar label
This function does nothing; it bears a
.Ar label