Improve tokenization for m- and v-flag parsing
I wasn't happy with the tokenizer for the m- and v-flags, because it was handling space-separated input and there was no way to have spaces within the tokens themselves. This is a fine detail, but I didn't want to impose this restriction where it could be solved (path prefixes or folder names can very well contain spaces). Given it's a bit quirky to handle multiple arguments to a single flag in the command line, especially when parameters are optional, this alternative wasn't further considered and I instead implemented a tokenizer that allows escaping spaces with '\'. While at it, I clarified the manual regarding this point. Signed-off-by: Laslo Hunhold <dev@frign.de>
This commit is contained in:
parent
065394cb64
commit
33def953e9
2 changed files with 88 additions and 24 deletions
106
main.c
106
main.c
|
@ -90,6 +90,77 @@ handlesignals(void(*hdl)(int))
|
||||||
sigaction(SIGQUIT, &sa, NULL);
|
sigaction(SIGQUIT, &sa, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
spacetok(const char *s, char **t, size_t tlen)
|
||||||
|
{
|
||||||
|
const char *tok;
|
||||||
|
size_t i, j, toki, spaces;
|
||||||
|
|
||||||
|
/* fill token-array with NULL-pointers */
|
||||||
|
for (i = 0; i < tlen; i++) {
|
||||||
|
t[i] = NULL;
|
||||||
|
}
|
||||||
|
toki = 0;
|
||||||
|
|
||||||
|
/* don't allow NULL string or leading spaces */
|
||||||
|
if (!s || *s == ' ') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
start:
|
||||||
|
/* skip spaces */
|
||||||
|
for (; *s == ' '; s++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* don't allow trailing spaces */
|
||||||
|
if (*s == '\0') {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* consume token */
|
||||||
|
for (tok = s, spaces = 0; ; s++) {
|
||||||
|
if (*s == '\\' && *(s + 1) == ' ') {
|
||||||
|
spaces++;
|
||||||
|
s++;
|
||||||
|
continue;
|
||||||
|
} else if (*s == ' ') {
|
||||||
|
/* end of token */
|
||||||
|
goto token;
|
||||||
|
} else if (*s == '\0') {
|
||||||
|
/* end of string */
|
||||||
|
goto token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token:
|
||||||
|
if (toki >= tlen) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (!(t[toki] = malloc(s - tok - spaces + 1))) {
|
||||||
|
die("malloc:");
|
||||||
|
}
|
||||||
|
for (i = 0, j = 0; j < s - tok - spaces + 1; i++, j++) {
|
||||||
|
if (tok[i] == '\\' && tok[i + 1] == ' ') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
t[toki][j] = tok[i];
|
||||||
|
}
|
||||||
|
t[toki][s - tok - spaces] = '\0';
|
||||||
|
toki++;
|
||||||
|
|
||||||
|
if (*s == ' ') {
|
||||||
|
s++;
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
for (i = 0; i < tlen; i++) {
|
||||||
|
free(t[i]);
|
||||||
|
t[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -113,7 +184,7 @@ main(int argc, char *argv[])
|
||||||
socklen_t in_sa_len;
|
socklen_t in_sa_len;
|
||||||
int insock, status = 0, infd;
|
int insock, status = 0, infd;
|
||||||
const char *err;
|
const char *err;
|
||||||
char *tok;
|
char *tok[4];
|
||||||
|
|
||||||
/* defaults */
|
/* defaults */
|
||||||
int maxnprocs = 512;
|
int maxnprocs = 512;
|
||||||
|
@ -148,21 +219,16 @@ main(int argc, char *argv[])
|
||||||
s.listdirs = 1;
|
s.listdirs = 1;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (!(tok = strdup(EARGF(usage())))) {
|
if (spacetok(EARGF(usage()), tok, 3) || !tok[0] || !tok[1]) {
|
||||||
die("strdup:");
|
usage();
|
||||||
}
|
}
|
||||||
if (!(s.map = reallocarray(s.map, ++s.map_len,
|
if (!(s.map = reallocarray(s.map, ++s.map_len,
|
||||||
sizeof(struct map)))) {
|
sizeof(struct map)))) {
|
||||||
die("reallocarray:");
|
die("reallocarray:");
|
||||||
}
|
}
|
||||||
if (!(s.map[s.map_len - 1].from = strtok(tok, " ")) ||
|
s.map[s.map_len - 1].from = tok[0];
|
||||||
!(s.map[s.map_len - 1].to = strtok(NULL, " "))) {
|
s.map[s.map_len - 1].to = tok[1];
|
||||||
usage();
|
s.map[s.map_len - 1].chost = tok[2];
|
||||||
}
|
|
||||||
s.map[s.map_len - 1].chost = strtok(NULL, " ");
|
|
||||||
if (strtok(NULL, "")) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
maxnprocs = strtonum(EARGF(usage()), 1, INT_MAX, &err);
|
maxnprocs = strtonum(EARGF(usage()), 1, INT_MAX, &err);
|
||||||
|
@ -180,22 +246,18 @@ main(int argc, char *argv[])
|
||||||
user = EARGF(usage());
|
user = EARGF(usage());
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
if (!(tok = strdup(EARGF(usage())))) {
|
if (spacetok(EARGF(usage()), tok, 4) || !tok[0] || !tok[1] ||
|
||||||
die("strdup:");
|
!tok[2]) {
|
||||||
|
usage();
|
||||||
}
|
}
|
||||||
if (!(s.vhost = reallocarray(s.vhost, ++s.vhost_len,
|
if (!(s.vhost = reallocarray(s.vhost, ++s.vhost_len,
|
||||||
sizeof(struct vhost)))) {
|
sizeof(struct vhost)))) {
|
||||||
die("reallocarray:");
|
die("reallocarray:");
|
||||||
}
|
}
|
||||||
if (!(s.vhost[s.vhost_len - 1].chost = strtok(tok, " ")) ||
|
s.vhost[s.vhost_len - 1].chost = tok[0];
|
||||||
!(s.vhost[s.vhost_len - 1].regex = strtok(NULL, " ")) ||
|
s.vhost[s.vhost_len - 1].regex = tok[1];
|
||||||
!(s.vhost[s.vhost_len - 1].dir = strtok(NULL, " "))) {
|
s.vhost[s.vhost_len - 1].dir = tok[2];
|
||||||
usage();
|
s.vhost[s.vhost_len - 1].prefix = tok[3];
|
||||||
}
|
|
||||||
s.vhost[s.vhost_len - 1].prefix = strtok(NULL, " ");
|
|
||||||
if (strtok(NULL, "")) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
|
6
quark.1
6
quark.1
|
@ -58,7 +58,8 @@ Add the target prefix mapping rule specified by
|
||||||
.Ar map ,
|
.Ar map ,
|
||||||
which has the form
|
which has the form
|
||||||
.Qq Pa from to [chost] ,
|
.Qq Pa from to [chost] ,
|
||||||
where each element is separated with whitespace.
|
where each element is separated with spaces (0x20) that can be
|
||||||
|
escaped with '\\'.
|
||||||
.Pp
|
.Pp
|
||||||
The prefix
|
The prefix
|
||||||
.Pa from
|
.Pa from
|
||||||
|
@ -96,7 +97,8 @@ Add the virtual host specified by
|
||||||
.Ar vhost ,
|
.Ar vhost ,
|
||||||
which has the form
|
which has the form
|
||||||
.Qq Pa chost regex dir [prefix] ,
|
.Qq Pa chost regex dir [prefix] ,
|
||||||
where each element is separated with whitespace.
|
where each element is separated with spaces (0x20) that can be
|
||||||
|
escaped with '\\'.
|
||||||
.Pp
|
.Pp
|
||||||
A request matching the virtual host regular expression
|
A request matching the virtual host regular expression
|
||||||
.Pa regex
|
.Pa regex
|
||||||
|
|
Loading…
Reference in a new issue