aboutsummaryrefslogtreecommitdiff
path: root/lib/src/rdline.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/rdline.c')
-rw-r--r--lib/src/rdline.c106
1 files changed, 56 insertions, 50 deletions
diff --git a/lib/src/rdline.c b/lib/src/rdline.c
index 18c9c85..47a9d2a 100644
--- a/lib/src/rdline.c
+++ b/lib/src/rdline.c
@@ -20,22 +20,10 @@
#include <string.h>
#include <errno.h>
#include <ctype.h>
+#include <stdio.h>
#include "util.h"
-typedef struct {
- int fd; /* input file descriptor */
- const char *argstr; /* if not NULL, read from this instead */
-
- size_t i; /* buffer offset */
- 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;
@@ -69,9 +57,6 @@ out:
static int rdline_append(rdline_t *t, int c)
{
- size_t newsz;
- char *new;
-
if (t->comment) {
if (c != '\0')
return 0;
@@ -102,67 +87,88 @@ static int rdline_append(rdline_t *t, int c)
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;
- }
+ if (t->i == sizeof(t->buffer))
+ return -1;
t->buffer[t->i++] = c;
return 0;
}
-char *rdline(int fd, int argc, const char *const *argv)
+void rdline_init(rdline_t *t, int fd, const char *filename,
+ int argc, const char *const *argv)
{
- rdline_t rd;
- int c, ret;
+ memset(t, 0, sizeof(*t));
+ t->fd = fd;
+ t->filename = filename;
+ t->argc = argc;
+ t->argv = argv;
+}
- memset(&rd, 0, sizeof(rd));
- rd.fd = fd;
+int rdline(rdline_t *t)
+{
+ const char *errstr;
+ int c;
+retry:
+ t->i = 0;
+ t->argstr = NULL;
+ t->string = t->escape = t->comment = false;
+ t->lineno += 1;
do {
- c = rdline_getc(&rd);
- if (c < 0)
+ errno = 0;
+ c = rdline_getc(t);
+ if (c < 0) {
+ if (errno == 0)
+ return 1;
+ errstr = strerror(errno);
goto fail;
- if (c == 0 && rd.string) {
- errno = EILSEQ;
+ }
+ if (c == 0 && t->string) {
+ errstr = "missing \"";
goto fail;
}
if (c == '%') {
- c = rdline_getc(&rd);
- if (c == 0)
- errno = EILSEQ;
- if (c <= 0)
+ c = rdline_getc(t);
+ if (c == 0) {
+ errstr = "unexpected end of line after '%%'";
goto fail;
+ }
+ if (c < 0) {
+ errstr = strerror(errno);
+ goto fail;
+ }
if (c != '%') {
- if (!isdigit(c) || (c - '0') >= argc) {
- errno = EINVAL;
+ if (!isdigit(c)) {
+ errstr = "exptected digit after '%%'";
goto fail;
}
- if (rd.argstr != NULL) {
- errno = ELOOP;
+ if ((c - '0') >= t->argc) {
+ errstr = "argument out of range";
goto fail;
}
- rd.argstr = argv[c - '0'];
+ if (t->argstr != NULL) {
+ errstr = "recursive argument "
+ "expansion";
+ goto fail;
+ }
+ t->argstr = t->argv[c - '0'];
continue;
}
}
- if (rdline_append(&rd, c))
+ if (rdline_append(t, c)) {
+ errstr = "line too long";
goto fail;
+ }
} while (c != '\0');
- return rd.buffer;
+ if (t->buffer[0] == '\0')
+ goto retry;
+
+ return 0;
fail:
- ret = errno;
- free(rd.buffer);
- errno = ret;
- return NULL;
+ fprintf(stderr, "%s: %zu: %s\n", t->filename, t->lineno, errstr);
+ return -1;
}