libopkg: support passing default state flags in pkg_hash_load_feeds()
[oweals/opkg-lede.git] / libopkg / parse_util.c
index e01b12427efee895f38a173e4360346864af7e4f..4d453afa2323e8f20c85f8857e7c9aa3ca1c2b0a 100644 (file)
 #include "libbb/libbb.h"
 
 #include "parse_util.h"
+#include "pkg_parse.h"
 
-int
-is_field(const char *type, const char *line)
+int is_field(const char *type, const char *line)
 {
        if (!strncmp(line, type, strlen(type)))
                return 1;
        return 0;
 }
 
-char *
-parse_simple(const char *type, const char *line)
+char *parse_simple(const char *type, const char *line)
 {
-       return trim_xstrdup(line + strlen(type) + 1);
+       char *field = trim_xstrdup(line + strlen(type) + 1);
+       if (strlen(field) == 0) {
+               free(field);
+               return NULL;
+       }
+       return field;
 }
 
 /*
  * Parse a comma separated string into an array.
  */
-char **
-parse_list(const char *raw, unsigned int *count, const char sep, int skip_field)
+char **parse_list(const char *raw, unsigned int *count, const char sep,
+                 int skip_field)
 {
        char **depends = NULL;
        const char *start, *end;
@@ -49,9 +53,9 @@ parse_list(const char *raw, unsigned int *count, const char sep, int skip_field)
 
        /* skip past the "Field:" marker */
        if (!skip_field) {
-       while (*raw && *raw != ':')
+               while (*raw && *raw != ':')
+                       raw++;
                raw++;
-       raw++;
        }
 
        if (line_is_blank(raw)) {
@@ -61,7 +65,7 @@ parse_list(const char *raw, unsigned int *count, const char sep, int skip_field)
 
        while (*raw) {
                depends = xrealloc(depends, sizeof(char *) * (line_count + 1));
-       
+
                while (isspace(*raw))
                        raw++;
 
@@ -76,13 +80,92 @@ parse_list(const char *raw, unsigned int *count, const char sep, int skip_field)
                if (sep == ' ')
                        end++;
 
-               depends[line_count] = xstrndup(start, end-start);
+               depends[line_count] = xstrndup(start, end - start);
 
-               line_count++;
+               line_count++;
                if (*raw == sep)
-                   raw++;
+                       raw++;
        }
 
        *count = line_count;
        return depends;
 }
+
+int
+parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE * fp,
+                          uint mask, char **buf0, size_t buf0len)
+{
+       int ret, lineno;
+       char *buf, *nl;
+       size_t buflen;
+
+       lineno = 1;
+       ret = 0;
+
+       buflen = buf0len;
+       buf = *buf0;
+       buf[0] = '\0';
+
+       while (1) {
+               if (fgets(buf, (int)buflen, fp) == NULL) {
+                       if (ferror(fp)) {
+                               opkg_perror(ERROR, "fgets");
+                               ret = -1;
+                       } else if (strlen(*buf0) == buf0len - 1) {
+                               opkg_msg(ERROR, "Missing new line character"
+                                        " at end of file!\n");
+                               parse_line(item, *buf0, mask);
+                       }
+                       break;
+               }
+
+               nl = strchr(buf, '\n');
+               if (nl == NULL) {
+                       if (strlen(buf) < buflen - 1) {
+                               /*
+                                * Line could be exactly buflen-1 long and
+                                * missing a newline, but we won't know until
+                                * fgets fails to read more data.
+                                */
+                               opkg_msg(ERROR, "Missing new line character"
+                                        " at end of file!\n");
+                               parse_line(item, *buf0, mask);
+                               break;
+                       }
+                       if (buf0len >= EXCESSIVE_LINE_LEN) {
+                               opkg_msg(ERROR, "Excessively long line at "
+                                        "%d. Corrupt file?\n", lineno);
+                               ret = -1;
+                               break;
+                       }
+
+                       /*
+                        * Realloc and point buf past the data already read,
+                        * at the NULL terminator inserted by fgets.
+                        * |<--------------- buf0len ----------------->|
+                        * |                     |<------- buflen ---->|
+                        * |---------------------|---------------------|
+                        * buf0                   buf
+                        */
+                       buflen = buf0len + 1;
+                       buf0len *= 2;
+                       *buf0 = xrealloc(*buf0, buf0len);
+                       buf = *buf0 + buflen - 2;
+
+                       continue;
+               }
+
+               *nl = '\0';
+
+               lineno++;
+
+               if (parse_line(item, *buf0, mask))
+                       break;
+
+               buf = *buf0;
+               buflen = buf0len;
+               buf[0] = '\0';
+       }
+
+       return ret;
+}