Update assuan and jnlib to 20020424 from newpg.
authorMarcus Brinkmann <mb@g10code.com>
Wed, 24 Apr 2002 01:55:58 +0000 (01:55 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Wed, 24 Apr 2002 01:55:58 +0000 (01:55 +0000)
15 files changed:
assuan/ChangeLog
assuan/assuan-buffer.c
assuan/assuan-client.c
assuan/assuan-defs.h
assuan/assuan-handler.c
assuan/assuan-inquire.c
assuan/assuan-pipe-server.c
assuan/assuan-socket-server.c
assuan/assuan.h
jnlib/ChangeLog
jnlib/argparse.c
jnlib/logging.c
jnlib/logging.h
jnlib/stringhelp.c
jnlib/stringhelp.h

index 290fef5..2b95d56 100644 (file)
@@ -1,3 +1,39 @@
+2002-04-04  Werner Koch  <wk@gnupg.org>
+
+       * assuan-buffer.c (my_log_prefix): New.  Use it for all i/o debug
+       output.
+
+2002-03-06  Werner Koch  <wk@gnupg.org>
+
+       * assuan-client.c (_assuan_read_from_server): Detect END.
+       (assuan_transact): Pass it to the data callback.
+
+2002-02-27  Werner Koch  <wk@gnupg.org>
+
+       * assuan-client.c (assuan_transact): Add 2 more arguments to
+       support status lines. Passing NULL yields the old behaviour.
+
+       * assuan-handler.c (process_request): Flush data lines send
+       without using the data fp.
+
+2002-02-14  Werner Koch  <wk@gnupg.org>
+
+       * assuan-inquire.c (assuan_inquire): Check for a cancel command
+       and return ASSUAN_Canceled.  Allow for non-data inquiry.
+
+       * assuan.h: Add a few token specific error codes.
+
+2002-02-13  Werner Koch  <wk@gnupg.org>
+
+       * assuan-defs.h (assuan_context_s): New var CLIENT_PID.
+       * assuan-pipe-server.c (_assuan_new_context): set default value.
+       * assuan-socket-server.c (accept_connection): get the actual pid.
+
+2002-02-12  Werner Koch  <wk@gnupg.org>
+
+       * assuan-buffer.c (writen,readline) [USE_GNU_PT]: Use pth_read/write.
+       * assuan-socket-server.c (accept_connection) [USE_GNU_PTH]: Ditto.
+
 2002-02-01  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (MOSTLYCLEANFILES): New variable.
index bd08817..29f9479 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 #include <assert.h>
-
+#ifdef USE_GNU_PTH
+# include <pth.h>
+#endif
 #include "assuan-defs.h"
 
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#endif
+
+
+static const char *
+my_log_prefix (void)
+{
+#ifdef HAVE_JNLIB_LOGGING
+  return log_get_prefix (NULL);
+#else
+  return "";
+#endif
+}
+
 
 static int
 writen ( int fd, const char *buffer, size_t length )
 {
   while (length)
     {
+#ifdef USE_GNU_PTH
+      int nwritten = pth_write (fd, buffer, length);
+#else
       int nwritten = write (fd, buffer, length);
+#endif
       
       if (nwritten < 0)
         {
@@ -59,7 +80,11 @@ readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
   *r_nread = 0;
   while (nleft > 0)
     {
+#ifdef USE_GNU_PTH
+      int n = pth_read (fd, buf, nleft);
+#else
       int n = read (fd, buf, nleft);
+#endif
       if (n < 0)
         {
           if (errno == EINTR)
@@ -122,15 +147,15 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
   if (rc)
     {
       if (ctx->log_fp)
-        fprintf (ctx->log_fp, "%p <- [Error: %s]\n",
-                 ctx, strerror (errno)); 
+        fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
+                 my_log_prefix (), ctx, strerror (errno)); 
       return ASSUAN_Read_Error;
     }
   if (!nread)
     {
       assert (ctx->inbound.eof);
       if (ctx->log_fp)
-        fprintf (ctx->log_fp, "%p <- [EOF]\n", ctx); 
+        fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); 
       return -1; 
     }
 
@@ -163,7 +188,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
           ctx->inbound.linelen = n;
           if (ctx->log_fp)
             {
-              fprintf (ctx->log_fp, "%p <- ", ctx); 
+              fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); 
               if (ctx->confidential)
                 fputs ("[Confidential data not shown]", ctx->log_fp);
               else
@@ -177,7 +202,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
     }
 
   if (ctx->log_fp)
-    fprintf (ctx->log_fp, "%p <- [Invalid line]\n", ctx);
+    fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
   *line = 0;
   ctx->inbound.linelen = 0;
   return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
@@ -229,7 +254,7 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
   /* fixme: we should do some kind of line buffering */
   if (ctx->log_fp)
     {
-      fprintf (ctx->log_fp, "%p -> ", ctx); 
+      fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
       if (ctx->confidential)
         fputs ("[Confidential data not shown]", ctx->log_fp);
       else
@@ -300,7 +325,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
         {
           if (ctx->log_fp)
             {
-              fprintf (ctx->log_fp, "%p -> ", ctx); 
+              fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
               if (ctx->confidential)
                 fputs ("[Confidential data not shown]", ctx->log_fp);
               else 
@@ -345,7 +370,7 @@ _assuan_cookie_write_flush (void *cookie)
     {
       if (ctx->log_fp)
         {
-          fprintf (ctx->log_fp, "%p -> ", ctx); 
+          fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
           if (ctx->confidential)
             fputs ("[Confidential data not shown]", ctx->log_fp);
           else
index d56357d..6c7a6e3 100644 (file)
@@ -57,6 +57,15 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
       *okay = 2; /* data line */
       *off = 2;
     }
+  else if (linelen >= 1
+           && line[0] == 'S' 
+           && (line[1] == '\0' || line[1] == ' '))
+    {
+      *okay = 4;
+      *off = 1;
+      while (line[*off] == ' ')
+        ++*off;
+    }  
   else if (linelen >= 2
            && line[0] == 'O' && line[1] == 'K'
            && (line[2] == '\0' || line[2] == ' '))
@@ -86,6 +95,13 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
       while (line[*off] == ' ')
         ++*off;
     }
+  else if (linelen >= 3
+           && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+           && (line[3] == '\0' || line[3] == ' '))
+    {
+      *okay = 5; /* end line */
+      *off = 3;
+    }
   else
     rc = ASSUAN_Invalid_Response;
   return rc;
@@ -101,6 +117,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
  * @data_cb_arg: first argument passed to @data_cb
  * @inquire_cb: Callback function for a inquire response
  * @inquire_cb_arg: first argument passed to @inquire_cb
+ * @status_cb: Callback function for a status response
+ * @status_cb_arg: first argument passed to @status_cb
  * 
  * FIXME: Write documentation
  * 
@@ -114,7 +132,9 @@ assuan_transact (ASSUAN_CONTEXT ctx,
                  AssuanError (*data_cb)(void *, const void *, size_t),
                  void *data_cb_arg,
                  AssuanError (*inquire_cb)(void*, const char *),
-                 void *inquire_cb_arg)
+                 void *inquire_cb_arg,
+                 AssuanError (*status_cb)(void*, const char *),
+                 void *status_cb_arg)
 {
   int rc, okay, off;
   unsigned char *line;
@@ -181,6 +201,25 @@ assuan_transact (ASSUAN_CONTEXT ctx,
             goto again;
         }
     }
+  else if (okay == 4)
+    {
+      if (status_cb)
+        rc = status_cb (status_cb_arg, line);
+      if (!rc)
+        goto again;
+    }
+  else if (okay == 5)
+    {
+      if (!data_cb)
+        rc = ASSUAN_No_Data_Callback;
+      else 
+        {
+          rc = data_cb (data_cb_arg, NULL, 0);
+          if (!rc)
+            goto again;
+        }
+    }
 
   return rc;
 }
+
index 7d55aab..6c502bf 100644 (file)
@@ -77,6 +77,9 @@ struct assuan_context_s {
                      In socket mode, the pid of the server */
   int listen_fd;  /* The fd we are listening on (used by socket servers) */
 
+  pid_t client_pid; /* for a socket server the PID of the client or -1
+                       if not available */
+
   void (*deinit_handler)(ASSUAN_CONTEXT);  
   int (*accept_handler)(ASSUAN_CONTEXT);
   int (*finish_handler)(ASSUAN_CONTEXT);
@@ -92,7 +95,6 @@ struct assuan_context_s {
   void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
   void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
 
-
   int input_fd;   /* set by INPUT command */
   int output_fd;  /* set by OUTPUT command */
 
@@ -135,9 +137,3 @@ void _assuan_log_sanitized_string (const char *string);
 
 #endif /*ASSUAN_DEFS_H*/
 
-
-
-
-
-
-
index 1c8aded..69b34b4 100644 (file)
@@ -464,6 +464,12 @@ process_request (ASSUAN_CONTEXT ctx)
       if (!rc && ctx->outbound.data.error)
         rc = ctx->outbound.data.error;
     }
+  else /* flush any data send w/o using the data fp */
+    {
+      assuan_send_data (ctx, NULL, 0);
+      if (!rc && ctx->outbound.data.error)
+        rc = ctx->outbound.data.error;
+    }
   /* Error handling */
   if (!rc)
     {
@@ -478,7 +484,7 @@ process_request (ASSUAN_CONTEXT ctx)
     {
       char errline[256];
 
-        if (rc < 100)
+      if (rc < 100)
         sprintf (errline, "ERR %d server fault (%.50s)",
                  ASSUAN_Server_Fault, assuan_strerror (rc));
       else
index 933091e..2bac130 100644 (file)
@@ -126,9 +126,10 @@ free_membuf (struct membuf *mb)
  * @keyword: The keyword used for the inquire
  * @r_buffer: Returns an allocated buffer
  * @r_length: Returns the length of this buffer
- * @maxlen: If no 0, the size limit of the inquired data.
+ * @maxlen: If not 0, the size limit of the inquired data.
  * 
- * A Server may use this to Send an inquire
+ * A Server may use this to Send an inquire.  r_buffer, r_length and
+ * maxlen may all be NULL/0 to indicate that no real data is expected.
  * 
  * Return value: 0 on success or an ASSUAN error code
  **/
@@ -141,9 +142,12 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
   char cmdbuf[100];
   unsigned char *line, *p;
   int linelen;
+  int nodataexpected;
 
-  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))
-      || !r_buffer || !r_length )
+  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
+    return ASSUAN_Invalid_Value;
+  nodataexpected = !r_buffer && !r_length && !maxlen;
+  if (!nodataexpected && (!r_buffer || !r_length))
     return ASSUAN_Invalid_Value;
   if (!ctx->is_server)
     return ASSUAN_Not_A_Server;
@@ -151,7 +155,10 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
     return ASSUAN_Nested_Commands;
   
   ctx->in_inquire = 1;
-  init_membuf (&mb, maxlen? maxlen:1024, maxlen);
+  if (nodataexpected)
+    memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
+  else
+    init_membuf (&mb, maxlen? maxlen:1024, maxlen);
 
   strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
   rc = assuan_write_line (ctx, cmdbuf);
@@ -172,7 +179,12 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
       if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
           && (!line[3] || line[3] == ' '))
         break; /* END command received*/
-      if (line[0] != 'D' || line[1] != ' ')
+      if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
+        {
+          rc = ASSUAN_Canceled;
+          goto leave;
+        }
+      if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
         {
           rc = ASSUAN_Unexpected_Command;
           goto leave;
@@ -205,13 +217,17 @@ assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
           goto leave;
         }
     }
-  
-  *r_buffer = get_membuf (&mb, r_length);
-  if (!*r_buffer)
-    rc = ASSUAN_Out_Of_Core;
+
+  if (!nodataexpected)
+    {
+      *r_buffer = get_membuf (&mb, r_length);
+      if (!*r_buffer)
+        rc = ASSUAN_Out_Of_Core;
+    }
 
  leave:
-  free_membuf (&mb);
+  if (!nodataexpected)
+    free_membuf (&mb);
   ctx->in_inquire = 0;
   return rc;
 }
index d15f54f..5c5d124 100644 (file)
@@ -64,6 +64,7 @@ _assuan_new_context (ASSUAN_CONTEXT *r_ctx)
   ctx->outbound.fd = -1;
 
   ctx->listen_fd = -1;
+  ctx->client_pid = (pid_t)-1;
   /* use the pipe server handler as a default */
   ctx->deinit_handler = deinit_pipe_server;
   ctx->accept_handler = accept_connection;
index 6ad6455..39dd84a 100644 (file)
@@ -25,6 +25,9 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <unistd.h>
+#ifdef USE_GNU_PTH
+# include <pth.h>
+#endif
 
 #include "assuan-defs.h"
 
@@ -35,13 +38,28 @@ accept_connection (ASSUAN_CONTEXT ctx)
   struct sockaddr_un clnt_addr;
   size_t len = sizeof clnt_addr;
 
+  ctx->client_pid = (pid_t)-1;
+#ifdef USE_GNU_PTH
+  fd = pth_accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
+#else
   fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
+#endif
   if (fd == -1)
     {
       ctx->os_errno = errno;
       return ASSUAN_Accept_Failed;
     }
 
+#ifdef HAVE_SO_PEERCRED
+  {
+    struct ucred cr; 
+    int cl = sizeof cr;
+
+    if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) ) 
+      ctx->client_pid = cr.pid;
+  }
+#endif
+
   ctx->inbound.fd = fd;
   ctx->inbound.eof = 0;
   ctx->inbound.linelen = 0;
