The following commit has been merged in the master branch:
commit 04c0362979a832bc0044d932cd1b705cef7b0d5b
Author: Raphaël Hertzog <[email protected]>
Date: Fri Jan 14 12:44:21 2011 +0100
libdpkg: Implement a centralized list of architectures
The goal is to avoid having hundreds of strdup'ed architecture strings in
memory when we can instead store some pointers to a new structure. Those
structs are singletons and it's thus now possible to compare the pointers
directly if we want to compare two architectures. Furthermore the struct
allows us to store conveniently some basic information like if the
architecture is the native one, a foreign one, a special one (all/any),
an illegal one, no architecture present or something completely unknown.
Sponsored-by: Linaro Limited
[[email protected]:
- Add an explicit test for dpkg_arch_reset(), and do not rely on
pkg_db_reset().
- Check that the default list has exactly 3 items instead of >= 3.
- Change call to dpkg_arch_reset() before nffreeall().
- Rename dpkg_arch_reset() to dpkg_arch_reset_list(). ]
Signed-off-by: Guillem Jover <[email protected]>
diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am
index 25c3159..d26a53b 100644
--- a/lib/dpkg/Makefile.am
+++ b/lib/dpkg/Makefile.am
@@ -25,6 +25,7 @@ lib_LIBRARIES = libdpkg.a
libdpkg_a_SOURCES = \
dlist.h \
ar.c \
+ arch.c \
buffer.c \
cleanup.c \
command.c \
@@ -74,6 +75,7 @@ libdpkg_a_SOURCES = \
pkginclude_HEADERS = \
ar.h \
+ arch.h \
buffer.h \
command.h \
compress.h \
diff --git a/lib/dpkg/arch.c b/lib/dpkg/arch.c
new file mode 100644
index 0000000..cbb9bab
--- /dev/null
+++ b/lib/dpkg/arch.c
@@ -0,0 +1,174 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * arch.c - architecture database functions
+ *
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <[email protected]>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/ehandle.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
+
+/**
+ * Verify if the architecture name is valid.
+ *
+ * Returns NULL if the architecture name is valid. Otherwise it returns a
+ * string describing why it's not valid. Currently it ensures the name
+ * starts with an alphanumeric and is then composed of a combinations of
+ * dashes and alphanumerics.
+ *
+ * The function will abort if you pass it a NULL pointer.
+ *
+ * @param name The architectute name to verify.
+ */
+const char *
+dpkg_arch_name_is_illegal(const char *name)
+{
+ static char buf[150];
+ const char *p = name;
+
+ assert(name);
+ if (!*p)
+ return _("may not be empty string");
+ if (!isalnum(*p))
+ return _("must start with an alphanumeric");
+ while (*++p != '\0')
+ if (!isalnum(*p) && *p != '-')
+ break;
+ if (*p == '\0')
+ return NULL;
+
+ snprintf(buf, sizeof(buf), _("character `%c' not allowed (only "
+ "letters, digits and characters `%s')"),
+ *p, "-");
+ return buf;
+}
+
+/* This is a special architecture used to guarantee we always have a valid
+ * structure to handle. */
+static struct dpkg_arch arch_item_none = {
+ .name = "",
+ .type = arch_none,
+ .next = NULL,
+};
+
+static struct dpkg_arch arch_item_any = {
+ .name = "any",
+ .type = arch_wildcard,
+ .next = NULL,
+};
+static struct dpkg_arch arch_item_all = {
+ .name = "all",
+ .type = arch_all,
+ .next = &arch_item_any,
+};
+static struct dpkg_arch arch_item_native = {
+ .name = ARCHITECTURE,
+ .type = arch_native,
+ .next = &arch_item_all,
+};
+static struct dpkg_arch *arch_list = &arch_item_native;
+
+static struct dpkg_arch *
+dpkg_arch_new(const char *name, enum arch_type type)
+{
+ struct dpkg_arch *new;
+
+ new = nfmalloc(sizeof(*new));
+ new->next = NULL;
+ new->name = nfstrsave(name);
+ new->type = type;
+
+ return new;
+}
+
+/**
+ * Retrieve the struct dpkg_arch for the given architecture.
+ *
+ * Create a new structure for the architecture if it's not yet known from
+ * the system, in that case it will have arch->type == arch_unknown, if the
+ * architecture is illegal it will have arch->type == arch_illegal and if
+ * name is NULL or an empty string then it will have arch->type == arch_none.
+ *
+ * @param name The architecture name.
+ */
+struct dpkg_arch *
+dpkg_arch_find(const char *name)
+{
+ struct dpkg_arch *arch, *last_arch = NULL;
+ enum arch_type type;
+
+ if (name == NULL || name[0] == '\0')
+ return &arch_item_none;
+
+ for (arch = arch_list; arch; arch = arch->next) {
+ if (strcmp(arch->name, name) == 0)
+ return arch;
+ last_arch = arch;
+ }
+
+ if (dpkg_arch_name_is_illegal(name))
+ type = arch_illegal;
+ else
+ type = arch_unknown;
+
+ arch = dpkg_arch_new(name, type);
+ last_arch->next = arch;
+
+ return arch;
+}
+
+/**
+ * Return the struct dpkg_arch corresponding to the native architecture.
+ */
+struct dpkg_arch *
+dpkg_arch_get_native(void)
+{
+ return &arch_item_native;
+}
+
+/**
+ * Return the complete list of architectures.
+ *
+ * In fact it returns the first item of the linked list and you can
+ * traverse the list by following arch->next until it's NULL.
+ */
+struct dpkg_arch *
+dpkg_arch_get_list(void)
+{
+ return arch_list;
+}
+
+/**
+ * Reset the list of architectures.
+ *
+ * Must be called before nffreeall() to ensure we don't point to
+ * unallocated memory.
+ */
+void
+dpkg_arch_reset_list(void)
+{
+ arch_item_any.next = NULL;
+}
diff --git a/lib/dpkg/namevalue.h b/lib/dpkg/arch.h
similarity index 54%
copy from lib/dpkg/namevalue.h
copy to lib/dpkg/arch.h
index 3f17c4b..e3ca20b 100644
--- a/lib/dpkg/namevalue.h
+++ b/lib/dpkg/arch.h
@@ -1,9 +1,9 @@
/*
* libdpkg - Debian packaging suite library routines
- * namevalue.h - name value structure handling
+ * arch.h - architecture database functions
*
- * Copyright © 1994,1995 Ian Jackson <[email protected]>
- * Copyright © 2009-2011 Guillem Jover <[email protected]>
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <[email protected]>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,27 +19,33 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LIBDPKG_NAMEVALUE_H
-#define LIBDPKG_NAMEVALUE_H
+#ifndef LIBDPKG_ARCH_H
+#define LIBDPKG_ARCH_H
#include <dpkg/macros.h>
DPKG_BEGIN_DECLS
-struct namevalue {
+struct dpkg_arch {
+ struct dpkg_arch *next;
const char *name;
- int value;
- int length;
+ enum arch_type {
+ arch_none,
+ arch_all,
+ arch_native,
+ arch_foreign,
+ arch_wildcard,
+ arch_unknown,
+ arch_illegal,
+ } type;
};
-#define NAMEVALUE_DEF(n, v) \
- [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 char *str);
+const char *dpkg_arch_name_is_illegal(const char *name) DPKG_ATTR_NONNULL(1);
+struct dpkg_arch *dpkg_arch_find(const char *name);
+struct dpkg_arch *dpkg_arch_get_native(void);
+struct dpkg_arch *dpkg_arch_get_list(void);
+void dpkg_arch_reset_list(void);
DPKG_END_DECLS
-#endif /* LIBDPKG_NAMEVALUE_H */
+#endif /* LIBDPKG_ARCH_H */
diff --git a/lib/dpkg/libdpkg.Versions b/lib/dpkg/libdpkg.Versions
index af1acd2..d6722bb 100644
--- a/lib/dpkg/libdpkg.Versions
+++ b/lib/dpkg/libdpkg.Versions
@@ -179,6 +179,13 @@ LIBDPKG_PRIVATE {
versionsatisfied3;
parseversion;
+ # Architecture database
+ dpkg_arch_name_is_illegal;
+ dpkg_arch_find;
+ dpkg_arch_get_native;
+ dpkg_arch_get_list;
+ dpkg_arch_reset_list;
+
# Package struct handling
pkg_blank;
pkgbin_blank;
diff --git a/lib/dpkg/pkg-db.c b/lib/dpkg/pkg-db.c
index 0b49479..d93dc0f 100644
--- a/lib/dpkg/pkg-db.c
+++ b/lib/dpkg/pkg-db.c
@@ -28,6 +28,7 @@
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
/* This must always be a prime for optimal performance.
* With 4093 buckets, we glean a 20% speedup, for 8191 buckets
@@ -123,6 +124,8 @@ void
pkg_db_reset(void)
{
int i;
+
+ dpkg_arch_reset_list();
nffreeall();
npackages= 0;
for (i=0; i<BINS; i++) bins[i]= NULL;
diff --git a/lib/dpkg/test/.gitignore b/lib/dpkg/test/.gitignore
index 8857e47..bacf610 100644
--- a/lib/dpkg/test/.gitignore
+++ b/lib/dpkg/test/.gitignore
@@ -1,4 +1,5 @@
t-ar
+t-arch
t-buffer
t-command
t-macros
diff --git a/lib/dpkg/test/Makefile.am b/lib/dpkg/test/Makefile.am
index 24fd66e..ab85c1b 100644
--- a/lib/dpkg/test/Makefile.am
+++ b/lib/dpkg/test/Makefile.am
@@ -23,6 +23,7 @@ check_PROGRAMS = \
t-command \
t-varbuf \
t-ar \
+ t-arch \
t-version \
t-pkginfo \
t-pkg-list \
diff --git a/lib/dpkg/test/t-arch.c b/lib/dpkg/test/t-arch.c
new file mode 100644
index 0000000..127dbb6
--- /dev/null
+++ b/lib/dpkg/test/t-arch.c
@@ -0,0 +1,134 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-arch.c - test dpkg_arch implementation
+ *
+ * Copyright © 2011 Linaro Limited
+ * Copyright © 2011 Raphaël Hertzog <[email protected]>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <dpkg/test.h>
+#include <dpkg/arch.h>
+
+static void
+test_dpkg_arch_name_is_illegal(void)
+{
+ /* Test invalid architecture names. */
+ test_fail(dpkg_arch_name_is_illegal("") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("-i386") == NULL);
+ test_fail(dpkg_arch_name_is_illegal(" i386") == NULL);
+ test_fail(dpkg_arch_name_is_illegal(":any") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("amd64_test") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("i386:test") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("i386 amd64") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("i386,amd64") == NULL);
+ test_fail(dpkg_arch_name_is_illegal("i386|amd64") == NULL);
+
+ /* Test valid architecture names. */
+ test_pass(dpkg_arch_name_is_illegal("i386") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("amd64") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("hurd-i386") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("kfreebsd-i386") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("kfreebsd-amd64") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("ia64") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("alpha") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("armel") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("hppa") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("mips") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("mipsel") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("powerpc") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("s390") == NULL);
+ test_pass(dpkg_arch_name_is_illegal("sparc") == NULL);
+}
+
+static void
+test_dpkg_arch_get_native(void)
+{
+ struct dpkg_arch *arch;
+
+ arch = dpkg_arch_get_native();
+ test_str(arch->name, ==, ARCHITECTURE);
+ test_pass(arch->type == arch_native);
+}
+
+static void
+test_dpkg_arch_get_list(void)
+{
+ struct dpkg_arch *arch;
+ int count = 1;
+
+ /* Must never return NULL. */
+ arch = dpkg_arch_get_list();
+ test_pass(arch != NULL);
+
+ while ((arch = arch->next))
+ count++;
+
+ /* The default list should contain 3 architectures. */
+ test_pass(count == 3);
+}
+
+static void
+test_dpkg_arch_find(void)
+{
+ struct dpkg_arch *arch;
+
+ /* Test existence and initial values of default architectures. */
+ arch = dpkg_arch_find("all");
+ test_pass(arch->type == arch_all);
+ arch = dpkg_arch_find(ARCHITECTURE);
+ test_pass(arch->type == arch_native);
+ arch = dpkg_arch_find("any");
+ test_pass(arch->type == arch_wildcard);
+
+ /* Empty architectures are marked none. */
+ arch = dpkg_arch_find(NULL);
+ test_pass(arch->type == arch_none);
+ test_str(arch->name, ==, "");
+ arch = dpkg_arch_find("");
+ test_pass(arch->type == arch_none);
+ test_str(arch->name, ==, "");
+
+ /* New valid architectures are marked unknown. */
+ arch = dpkg_arch_find("foobar");
+ test_pass(arch->type == arch_unknown);
+ test_str(arch->name, ==, "foobar");
+
+ /* New illegal architectures are marked illegal. */
+ arch = dpkg_arch_find("a:b");
+ test_pass(arch->type == arch_illegal);
+ test_str(arch->name, ==, "a:b");
+}
+
+static void
+test_dpkg_arch_reset_list(void)
+{
+ dpkg_arch_reset_list();
+
+ test_dpkg_arch_get_list();
+}
+
+void
+test(void)
+{
+ test_dpkg_arch_name_is_illegal();
+ test_dpkg_arch_get_native();
+ test_dpkg_arch_get_list();
+ test_dpkg_arch_find();
+ test_dpkg_arch_reset_list();
+}
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]