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