index 5971d81..a934001 100644 (file)
@@ -73,6 +73,12 @@ typedef enum {
   ASSUAN_Inquire_Unknown = 120,
   ASSUAN_Inquire_Error = 121,
   ASSUAN_Invalid_Option = 122,
+  ASSUAN_Invalid_Index = 123,
+  ASSUAN_Unexpected_Status = 124,
+  ASSUAN_Unexpected_Data = 125,
+  ASSUAN_Invalid_Status = 126,
+
+  ASSUAN_Not_Confirmed = 128,
 
   ASSUAN_Bad_Certificate = 201,
   ASSUAN_Bad_Certificate_Path = 202,
@@ -89,6 +95,12 @@ typedef enum {
   ASSUAN_CRL_Too_Old = 303,
   ASSUAN_Not_Trusted = 304,
 
+  ASSUAN_Card_Error = 401,
+  ASSUAN_Invalid_Card = 402,
+  ASSUAN_No_PKCS15_App = 403,
+  ASSUAN_Card_Not_Present = 404,
+  ASSUAN_Invalid_Id = 405
+
 } AssuanError;
 
 /* This is a list of pre-registered ASSUAN commands */
@@ -178,7 +190,9 @@ assuan_transact (ASSUAN_CONTEXT ctx,
                  AssuanError (*data_cb)(void *, const void *, size_t),
                  void *data_cb_arg,
                  AssuanError (*inquire_cb)(void*, const char *),
-                 void *inquire_cb_arg);
+                 void *inquire_cb_arg,
+                 AssuanError (*status_cb)(void*, const char *),
+                 void *status_cb_arg);
 
 
 /*-- assuan-inquire.c --*/
