Added silc_snprintf, silc_vsnprintf, silc_asprintf, silc_vasprintf
authorPekka Riikonen <priikone@silcnet.org>
Tue, 2 Jan 2007 20:33:03 +0000 (20:33 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 2 Jan 2007 20:33:03 +0000 (20:33 +0000)
to lib/silcutil/silcsnprintf.[ch].
Added lib/silcske/silcconauth.h header documentation.

CHANGES
TODO
includes/silc.h.in
lib/silcske/silcconnauth.h
lib/silcutil/Makefile.ad
lib/silcutil/silcfsm.h
lib/silcutil/silcsnprintf.c [new file with mode: 0644]
lib/silcutil/silcsnprintf.h [new file with mode: 0644]
lib/silcutil/silcstrutil.c
lib/silcutil/silcstrutil.h
lib/silcutil/silcutil.c

diff --git a/CHANGES b/CHANGES
index 20856172133d29f915832ea630ad1125913fbada..926223bca12fcb7af088a5885c119f34a181c90f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+Tue Jan  2 17:18:46 EET 2007  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added lib/silcutil/silcsnprintf.[ch].  Added in addition
+         of silc_snprintf, silc_vsnprintf, silc_asprintf and
+         silc_vasprintf.
+
 Sat Dec 30 23:23:17 EET 2006  Pekka Riikonen <priikone@silcnet.org>
 
        * Added preliminary Symbian support.  Changes around the source
diff --git a/TODO b/TODO
index 22cd60b3f0725088099f86761ffd4b8618db7d81..486a18aba0dd867452ca54da7bc7e7a2f4a871ab 100644 (file)
--- a/TODO
+++ b/TODO
@@ -119,7 +119,7 @@ lib/silcskr
    be.
 
 
-lib/silcske/silcske.[ch] ****PARTLY DONE****
+lib/silcske/silcske.[ch]       ****DONE****
 ========================
 
  o IV Included flag support in SKE (***DONE)
@@ -127,7 +127,7 @@ lib/silcske/silcske.[ch] ****PARTLY DONE****
  o UDP transport changes; retransmission support by using exponential
    backoff algorithm. (***DONE)
 
- o SilcConnAuth header file documentation.
+ o SilcConnAuth header file documentation. (***DONE)
 
 
 lib/silccrypt                  ****PARTLY DONE****
index e633638d87a0a1ba6ee3b9e84b40bb7a739592d5..accf52253b65e52d30cbe70023af67db24c19949 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -222,6 +222,7 @@ extern "C" {
 /* SILC util library includes */
 #include "silcstack.h"
 #include "silcmemory.h"
+#include "silcsnprintf.h"
 
 /* Math library includes */
 #include "silcmp.h"
index 76ceb536d67c3f98b3791046f0b0df7683ae52a2..5f48fcb4e51f9013cec2286446a1aa368c93b06d 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2005 Pekka Riikonen
+  Copyright (C) 2005 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
  *
  * DESCRIPTION
  *
- * SILC Connection Authentication protocol is closely related to the SILC
- * Key Exchange protocol.  After successful key exchange, additional
- * authentication is usually required to gain access to remote server or
- * service.  Connection authentication may be based on passphrase or
- * digital signatures.  It is also possible to have no authentication at
- * all.
+ * SILC Connection Authenetication protocol API is used to perform the
+ * connection authentication after successful SILC Key Exchange protocol.
+ * The interface supports authentication based on passphrases and digital
+ * signatures.  It is also possible to have no authentication at all.
  *
  ***/
 
 #ifndef SILCCONNAUTH_H
 #define SILCCONNAUTH_H
 
+/****s* silcske/SilcConnAuthAPI/SilcConnAuth
+ *
+ * NAME
+ *
+ *    typedef struct SilcConnAuthStruct *SilcConnAuth;
+ *
+ * DESCRIPTION
+ *
+ *    The connection authentication context allocated by silc_connauth_alloc
+ *    and given as arguments to all silc_connauth_* functions.  It is freed
+ *    by silc_connauth_free.
+ *
+ ***/
 typedef struct SilcConnAuthStruct *SilcConnAuth;
 
+/****d* silcske/SilcConnAuthAPI/SilcConnectionType
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcConnectionType;
+ *
+ * DESCRIPTION
+ *
+ *    The type of the connection.
+ *
+ * SOURCE
+ */
 typedef enum {
-  SILC_CONN_UNKNOWN  = 0,
+  SILC_CONN_UNKNOWN  = 0,      /* Unknown type, cannot be sent */
   SILC_CONN_CLIENT   = 1,      /* Client connection */
   SILC_CONN_SERVER   = 2,      /* Server connection */
   SILC_CONN_ROUTER   = 3       /* Router connection */
 } SilcConnectionType;
+/***/
 
+/****f* silcske/SilcConnAuthAPI/SilcConnAuthGetAuthData
+ *
+ * SYNOPSIS
+ *
+ *    typedef SilcBool
+ *    (*SilcConnAuthGetAuthData)(SilcConnAuth connauth,
+ *                               SilcConnectionType conn_type,
+ *                               unsigned char **passphrase,
+ *                               SilcUInt32 *passphrase_len,
+ *                               SilcSKR *repository,
+ *                               void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Authentication callback to retrieve the authentication data from the
+ *    application.  This is responder callback.  If the authentication
+ *    method is passphrase it must be returned to `passphrase' pointer.
+ *    If it is digital signatures the key repository pointer must be
+ *    returned into `repository' pointer, which the library will use to
+ *    find the correct public key to verify the digital signature.
+ *
+ *    If this connection is not configured at all this returns FALSE which
+ *    will result into authentication failure.  Otherwise TRUE must be
+ *    returned.
+ *
+ ***/
 typedef SilcBool (*SilcConnAuthGetAuthData)(SilcConnAuth connauth,
                                            SilcConnectionType conn_type,
                                            unsigned char **passphrase,
@@ -49,15 +99,98 @@ typedef SilcBool (*SilcConnAuthGetAuthData)(SilcConnAuth connauth,
                                            SilcSKR *repository,
                                            void *context);
 
+/****f* silcske/SilcConnAuthAPI/SilcConnAuthCompletion
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcConnAuthCompletion)(SilcConnAuth connauth,
+ *                                           SilcBool success,
+ *                                           void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Completion callback called to indicated the result of the connection
+ *    authentication protocol.  If the `success' is FALSE the authentication
+ *    was a failure.  The authentication protocol is over after this callback
+ *    is called.
+ *
+ ***/
 typedef void (*SilcConnAuthCompletion)(SilcConnAuth connauth,
                                       SilcBool success,
                                       void *context);
 
-SilcConnAuth silc_connauth_alloc(SilcSchedule schedule,
-                                SilcSKE ske,
+/****f* silcske/SilcConnAuthAPI/silc_connauth_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcConnAuth silc_connauth_alloc(SilcSchedule schedule, SilcSKE ske,
+ *                                     SilcUInt32 timeout_secs);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates the connection authentication protocol context.  The `ske'
+ *    is the successfully completed key exchange context.  The `timeout_secs'
+ *    is the maximum time we are waiting for the protocol to finish before
+ *    it is timedout.  Returns NULL on error.
+ *
+ ***/
+SilcConnAuth silc_connauth_alloc(SilcSchedule schedule, SilcSKE ske,
                                 SilcUInt32 timeout_secs);
+
+/****f* silcske/SilcConnAuthAPI/silc_connauth_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_connauth_free(SilcConnAuth connauth);
+ *
+ * DESCRIPTION
+ *
+ *    Frees the connection authentication protocol context `connauth'.
+ *
+ ***/
 void silc_connauth_free(SilcConnAuth connauth);
+
+/****f* silcske/SilcConnAuthAPI/silc_connauth_get_ske
+ *
+ * SYNOPSIS
+ *
+ *    SilcSKE silc_connauth_get_ske(SilcConnAuth connauth);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the associated SilcSKE context from the `connauth'.  It is the
+ *    pointer given as argument to silc_connauth_alloc.
+ *
+ ***/
 SilcSKE silc_connauth_get_ske(SilcConnAuth connauth);
+
+/****f* silcske/SilcConnAuthAPI/silc_connauth_initiator
+ *
+ * SYNOPSIS
+ *
+ *    SilcAsyncOperation
+ *    silc_connauth_initiator(SilcConnAuth connauth,
+ *                            SilcConnectionType conn_type,
+ *                            SilcAuthMethod auth_method, void *auth_data,
+ *                            SilcUInt32 auth_data_len,
+ *                            SilcConnAuthCompletion completion,
+ *                            void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Starts the connection authentication protocol as initiator.  The
+ *    `conn_type' is the type of connection we are.  The `auth_method' is
+ *    the authentication method.  If it is SILC_AUTH_PASSWORD the `auth_data'
+ *    and `auth_data_len' is the passphrase and its length, respectively.
+ *    If it is SILC_AUTH_PUBLIC_KEY the `auth_data' is the SilcPrivateKey
+ *    used to produce the digital signature.  The `auth_data_len' is 0.
+ *    The `completion' with `context' will be called after the protocol
+ *    has completed.
+ *
+ *    This returns SilcAsyncOperation context which can be used to abort
+ *    the protocol before it is completed.  Returns NULL on error.
+ *
+ ***/
 SilcAsyncOperation
 silc_connauth_initiator(SilcConnAuth connauth,
                        SilcConnectionType conn_type,
@@ -65,6 +198,28 @@ silc_connauth_initiator(SilcConnAuth connauth,
                        SilcUInt32 auth_data_len,
                        SilcConnAuthCompletion completion,
                        void *context);
+
+/****f* silcske/SilcConnAuthAPI/silc_connauth_responder
+ *
+ * SYNOPSIS
+ *
+ *    SilcAsyncOperation
+ *    silc_connauth_responder(SilcConnAuth connauth,
+ *                            SilcConnAuthGetAuthData get_auth_data,
+ *                            SilcConnAuthCompletion completion,
+ *                            void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Starts the connection authentication protocol as responder.  The
+ *    `get_auth_data' is called to retrieve the authentication data for
+ *    this connection.  The `completion' will be called after the protocol
+ *    has completed.
+ *
+ *    This returns SilcAsyncOperation context which can be used to abort
+ *    the protocol before it is completed.  Returns NULL on error.
+ *
+ ***/
 SilcAsyncOperation
 silc_connauth_responder(SilcConnAuth connauth,
                        SilcConnAuthGetAuthData get_auth_data,
index cb837bd31d619ebe5438c535b4bbf4f28516967a..7629855df15ee134365cd0b308f50f82030cb7b6 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  Copyright (C) 2000 - 2006 Pekka Riikonen
+#  Copyright (C) 2000 - 2007 Pekka Riikonen
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
@@ -57,7 +57,8 @@ libsilcutil_la_SOURCES = \
        silcasync.c     \
        silctime.c      \
        silcmime.c      \
-       silcstack.c
+       silcstack.c     \
+       silcsnprintf.c
 
 #ifdef SILC_DIST_TOOLKIT
 include_HEADERS =      \
@@ -92,7 +93,8 @@ include_HEADERS =     \
        silcasync.h     \
        silcasync_i.h   \
        silcstack.h     \
-       silcstack_i.h
+       silcstack_i.h   \
+       silcsnprintf.h
 
 SILC_EXTRA_DIST = tests
 #endif SILC_DIST_TOOLKIT
index 29ec90163febf4092ba267b639fcb263713d7f04..cc9220519e0f76717b05fbcb9eb8d4d3c0417d4d 100644 (file)
@@ -133,12 +133,12 @@ typedef struct SilcFSMObject SilcFSMThreadStruct;
  *    }
  *
  ***/
-#ifndef SILC_FSM_SMALL_STACK
+#if defined(SILC_DEBUG)
 #define SILC_FSM_CONTINUE \
   return fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
 #else
 #define SILC_FSM_CONTINUE return SILC_FSM_ST_CONTINUE;
-#endif /* SILC_FSM_SMALL_STACK */
+#endif /* SILC_DEBUG */
 
 /****d* silcutil/SilcFSMAPI/SILC_FSM_YIELD
  *
diff --git a/lib/silcutil/silcsnprintf.c b/lib/silcutil/silcsnprintf.c
new file mode 100644 (file)
index 0000000..633bdf1
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ *
+ *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats.
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge@samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ **************************************************************/
+
+#include "silc.h"
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS     (1 << 0)
+#define DP_F_PLUS      (1 << 1)
+#define DP_F_SPACE     (1 << 2)
+#define DP_F_NUM       (1 << 3)
+#define DP_F_ZERO      (1 << 4)
+#define DP_F_UP        (1 << 5)
+#define DP_F_UNSIGNED  (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT   1
+#define DP_C_LONG    2
+#define DP_C_LDOUBLE 3
+#define DP_C_LLONG   4
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format,
+                  va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+                   char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+                   long value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+                  LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format,
+                  va_list args_in)
+{
+  char ch;
+  LLONG value;
+  LDOUBLE fvalue;
+  char *strvalue;
+  int min;
+  int max;
+  int state;
+  int flags;
+  int cflags;
+  size_t currlen;
+  va_list args;
+
+  silc_va_copy(args, args_in);
+
+  state = DP_S_DEFAULT;
+  currlen = flags = cflags = min = 0;
+  max = -1;
+  ch = *format++;
+
+  while (state != DP_S_DONE) {
+    if (ch == '\0')
+      state = DP_S_DONE;
+
+    switch(state) {
+    case DP_S_DEFAULT:
+      if (ch == '%')
+       state = DP_S_FLAGS;
+      else
+       dopr_outch (buffer, &currlen, maxlen, ch);
+      ch = *format++;
+      break;
+    case DP_S_FLAGS:
+      switch (ch) {
+      case '-':
+       flags |= DP_F_MINUS;
+       ch = *format++;
+       break;
+      case '+':
+       flags |= DP_F_PLUS;
+       ch = *format++;
+       break;
+      case ' ':
+       flags |= DP_F_SPACE;
+       ch = *format++;
+       break;
+      case '#':
+       flags |= DP_F_NUM;
+       ch = *format++;
+       break;
+      case '0':
+       flags |= DP_F_ZERO;
+       ch = *format++;
+       break;
+      default:
+       state = DP_S_MIN;
+       break;
+      }
+      break;
+    case DP_S_MIN:
+      if (isdigit((unsigned char)ch)) {
+       min = 10*min + char_to_int (ch);
+       ch = *format++;
+      } else if (ch == '*') {
+       min = va_arg (args, int);
+       ch = *format++;
+       state = DP_S_DOT;
+      } else {
+       state = DP_S_DOT;
+      }
+      break;
+    case DP_S_DOT:
+      if (ch == '.') {
+       state = DP_S_MAX;
+       ch = *format++;
+      } else {
+       state = DP_S_MOD;
+      }
+      break;
+    case DP_S_MAX:
+      if (isdigit((unsigned char)ch)) {
+       if (max < 0)
+         max = 0;
+       max = 10*max + char_to_int (ch);
+       ch = *format++;
+      } else if (ch == '*') {
+       max = va_arg (args, int);
+       ch = *format++;
+       state = DP_S_MOD;
+      } else {
+       state = DP_S_MOD;
+      }
+      break;
+    case DP_S_MOD:
+      switch (ch) {
+      case 'h':
+       cflags = DP_C_SHORT;
+       ch = *format++;
+       break;
+      case 'l':
+       cflags = DP_C_LONG;
+       ch = *format++;
+       if (ch == 'l') {        /* It's a long long */
+         cflags = DP_C_LLONG;
+         ch = *format++;
+       }
+       break;
+      case 'L':
+       cflags = DP_C_LDOUBLE;
+       ch = *format++;
+       break;
+      default:
+       break;
+      }
+      state = DP_S_CONV;
+      break;
+    case DP_S_CONV:
+      switch (ch) {
+      case 'd':
+      case 'i':
+       if (cflags == DP_C_SHORT)
+         value = va_arg (args, int);
+       else if (cflags == DP_C_LONG)
+         value = va_arg (args, long int);
+       else if (cflags == DP_C_LLONG)
+         value = va_arg (args, LLONG);
+       else
+         value = va_arg (args, int);
+       fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+       break;
+      case 'o':
+       flags |= DP_F_UNSIGNED;
+       if (cflags == DP_C_SHORT)
+         value = va_arg (args, unsigned int);
+       else if (cflags == DP_C_LONG)
+         value = (long)va_arg (args, unsigned long int);
+       else if (cflags == DP_C_LLONG)
+         value = (long)va_arg (args, unsigned LLONG);
+       else
+         value = (long)va_arg (args, unsigned int);
+       fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
+       break;
+      case 'u':
+       flags |= DP_F_UNSIGNED;
+       if (cflags == DP_C_SHORT)
+         value = va_arg (args, unsigned int);
+       else if (cflags == DP_C_LONG)
+         value = (long)va_arg (args, unsigned long int);
+       else if (cflags == DP_C_LLONG)
+         value = (LLONG)va_arg (args, unsigned LLONG);
+       else
+         value = (long)va_arg (args, unsigned int);
+       fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+       break;
+      case 'X':
+       flags |= DP_F_UP;
+      case 'x':
+       flags |= DP_F_UNSIGNED;
+       if (cflags == DP_C_SHORT)
+         value = va_arg (args, unsigned int);
+       else if (cflags == DP_C_LONG)
+         value = (long)va_arg (args, unsigned long int);
+       else if (cflags == DP_C_LLONG)
+         value = (LLONG)va_arg (args, unsigned LLONG);
+       else
+         value = (long)va_arg (args, unsigned int);
+       fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
+       break;
+      case 'f':
+       if (cflags == DP_C_LDOUBLE)
+         fvalue = va_arg (args, LDOUBLE);
+       else
+         fvalue = va_arg (args, double);
+       /* um, floating point? */
+       fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+       break;
+      case 'E':
+       flags |= DP_F_UP;
+      case 'e':
+       if (cflags == DP_C_LDOUBLE)
+         fvalue = va_arg (args, LDOUBLE);
+       else
+         fvalue = va_arg (args, double);
+       fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+       break;
+      case 'G':
+       flags |= DP_F_UP;
+      case 'g':
+       if (cflags == DP_C_LDOUBLE)
+         fvalue = va_arg (args, LDOUBLE);
+       else
+         fvalue = va_arg (args, double);
+       fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
+       break;
+      case 'c':
+       dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
+       break;
+      case 's':
+       strvalue = va_arg (args, char *);
+       if (!strvalue) strvalue = "(NULL)";
+       if (max == -1) {
+         max = strlen(strvalue);
+       }
+       if (min > 0 && max >= 0 && min > max) max = min;
+       fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
+       break;
+      case 'p':
+       strvalue = va_arg (args, void *);
+       fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+       break;
+      case 'n':
+       if (cflags == DP_C_SHORT) {
+         short int *num;
+         num = va_arg (args, short int *);
+         *num = currlen;
+       } else if (cflags == DP_C_LONG) {
+         long int *num;
+         num = va_arg (args, long int *);
+         *num = (long int)currlen;
+       } else if (cflags == DP_C_LLONG) {
+         LLONG *num;
+         num = va_arg (args, LLONG *);
+         *num = (LLONG)currlen;
+       } else {
+         int *num;
+         num = va_arg (args, int *);
+         *num = currlen;
+       }
+       break;
+      case '%':
+       dopr_outch (buffer, &currlen, maxlen, ch);
+       break;
+      case 'w':
+       /* not supported yet, treat as next char */
+       ch = *format++;
+       break;
+      default:
+       /* Unknown, skip */
+       break;
+      }
+      ch = *format++;
+      state = DP_S_DEFAULT;
+      flags = cflags = min = 0;
+      max = -1;
+      break;
+    case DP_S_DONE:
+      break;
+    default:
+      /* hmm? */
+      break; /* some picky compilers need this */
+    }
+  }
+  if (maxlen != 0) {
+    if (currlen < maxlen - 1)
+      buffer[currlen] = '\0';
+    else if (maxlen > 0)
+      buffer[maxlen - 1] = '\0';
+  }
+
+  return currlen;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+                   char *value, int flags, int min, int max)
+{
+  int padlen, strln;     /* amount to pad */
+  int cnt = 0;
+
+  if (value == 0) {
+    value = "<NULL>";
+  }
+
+  for (strln = 0; value[strln]; ++strln); /* strlen */
+  padlen = min - strln;
+  if (padlen < 0)
+    padlen = 0;
+  if (flags & DP_F_MINUS)
+    padlen = -padlen; /* Left Justify */
+
+  while ((padlen > 0) && (cnt < max)) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --padlen;
+    ++cnt;
+  }
+  while (*value && (cnt < max)) {
+    dopr_outch (buffer, currlen, maxlen, *value++);
+    ++cnt;
+  }
+  while ((padlen < 0) && (cnt < max)) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++padlen;
+    ++cnt;
+  }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+                   long value, int base, int min, int max, int flags)
+{
+  int signvalue = 0;
+  unsigned long uvalue;
+  char convert[20];
+  int place = 0;
+  int spadlen = 0; /* amount to space pad */
+  int zpadlen = 0; /* amount to zero pad */
+  int caps = 0;
+
+  if (max < 0)
+    max = 0;
+
+  uvalue = value;
+
+  if(!(flags & DP_F_UNSIGNED)) {
+    if( value < 0 ) {
+      signvalue = '-';
+      uvalue = -value;
+    } else {
+      if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+       signvalue = '+';
+      else if (flags & DP_F_SPACE)
+       signvalue = ' ';
+    }
+  }
+
+  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+  do {
+    convert[place++] =
+      (caps? "0123456789ABCDEF":"0123456789abcdef")
+      [uvalue % (unsigned)base  ];
+    uvalue = (uvalue / (unsigned)base );
+  } while(uvalue && (place < 20));
+  if (place == 20) place--;
+  convert[place] = 0;
+
+  zpadlen = max - place;
+  spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+  if (zpadlen < 0) zpadlen = 0;
+  if (spadlen < 0) spadlen = 0;
+  if (flags & DP_F_ZERO) {
+    zpadlen = MAX(zpadlen, spadlen);
+    spadlen = 0;
+  }
+  if (flags & DP_F_MINUS)
+    spadlen = -spadlen; /* Left Justifty */
+
+  /* Spaces */
+  while (spadlen > 0) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --spadlen;
+  }
+
+  /* Sign */
+  if (signvalue)
+    dopr_outch (buffer, currlen, maxlen, signvalue);
+
+  /* Zeros */
+  if (zpadlen > 0) {
+    while (zpadlen > 0) {
+      dopr_outch (buffer, currlen, maxlen, '0');
+      --zpadlen;
+    }
+  }
+
+  /* Digits */
+  while (place > 0)
+    dopr_outch (buffer, currlen, maxlen, convert[--place]);
+
+  /* Left Justified spaces */
+  while (spadlen < 0) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++spadlen;
+  }
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+  LDOUBLE result = value;
+
+  if (value < 0)
+    result = -value;
+
+  return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+  LDOUBLE result = 1;
+
+  while (exp) {
+    result *= 10;
+    exp--;
+  }
+
+  return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+  LLONG intpart;
+
+  intpart = (LLONG)value;
+  value = value - intpart;
+  if (value >= 0.5) intpart++;
+
+  return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+  int i;
+  long l;
+  double x = x0;
+  double f = 1.0;
+
+  for (i=0;i<100;i++) {
+    l = (long)x;
+    if (l <= (x+1) && l >= (x-1)) break;
+    x *= 0.1;
+    f *= 10.0;
+  }
+
+  if (i == 100) {
+    /* yikes! the number is beyond what we can handle.
+       What do we do? */
+    (*iptr) = 0;
+    return 0;
+  }
+
+  if (i != 0) {
+    double i2;
+    double ret;
+
+    ret = my_modf(x0-l*f, &i2);
+    (*iptr) = l*f + i2;
+    return ret;
+  }
+
+  (*iptr) = l;
+  return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+                  LDOUBLE fvalue, int min, int max, int flags)
+{
+  int signvalue = 0;
+  double ufvalue;
+  char iconvert[311];
+  char fconvert[311];
+  int iplace = 0;
+  int fplace = 0;
+  int padlen = 0; /* amount to pad */
+  int zpadlen = 0;
+  int caps = 0;
+  int idx;
+  double intpart;
+  double fracpart;
+  double temp;
+
+  /*
+   * AIX manpage says the default is 0, but Solaris says the default
+   * is 6, and sprintf on AIX defaults to 6
+   */
+  if (max < 0)
+    max = 6;
+
+  ufvalue = abs_val (fvalue);
+
+  if (fvalue < 0) {
+    signvalue = '-';
+  } else {
+    if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+      signvalue = '+';
+    } else {
+      if (flags & DP_F_SPACE)
+       signvalue = ' ';
+    }
+  }
+
+#if 0
+  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+  if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+  /*
+   * Sorry, we only support 16 digits past the decimal because of our
+   * conversion method
+   */
+  if (max > 16)
+    max = 16;
+
+  /* We "cheat" by converting the fractional part to integer by
+   * multiplying by a factor of 10
+   */
+
+  temp = ufvalue;
+  my_modf(temp, &intpart);
+
+  fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+
+  if (fracpart >= POW10(max)) {
+    intpart++;
+    fracpart -= POW10(max);
+  }
+
+
+  /* Convert integer part */
+  do {
+    temp = intpart*0.1;
+    my_modf(temp, &intpart);
+    idx = (int) ((temp -intpart +0.05)* 10.0);
+    /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+    /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+    iconvert[iplace++] =
+      (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+  } while (intpart && (iplace < 311));
+  if (iplace == 311) iplace--;
+  iconvert[iplace] = 0;
+
+  /* Convert fractional part */
+  if (fracpart)
+    {
+      do {
+       temp = fracpart*0.1;
+       my_modf(temp, &fracpart);
+       idx = (int) ((temp -fracpart +0.05)* 10.0);
+       /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+       /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+       fconvert[fplace++] =
+         (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+      } while(fracpart && (fplace < 311));
+      if (fplace == 311) fplace--;
+    }
+  fconvert[fplace] = 0;
+
+  /* -1 for decimal point, another -1 if we are printing a sign */
+  padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+  zpadlen = max - fplace;
+  if (zpadlen < 0) zpadlen = 0;
+  if (padlen < 0)
+    padlen = 0;
+  if (flags & DP_F_MINUS)
+    padlen = -padlen; /* Left Justifty */
+
+  if ((flags & DP_F_ZERO) && (padlen > 0)) {
+    if (signvalue) {
+      dopr_outch (buffer, currlen, maxlen, signvalue);
+      --padlen;
+      signvalue = 0;
+    }
+    while (padlen > 0) {
+      dopr_outch (buffer, currlen, maxlen, '0');
+      --padlen;
+    }
+  }
+  while (padlen > 0) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    --padlen;
+  }
+  if (signvalue)
+    dopr_outch (buffer, currlen, maxlen, signvalue);
+
+  while (iplace > 0)
+    dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+  /*
+   * Decimal point.  This should probably use locale to find the correct
+   * char to print out.
+   */
+  if (max > 0) {
+    dopr_outch (buffer, currlen, maxlen, '.');
+
+    while (zpadlen > 0) {
+      dopr_outch (buffer, currlen, maxlen, '0');
+      --zpadlen;
+    }
+
+    while (fplace > 0)
+      dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+  }
+
+  while (padlen < 0) {
+    dopr_outch (buffer, currlen, maxlen, ' ');
+    ++padlen;
+  }
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+  if (*currlen < maxlen) {
+    buffer[(*currlen)] = c;
+  }
+  (*currlen)++;
+}
+
+int silc_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+  if (str != NULL)
+    str[0] = 0;
+  return dopr(str, count, fmt, args);
+}
+
+int silc_snprintf(char *str, size_t count, const char *fmt, ...)
+{
+  size_t ret;
+  va_list ap;
+
+  va_start(ap, fmt);
+  ret = silc_vsnprintf(str, count, fmt, ap);
+  va_end(ap);
+  return ret;
+}
+
+int silc_vasprintf(char **ptr, const char *format, va_list ap)
+{
+  int ret;
+  va_list ap2;
+
+  silc_va_copy(ap2, ap);
+
+  ret = silc_vsnprintf(NULL, 0, format, ap2);
+  if (ret <= 0) return ret;
+
+  (*ptr) = (char *)silc_malloc(ret+1);
+  if (!*ptr) return -1;
+
+  silc_va_copy(ap2, ap);
+
+  ret = silc_vsnprintf(*ptr, ret+1, format, ap2);
+
+  return ret;
+}
+
+int silc_asprintf(char **ptr, const char *format, ...)
+{
+  va_list ap;
+  int ret;
+
+  *ptr = NULL;
+  va_start(ap, format);
+  ret = silc_vasprintf(ptr, format, ap);
+  va_end(ap);
+
+  return ret;
+}
diff --git a/lib/silcutil/silcsnprintf.h b/lib/silcutil/silcsnprintf.h
new file mode 100644 (file)
index 0000000..d15b1c9
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+
+  silcsnprintf.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  This program 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; version 2 of the License.
+
+  This program 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.
+
+*/
+
+#ifndef SILCSNPRINTF_H
+#define SILCSNPRINTF_H
+
+/****f* silcutil/SilcSnprintf/silc_snprintf
+ *
+ * SYNOPSIS
+ *
+ *    int silc_snprintf(char *str, size_t count, const char *fmt, ...);
+ *
+ * DESCRIPTION
+ *
+ *    Outputs string into `str' of maximum of size `count' including the
+ *    trailing '\0' according to the `fmt'.  The `fmt' is equivalent to
+ *    snprintf(3) and printf(3) formatting.  Returns the number of character
+ *    in `str' or negative value on error.
+ *
+ ***/
+int silc_snprintf(char *str, size_t count, const char *fmt, ...);
+
+/****f* silcutil/SilcSnprintf/silc_vsnprintf
+ *
+ * SYNOPSIS
+ *
+ *    int silc_vsnprintf(char *str, size_t count, const char *fmt,
+ *                       va_list args)
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_snprintf but takes the argument for the formatting from
+ *    the `args' variable argument list.
+ *
+ ***/
+int silc_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+
+/****f* silcutil/SilcSnprintf/silc_asprintf
+ *
+ * SYNOPSIS
+ *
+ *    int silc_asprintf(char **ptr, const char *format, ...)
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_snprintf but allocates a string large enough to hold the
+ *    output including the trailing '\0'.  The caller must free the `ptr'.
+ *
+ ***/
+int silc_asprintf(char **ptr, const char *format, ...);
+
+/****f* silcutil/SilcSnprintf/silc_vasprintf
+ *
+ * SYNOPSIS
+ *
+ *    int silc_vasprintf(char **ptr, const char *format, va_list ap)
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_asprintf but takes the argument from the `ap' variable
+ *    argument list.
+ *
+ ***/
+int silc_vasprintf(char **ptr, const char *format, va_list ap);
+
+#endif /* SILCSNPRINTF_H */
index 5ba4c02e271d22d1a8d4731e8d67a475d22fc69a..1c537c1152f0ef7365916cd7520b5234418b856e 100644 (file)
@@ -170,15 +170,6 @@ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
   return data;
 }
 
