gEDA-dev: [PATCH] GAF: Two new utility functions
Bernd Jendrissek
bernd.jendrissek at gmail.com
Tue Jul 24 13:12:21 EDT 2007
I'm working on The Right Way (TM & IMHO & etc.) to do slotted components
and here are two utility functions that I have found necessary so far.
Maybe they have other uses too?
The UUID generation is ugly - I only made a minimal implementation here.
It turns out (very unfortunately) that there are several hostilely
incompatible UUID libraries floating around. libuuid from e2fsprogs
has:
int uuid_parse( char *in, uuid_t uu);
while another library on a FreeBSD system I have access to has:
void uuid_from_string(const char *str, uuid_t *uuid, uint32_t *status);
Notice how the one wants a (uuid_t) and the other wants a (uuid_t *). I
think ultimately I'll redo u_basic_make_uuid() to use libaprutil's
apr_uuid_get() if available, and fall back to a stupid version if not.
2007-07-24 Bernd Jendrissek <bernd.jendrissek at gmail.com>
* libgeda/src/u_basic.c: u_basic_populate_hash(): New function
to help build key=>value maps from attribute strings.
* libgeda/src/u_basic.c: u_basic_make_uuid(): New function to
provide dynamically allocated UUID as a string.
* libgeda/include/prototype.h: Provide prototypes for new
functions.
* libgeda/Makefile.am, libgeda/tests/Makefile.am: Add unit tests
for new functions.
* libgeda/tests/globals.c: Provide globals that libgeda
annoyingly wants to link to.
* libgeda/tests/hashpop.c, libgeda/tests/hashpop.sh: Check that
u_basic_populate_hash() inserts the right key=>value pairs.
* libgeda/tests/uuidgen.c, libgeda/tests/uuidgen.sh: Check that
u_basic_make_uuid() returns no duplicate strings.
* libgeda/configure.ac: Check for uuid_generate() in -luuid.
-------------- next part --------------
Index: gaf.git/libgeda/include/prototype.h
diff -u -p -- gaf.git/libgeda/include/prototype.h.borig gaf.git/libgeda/include/prototype.h
--- gaf.git/libgeda/include/prototype.h
+++ gaf.git/libgeda/include/prototype.h 2007-07-24 01:29:52.000000000 +0200
@@ -670,6 +683,9 @@ char *u_basic_breakup_string(char *strin
void u_basic_strip_trailing(char *string, char c);
int u_basic_has_trailing(char *string, char c);
int u_basic_count_char(const char *string, char character);
+void u_basic_populate_hash(GHashTable *tab, char *s,
+ char comma, char equals);
+char *u_basic_make_uuid(void);
/* s_textbuffer.c */
TextBuffer *s_textbuffer_new (gchar *data, const gint size);
Index: gaf.git/libgeda/src/u_basic.c
diff -u -p -- gaf.git/libgeda/src/u_basic.c.borig gaf.git/libgeda/src/u_basic.c
--- gaf.git/libgeda/src/u_basic.c
+++ gaf.git/libgeda/src/u_basic.c 2007-07-24 01:02:14.000000000 +0200
@@ -29,8 +29,11 @@
#include <stdlib.h>
#endif
-#include <gtk/gtk.h>
+#include <glib.h>
#include <libguile.h>
+#ifdef HAVE_LIBUUID
+#include <uuid/uuid.h>
+#endif
#include "defines.h"
#include "struct.h"
@@ -165,3 +168,87 @@ int u_basic_count_char(const char *strin
return count;
}
+
+/*! \brief Populate a hash table with a string of name=value pairs.
+ * \param [inout] tab The hash table to receive the name=value pairs.
+ * \param [in] s The string to break up into name=value pairs.
+ * \param [in] comma The character separating name=value pairs.
+ * \param [in] equals The character separating name from value in pairs.
+ */
+void u_basic_populate_hash(GHashTable *tab, char *s, char comma, char equals)
+{
+ char *first_comma, *pair;
+
+ if (s == NULL) {
+ return;
+ }
+
+ for (pair = s; pair && pair[0]; pair = first_comma) {
+ char *first_equals;
+
+ /* Break out one name=value pair. */
+ first_comma = strchr(pair, comma);
+ if (first_comma) {
+ *first_comma = 0;
+ }
+
+ first_equals = strchr(pair, equals);
+ if (first_equals) {
+ /* Break the pair into name and value, then add to the hash table. */
+ *first_equals = 0;
+
+ g_hash_table_replace(tab,
+ g_strdup(pair),
+ g_strdup(first_equals + 1));
+
+ *first_equals = equals;
+ } else {
+ /* Just add a name=1 pair to the hash table. */
+ g_hash_table_replace(tab, g_strdup(pair), g_strdup("1"));
+ }
+
+ /* Reset the string and advance to the next pair. */
+ if (first_comma) {
+ *first_comma = comma;
+ first_comma++;
+ }
+ }
+}
+
+/*! \brief Return a universally unique identifier.
+ * \par Some objects need to be uniquely and persistently identifiable.
+ * Inside a running program, pointers meet this responsibility, but a saved
+ * file needs these "cookies".
+ * \return A dynamically allocated universally unique identifier
+ */
+char *u_basic_make_uuid(void)
+{
+ char *s = NULL;
+
+#ifdef HAVE_LIBUUID
+ {
+ uuid_t u;
+
+ /* XXX Ick, but <uuid/uuid.h> doesn't seem to have anything better. */
+ s = g_malloc(36 + 1);
+
+ uuid_generate(u);
+ uuid_unparse(u, s);
+ }
+#else /* HAVE_LIBUUID */
+ /* FIXME: Do just a *little* bit better - at least try to read from
+ * /proc/sys/kernel/random/uuid.
+ */
+ {
+ static unsigned long uuid_diversifier;
+
+ s = g_malloc(sizeof("XXXX-XXXXXXXX"));
+
+ sprintf(s, "%04x-%08x",
+ ((unsigned int) getpid()) & 0xffff,
+ uuid_diversifier++ & 0xffffffffUL);
+ }
+#endif /* !HAVE_LIBUUID */
+
+ return s;
+}
Index: gaf.git/libgeda/tests/Makefile.am
diff -u -p -- gaf.git/libgeda/tests/Makefile.am.borig gaf.git/libgeda/tests/Makefile.am
--- gaf.git/libgeda/tests/Makefile.am
+++ gaf.git/libgeda/tests/Makefile.am 2007-07-24 01:19:33.000000000 +0200
@@ -0,0 +1,16 @@
+AM_CFLAGS = -I$(top_srcdir)/include @LIBGEDA_CFLAGS@
+AM_LDFLAGS = @LIBGEDA_LDFLAGS@
+
+check_PROGRAMS = \
+ hashpop \
+ uuidgen
+
+TESTS = \
+ hashpop.sh \
+ uuidgen.sh
+
+hashpop_SOURCES = globals.c hashpop.c
+hashpop_LDADD = $(top_srcdir)/src/libgeda.la
+
+uuidgen_SOURCES = globals.c uuidgen.c
+uuidgen_LDADD = $(top_srcdir)/src/libgeda.la
Index: gaf.git/libgeda/tests/hashpop.c
diff -u -p -- gaf.git/libgeda/tests/hashpop.c.borig gaf.git/libgeda/tests/hashpop.c
--- gaf.git/libgeda/tests/hashpop.c
+++ gaf.git/libgeda/tests/hashpop.c 2007-07-24 01:12:32.000000000 +0200
@@ -0,0 +1,34 @@
+#include "config.h"
+
+#include <glib.h>
+#include <libguile.h>
+#include <stdio.h>
+#include "defines.h"
+#include "struct.h"
+#include "prototype.h"
+
+void hashprinter(gpointer key, gpointer value, gpointer user_data)
+{
+ printf("key=%s, value=%s\n", (char *) key, (char *) value);
+}
+
+int main(int argc, char *argv[])
+{
+ char const *pairs = "foo=bar,test=hashpop,answer=42";
+ GHashTable *tab;
+
+ if (argc > 1) {
+ pairs = argv[1];
+ }
+
+ tab = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free);
+
+ pairs = g_strdup(pairs);
+
+ u_basic_populate_hash(tab, pairs, ',', '=');
+ g_hash_table_foreach(tab, &hashprinter, NULL);
+
+ g_free(pairs);
+
+ return 0;
+}
Index: gaf.git/libgeda/tests/hashpop.sh
diff -u -p -- gaf.git/libgeda/tests/hashpop.sh.borig gaf.git/libgeda/tests/hashpop.sh
--- gaf.git/libgeda/tests/hashpop.sh
+++ gaf.git/libgeda/tests/hashpop.sh 2007-07-24 01:15:34.000000000 +0200
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+if test "x$srcdir" = x; then
+ srcdir=.
+fi
+
+expected=`mktemp -t hpXXXXXX`
+cat >$expected <<EOF
+key=answer, value=42
+key=foo, value=bar
+key=test, value=hashpop
+EOF
+
+$srcdir/hashpop |sort |diff $expected -
+status=$?
+
+rm -f $expected
+
+exit $status
Index: gaf.git/libgeda/tests/globals.c
diff -u -p -- gaf.git/libgeda/tests/globals.c.borig gaf.git/libgeda/tests/globals.c
--- gaf.git/libgeda/tests/globals.c
+++ gaf.git/libgeda/tests/globals.c 2007-07-24 01:07:43.000000000 +0200
@@ -0,0 +1,24 @@
+#include "config.h"
+
+#include <glib.h>
+#include <libguile.h>
+#include <stdio.h>
+#include "defines.h"
+#include "struct.h"
+#include "prototype.h"
+
+int (*load_newer_backup_func)() = NULL;
+void (*arc_draw_func)() = NULL;
+void (*line_draw_func)() = NULL;
+void (*text_draw_func)() = NULL;
+void (*x_log_update_func)() = NULL;
+void (*net_draw_func)() = NULL;
+void (*select_func)() = NULL;
+void (*complex_draw_func)() = NULL;
+void (*circle_draw_func)() = NULL;
+void (*box_draw_func)() = NULL;
+int do_logging=TRUE;
+void (*bus_draw_func)() = NULL;
+void (*pin_draw_func)() = NULL;
+void (*picture_draw_func)() = NULL;
+void (*variable_set_func)() = NULL;
Index: gaf.git/libgeda/tests/uuidgen.c
diff -u -p -- gaf.git/libgeda/tests/uuidgen.c.borig gaf.git/libgeda/tests/uuidgen.c
--- gaf.git/libgeda/tests/uuidgen.c
+++ gaf.git/libgeda/tests/uuidgen.c 2007-07-24 01:10:18.000000000 +0200
@@ -0,0 +1,24 @@
+#include "config.h"
+
+#include <glib.h>
+#include <libguile.h>
+#include <stdio.h>
+#include "defines.h"
+#include "struct.h"
+#include "prototype.h"
+
+int main()
+{
+ char *uuid;
+
+ uuid = u_basic_make_uuid();
+ if (uuid == NULL) {
+ return 1;
+ }
+
+ printf("%s\n", uuid);
+
+ g_free(uuid);
+
+ return 0;
+}
Index: gaf.git/libgeda/tests/uuidgen.sh
diff -u -p -- gaf.git/libgeda/tests/uuidgen.sh.borig gaf.git/libgeda/tests/uuidgen.sh
--- gaf.git/libgeda/tests/uuidgen.sh
+++ gaf.git/libgeda/tests/uuidgen.sh 2007-07-24 01:21:26.000000000 +0200
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if test "x$srcdir" = x; then
+ srcdir=.
+fi
+
+uuids=`mktemp -t ugXXXXXX`
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ $srcdir/uuidgen >>$uuids
+done
+
+lines=`sort -u $uuids |wc -l`
+test $lines = 10
+status=$?
+
+rm -f uuids
+
+exit $status
Index: gaf.git/libgeda/configure.ac
diff -u -p -- gaf.git/libgeda/configure.ac.borig gaf.git/libgeda/configure.ac
--- gaf.git/libgeda/configure.ac
+++ gaf.git/libgeda/configure.ac 2007-07-24 00:36:09.000000000 +0200
@@ -102,10 +109,18 @@ fi
# Checking for rint in math library
AC_CHECK_LIB(m, rint, AC_DEFINE(HAS_RINT, 1, [If your math library has rint in it, define this]), no_RINT="yes")
+# An implementation of libuuid lives in e2fsprogs, of all places!
+# FIXME: There are several hostilely incompatible uuid libraries. Rather just
+# use libaprutil to hide the porting complexity.
+AC_CHECK_LIB(uuid, uuid_generate,
+ UUID_LDFLAGS="-luuid"
+ AC_DEFINE(HAVE_LIBUUID, 1, [Define to 1 if you have libuuid]),
+ UUID_LDFLAGS="")
+
# Checking for dynamic lib
AC_CHECK_LIB(dl, dlopen, DL_LIB="-ldl", DL_LIB="")
#
-# Check for mics things start
+# Check for mics things end
############################################################################
############################################################################
@@ -467,7 +478,7 @@ AC_DEFINE_UNQUOTED(VERSION, "$VERSION",
# Finally create the final CFLAGS and LDFLAGS for use in the makefiles
LIBGEDA_CFLAGS="$MINGW_CFLAGS $GUILE_CFLAGS $GD_CFLAGS $GTK_CFLAGS $X_CFLAGS $GDK_PIXBUF_CFLAGS $GDK_CFLAGS"
-LIBGEDA_LDFLAGS="$GUILE_LDFLAGS $GD_LIBS $GLIB_LIBS $MINGW_LIBS $DMALLOC_LIBS $GDK_PIXBUF_LIBS $GDK_LIBS"
+LIBGEDA_LDFLAGS="$GUILE_LDFLAGS $GD_LIBS $GLIB_LIBS $MINGW_LIBS $DMALLOC_LIBS $GDK_PIXBUF_LIBS $GDK_LIBS $UUID_LDFLAGS"
LIBTOOL_FLAGS="-version-info $SHARED_LIBRARY_VERSION"
# Makefile.in variable substitution
@@ -492,7 +506,8 @@ AC_CONFIG_FILES([Makefile
libgeda.pc
share/Makefile
lib/Makefile
- scheme/Makefile ])
+ scheme/Makefile
+ tests/Makefile])
AC_OUTPUT
Index: gaf.git/libgeda/Makefile.am
diff -u -p -- gaf.git/libgeda/Makefile.am.borig gaf.git/libgeda/Makefile.am
--- gaf.git/libgeda/Makefile.am
+++ gaf.git/libgeda/Makefile.am 2007-07-24 00:21:06.000000000 +0200
@@ -1,5 +1,5 @@
-SUBDIRS = src include scripts docs share lib scheme
+SUBDIRS = src include scripts docs share lib scheme tests
EXTRA_DIST = HACKING BUGS autogen.sh
More information about the geda-dev
mailing list