index b5f723c..bf5e6c7 100644 (file)
@@ -1,3 +1,33 @@
+2002-04-04  Werner Koch  <wk@gnupg.org>
+
+       * logging.c (log_get_prefix): New.
+
+2002-03-15  Werner Koch  <wk@gnupg.org>
+
+       * argparse.c (optfile_parse): Fixed missing argument handling.
+
+2002-02-25  Werner Koch  <wk@gnupg.org>
+
+       * stringhelp.c (ascii_memcasemem): New.
+
+2002-02-14  Werner Koch  <wk@gnupg.org>
+
+       * Makefile.am (INCLUDES): Add cflags for libgcrypt.
+
+2002-02-07  Werner Koch  <wk@gnupg.org>
+
+       * logging.c (log_set_fd): New.
+
+       * stringhelp.c (print_sanitized_buffer): New.
+       (print_sanitized_string): New.
+
+2002-01-24  Werner Koch  <wk@gnupg.org>
+
+       * argparse.c (strusage): Set default copyright notice year to 2002.
+
+       Fixed the copyright notice of this file, as it has always been
+       part of GnuPG and therefore belongs to the FSF.
+
 2001-11-01  Marcus Brinkmann  <marcus@g10code.de>
 
        * logging.c (log_printf): Do not initialize ARG_PTR with 0, we
