Fix for bug 537
[gnupg.git] / jnlib / stringhelp.c
index 5a3b415..4e27682 100644 (file)
@@ -1,22 +1,23 @@
 /* stringhelp.c -  standard string helper functions
- * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- *               2004  Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+ *               2006  Free Software Foundation, Inc.
  *
- * This file is part of GnuPG.
+ * This file is part of JNLIB.
  *
- * GnuPG 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.
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
- * GnuPG 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.
+ * JNLIB 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
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <config.h>
 
 /*
  * Look for the substring SUB in buffer and return a pointer to that
- * substring in BUF or NULL if not found.
+ * substring in BUFFER or NULL if not found.
  * Comparison is case-insensitive.
  */
 const char *
-memistr( const char *buf, size_t buflen, const char *sub )
+memistr (const void *buffer, size_t buflen, const char *sub)
 {
-    const byte *t, *s ;
-    size_t n;
+  const unsigned char *buf = buffer;
+  const unsigned char *t = (const unsigned char *)buffer;
+  const unsigned char *s = (const unsigned char *)sub;
+  size_t n = buflen;
 
-    for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
-       if( toupper(*t) == toupper(*s) ) {
-           for( buf=t++, buflen = n--, s++;
-                n && toupper(*t) == toupper(*s); t++, s++, n-- )
-               ;
-           if( !*s )
-               return buf;
-           t = buf; n = buflen; s = sub ;
+  for ( ; n ; t++, n-- )
+    {
+      if ( toupper (*t) == toupper (*s) )
+        {
+          for ( buf=t++, buflen = n--, s++;
+                n && toupper (*t) == toupper (*s); t++, s++, n-- )
+            ;
+          if (!*s)
+            return (const char*)buf;
+          t = buf;
+          s = (const unsigned char *)sub ;
+          n = buflen;
        }
-
-    return NULL ;
+    }
+  return NULL;
 }
 
 const char *
-ascii_memistr( const char *buf, size_t buflen, const char *sub )
+ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
 {
-    const byte *t, *s ;
-    size_t n;
+  const unsigned char *buf = buffer;
+  const unsigned char *t = (const unsigned char *)buf;
+  const unsigned char *s = (const unsigned char *)sub;
+  size_t n = buflen;
 
-    for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
-       if( ascii_toupper(*t) == ascii_toupper(*s) ) {
-           for( buf=t++, buflen = n--, s++;
-                n && ascii_toupper(*t) == ascii_toupper(*s); t++, s++, n-- )
-               ;
-           if( !*s )
-               return buf;
-           t = buf; n = buflen; s = sub ;
+  for ( ; n ; t++, n-- )
+    {
+      if (ascii_toupper (*t) == ascii_toupper (*s) )
+        {
+          for ( buf=t++, buflen = n--, s++;
+                n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
+            ;
+          if (!*s)
+            return (const char*)buf;
+          t = (const unsigned char *)buf;
+          s = (const unsigned char *)sub ;
+          n = buflen;
        }
-
-    return NULL ;
+    }
+  return NULL;
 }
 
 /* This function is similar to strncpy().  However it won't copy more
@@ -206,8 +219,8 @@ length_sans_trailing_chars (const unsigned char *line, size_t len,
   return len;
 }
 
-/****************
- * remove trailing white spaces and return the length of the buffer
+/*
+ *  Return the length of line ignoring trailing white-space.
  */
 size_t
 length_sans_trailing_ws (const unsigned char *line, size_t len)
@@ -222,15 +235,19 @@ length_sans_trailing_ws (const unsigned char *line, size_t len)
  *
  */
 char *
-make_basename(const char *filepath)
+make_basename(const char *filepath, const char *inputpath)
 {
     char *p;
 
+#ifdef __riscos__
+    return riscos_make_basename(filepath, inputpath);
+#endif
+
     if ( !(p=strrchr(filepath, '/')) )
-      #ifdef HAVE_DRIVE_LETTERS
+#ifdef HAVE_DRIVE_LETTERS
        if ( !(p=strrchr(filepath, '\\')) )
            if ( !(p=strrchr(filepath, ':')) )
-      #endif
+#endif
              {
                return jnlib_xstrdup(filepath);
              }
@@ -320,47 +337,111 @@ compare_filenames( const char *a, const char *b )
 #endif
 }
 
+
+/* Convert 2 hex characters at S to a byte value.  Return this value
+   or -1 if there is an error. */
+int
+hextobyte (const char *s)
+{
+  int c;
+
+  if ( *s >= '0' && *s <= '9' )
+    c = 16 * (*s - '0');
+  else if ( *s >= 'A' && *s <= 'F' )
+    c = 16 * (10 + *s - 'A');
+  else if ( *s >= 'a' && *s <= 'f' )
+    c = 16 * (10 + *s - 'a');
+  else
+    return -1;
+  s++;
+  if ( *s >= '0' && *s <= '9' )
+    c += *s - '0';
+  else if ( *s >= 'A' && *s <= 'F' )
+    c += 10 + *s - 'A';
+  else if ( *s >= 'a' && *s <= 'f' )
+    c += 10 + *s - 'a';
+  else
+    return -1;
+  return c;
+}
+
+
 /* Print a BUFFER to stream FP while replacing all control characters
-   and the character DELIM with standard C escape sequences.  Returns
-   the number of characters printed. */
+   and the characters DELIM and DELIM2 with standard C escape
+   sequences.  Returns the number of characters printed. */
 size_t 
-print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
-                        int delim)
+print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
+                         int delim, int delim2)
 {
   const unsigned char *p = buffer;
   size_t count = 0;
 
   for (; length; length--, p++, count++)
     {
-      if (*p < 0x20 || *p == 0x7f || *p == delim)
+      /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
+      if (*p < 0x20 
+          || (*p >= 0x7f && *p < 0xa0)
+          || *p == delim 
+          || *p == delim2
+          || ((delim || delim2) && *p=='\\'))
         {
           putc ('\\', fp);
           count++;
           if (*p == '\n')
-            putc ('n', fp);
+            {
+              putc ('n', fp);
+              count++;
+            }
           else if (*p == '\r')
-            putc ('r', fp);
+            {
+              putc ('r', fp);
+              count++;
+            }
           else if (*p == '\f')
-            putc ('f', fp);
+            {
+              putc ('f', fp);
+              count++;
+            }
           else if (*p == '\v')
-            putc ('v', fp);
+            {
+              putc ('v', fp);
+              count++;
+            }
           else if (*p == '\b')
-            putc ('b', fp);
+            {
+              putc ('b', fp);
+              count++;
+            }
           else if (!*p)
-            putc('0', fp);
+            {
+              putc('0', fp);
+              count++;
+            }
           else
             {
               fprintf (fp, "x%02x", *p);
-              count += 2;
+              count += 3;
             }
        }
       else
-        putc (*p, fp);
+        {
+          putc (*p, fp);
+          count++;
+        }
     }
 
   return count;
 }
 
+/* Same as print_sanitized_buffer2 but with just one delimiter. */
+size_t 
+print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
+                        int delim)
+{
+  return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
+}
+
+
 size_t 
 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
                              size_t length, int delim)
