Re: Glib proposal: add strlcpy and strlcat to glib




Okay, here's my cut at porting strlcpy/strlcat to glib.

In glib they'll be called g_strlcpy/g_strlcat, for glib naming consistency.
If strlcpy/strlcat already exists on your machine in <string.h>
(true for Sun Solaris, as well as for several BSDs such as OpenBSD),
then they're called. Otherwise, an implementation is compiled
into the glib library and called when requested.

This patch modifies:
* gstrfuncs.c (with the implementation),
* glib.h (with the prototypes),
* testglib.c (adding torture tests for them),
* ChangeLog (describing the change),
* configure.in and acconfig.h (for detecting if strlcpy/strlcat exist).

It _seems_ to work for me, but I'm only human.  Comments welcome!
If there are no complaints, I'll throw it into the "incoming"
area (or tell me if you'd prefer me do something different).



--- glib.orig/gstrfuncs.c	Wed Mar  1 04:44:09 2000
+++ glib/gstrfuncs.c	Fri May  5 00:54:24 2000
@@ -1323,6 +1323,115 @@
   return string;
 }
 
+/*
+ * Functions g_strlcpy and g_strlcat were originally developed by 
+ * Todd C. Miller <Todd.Miller@courtesan.com>.
+ * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
+ * for more information.
+ */
+
+/* Use the native ones, if available; they might be implemented in assembly */
+
+#ifdef HAVE_STRLCPY
+
+size_t
+g_strlcpy(char *dst, const char *src, size_t siz)
+{
+  return strlcpy(dst, src, siz);
+}
+
+size_t
+g_strlcat(char *dst, const char *src, size_t siz)
+{
+  return strlcat(dst, src, siz);
+}
+
+#else /* ! HAVE_STRLCPY */
+
+/*
+ * g_strlcpy
+ *
+ * Copy string src to buffer dst (of buffer size siz).  At most siz-1
+ * characters will be copied.  Always NUL terminates (unless siz == 0).
+ * This function does NOT allocate memory.
+ * Unlike strncpy, this function doesn't pad dst (so it's often faster).
+ * Returns size of attempted result, strlen(src),
+ * so if retval >= siz, truncation occurred.
+ */
+
+size_t
+g_strlcpy(char *dst, const char *src, size_t siz)
+{
+  register char *d = dst;
+  register const char *s = src;
+  register size_t n = siz;
+
+  /* Copy as many bytes as will fit */
+  if (n != 0 && --n != 0) {
+    do {
+      if ((*d++ = *s++) == '\0')
+        break;
+    } while (--n != 0);
+  }
+
+  /* Not enough room in dst, add NUL and traverse rest of src */
+  if (n == 0) {
+    if (siz != 0)
+      *d = '\0';    /* NUL-terminate dst */
+    while (*s++)
+      ;
+  }
+
+  return(s - src - 1);  /* count does not include NUL */
+}
+
+
+/*
+ * g_strlcat
+ *
+ * Appends string src to buffer dst (of buffer size siz).
+ * At most siz-1 characters will be copied.
+ * Unlike strncat, siz is the full size of dst, not the space left over.
+ * This function does NOT allocate memory.
+ * This always NUL terminates (unless siz == 0 or
+ * there were no NUL characters in the siz characters of dst to start with).
+ * Returns size of attempted result, which is
+ * MIN(siz,strlen(original dst)) + strlen(src), 
+ * so if retval >= siz, truncation occurred.
+ */
+
+size_t
+g_strlcat(char *dst, const char *src, size_t siz)
+{
+  register char *d = dst;
+  register const char *s = src;
+  register size_t n = siz;
+  size_t dlen;
+
+  /* Find the end of dst and adjust bytes left but don't go past end */
+  while (*d != '\0' && n-- != 0)
+    d++;
+  dlen = d - dst;
+  n = siz - dlen;
+
+  if (n == 0)
+    return(dlen + strlen(s));
+  while (*s != '\0') {
+    if (n != 1) {
+      *d++ = *s;
+      n--;
+    }
+    s++;
+  }
+  *d = '\0';
+
+  return(dlen + (s - src));  /* count does not include NUL */
+}
+
+#endif /* HAVE_STRLCPY */
+
+
+
 gchar**
 g_strsplit (const gchar *string,
 	    const gchar *delimiter,
--- glib.orig/glib.h	Fri Apr 28 08:24:52 2000
+++ glib/glib.h	Tue May  2 00:03:44 2000
@@ -78,6 +78,9 @@
  */
 #include <stdarg.h>
 
+/* include stddef for the definition of size_t */
+#include <stddef.h>
+
 /* optionally feature DMALLOC memory allocation debugger
  */
 #ifdef USE_DMALLOC
@@ -1585,6 +1588,10 @@
 gchar*  g_strchomp              (gchar        *string);
 /* removes leading & trailing spaces */
 #define g_strstrip( string )	g_strchomp (g_strchug (string))
+
+size_t	 g_strlcpy		(char *dst, const char *src, size_t size);
+size_t	 g_strlcat		(char *dst, const char *src, size_t size);
+
 
 /* String utility functions that return a newly allocated string which
  * ought to be freed with g_free from the caller at some point.
--- glib.orig/testglib.c	Wed Mar  1 04:44:09 2000
+++ glib/testglib.c	Thu May  4 22:14:15 2000
@@ -18,7 +18,7 @@
  */
 
 /*
- * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GLib Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
@@ -852,6 +852,63 @@
   g_free(string);
   
   g_print ("ok\n");
+
+  g_print("checking g_strlcpy/g_strlcat...");
+  /* The following is a torture test for strlcpy/strlcat, with lots of
+   * checking; normal users wouldn't use them this way! */
+  string = g_malloc(6);
+  *(string + 5) = 'Z'; /* guard value, shouldn't change during test */
+  *string = 'q';
+  g_assert (g_strlcpy(string, "" , 5) == 0);
+  g_assert ( *string == '\0' );
+  *string = 'q';
+  g_assert (g_strlcpy(string, "abc" , 5) == 3);
+  g_assert ( *(string + 3) == '\0' );
+  g_assert (g_str_equal(string, "abc"));
+  g_assert (g_strlcpy(string, "abcd" , 5) == 4);
+  g_assert ( *(string + 4) == '\0' );
+  g_assert ( *(string + 5) == 'Z' );
+  g_assert (g_str_equal(string, "abcd"));
+  g_assert (g_strlcpy(string, "abcde" , 5) == 5);
+  g_assert ( *(string + 4) == '\0' );
+  g_assert ( *(string + 5) == 'Z' );
+  g_assert (g_str_equal(string, "abcd"));
+  g_assert (g_strlcpy(string, "abcdef" , 5) == 6);
+  g_assert ( *(string + 4) == '\0' );
+  g_assert ( *(string + 5) == 'Z' );
+  g_assert (g_str_equal(string, "abcd"));
+  *string = 'Y';
+  *(string + 1)= '\0';
+  g_assert (g_strlcpy(string, "Hello" , 0) == 5);
+  g_assert (*string == 'Y');
+
+  *string = '\0';
+  g_assert (g_strlcat(string, "123" , 5) == 3);
+  g_assert ( *(string + 3) == '\0' );
+  g_assert (g_str_equal(string, "123"));
+  g_assert (g_strlcat(string, "" , 5) == 3);
+  g_assert ( *(string + 3) == '\0' );
+  g_assert (g_str_equal(string, "123"));
+  g_assert (g_strlcat(string, "4", 5) == 4);
+  g_assert (g_str_equal(string, "1234"));
+  g_assert (g_strlcat(string, "5", 5) == 5);
+  g_assert ( *(string + 4) == '\0' );
+  g_assert (g_str_equal(string, "1234"));
+  g_assert ( *(string + 5) == 'Z' );
+  *string = 'Y';
+  *(string + 1)= '\0';
+  g_assert (g_strlcat(string, "123" , 0) == 3);
+  g_assert (*string == 'Y');
+  
+  /* A few more tests, demonstrating more "normal" use  */
+  g_assert (g_strlcpy(string, "hi", 5) == 2);
+  g_assert (g_str_equal(string, "hi"));
+  g_assert (g_strlcat(string, "t", 5) == 3);
+  g_assert (g_str_equal(string, "hit"));
+  g_free(string);
+
+  g_print ("ok\n");
+
 
   g_print ("checking g_strdup_printf...");
   string = g_strdup_printf ("%05d %-5s", 21, "test");
--- glib.orig/ChangeLog	Mon May  1 17:13:01 2000
+++ glib/ChangeLog	Wed May  3 00:21:28 2000
@@ -1,3 +1,13 @@
+2000-05-02  David A. Wheeler <dwheeler@dwheeler.com>
+
+	* glib.h, gstrfuncs.c: added g_strlcpy and g_strlcat to support
+	  safe manipulation of fixed-length string buffers.
+	  These functions were originally developed by Todd Miller, and
+	  are available on many (but not all) Unix-like systems; see
+	  ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3.
+
+	* testglib.c: Added tests for g_strlcpy, g_strlcat.
+
 2000-05-02  Tor Lillqvist  <tml@iki.fi>
 
 	* glib.def: Add new functions.
--- glib.orig/configure.in	Wed Apr 26 09:03:49 2000
+++ glib/configure.in	Thu May  4 22:53:23 2000
@@ -1053,6 +1053,22 @@
 	glibconfig-sysdefs.h,
 	=)
 
+dnl ****************************************
+dnl *** strlcpy/strlcat                  ***
+dnl ****************************************
+# Check for sys_siglist
+AC_MSG_CHECKING(for strlcpy/strlcat)
+AC_TRY_LINK([#include <stdlib.h>
+#include <string.h>], [
+char *p = malloc(10);
+(void) strlcpy(p, "hi", 10);
+(void) strlcat(p, "bye", 10);
+], glib_ok=yes, glib_ok=no)
+AC_MSG_RESULT($glib_ok)
+if test $glib_ok = yes; then
+    AC_DEFINE(HAVE_STRLCPY)
+fi
+
 
 dnl ******************************
 dnl *** output the whole stuff ***
--- glib.orig/acconfig.h	Mon Apr 17 09:23:27 2000
+++ glib/acconfig.h	Thu May  4 22:48:52 2000
@@ -64,6 +64,7 @@
 #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
 #undef HAVE_PWD_H
 #undef HAVE_PW_GECOS
+#undef HAVE_STRLCPY
 #undef HAVE_SYS_PARAM_H
 #undef HAVE_SYS_POLL_H
 #undef HAVE_SYS_SELECT_H





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]