@@ -72,8 +102,12 @@ Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
   (do_logv): Add kludge to insert LFs.
 
 
- Copyright 2000 Werner Koch (dd9jn)
- Copyright 2001 g10 Code GmbH
+     ***********************************************************
+     * Please note that Jnlib is maintained as part of GnuPG.  *
+     * You may find it source-copied in other packages.        *
+     ***********************************************************       
+       
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index 0e353e4..0eb99d4 100644 (file)
@@ -276,10 +276,12 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
                    arg->r_opt = -arg->r_opt;
                if( !opts[idx].short_opt )   /* unknown command/option */
                    arg->r_opt = (opts[idx].flags & 256)? -7:-2;
-               else if( (opts[idx].flags & 8) ) /* no argument */
-                   arg->r_opt = -3;           /* error */
-               else                           /* no or optional argument */
+               else if( !(opts[idx].flags & 7) ) /* does not take an arg */
                    arg->r_type = 0;           /* okay */
+               else if( (opts[idx].flags & 8) )  /* argument is optional */
+                    arg->r_type = 0;          /* okay */
+               else                           /* required argument */
+                   arg->r_opt = -3;           /* error */
                break;
            }
            else if( state == 3 ) {            /* no argument found */
@@ -900,7 +902,7 @@ strusage( int level )
     switch( level ) {
       case 11: p = "foo"; break;
       case 13: p = "0.0"; break;
-      case 14: p = "Copyright (C) 2001 Free Software Foundation, Inc."; break;
+      case 14: p = "Copyright (C) 2002 Free Software Foundation, Inc."; break;
       case 15: p =
 "This program comes with ABSOLUTELY NO WARRANTY.\n"
 "This is free software, and you are welcome to redistribute it\n"
index 2e0d53a..647e757 100644 (file)
@@ -89,12 +89,37 @@ log_set_file( const char *name )
     }
     setvbuf( fp, NULL, _IOLBF, 0 );
 
-    if( logstream && logstream != stderr )
-       fclose( logstream );
+    if (logstream && logstream != stderr && logstream != stdout)
+      fclose( logstream );
     logstream = fp;
     missing_lf = 0;
 }
 
