Still merging 1.4.3 code back
[gnupg.git] / jnlib / stringhelp.c
index f3dbedb..e999170 100644 (file)
@@ -1,5 +1,6 @@
 /* stringhelp.c -  standard string helper functions
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ *               2004, 2005  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #include <ctype.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#endif
 
 #include "libjnlib-config.h"
+#include "utf8conv.h"
 #include "stringhelp.h"
 
 
-/****************
- * look for the substring SUB in buffer and return a pointer to that
- * substring in BUF or NULL if not found.
+/*
+ * Look for the substring SUB in buffer and return a pointer to that
+ * 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;
-
-    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 ;
+  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 ( ; 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 void *buffer, size_t buflen, const char *sub )
+{
+  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 ( ; 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;
 }
 
-/****************
- * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein
- * '\0' angehängt. Ist n = 0, so geschieht nichts, ist Destination
- * gleich NULL, so wird via jnlib_xmalloc Speicher besorgt, ist dann nicht
- * genügend Speicher vorhanden, so bricht die funktion ab.
+/* This function is similar to strncpy().  However it won't copy more
+   than N - 1 characters and makes sure that a '\0' is appended. With
+   N given as 0, nothing will happen.  With DEST given as NULL, memory
+   will be allocated using jnlib_xmalloc (i.e. if it runs out of core
+   the function terminates).  Returns DES or a pointer to the
+   allocated memory.
  */
 char *
 mem2str( char *dest , const void *src , size_t n )
@@ -126,7 +164,6 @@ trim_trailing_spaces( char *string )
 }
 
 
-
 unsigned
 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
 {
@@ -158,7 +195,429 @@ trim_trailing_ws( byte *line, unsigned len )
     return trim_trailing_chars( line, len, " \t\r\n" );
 }
 
+size_t
+length_sans_trailing_chars (const unsigned char *line, size_t len,
+                            const char *trimchars )
+{
+  const unsigned char *p, *mark;
+  size_t n;
+  
+  for( mark=NULL, p=line, n=0; n < len; n++, p++ )
+    {
+      if (strchr (trimchars, *p ))
+        {
+          if( !mark )
+            mark = p;
+        }
+      else
+        mark = NULL;
+    }
+  
+  if (mark) 
+    return mark - line;
+  return len;
+}
 
