mirror of
https://github.com/pygos/init.git
synced 2024-11-22 19:19:47 +01:00
Split rdline into multiple, easier to read functions
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
parent
65d2abc3f0
commit
00daf470d1
1 changed files with 130 additions and 107 deletions
237
lib/src/rdline.c
237
lib/src/rdline.c
|
@ -17,130 +17,153 @@
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
enum {
|
typedef struct {
|
||||||
STATE_INITIAL = 0,
|
int fd; /* input file descriptor */
|
||||||
STATE_STRING = 1,
|
const char *argstr; /* if not NULL, read from this instead */
|
||||||
STATE_STRING_ESC = 2,
|
|
||||||
STATE_COMMENT = 3,
|
size_t i; /* buffer offset */
|
||||||
STATE_ARG = 4,
|
size_t bufsiz; /* buffer size */
|
||||||
};
|
char *buffer;
|
||||||
|
|
||||||
|
bool string; /* inside a string? */
|
||||||
|
bool escape; /* reading an escape sequence? */
|
||||||
|
bool comment; /* inside a comment */
|
||||||
|
} rdline_t;
|
||||||
|
|
||||||
|
static int rdline_getc(rdline_t *t)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (t->argstr != NULL) {
|
||||||
|
c = *(t->argstr++);
|
||||||
|
if (c != '\0')
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
t->argstr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = read(t->fd, &c, 1);
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (t->i == 0) {
|
||||||
|
errno = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
c = '\0';
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return (c == '\n') ? '\0' : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rdline_append(rdline_t *t, int c)
|
||||||
|
{
|
||||||
|
size_t newsz;
|
||||||
|
char *new;
|
||||||
|
|
||||||
|
if (t->comment) {
|
||||||
|
if (c != '\0')
|
||||||
|
return 0;
|
||||||
|
} else if (t->string) {
|
||||||
|
if (t->escape) {
|
||||||
|
t->escape = false;
|
||||||
|
} else {
|
||||||
|
if (c == '\\')
|
||||||
|
t->escape = true;
|
||||||
|
if (c == '"')
|
||||||
|
t->string = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isspace(c))
|
||||||
|
c = ' ';
|
||||||
|
if (c == ' ' && (t->i == 0 || t->buffer[t->i - 1] == ' '))
|
||||||
|
return 0;
|
||||||
|
if (c == '#') {
|
||||||
|
t->comment = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (c == '"')
|
||||||
|
t->string = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\0') {
|
||||||
|
while (t->i > 0 && t->buffer[t->i - 1] == ' ')
|
||||||
|
t->i -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->i == t->bufsiz) {
|
||||||
|
newsz = t->bufsiz ? t->bufsiz * 2 : 16;
|
||||||
|
new = realloc(t->buffer, newsz);
|
||||||
|
|
||||||
|
if (new == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
t->buffer = new;
|
||||||
|
t->bufsiz = newsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->buffer[t->i++] = c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char *rdline(int fd, int argc, const char *const *argv)
|
char *rdline(int fd, int argc, const char *const *argv)
|
||||||
{
|
{
|
||||||
size_t i = 0, bufsiz = 0, newsz;
|
rdline_t rd;
|
||||||
int ret, state = STATE_INITIAL;
|
int ret;
|
||||||
char c, *new, *buffer = NULL;
|
char c;
|
||||||
const char *argstr = NULL;
|
|
||||||
|
|
||||||
for (;;) {
|
memset(&rd, 0, sizeof(rd));
|
||||||
if (argstr == NULL) {
|
rd.fd = fd;
|
||||||
switch (read(fd, &c, 1)) {
|
|
||||||
case 0:
|
do {
|
||||||
if (i == 0) {
|
c = rdline_getc(&rd);
|
||||||
errno = 0;
|
if (c < 0)
|
||||||
return NULL;
|
goto fail;
|
||||||
|
if (c == 0 && rd.string) {
|
||||||
|
errno = EILSEQ;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '%') {
|
||||||
|
c = rdline_getc(&rd);
|
||||||
|
if (c == 0)
|
||||||
|
errno = EILSEQ;
|
||||||
|
if (c <= 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (c != '%') {
|
||||||
|
if (!isdigit(c) || (c - '0') >= argc) {
|
||||||
|
errno = EINVAL;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
c = '\0';
|
if (rd.argstr != NULL) {
|
||||||
break;
|
errno = ELOOP;
|
||||||
case 1:
|
goto fail;
|
||||||
break;
|
}
|
||||||
default:
|
rd.argstr = argv[c - '0'];
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = *(argstr++);
|
|
||||||
|
|
||||||
if (c == '\0') {
|
|
||||||
argstr = NULL;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == '\n')
|
if (rdline_append(&rd, c))
|
||||||
c = '\0';
|
goto fail;
|
||||||
|
} while (c != '\0');
|
||||||
|
|
||||||
switch (state) {
|
return rd.buffer;
|
||||||
case STATE_STRING:
|
|
||||||
if (c == '\\')
|
|
||||||
state = STATE_STRING_ESC;
|
|
||||||
if (c == '"')
|
|
||||||
state = STATE_INITIAL;
|
|
||||||
break;
|
|
||||||
case STATE_STRING_ESC:
|
|
||||||
state = STATE_STRING;
|
|
||||||
break;
|
|
||||||
case STATE_COMMENT:
|
|
||||||
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 = ' ';
|
|
||||||
if (c == ' ' && (i == 0 || buffer[i - 1] == ' '))
|
|
||||||
continue;
|
|
||||||
if (c == '#') {
|
|
||||||
state = STATE_COMMENT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '%') {
|
|
||||||
state = STATE_ARG;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '"')
|
|
||||||
state = STATE_STRING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\0') {
|
|
||||||
while (i > 0 && buffer[i - 1] == ' ')
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == bufsiz) {
|
|
||||||
newsz = bufsiz ? bufsiz * 2 : 16;
|
|
||||||
new = realloc(buffer, newsz);
|
|
||||||
|
|
||||||
if (new == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
buffer = new;
|
|
||||||
bufsiz = newsz;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[i++] = c;
|
|
||||||
if (c == '\0')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == STATE_STRING || state == STATE_STRING_ESC) {
|
|
||||||
errno = EILSEQ;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
fail:
|
fail:
|
||||||
ret = errno;
|
ret = errno;
|
||||||
free(buffer);
|
free(rd.buffer);
|
||||||
errno = ret;
|
errno = ret;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue