commit 7790fb401e46238565b651c05d019988bd549ae3
parent 4af0be8f006db00cdbe97b881eedf2b0d5275702
Author: Jacob R. Edwards <n/a>
Date: Sun, 11 Dec 2022 17:48:07 -0600
Rework unquoting functions
Unquoting no longer modifies the string being unquoted, and therefor
allow gathering information ahead of time (such as how many words
are in a string and how long they are) without making a copy of it.
This ability is used in the server's splitting function to that
end. It is also used in the client so that it can use the original
string if there are multiple words.
Diffstat:
6 files changed, 91 insertions(+), 57 deletions(-)
diff --git a/apc/apc.c b/apc/apc.c
@@ -46,15 +46,21 @@ die(char *s)
int
printline(char *buf)
{
- char *p;
-
- p = apunquote(&buf, NULL);
- if (p && !buf)
- return puts(p) < 0;
+ int status;
+ char *word, *bufp;
- if (!(p = apquote(p, NULL)))
+ bufp = buf;
+ word = apunquote(&buf, NULL);
+ if (!word)
return 1;
- return printf("%s %s\n", p, buf) < 0;
+
+ if (!buf)
+ status = puts(word) < 0;
+ else
+ status = puts(bufp) < 0;
+ free(word);
+
+ return status;
}
int
diff --git a/aps/aps.c b/aps/aps.c
@@ -244,7 +244,7 @@ aps_command(struct aps *aps, int fd)
aps_logfmt(aps, COMMAND, fd, "input '%s'", buf);
- argv = asplit(buf, NULL);
+ argv = split(buf, NULL);
if (argv == NULL) {
status = "Unable to split arguments";
goto exit;
diff --git a/aps/split.c b/aps/split.c
@@ -25,41 +25,33 @@
#include <string.h>
int
-split(char **ap, unsigned int len, char *s, int (*sep)(int))
+countsplits(char *s)
{
- char *p;
- unsigned int i;
+ int n;
- for (i = 0; (p = apunquote(&s, sep)); ++i) {
- if (i < len)
- ap[i] = p;
- }
+ for (n = 0; apfindquote(&s, NULL); ++n)
+ ;
if (s)
return -1;
-
- if (len)
- ap[MIN(len - 1, i)] = NULL;
- return i;
+ return n;
}
char **
-asplit(char *s, int (*issep)(int))
+split(char *s, int (*sep)(int))
{
- char **args, *copy;
+ char **args, **ap;
int len;
- copy = strdup(s);
- if (copy == NULL)
- return NULL;
- len = split(NULL, 0, copy, issep);
- free(copy);
-
+ len = countsplits(s);
if (len < 0)
return NULL;
args = calloc(++len, sizeof(*args));
if (args == NULL)
return NULL;
- split(args, len, s, issep);
+
+ ap = args;
+ while (*ap = apunquote(&s, sep))
+ ++ap;
return args;
}
diff --git a/aps/split.h b/aps/split.h
@@ -1,2 +1 @@
-int split(char **, unsigned int, char *, int (*)(int));
-char **asplit(char *, int (*)(int));
+char **split(char *, int (*)(int));
diff --git a/lib/ap/quote.c b/lib/ap/quote.c
@@ -65,47 +65,83 @@ apissep(int c, int (*issep)(int))
return c != '\'' && apneedquote(c, issep);
}
+int
+nextchar(char **sp, int *quoted, int (*issep)(int))
+{
+ char *s;
+
+ s = *sp;
+beginning:
+ if (!*s) {
+ *sp = s;
+ return 0;
+ }
+
+ if (!*quoted && apissep(*s, issep)) {
+ *sp = s;
+ return 0;
+ }
+
+ if (*s == '\'') {
+ ++s;
+ if (!*quoted || *s != '\'') {
+ *quoted = !*quoted;
+ goto beginning;
+ }
+ }
+
+ *sp = s + 1;
+ return *s;
+}
+
char *
-apunquote(char **sp, int (*issep)(int))
+apfindquote(char **sp, int (*issep)(int))
{
char *s, *p;
- int quoted;
- size_t len;
+ int c, quoted;
if (!*sp)
return NULL;
s = *sp;
- while (s[0] && apissep(s[0], issep))
+ while (*s && apissep(*s, issep))
++s;
p = s;
- len = strlen(p);
- quoted = 0;
- while (s[0] && (quoted || !apissep(s[0], issep))) {
- if (s[0] == '\'') {
- if (!quoted)
- quoted = 1;
- else if (s[1] == '\'')
- ++s;
- else
- quoted = 0;
- memmove(s, s + 1, (len + 1) - (s - p));
- } else
- ++s;
+ if (!*p) {
+ *sp = NULL;
+ return NULL;
}
- if (quoted) {
- errno = EINVAL;
+ quoted = 0;
+ while ((c = nextchar(&s, "ed, issep)))
+ ;
+ if (quoted)
return NULL;
- }
+ *sp = s;
+ return p;
+}
- if (s[0]) {
- s[0] = '\0';
- *sp = s + 1;
- return p;
- }
+char *
+apunquote(char **sp, int (*issep)(int))
+{
+ char *buf, *bp;
+ char *s;
+ int c, quoted;
- *sp = NULL;
- return p[0] ? p : NULL;
+ s = apfindquote(sp, issep);
+ if (!s || !*sp)
+ return NULL;
+
+ buf = malloc(*sp - s);
+ if (!buf)
+ return NULL;
+ *sp = s;
+
+ quoted = 0;
+ for (bp = buf; (c = nextchar(sp, "ed, NULL)); ++bp)
+ *bp = c;
+ *bp = 0;
+
+ return buf;
}
diff --git a/lib/ap/quote.h b/lib/ap/quote.h
@@ -1,2 +1,3 @@
char *apquote(char *, int (*)(int));
+char *apfindquote(char **, int (*)(int));
char *apunquote(char **, int (*)(int));