+void
+log_set_fd (int fd)
+{
+  FILE *fp;
+  
+  if (fd == 1)
+    fp = stdout;
+  else if (fd == 2)
+    fp = stderr;
+  else
+    fp = fdopen (fd, "a");
+  if (!fp)
+    {
+      fprintf (stderr, "failed to fdopen log fd %d: %s\n",
+               fd, strerror(errno));
+      return;
+    }
+  setvbuf (fp, NULL, _IOLBF, 0);
+  
+  if (logstream && logstream != stderr && logstream != stdout)
+    fclose( logstream);
+  logstream = fp;
+  missing_lf = 0;
+}
+
 
 void
 log_set_prefix (const char *text, unsigned int flags)
@@ -110,6 +135,23 @@ log_set_prefix (const char *text, unsigned int flags)
   with_pid  = (flags & 4);
 }
 
+
+const char *
+log_get_prefix (unsigned int *flags)
+{
+  if (flags)
+    {
+      *flags = 0;
+      if (with_prefix)
+        *flags |= 1;
+      if (with_time)
+        *flags |= 2;
+      if (with_pid)
+        *flags |=4;
+    }
+  return prefix_buffer;
+}
+
 int
 log_get_fd()
 {
index 7b7b8c8..224db36 100644 (file)
@@ -27,7 +27,9 @@
 
 int  log_get_errorcount (int clear);
 void log_set_file( const char *name );
+void log_set_fd (int fd);
 void log_set_prefix (const char *text, unsigned int flags);
+const char *log_get_prefix (unsigned int *flags);
 int  log_get_fd(void);
 FILE *log_get_stream (void);
 
index 0d3035e..d6883e7 100644 (file)
@@ -263,6 +263,52 @@ compare_filenames( const char *a, const char *b )
   #endif
 }
 
+/* Print a BUFFER to stream FP while replacing all control characters
+   and the character DELIM with standard C eescape 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 < 0xa0) || *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_string (FILE *fp, const char *string, int delim)
+{
+  return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
+}
+
 
 /****************************************************
  ******** locale insensitive ctype functions ********
@@ -336,6 +382,26 @@ ascii_strcmp( const char *a, const 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 unsigned char *a = haystack;
+      const unsigned char *b = a + nhaystack - nneedle;
+      
+      for (; a <= b; a++)
+        {
+          if ( !ascii_memcasecmp (a, needle, nneedle) )
+            return (void *)a;
+        }
+    }
+  return NULL;
+}
 
 /*********************************************
  ********** missing string functions *********
index 17a6ad0..bfdb0d9 100644 (file)
@@ -37,6 +37,11 @@ char *make_dirname(const char *filepath);
 char *make_filename( const char *first_part, ... );
 int compare_filenames( const char *a, const char *b );
 
+size_t print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
+                               int delim);
+size_t print_sanitized_string (FILE *fp, const char *string, int delim);
+
+
 const char *ascii_memistr( const char *buf, size_t buflen, const char *sub );
 int ascii_isupper (int c);
 int ascii_islower (int c);
@@ -44,6 +49,8 @@ int ascii_toupper (int c);
 int ascii_tolower (int c);
 int ascii_strcasecmp( const char *a, const char *b );
 int ascii_memcasecmp( const char *a, const char *b, size_t n );
+void *ascii_memcasemem (const void *haystack, size_t nhaystack,
+                        const void *needle, size_t nneedle);
 
 
 #ifndef HAVE_MEMICMP