summaryrefslogtreecommitdiff
path: root/lib/src/rdline.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/rdline.c')
-rw-r--r--lib/src/rdline.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/lib/src/rdline.c b/lib/src/rdline.c
index 1b91008..4e72a25 100644
--- a/lib/src/rdline.c
+++ b/lib/src/rdline.c
@@ -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;