Kaynağa Gözat

libdpkg: Refactor pkg_parse_field() out from parsedb()

Guillem Jover 15 yıl önce
ebeveyn
işleme
36d762414b
1 değiştirilmiş dosya ile 84 ekleme ve 60 silme
  1. 84 60
      lib/dpkg/parse.c

+ 84 - 60
lib/dpkg/parse.c

@@ -83,6 +83,70 @@ const struct fieldinfo fieldinfos[]= {
   {  NULL                                                                             }
 };
 
+struct field_state {
+  const char *fieldstart;
+  const char *valuestart;
+  char *value;
+  int fieldlen;
+  int valuelen;
+  int fieldencountered[array_count(fieldinfos)];
+};
+
+/**
+ * Parse the field and value into the package being constructed.
+ */
+static void
+pkg_parse_field(struct parsedb_state *ps, struct field_state *fs,
+                struct pkginfo *pkg, struct pkgbin *pkgbin)
+{
+  const struct nickname *nick;
+  const struct fieldinfo *fip;
+  int *ip;
+
+  for (nick = nicknames;
+       nick->nick && (strncasecmp(nick->nick, fs->fieldstart, fs->fieldlen) ||
+                      nick->nick[fs->fieldlen] != '\0'); nick++) ;
+  if (nick->nick) {
+    fs->fieldstart = nick->canon;
+    fs->fieldlen = strlen(fs->fieldstart);
+  }
+
+  for (fip = fieldinfos, ip = fs->fieldencountered;
+       fip->name && strncasecmp(fs->fieldstart, fip->name, fs->fieldlen);
+       fip++, ip++) ;
+  if (fip->name) {
+    if ((*ip)++)
+      parse_error(ps, pkg,
+                  _("duplicate value for `%s' field"), fip->name);
+
+    fs->value = m_realloc(fs->value, fs->valuelen + 1);
+    memcpy(fs->value, fs->valuestart, fs->valuelen);
+    *(fs->value + fs->valuelen) = '\0';
+
+    fip->rcall(pkg, pkgbin, ps, fs->value, fip);
+  } else {
+    struct arbitraryfield *arp, **larpp;
+
+    if (fs->fieldlen < 2)
+      parse_error(ps, pkg,
+                  _("user-defined field name `%.*s' too short"),
+                  fs->fieldlen, fs->fieldstart);
+    larpp = &pkgbin->arbs;
+    while ((arp = *larpp) != NULL) {
+      if (!strncasecmp(arp->name, fs->fieldstart, fs->fieldlen))
+        parse_error(ps, pkg,
+                   _("duplicate value for user-defined field `%.*s'"),
+                   fs->fieldlen, fs->fieldstart);
+      larpp = &arp->next;
+    }
+    arp = nfmalloc(sizeof(struct arbitraryfield));
+    arp->name = nfstrnsave(fs->fieldstart, fs->fieldlen);
+    arp->value = nfstrnsave(fs->valuestart, fs->valuelen);
+    arp->next = NULL;
+    *larpp = arp;
+  }
+}
+
 /**
  * Verify and fixup the package structure being constructed.
  */
