mirror of
https://github.com/pygos/init.git
synced 2024-12-22 15:20:49 +01:00
Merge argument substitution into rdline
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
parent
352a9060b6
commit
ca7b7c15c5
5 changed files with 79 additions and 104 deletions
|
@ -2,7 +2,7 @@ HEADRS = lib/include/util.h lib/include/service.h lib/include/telinit.h
|
|||
|
||||
libinit_a_SOURCES = lib/src/delsvc.c lib/src/rdline.c lib/src/svcmap.c
|
||||
libinit_a_SOURCES += lib/src/splitkv.c lib/src/enum_by_name.c
|
||||
libinit_a_SOURCES += lib/src/strexpand.c lib/src/rdsvc.c lib/src/svcscan.c
|
||||
libinit_a_SOURCES += lib/src/rdsvc.c lib/src/svcscan.c
|
||||
libinit_a_SOURCES += lib/src/del_svc_list.c lib/src/svc_tsort.c
|
||||
libinit_a_SOURCES += lib/src/opensock.c lib/src/enum_to_name.c $(HEADRS)
|
||||
libinit_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
|
|
@ -55,8 +55,17 @@ typedef struct {
|
|||
it with a backslash.
|
||||
- If a second, coresponding '"' is not found, processing fails with
|
||||
errno set to EILSEQ.
|
||||
- If a '%' character is encountered, the next character is expected
|
||||
to be a single digit index into argv. If it is not a digit or
|
||||
outside the bounds set by argc, processing fails and sets errno
|
||||
to EINVAL. On success, the argv value is inserted and processed
|
||||
as described above.
|
||||
- A '%' character can be escaped by writing '%%' or, if inside
|
||||
a double quite string, by writing \%.
|
||||
- An attempt to use such an indexed argument inside an argument
|
||||
expansion, results in failure with errno set to ELOOP.
|
||||
*/
|
||||
char *rdline(int fd);
|
||||
char *rdline(int fd, int argc, const char *const *argv);
|
||||
|
||||
/*
|
||||
Split a line of the shape "key = value" into key and value part.
|
||||
|
@ -88,12 +97,5 @@ const enum_map_t *enum_by_name(const enum_map_t *map, const char *name);
|
|||
*/
|
||||
const char *enum_to_name(const enum_map_t *map, int value);
|
||||
|
||||
/*
|
||||
Create a copy of the input string inp, but replace all occourances
|
||||
of %<number> with argv[number] if the number is within the bounds
|
||||
specified by argc.
|
||||
*/
|
||||
char *strexpand(const char *inp, size_t argc, const char *const *argv);
|
||||
|
||||
#endif /* UTIL_H */
|
||||
|
||||
|
|
|
@ -27,33 +27,45 @@ enum {
|
|||
STATE_STRING = 1,
|
||||
STATE_STRING_ESC = 2,
|
||||
STATE_COMMENT = 3,
|
||||
STATE_ARG = 4,
|
||||
};
|
||||
|
||||
char *rdline(int fd)
|
||||
char *rdline(int fd, int argc, const char *const *argv)
|
||||
{
|
||||
size_t i = 0, bufsiz = 0, newsz;
|
||||
int ret, state = STATE_INITIAL;
|
||||
char c, *new, *buffer = NULL;
|
||||
const char *argstr = NULL;
|
||||
|
||||
for (;;) {
|
||||
switch (read(fd, &c, 1)) {
|
||||
case 0:
|
||||
if (i == 0) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
c = '\0';
|
||||
break;
|
||||
case 1:
|
||||
if (c == '\n')
|
||||
if (argstr == NULL) {
|
||||
switch (read(fd, &c, 1)) {
|
||||
case 0:
|
||||
if (i == 0) {
|
||||
errno = 0;
|
||||
return NULL;
|
||||
}
|
||||
c = '\0';
|
||||
break;
|
||||
default:
|
||||
if (errno == EINTR)
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
c = *(argstr++);
|
||||
|
||||
if (c == '\0') {
|
||||
argstr = NULL;
|
||||
continue;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
c = '\0';
|
||||
|
||||
switch (state) {
|
||||
case STATE_STRING:
|
||||
if (c == '\\')
|
||||
|
@ -68,6 +80,20 @@ char *rdline(int fd)
|
|||
if (c != '\0')
|
||||
continue;
|
||||
break;
|
||||
case STATE_ARG:
|
||||
state = STATE_INITIAL;
|
||||
if (c == '%')
|
||||
break;
|
||||
if (!isdigit(c) || (c - '0') >= argc) {
|
||||
errno = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (argstr != NULL) {
|
||||
errno = ELOOP;
|
||||
goto fail;
|
||||
}
|
||||
argstr = argv[c - '0'];
|
||||
continue;
|
||||
default:
|
||||
if (isspace(c))
|
||||
c = ' ';
|
||||
|
@ -77,6 +103,10 @@ char *rdline(int fd)
|
|||
state = STATE_COMMENT;
|
||||
continue;
|
||||
}
|
||||
if (c == '%') {
|
||||
state = STATE_ARG;
|
||||
continue;
|
||||
}
|
||||
if (c == '"')
|
||||
state = STATE_STRING;
|
||||
break;
|
||||
|
|
|
@ -171,7 +171,7 @@ static const struct {
|
|||
|
||||
service_t *rdsvc(int dirfd, const char *filename)
|
||||
{
|
||||
const char *arg, *args[1];
|
||||
const char *arg, *args[1], *error;
|
||||
char *line, *key, *value;
|
||||
size_t i, argc, lineno;
|
||||
service_t *svc;
|
||||
|
@ -213,15 +213,30 @@ service_t *rdsvc(int dirfd, const char *filename)
|
|||
|
||||
for (lineno = 1; ; ++lineno) {
|
||||
errno = 0;
|
||||
line = rdline(fd);
|
||||
line = rdline(fd, argc, args);
|
||||
|
||||
if (line == NULL) {
|
||||
if (errno != 0) {
|
||||
fprintf(stderr, "read: %s: %zu: %s\n",
|
||||
filename, lineno, strerror(errno));
|
||||
goto fail;
|
||||
if (errno == 0)
|
||||
break;
|
||||
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
error = "error in argument expansion";
|
||||
break;
|
||||
case ELOOP:
|
||||
error = "recursive argument expansion";
|
||||
break;
|
||||
case EILSEQ:
|
||||
error = "missing \"";
|
||||
break;
|
||||
default:
|
||||
error = strerror(errno);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
fprintf(stderr, "%s: %zu: %s\n",
|
||||
filename, lineno, error);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (splitkv(line, &key, &value)) {
|
||||
|
@ -258,7 +273,7 @@ service_t *rdsvc(int dirfd, const char *filename)
|
|||
goto fail_line;
|
||||
}
|
||||
|
||||
value = strexpand(value, argc, args);
|
||||
value = strdup(value);
|
||||
if (value == NULL) {
|
||||
fputs("out of memory", stderr);
|
||||
goto fail_line;
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018 - David Oberhollenzer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
char *strexpand(const char *inp, size_t argc, const char *const *argv)
|
||||
{
|
||||
char *out, *dst;
|
||||
const char *ptr;
|
||||
size_t i, len;
|
||||
|
||||
ptr = inp;
|
||||
len = 0;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '%' && isdigit(ptr[1])) {
|
||||
i = ptr[1] - '0';
|
||||
if (i < argc)
|
||||
len += strlen(argv[i]);
|
||||
ptr += 2;
|
||||
} else if (ptr[0] == '%' && ptr[1] == '%') {
|
||||
ptr += 2;
|
||||
len += 1;
|
||||
} else {
|
||||
++ptr;
|
||||
++len;
|
||||
}
|
||||
}
|
||||
|
||||
out = calloc(1, len + 1);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
dst = out;
|
||||
|
||||
while (*inp != '\0') {
|
||||
if (inp[0] == '%' && isdigit(inp[1])) {
|
||||
i = inp[1] - '0';
|
||||
if (i < argc) {
|
||||
len = strlen(argv[i]);
|
||||
memcpy(dst, argv[i], len);
|
||||
dst += len;
|
||||
}
|
||||
inp += 2;
|
||||
} else if (inp[0] == '%' && inp[1] == '%') {
|
||||
*(dst++) = '%';
|
||||
inp += 2;
|
||||
} else {
|
||||
*(dst++) = *(inp++);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
Loading…
Reference in a new issue