-#ifndef HAVE_SNPRINTF
-/* Outputs string according to the `format'. */
-
-int silc_snprintf(char *str, SilcUInt32 size, const char *format, ...)
-{
-
-}
-#endif /* HAVE_SNPRINTF */
-
 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
    size of the `dest' (minus NULL at the end) the `src' will be
    truncated to fit. */
index 1fdc0fd16b486c89242d7e91c14d8d17324cbb1a..26defd31f4ac68b05f905ba9d720ed90d0bb29fe 100644 (file)
@@ -111,26 +111,6 @@ char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len);
 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
                               SilcUInt32 *ret_len);
 
-/****f* silcutil/SilcStrStrUtilAPI/silc_snprintf
- *
- * SYNOPSIS
- *
- *    int silc_snprintf(char *str, SilcUInt32 size, const char *format, ...);
- *
- * DESCRIPTION
- *
- *    Produces output string according to the `format'.  The formatting
- *    is equivalent to silc_snprintf(3) and sprintf(3).  Returns the number of
- *    characters output into `str', at most `size' characters including the
- *    trailing '\0' character.  Returns negative value on error.
- *
- ***/
-#ifndef SILC_SNPRINTF
-int silc_snprintf(char *str, SilcUInt32 size, const char *format, ...);
-#else
-#define silc_snprintf snprintf
-#endif /* SILC_SNPRINTF */
-
 /****f* silcutil/SilcStrStrUtilAPI/silc_strncat
  *
  * SYNOPSIS
index 5fd5de84b3a241e936d3735b956a91d083f23524..a63efa9f5e50e3bc717eb188028aca432552ddb0 100644 (file)
@@ -236,7 +236,7 @@ char *silc_format(char *fmt, ...)
 
   memset(buf, 0, sizeof(buf));
   va_start(args, fmt);
-  vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+  silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
   va_end(args);
 
   return strdup(buf);