@@ -238,21 +302,17 @@ int parsedb(const char *filename, enum parsedbflags flags,
   struct pkginfo newpig, *pigp;
   struct pkgbin *newpifp, *pifp;
   int pdone;
-  int fieldencountered[array_count(fieldinfos)];
-  const struct fieldinfo *fip;
-  const struct nickname *nick;
   char *data, *dataptr, *endptr;
-  const char *fieldstart, *valuestart;
-  char *value= NULL;
-  int fieldlen= 0, valuelen= 0;
-  int *ip;
   struct stat st;
   struct parsedb_state ps;
+  struct field_state fs;
 
   ps.filename = filename;
   ps.flags = flags;
   ps.lno = 0;
 
+  memset(&fs, 0, sizeof(fs));
+
   newpifp= (flags & pdb_recordavailable) ? &newpig.available : &newpig.installed;
   fd= open(filename, O_RDONLY);
   if (fd == -1) ohshite(_("failed to open package info file `%.255s' for reading"),filename);
@@ -288,7 +348,7 @@ int parsedb(const char *filename, enum parsedbflags flags,
   for (;;) {
     int c;
 
-    memset(fieldencountered, 0, sizeof(fieldencountered));
+    memset(fs.fieldencountered, 0, sizeof(fs.fieldencountered));
     pkg_blank(&newpig);
 
     /* Skip adjacent new lines. */
@@ -300,25 +360,25 @@ int parsedb(const char *filename, enum parsedbflags flags,
 
     /* Loop per field. */
     for (;;) {
-      fieldstart= dataptr - 1;
+      fs.fieldstart = dataptr - 1;
       while (!EOF_mmap(dataptr, endptr) && !isspace(c) && c!=':' && c!=MSDOS_EOF_CHAR)
         c= getc_mmap(dataptr);
-      fieldlen= dataptr - fieldstart - 1;
+      fs.fieldlen = dataptr - fs.fieldstart - 1;
       while (!EOF_mmap(dataptr, endptr) && c != '\n' && isspace(c)) c= getc_mmap(dataptr);
       if (EOF_mmap(dataptr, endptr))
         parse_error(&ps, &newpig,
-                    _("EOF after field name `%.*s'"), fieldlen, fieldstart);
+                    _("EOF after field name `%.*s'"), fs.fieldlen, fs.fieldstart);
       if (c == '\n')
         parse_error(&ps, &newpig,
-                    _("newline in field name `%.*s'"), fieldlen, fieldstart);
+                    _("newline in field name `%.*s'"), fs.fieldlen, fs.fieldstart);
       if (c == MSDOS_EOF_CHAR)
         parse_error(&ps, &newpig,
                     _("MSDOS EOF (^Z) in field name `%.*s'"),
-                    fieldlen, fieldstart);
+                    fs.fieldlen, fs.fieldstart);
       if (c != ':')
         parse_error(&ps, &newpig,
                     _("field name `%.*s' must be followed by colon"),
-                    fieldlen, fieldstart);
+                    fs.fieldlen, fs.fieldstart);
       /* Skip space after ‘:’ but before value and EOL. */
       while(!EOF_mmap(dataptr, endptr)) {
         c= getc_mmap(dataptr);
@@ -327,12 +387,12 @@ int parsedb(const char *filename, enum parsedbflags flags,
       if (EOF_mmap(dataptr, endptr))
         parse_error(&ps, &newpig,
                     _("EOF before value of field `%.*s' (missing final newline)"),
-                 fieldlen,fieldstart);
+                    fs.fieldlen, fs.fieldstart);
       if (c == MSDOS_EOF_CHAR)
         parse_error(&ps, &newpig,
                     _("MSDOS EOF char in value of field `%.*s' (missing newline?)"),
-                    fieldlen,fieldstart);
-      valuestart= dataptr - 1;
+                    fs.fieldlen, fs.fieldstart);
+      fs.valuestart = dataptr - 1;
       for (;;) {
         if (c == '\n' || c == MSDOS_EOF_CHAR) {
           ps.lno++;
@@ -345,53 +405,17 @@ int parsedb(const char *filename, enum parsedbflags flags,
         } else if (EOF_mmap(dataptr, endptr)) {
           parse_error(&ps, &newpig,
                       _("EOF during value of field `%.*s' (missing final newline)"),
-                      fieldlen,fieldstart);
+                      fs.fieldlen, fs.fieldstart);
         }
         c= getc_mmap(dataptr);
       }
-      valuelen= dataptr - valuestart - 1;
+      fs.valuelen = dataptr - fs.valuestart - 1;
       /* Trim ending space on value. */
-      while (valuelen && isspace(*(valuestart+valuelen-1)))
- valuelen--;
-      for (nick = nicknames;
-           nick->nick && (strncasecmp(nick->nick, fieldstart, fieldlen) ||
-                          nick->nick[fieldlen] != '\0'); nick++) ;
-      if (nick->nick) {
-	fieldstart= nick->canon;
-	fieldlen= strlen(fieldstart);
-      }
-      for (fip= fieldinfos, ip= fieldencountered;
-           fip->name && strncasecmp(fieldstart,fip->name, fieldlen);
-           fip++, ip++);
-      if (fip->name) {
-        value = m_realloc(value, valuelen + 1);
-	memcpy(value,valuestart,valuelen);
-        *(value + valuelen) = '\0';
-        if ((*ip)++)
-          parse_error(&ps, &newpig,
-                      _("duplicate value for `%s' field"), fip->name);
-        fip->rcall(&newpig, newpifp, &ps, value, fip);
-      } else {
-        struct arbitraryfield *arp, **larpp;
+      while (fs.valuelen && isspace(*(fs.valuestart + fs.valuelen - 1)))
+        fs.valuelen--;
+
+      pkg_parse_field(&ps, &fs, &newpig, newpifp);
 
-        if (fieldlen<2)
-          parse_error(&ps, &newpig,
-                      _("user-defined field name `%.*s' too short"),
-                      fieldlen, fieldstart);
-        larpp= &newpifp->arbs;
-        while ((arp= *larpp) != NULL) {
-          if (!strncasecmp(arp->name,fieldstart,fieldlen))
-            parse_error(&ps, &newpig,
-                       _("duplicate value for user-defined field `%.*s'"),
-                       fieldlen, fieldstart);
-          larpp= &arp->next;
-        }
-        arp= nfmalloc(sizeof(struct arbitraryfield));
-        arp->name= nfstrnsave(fieldstart,fieldlen);
-        arp->value= nfstrnsave(valuestart,valuelen);
-        arp->next= NULL;
-        *larpp= arp;
-      }
       if (EOF_mmap(dataptr, endptr) || c == '\n' || c == MSDOS_EOF_CHAR) break;
     } /* Loop per field. */
 
@@ -423,7 +447,7 @@ int parsedb(const char *filename, enum parsedbflags flags,
     free(data);
 #endif
   }
-  free(value);
+  free(fs.value);
   pop_cleanup(ehflag_normaltidy);
   if (close(fd)) ohshite(_("failed to close after read: `%.255s'"),filename);
   if (donep && !pdone) ohshit(_("no package information in `%.255s'"),filename);