1
0
Fork 0
mirror of https://github.com/pygos/init.git synced 2024-11-22 03:09:46 +01:00

Add statefull preprocessing to rdline

Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
David Oberhollenzer 2018-04-02 21:26:45 +02:00
parent dc5afbc771
commit 352a9060b6
2 changed files with 58 additions and 1 deletions

View file

@ -43,6 +43,18 @@ typedef struct {
cleared if end-of-file is reached.
The line must be deallocated with free().
The following transformations are applied:
- Space characters are replaced with regular white space characters.
- Sequences of space characters are truncated to a single space.
- A '#' sign is interpreted as the start of a comment and removed,
together with everything that follows.
- Padding spaces are removed from the line.
- If a '"' is encounterd, the above rules are disabled, until a
after the matching '"' is read. A '"' can be escaped by preceeding
it with a backslash.
- If a second, coresponding '"' is not found, processing fails with
errno set to EILSEQ.
*/
char *rdline(int fd);

View file

@ -22,11 +22,18 @@
#include "util.h"
enum {
STATE_INITIAL = 0,
STATE_STRING = 1,
STATE_STRING_ESC = 2,
STATE_COMMENT = 3,
};
char *rdline(int fd)
{
size_t i = 0, bufsiz = 0, newsz;
int ret, state = STATE_INITIAL;
char c, *new, *buffer = NULL;
int ret;
for (;;) {
switch (read(fd, &c, 1)) {
@ -47,6 +54,39 @@ char *rdline(int fd)
goto fail;
}
switch (state) {
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;
default:
if (isspace(c))
c = ' ';
if (c == ' ' && (i == 0 || buffer[i - 1] == ' '))
continue;
if (c == '#') {
state = STATE_COMMENT;
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);
@ -62,6 +102,11 @@ char *rdline(int fd)
if (c == '\0')
break;
}
if (state == STATE_STRING || state == STATE_STRING_ESC) {
errno = EILSEQ;
goto fail;
}
return buffer;
fail:
ret = errno;