@@ -389,6 +470,13 @@ print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
 
 
 size_t 
+print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
+{
+  return string? print_sanitized_buffer2 (fp, string, strlen (string),
+                                          delim, delim2):0;
+}
+
+size_t 
 print_sanitized_string (FILE *fp, const char *string, int delim)
 {
   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
@@ -402,16 +490,17 @@ print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
                                               delim) : 0;
 }
 
-/* Create a string from the buffer P of length N which is suitable for
+/* Create a string from the buffer P_ARG of length N which is suitable for
    printing.  Caller must release the created string using xfree. */
 char *
-sanitize_buffer (const unsigned char *p, size_t n, int delim)
+sanitize_buffer (const void *p_arg, size_t n, int delim)
 {
+  const unsigned char *p = p_arg;
   size_t save_n, buflen;
-  const byte *save_p;
+  const unsigned char *save_p;
   char *buffer, *d;
 
-  /* first count length */
+  /* First count length. */
   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
     {
       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
@@ -420,14 +509,14 @@ sanitize_buffer (const unsigned char *p, size_t n, int delim)
                || *p=='\v' || *p=='\b' || !*p )
             buflen += 2;
           else
-            buflen += 4;
+            buflen += 5;
        }
       else
         buflen++;
     }
   p = save_p;
   n = save_n;
-  /* and now make the string */
+  /* And now make the string */
   d = buffer = jnlib_xmalloc( buflen );
   for ( ; n; n--, p++ )
     {
@@ -447,7 +536,7 @@ sanitize_buffer (const unsigned char *p, size_t n, int delim)
           *d++ = '0';
         else {
           sprintf(d, "x%02x", *p );
-          d += 2;
+          d += 3;
         }
       }
       else
@@ -552,15 +641,19 @@ ascii_strncasecmp (const char *a, const char *b, size_t n)
 
 
 int
-ascii_memcasecmp( const char *a, const char *b, size_t n )
+ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
 {
-    if (a == b)
-        return 0;
-    for ( ; n; n--, a++, b++ ) {
-       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
-            return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
-    }
+  const char *a = a_arg;
+  const char *b = b_arg;
+
+  if (a == b)
     return 0;
+  for ( ; n; n--, a++, b++ )
+    {
+      if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
+        return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+    }
+  return 0;
 }
 
 int
@@ -586,8 +679,8 @@ ascii_memcasemem (const void *haystack, size_t nhaystack,
     return (void*)haystack; /* finding an empty needle is really easy */
   if (nneedle <= nhaystack)
     {
-      const unsigned char *a = haystack;
-      const unsigned char *b = a + nhaystack - nneedle;
+      const char *a = haystack;
+      const char *b = a + nhaystack - nneedle;
       
       for (; a <= b; a++)
         {
@@ -614,6 +707,55 @@ stpcpy(char *a,const char *b)
 }
 #endif
 
+#ifndef HAVE_STRSEP
+/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
+char *
+strsep (char **stringp, const char *delim)
+{
+  char *begin, *end;
+
+  begin = *stringp;
+  if (begin == NULL)
+    return NULL;
+
+  /* A frequent case is when the delimiter string contains only one
+     character.  Here we don't need to call the expensive `strpbrk'
+     function and instead work using `strchr'.  */
+  if (delim[0] == '\0' || delim[1] == '\0')
+    {
+      char ch = delim[0];
+
+      if (ch == '\0')
+        end = NULL;
+      else
+        {
+          if (*begin == ch)
+            end = begin;
+          else if (*begin == '\0')
+            end = NULL;
+          else
+            end = strchr (begin + 1, ch);
+        }
+    }
+  else
+    /* Find the end of the token.  */
+    end = strpbrk (begin, delim);
+
+  if (end)
+    {
+      /* Terminate the token and set *STRINGP past NUL character.  */
+      *end++ = '\0';
+      *stringp = end;
+    }
+  else
+    /* No more delimiters; this is the last token.  */
+    *stringp = NULL;
+
+  return begin;
+}
+#endif /*HAVE_STRSEP*/
+
+
 #ifndef HAVE_STRLWR
 char *
 strlwr(char *s)