summaryrefslogtreecommitdiff
path: root/usr.bin/sed/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/sed/compile.c')
-rw-r--r--usr.bin/sed/compile.c167
1 files changed, 116 insertions, 51 deletions
diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c
index 526f21c89f7e..72cb93fcd3f4 100644
--- a/usr.bin/sed/compile.c
+++ b/usr.bin/sed/compile.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992 Diomidis Spinellis.
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92";
+/* from: static char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93"; */
+static char *rcsid = "$Id: compile.c,v 1.5 1994/04/17 09:41:36 alm Exp $";
#endif /* not lint */
#include <sys/types.h>
@@ -54,6 +55,15 @@ static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92";
#include "defs.h"
#include "extern.h"
+#define LHSZ 128
+#define LHMASK (LHSZ - 1)
+static struct labhash {
+ struct labhash *lh_next;
+ u_int lh_hash;
+ struct s_command *lh_cmd;
+ int lh_ref;
+} *labels[LHSZ];
+
static char *compile_addr __P((char *, struct s_addr *));
static char *compile_ccl __P((char **, char *));
static char *compile_delimited __P((char *, char *));
@@ -64,11 +74,12 @@ static char *compile_text __P((void));
static char *compile_tr __P((char *, char **));
static struct s_command
**compile_stream __P((char *, struct s_command **, char *));
-static char *duptoeol __P((char *));
+static char *duptoeol __P((char *, char *));
+static void enterlabel __P((struct s_command *));
static struct s_command
- *findlabel __P((struct s_command *, struct s_command *));
-static void fixuplabel __P((struct s_command *, struct s_command *,
- struct s_command *));
+ *findlabel __P((char *));
+static void fixuplabel __P((struct s_command *, struct s_command *));
+static void uselabel __P((void));
/*
* Command specification. This is used to drive the command parser.
@@ -121,7 +132,8 @@ void
compile()
{
*compile_stream(NULL, &prog, NULL) = NULL;
- fixuplabel(prog, prog, NULL);
+ fixuplabel(prog, NULL);
+ uselabel();
appends = xmalloc(sizeof(struct s_appends) * appendnum);
match = xmalloc((maxnsub + 1) * sizeof(regmatch_t));
}
@@ -208,8 +220,6 @@ nonsel: /* Now parse the command */
p = NULL;
cmd2 = xmalloc(sizeof(struct s_command));
cmd2->code = '}';
- cmd2->a1 = cmd2->a2 = NULL;
- cmd2->nonsel = 0;
*compile_stream("}", &cmd->u.c, p) = cmd2;
cmd->next = cmd2;
link = &cmd2->next;
@@ -246,7 +256,7 @@ nonsel: /* Now parse the command */
EATSPACE();
if (*p == '\0')
err(COMPILE, "filename expected");
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "w command");
if (aflag)
cmd->u.fd = -1;
else if ((cmd->u.fd = open(p,
@@ -260,7 +270,7 @@ nonsel: /* Now parse the command */
if (*p == '\0')
err(COMPILE, "filename expected");
else
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "read command");
break;
case BRANCH: /* b t */
p++;
@@ -268,14 +278,15 @@ nonsel: /* Now parse the command */
if (*p == '\0')
cmd->t = NULL;
else
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "branch");
break;
case LABEL: /* : */
p++;
EATSPACE();
- cmd->t = duptoeol(p);
+ cmd->t = duptoeol(p, "label");
if (strlen(p) == 0)
err(COMPILE, "empty label");
+ enterlabel(cmd);
break;
case SUBST: /* s */
p++;
@@ -340,6 +351,8 @@ compile_delimited(p, d)
if ((d = compile_ccl(&p, d)) == NULL)
err(COMPILE, "unbalanced brackets ([])");
continue;
+ } else if (*p == '\\' && p[1] == '[') {
+ *d++ = *p++;
} else if (*p == '\\' && p[1] == c)
p++;
else if (*p == '\\' && p[1] == 'n') {
@@ -664,77 +677,129 @@ compile_addr(p, a)
}
/*
- * Return a copy of all the characters up to \n or \0
+ * duptoeol --
+ * Return a copy of all the characters up to \n or \0.
*/
static char *
-duptoeol(s)
+duptoeol(s, ctype)
register char *s;
+ char *ctype;
{
size_t len;
+ int ws;
char *start;
- for (start = s; *s != '\0' && *s != '\n'; ++s);
+ ws = 0;
+ for (start = s; *s != '\0' && *s != '\n'; ++s)
+ ws = isspace(*s);
*s = '\0';
+ if (ws)
+ err(WARNING, "whitespace after %s", ctype);
len = s - start + 1;
return (memmove(xmalloc(len), start, len));
}
/*
- * Find the label contained in the command l in the command linked list cp.
- * L is excluded from the search. Return NULL if not found.
- */
-static struct s_command *
-findlabel(l, cp)
- struct s_command *l, *cp;
-{
- struct s_command *r;
-
- for (; cp; cp = cp->next)
- if (cp->code == ':' && cp != l && strcmp(l->t, cp->t) == 0)
- return (cp);
- else if (cp->code == '{' && (r = findlabel(l, cp->u.c)))
- return (r);
- return (NULL);
-}
-
-/*
- * Convert goto label names to addresses.
- * Detect duplicate labels.
- * Set appendnum to the number of a and r commands in the script.
- * Free the memory used by labels in b and t commands (but not by :)
- * Root is a pointer to the script linked list; cp points to the
- * search start.
+ * Convert goto label names to addresses, and count a and r commands, in
+ * the given subset of the script. Free the memory used by labels in b
+ * and t commands (but not by :).
+ *
* TODO: Remove } nodes
*/
static void
-fixuplabel(root, cp, end)
- struct s_command *root, *cp, *end;
+fixuplabel(cp, end)
+ struct s_command *cp, *end;
{
- struct s_command *cp2;
for (; cp != end; cp = cp->next)
switch (cp->code) {
- case ':':
- if (findlabel(cp, root))
- err(COMPILE2, "duplicate label %s", cp->t);
- break;
case 'a':
case 'r':
appendnum++;
break;
case 'b':
case 't':
+ /* Resolve branch target. */
if (cp->t == NULL) {
cp->u.c = NULL;
break;
}
- if ((cp2 = findlabel(cp, root)) == NULL)
+ if ((cp->u.c = findlabel(cp->t)) == NULL)
err(COMPILE2, "undefined label '%s'", cp->t);
free(cp->t);
- cp->u.c = cp2;
break;
case '{':
- fixuplabel(root, cp->u.c, cp->next);
+ /* Do interior commands. */
+ fixuplabel(cp->u.c, cp->next);
break;
}
}
+
+/*
+ * Associate the given command label for later lookup.
+ */
+static void
+enterlabel(cp)
+ struct s_command *cp;
+{
+ register struct labhash **lhp, *lh;
+ register u_char *p;
+ register u_int h, c;
+
+ for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ lhp = &labels[h & LHMASK];
+ for (lh = *lhp; lh != NULL; lh = lh->lh_next)
+ if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0)
+ err(COMPILE2, "duplicate label '%s'", cp->t);
+ lh = xmalloc(sizeof *lh);
+ lh->lh_next = *lhp;
+ lh->lh_hash = h;
+ lh->lh_cmd = cp;
+ lh->lh_ref = 0;
+ *lhp = lh;
+}
+
+/*
+ * Find the label contained in the command l in the command linked
+ * list cp. L is excluded from the search. Return NULL if not found.
+ */
+static struct s_command *
+findlabel(name)
+ char *name;
+{
+ register struct labhash *lh;
+ register u_char *p;
+ register u_int h, c;
+
+ for (h = 0, p = (u_char *)name; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
+ if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
+ lh->lh_ref = 1;
+ return (lh->lh_cmd);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Warn about any unused labels. As a side effect, release the label hash
+ * table space.
+ */
+static void
+uselabel()
+{
+ register struct labhash *lh, *next;
+ register int i;
+
+ for (i = 0; i < LHSZ; i++) {
+ for (lh = labels[i]; lh != NULL; lh = next) {
+ next = lh->lh_next;
+ if (!lh->lh_ref)
+ err(WARNING, "unused label '%s'",
+ lh->lh_cmd->t);
+ free(lh);
+ }
+ }
+}