* This file contains wrappers to standard functions, which
* throw exceptions upon failure.
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
#include <stdbool.h>
+#include <unistd.h>
#include <ctype.h>
+#include <fcntl.h>
+
+#define LINEBUF 32
+#define LINEBUF_MAX 4096
static void *uci_malloc(struct uci_context *ctx, size_t size)
{
return ptr;
}
-static bool uci_validate_name(char *str)
+static bool uci_validate_name(const char *str)
{
if (!*str)
return false;
last++;
if (!*last)
goto error;
+ *value = last;
}
if (*section && !uci_validate_name(*section))
return 0;
}
+
+static void uci_parse_error(struct uci_context *ctx, char *pos, char *reason)
+{
+ struct uci_parse_context *pctx = ctx->pctx;
+
+ pctx->reason = reason;
+ pctx->byte = pos - pctx->buf;
+ UCI_THROW(ctx, UCI_ERR_PARSE);
+}
+
+
+/*
+ * Fetch a new line from the input stream and resize buffer if necessary
+ */
+static void uci_getln(struct uci_context *ctx, int offset)
+{
+ struct uci_parse_context *pctx = ctx->pctx;
+ char *p;
+ int ofs;
+
+ if (pctx->buf == NULL) {
+ pctx->buf = uci_malloc(ctx, LINEBUF);
+ pctx->bufsz = LINEBUF;
+ }
+
+ ofs = offset;
+ do {
+ p = &pctx->buf[ofs];
+ p[ofs] = 0;
+
+ p = fgets(p, pctx->bufsz - ofs, pctx->file);
+ if (!p || !*p)
+ return;
+
+ ofs += strlen(p);
+ if (pctx->buf[ofs - 1] == '\n') {
+ pctx->line++;
+ pctx->buf[ofs - 1] = 0;
+ return;
+ }
+
+ if (pctx->bufsz > LINEBUF_MAX/2)
+ uci_parse_error(ctx, p, "line too long");
+
+ pctx->bufsz *= 2;
+ pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz);
+ } while (1);
+}
+
+/*
+ * open a stream and go to the right position
+ *
+ * note: when opening for write and seeking to the beginning of
+ * the stream, truncate the file
+ */
+static FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create)
+{
+ struct stat statbuf;
+ FILE *file = NULL;
+ int fd, ret;
+ int mode = (write ? O_RDWR : O_RDONLY);
+
+ if (create)
+ mode |= O_CREAT;
+
+ if (!write && ((stat(filename, &statbuf) < 0) ||
+ ((statbuf.st_mode & S_IFMT) != S_IFREG))) {
+ UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+ }
+
+ fd = open(filename, mode, UCI_FILEMODE);
+ if (fd <= 0)
+ goto error;
+
+ if (flock(fd, (write ? LOCK_EX : LOCK_SH)) < 0)
+ goto error;
+
+ ret = lseek(fd, 0, pos);
+
+ if (ret < 0)
+ goto error;
+
+ file = fdopen(fd, (write ? "w+" : "r"));
+ if (file)
+ goto done;
+
+error:
+ UCI_THROW(ctx, UCI_ERR_IO);
+done:
+ return file;
+}
+
+static void uci_close_stream(FILE *stream)
+{
+ int fd;
+
+ if (!stream)
+ return;
+
+ fd = fileno(stream);
+ flock(fd, LOCK_UN);
+ fclose(stream);
+}
+
+