Explorar o código

libdpkg: Simplify namevalue parsing code

This removes the special fallback value from the name/value table,
so that we cannot accidentally parse it as a valid value.
Guillem Jover %!s(int64=11) %!d(string=hai) anos
pai
achega
2a6d9275c0
Modificáronse 5 ficheiros con 56 adicións e 43 borrados
  1. 0 1
      dselect/pkgdisplay.cc
  2. 54 33
      lib/dpkg/fields.c
  3. 2 6
      lib/dpkg/namevalue.c
  4. 0 2
      lib/dpkg/namevalue.h
  5. 0 1
      lib/dpkg/pkg-namevalue.c

+ 0 - 1
dselect/pkgdisplay.cc

@@ -63,7 +63,6 @@ const char
 			       N_("Standard"),
 			       N_("Standard"),
 			       N_("Optional"),
 			       N_("Optional"),
 			       N_("Extra"),
 			       N_("Extra"),
-			       N_("!Bug!"),
 			       N_("Unclassified"),
 			       N_("Unclassified"),
 			       nullptr },
 			       nullptr },
 
 

+ 54 - 33
lib/dpkg/fields.c

@@ -40,45 +40,57 @@
 #include <dpkg/pkg-spec.h>
 #include <dpkg/pkg-spec.h>
 #include <dpkg/triglib.h>
 #include <dpkg/triglib.h>
 
 
+/**
+ * Flags to parse a name associated to a value.
+ */
+enum parse_nv_flags {
+  /** Expect no more words (default). */
+  PARSE_NV_LAST		= 0,
+  /** Expect another word after the parsed name. */
+  PARSE_NV_NEXT		= DPKG_BIT(0),
+  /** Do not fail if there is no name with an associated value found. */
+  PARSE_NV_FALLBACK	= DPKG_BIT(1),
+};
+
+/**
+ * Parses a name and returns its associated value.
+ *
+ * Gets a pointer to the string to parse in @a strp, and modifies the pointer
+ * to the string to point to the end of the parsed text. If no value is found
+ * for the name and #PARSE_NV_FALLBACK is set in @a flags then @a strp is set
+ * to NULL and returns -1, otherwise a parse error is emitted.
+ */
 static int
 static int
-parse_nv_next(struct parsedb_state *ps,
-              const char *what, const struct namevalue *nv_head,
-              const char **strp)
+parse_nv(struct parsedb_state *ps, enum parse_nv_flags flags,
+         const char **strp, const struct namevalue *nv_head, const char *what)
 {
 {
   const char *str_start = *strp, *str_end;
   const char *str_start = *strp, *str_end;
   const struct namevalue *nv;
   const struct namevalue *nv;
+  int value;
 
 
   if (str_start[0] == '\0')
   if (str_start[0] == '\0')
     parse_error(ps, _("%s is missing"), what);
     parse_error(ps, _("%s is missing"), what);
 
 
   nv = namevalue_find_by_name(nv_head, str_start);
   nv = namevalue_find_by_name(nv_head, str_start);
-  if (nv == NULL)
-    parse_error(ps, _("'%.50s' is not allowed for %s"), str_start, what);
+  if (nv == NULL) {
+    /* We got no match, skip further string validation. */
+    if (!(flags & PARSE_NV_FALLBACK))
+      parse_error(ps, _("'%.50s' is not allowed for %s"), str_start, what);
 
 
-  /* We got the fallback value, skip further string validation. */
-  if (nv->length == 0) {
     str_end = NULL;
     str_end = NULL;
+    value = -1;
   } else {
   } else {
     str_end = str_start + nv->length;
     str_end = str_start + nv->length;
     while (c_isspace(str_end[0]))
     while (c_isspace(str_end[0]))
       str_end++;
       str_end++;
+    value = nv->value;
   }
   }
-  *strp = str_end;
-
-  return nv->value;
-}
-
-static int
-parse_nv_last(struct parsedb_state *ps,
-              const char *what, const struct namevalue *nv_head,
-              const char *str)
-{
-  int value;
 
 
-  value = parse_nv_next(ps, what, nv_head, &str);
-  if (str_is_set(str))
+  if (!(flags & PARSE_NV_NEXT) && str_is_set(str_end))
     parse_error(ps, _("junk after %s"), what);
     parse_error(ps, _("junk after %s"), what);
 
 
+  *strp = str_end;
+
   return value;
   return value;
 }
 }
 
 
@@ -162,8 +174,8 @@ f_boolean(struct pkginfo *pkg, struct pkgbin *pkgbin,
   if (!*value)
   if (!*value)
     return;
     return;
 
 
-  boolean = parse_nv_last(ps, _("yes/no in boolean field"),
-                          booleaninfos, value);
+  boolean = parse_nv(ps, PARSE_NV_LAST, &value, booleaninfos,
+                     _("yes/no in boolean field"));
   STRUCTFIELD(pkgbin, fip->integer, bool) = boolean;
   STRUCTFIELD(pkgbin, fip->integer, bool) = boolean;
 }
 }
 
 