+/****************
+ * remove trailing white spaces and return the length of the buffer
+ */
+size_t
+length_sans_trailing_ws (const unsigned char *line, size_t len)
+{
+  return length_sans_trailing_chars (line, len, " \t\r\n");
+}
+
+
+
+/***************
+ * Extract from a given path the filename component.
+ *
+ */
+char *
+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
+       if ( !(p=strrchr(filepath, '\\')) )
+           if ( !(p=strrchr(filepath, ':')) )
+#endif
+             {
+               return jnlib_xstrdup(filepath);
+             }
+
+    return jnlib_xstrdup(p+1);
+}
+
+
+
+/***************
+ * Extract from a given filename the path prepended to it.
+ * If their isn't a path prepended to the filename, a dot
+ * is returned ('.').
+ *
+ */
+char *
+make_dirname(const char *filepath)
+{
+    char *dirname;
+    int  dirname_length;
+    char *p;
+
+    if ( !(p=strrchr(filepath, '/')) )
+      #ifdef HAVE_DRIVE_LETTERS
+       if ( !(p=strrchr(filepath, '\\')) )
+           if ( !(p=strrchr(filepath, ':')) )
+      #endif
+             {
+               return jnlib_xstrdup(".");
+             }
+
+    dirname_length = p-filepath;
+    dirname = jnlib_xmalloc(dirname_length+1);
+    strncpy(dirname, filepath, dirname_length);
+    dirname[dirname_length] = 0;
+
+    return dirname;
+}
+
+
+
+/****************
+ * Construct a filename from the NULL terminated list of parts.
+ * Tilde expansion is done here.
+ */
+char *
+make_filename( const char *first_part, ... )
+{
+    va_list arg_ptr ;
+    size_t n;
+    const char *s;
+    char *name, *home, *p;
+
+    va_start( arg_ptr, first_part ) ;
+    n = strlen(first_part)+1;
+    while( (s=va_arg(arg_ptr, const char *)) )
+       n += strlen(s) + 1;
+    va_end(arg_ptr);
+
+    home = NULL;
+    if( *first_part == '~' && first_part[1] == '/'
+                          && (home = getenv("HOME")) && *home )
+       n += strlen(home);
+
+    name = jnlib_xmalloc(n);
+    p = home ? stpcpy(stpcpy(name,home), first_part+1)
+            : stpcpy(name, first_part);
+    va_start( arg_ptr, first_part ) ;
+    while( (s=va_arg(arg_ptr, const char *)) )
+       p = stpcpy(stpcpy(p,"/"), s);
+    va_end(arg_ptr);
+
+    return name;
+}
+
+
+int
+compare_filenames( const char *a, const char *b )
+{
+    /* ? check whether this is an absolute filename and
+     * resolve symlinks?
+     */
+#ifdef HAVE_DRIVE_LETTERS
+    return stricmp(a,b);
+#else
+    return strcmp(a,b);
+#endif
+}
+
+/* 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. */
+size_t 
+print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
+                        int delim)
+{
+  const unsigned char *p = buffer;
+  size_t count = 0;
+
+  for (; length; length--, p++, count++)
+    {
+      if (*p < 0x20 || *p == 0x7f || *p == delim)
+        {
+          putc ('\\', fp);
+          count++;
+          if (*p == '\n')
+            putc ('n', fp);
+          else if (*p == '\r')
+            putc ('r', fp);
+          else if (*p == '\f')
+            putc ('f', fp);
+          else if (*p == '\v')
+            putc ('v', fp);
+          else if (*p == '\b')
+            putc ('b', fp);
+          else if (!*p)
+            putc('0', fp);
+          else
+            {
+              fprintf (fp, "x%02x", *p);
+              count += 2;
+            }
+       }
+      else
+        putc (*p, fp);
+    }
+
+  return count;
+}
+
+size_t 
+print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
+                             size_t length, int delim)
+{
+  const char *p = buffer;
+  size_t i;
+
+  /* We can handle plain ascii simpler, so check for it first. */
+  for (i=0; i < length; i++ ) 
+    {
+      if ( (p[i] & 0x80) )
+        break;
+    }
+  if (i < length)
+    {
+       char *buf = utf8_to_native (p, length, delim);
+       /*(utf8 conversion already does the control character quoting)*/
+        i = strlen (buf);
+       fputs (buf, fp);
+       jnlib_free (buf);
+        return i;
+    }
+  else
+    return print_sanitized_buffer (fp, p, length, delim);
+}
+
+
+size_t 
+print_sanitized_string (FILE *fp, const char *string, int delim)
+{
+  return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
+}
+
+size_t 
+print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
+{
+  return string? print_sanitized_utf8_buffer (fp,
+                                              string, strlen (string),
+                                              delim) : 0;
+}
+
+/* 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 void *p_arg, size_t n, int delim)
+{
+  const unsigned char *p = p_arg;
+  size_t save_n, buflen;
+  const unsigned char *save_p;
+  char *buffer, *d;
+
+  /* first count length */
+  for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
+    {
+      if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
+        {
+          if ( *p=='\n' || *p=='\r' || *p=='\f'
+               || *p=='\v' || *p=='\b' || !*p )
+            buflen += 2;
+          else
+            buflen += 4;
+       }
+      else
+        buflen++;
+    }
+  p = save_p;
+  n = save_n;
+  /* and now make the string */
+  d = buffer = jnlib_xmalloc( buflen );
+  for ( ; n; n--, p++ )
+    {
+      if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
+        *d++ = '\\';
+        if( *p == '\n' )
+          *d++ = 'n';
+        else if( *p == '\r' )
+          *d++ = 'r';
+        else if( *p == '\f' )
+          *d++ = 'f';
+        else if( *p == '\v' )
+          *d++ = 'v';
+        else if( *p == '\b' )
+          *d++ = 'b';
+        else if( !*p )
+          *d++ = '0';
+        else {
+          sprintf(d, "x%02x", *p );
+          d += 2;
+        }
+      }
+      else
+        *d++ = *p;
+    }
+  *d = 0;
+  return buffer;
+}
+
+
+/****************************************************
+ **********  W32 specific functions  ****************
+ ****************************************************/
+
+#ifdef HAVE_W32_SYSTEM
+const char *
+w32_strerror (int ec)
+{
+  static char strerr[256];
+  
+  if (ec == -1)
+    ec = (int)GetLastError ();
+  FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
+                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                 strerr, DIM (strerr)-1, NULL);
+  return strerr;    
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/****************************************************
+ ******** Locale insensitive ctype functions ********
+ ****************************************************/
+/* FIXME: replace them by a table lookup and macros */
+int
+ascii_isupper (int c)
+{
+    return c >= 'A' && c <= 'Z';
+}
+
+int
+ascii_islower (int c)
+{
+    return c >= 'a' && c <= 'z';
+}
+
+int 
+ascii_toupper (int c)
+{
+    if (c >= 'a' && c <= 'z')
+        c &= ~0x20;
+    return c;
+}
+
+int 
+ascii_tolower (int c)
+{
+    if (c >= 'A' && c <= 'Z')
+        c |= 0x20;
+    return c;
+}
+
+
+int
+ascii_strcasecmp( const char *a, const char *b )
+{
+    if (a == b)
+        return 0;
+
+    for (; *a && *b; a++, b++) {
+       if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
+           break;
+    }
+    return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+}
+
+int 
+ascii_strncasecmp (const char *a, const char *b, size_t n)
+{
+  const unsigned char *p1 = (const unsigned char *)a;
+  const unsigned char *p2 = (const unsigned char *)b;
+  unsigned char c1, c2;
+
+  if (p1 == p2 || !n )
+    return 0;
+
+  do
+    {
+      c1 = ascii_tolower (*p1);
+      c2 = ascii_tolower (*p2);
+
+      if ( !--n || c1 == '\0')
+       break;
+
+      ++p1;
+      ++p2;
+    }
+  while (c1 == c2);
+  
+  return c1 - c2;
+}
+
+
+int
+ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
+{
+  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
+ascii_strcmp( const char *a, const char *b )
+{
+    if (a == b)
+        return 0;
+
+    for (; *a && *b; a++, b++) {
+       if (*a != *b )
+           break;
+    }
+    return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
+}
+
+
+void *
+ascii_memcasemem (const void *haystack, size_t nhaystack,
+                  const void *needle, size_t nneedle)
+{
+
+  if (!nneedle)
+    return (void*)haystack; /* finding an empty needle is really easy */
+  if (nneedle <= nhaystack)
+    {
+      const char *a = haystack;
+      const char *b = a + nhaystack - nneedle;
+      
+      for (; a <= b; a++)
+        {
+          if ( !ascii_memcasecmp (a, needle, nneedle) )
+            return (void *)a;
+        }
+    }
+  return NULL;
+}
 
 /*********************************************
  ********** missing string functions *********
@@ -216,4 +675,3 @@ memicmp( const char *a, const char *b, size_t n )
 #endif
 
 
-