@@ -177,8 +189,8 @@ f_multiarch(struct pkginfo *pkg, struct pkgbin *pkgbin,
   if (!*value)
   if (!*value)
     return;
     return;
 
 
-  multiarch = parse_nv_last(ps, _("foreign/allowed/same/no in quadstate field"),
-                            multiarchinfos, value);
+  multiarch = parse_nv(ps, PARSE_NV_LAST, &value, multiarchinfos,
+                       _("foreign/allowed/same/no in quadstate field"));
   STRUCTFIELD(pkgbin, fip->integer, int) = multiarch;
   STRUCTFIELD(pkgbin, fip->integer, int) = multiarch;
 }
 }
 
 
@@ -207,11 +219,20 @@ f_priority(struct pkginfo *pkg, struct pkgbin *pkgbin,
            struct parsedb_state *ps,
            struct parsedb_state *ps,
            const char *value, const struct fieldinfo *fip)
            const char *value, const struct fieldinfo *fip)
 {
 {
+  const char *str = value;
+  int priority;
+
   if (!*value) return;
   if (!*value) return;
-  pkg->priority = parse_nv_last(ps, _("word in 'Priority' field"),
-                                priorityinfos, value);
-  if (pkg->priority == PKG_PRIO_OTHER)
+
+  priority = parse_nv(ps, PARSE_NV_LAST | PARSE_NV_FALLBACK, &str,
+                      priorityinfos, _("word in 'Priority' field"));
+
+  if (str == NULL) {
+    pkg->priority = PKG_PRIO_OTHER;
     pkg->otherpriority = nfstrsave(value);
     pkg->otherpriority = nfstrsave(value);
+  } else {
+    pkg->priority = priority;
+  }
 }
 }
 
 
 void
 void
@@ -226,12 +247,12 @@ f_status(struct pkginfo *pkg, struct pkgbin *pkgbin,
   if (ps->flags & pdb_recordavailable)
   if (ps->flags & pdb_recordavailable)
     return;
     return;
 
 
-  pkg->want = parse_nv_next(ps, _("first (want) word in 'Status' field"),
-                            wantinfos, &value);
-  pkg->eflag = parse_nv_next(ps, _("second (error) word in 'Status' field"),
-                             eflaginfos, &value);
-  pkg->status = parse_nv_last(ps, _("third (status) word in 'Status' field"),
-                              statusinfos, value);
+  pkg->want = parse_nv(ps, PARSE_NV_NEXT, &value, wantinfos,
+                       _("first (want) word in 'Status' field"));
+  pkg->eflag = parse_nv(ps, PARSE_NV_NEXT, &value, eflaginfos,
+                        _("second (error) word in 'Status' field"));
+  pkg->status = parse_nv(ps, PARSE_NV_LAST, &value, statusinfos,
+                         _("third (status) word in 'Status' field"));
 }
 }
 
 
 void
 void

+ 2 - 6
lib/dpkg/namevalue.c

@@ -29,16 +29,12 @@
 const struct namevalue *
 const struct namevalue *
 namevalue_find_by_name(const struct namevalue *head, const char *str)
 namevalue_find_by_name(const struct namevalue *head, const char *str)
 {
 {
-	const struct namevalue *nv, *nv_fallback = NULL;
+	const struct namevalue *nv;
 
 
 	for (nv = head; nv->name; nv++) {
 	for (nv = head; nv->name; nv++) {
-		if (nv->length == 0) {
-			nv_fallback = nv;
-			continue;
-		}
 		if (strncasecmp(str, nv->name, nv->length) == 0)
 		if (strncasecmp(str, nv->name, nv->length) == 0)
 			return nv;
 			return nv;
 	}
 	}
 
 
-	return nv_fallback;
+	return NULL;
 }
 }

+ 0 - 2
lib/dpkg/namevalue.h

@@ -40,8 +40,6 @@ struct namevalue {
 
 
 #define NAMEVALUE_DEF(n, v) \
 #define NAMEVALUE_DEF(n, v) \
 	[v] = { .name = n, .value = v, .length = sizeof(n) - 1 }
 	[v] = { .name = n, .value = v, .length = sizeof(n) - 1 }
-#define NAMEVALUE_FALLBACK_DEF(n, v) \
-	[v] = { .name = n, .value = v, .length = 0 }
 
 
 const struct namevalue *namevalue_find_by_name(const struct namevalue *head,
 const struct namevalue *namevalue_find_by_name(const struct namevalue *head,
                                                const char *str);
                                                const char *str);

+ 0 - 1
lib/dpkg/pkg-namevalue.c

@@ -45,7 +45,6 @@ const struct namevalue priorityinfos[] = {
 	NAMEVALUE_DEF("standard",		PKG_PRIO_STANDARD),
 	NAMEVALUE_DEF("standard",		PKG_PRIO_STANDARD),
 	NAMEVALUE_DEF("optional",		PKG_PRIO_OPTIONAL),
 	NAMEVALUE_DEF("optional",		PKG_PRIO_OPTIONAL),
 	NAMEVALUE_DEF("extra",			PKG_PRIO_EXTRA),
 	NAMEVALUE_DEF("extra",			PKG_PRIO_EXTRA),
-	NAMEVALUE_FALLBACK_DEF("this is a bug - please report", PKG_PRIO_OTHER),
 	NAMEVALUE_DEF("unknown",		PKG_PRIO_UNKNOWN),
 	NAMEVALUE_DEF("unknown",		PKG_PRIO_UNKNOWN),
 	{ .name = NULL }
 	{ .name = NULL }
 };
 };