hpux-snprintf-support-20031126
[openafs.git] / src / util / snprintf.c
index ef6c511..7bd7b5b 100644 (file)
@@ -1,16 +1,31 @@
 /* snprintf.c - Formatted, length-limited print to a string */
 
+#include <afsconfig.h>
 #include <afs/param.h>
-#if defined(AFS_OSF20_ENV) && !defined(AFS_DUX50_ENV) || defined(AFS_AIX32_ENV) || (defined(AFS_SUN55_ENV) && !defined(AFS_SUN56_ENV))
+
+RCSID
+    ("$Header$");
+
 #include <sys/types.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <ctype.h>
+#ifndef AFS_NT40_ENV
 #include <netinet/in.h>
 #include <netdb.h>
-#if defined(AFS_AIX32_ENV) || defined(AFS_SUN55_ENV)
+#else
+#include <winsock2.h>
+#endif
+#if defined(AFS_AIX32_ENV) || defined(AFS_SUN_ENV) || defined(AFS_XBSD_ENV) || defined(AFS_HPUX_ENV)
 #include <sys/socket.h>
 #endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
 
 #define MAXPREC 100
 
  * to receive it.  The minimum length is <prec> or ceil(log{base}(val)),
  * whichever is larger, plus room for a trailing NUL.
  */
-static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
+static void
+mkint(char *buf, afs_uintmax_t val, int base, int uc, unsigned prec)
 {
-  int len = 0, dig, i;
-
-  while (val) {
-    dig = val % base;
-    val = (val - dig) / base;
-    if (dig < 10)  dig = dig + '0';
-    else if (uc) dig = dig + 'A' - 10;
-    else         dig = dig + 'a' - 10;
-    buf[len++] = dig;
-  }
-  while (len < prec) buf[len++] = '0';
-  for (i = 0; i < (len + 1) / 2; i++) {
-    dig = buf[i];
-    buf[i] = buf[len - i - 1];
-    buf[len - i - 1] = dig;
-  }
-  buf[len] = 0;
+    int len = 0, dig, i;
+
+    while (val) {
+       dig = val % base;
+       val = (val - dig) / base;
+       if (dig < 10)
+           dig = dig + '0';
+       else if (uc)
+           dig = dig + 'A' - 10;
+       else
+           dig = dig + 'a' - 10;
+       buf[len++] = dig;
+    }
+    while (len < prec)
+       buf[len++] = '0';
+    for (i = 0; i < (len + 1) / 2; i++) {
+       dig = buf[i];
+       buf[i] = buf[len - i - 1];
+       buf[len - i - 1] = dig;
+    }
+    buf[len] = 0;
 }
 
 
@@ -114,276 +134,416 @@ static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
  *       both '0' and ' ' are given, the ' ' flag will be ignored.
  *     + The '#' and '+' flags have no effect.
  */
-static void vsnprintf(char *p, unsigned int avail, char *fmt, va_list ap)
+int
+afs_vsnprintf(char *p, size_t avail, const char *fmt, va_list ap)
 {
-  unsigned int width, precision, haveprec, len;
-  int ljust, plsign, spsign, altform, zfill;
-  int hflag, lflag, count, *countp, j;
-  char *x, *y, xbuf[MAXPREC + 21], fbuf[20];
-  struct hostent *he;
-  struct in_addr ia;
-  unsigned long UVAL;
-  long SVAL, *lcountp;
-  double FVAL;
-  short *hcountp;
-
-  count = 0;
-  avail--;
-  while (*fmt && avail) {
-    if (*fmt != '%') {
-      *p++ = *fmt++;
-      avail--;
-      count++;
-      continue;
-    }
+    unsigned int width, precision, haveprec, len;
+    int ljust, plsign, spsign, altform, zfill;
+    int hflag, lflag, count, *countp, j;
+    char *x, *y, xbuf[MAXPREC + 21], fbuf[20];
+    struct hostent *he;
+    struct in_addr ia;
+    afs_uintmax_t UVAL;
+    afs_intmax_t SVAL;
+    afs_intmax_t *llcountp;
+    long *lcountp;
+    double FVAL;
+    short *hcountp;
+
+    count = 0;
+    avail--;
+    while (*fmt && avail) {
+       if (*fmt != '%') {
+           *p++ = *fmt++;
+           avail--;
+           count++;
+           continue;
+       }
 
     /** Found a format specifier **/
-    ljust = plsign = spsign = altform = zfill = 0;
-    width = precision = haveprec = 0;
-    hflag = lflag = 0;
-    fmt++;
-
-    /* parse format flags */
-    while (*fmt) {
-      switch (*fmt) {
-        case '-': ljust   = 1; fmt++; continue;      /* left justify */
-        case '+': plsign  = 1; fmt++; continue;      /* use + or - */
-        case ' ': spsign  = 1; fmt++; continue;      /* use space or - */
-        case '#': altform = 1; fmt++; continue;      /* alternate form */
-        case '0': zfill   = 1; fmt++; continue;      /* pad with 0 */
-        default: break;
-      }
-      break;
-    }
-
-    /* parse minimum width */
-    if (*fmt == '*') {
-      width = va_arg(ap, int);
-      fmt++;
-    } else while (isdigit(*fmt)) {
-      width = (width * 10) + (*fmt - '0');
-      fmt++;
-    }
-
-    /* parse precision */
-    if (*fmt == '.') {
-      fmt++;
-      haveprec = 1;
-      if (*fmt == '*') {
-        precision = va_arg(ap, int);
-        fmt++;
-      } else while (isdigit(*fmt)) {
-        precision = (precision * 10) + (*fmt - '0');
-        fmt++;
-      }
-    }
-
-    /* parse size flags */
-    while (*fmt) {
-      switch (*fmt) {
-        case 'h': hflag   = 1; fmt++; continue;      /* short argument */
-        case 'l': lflag   = 1; fmt++; continue;      /* long argument */
-        default: break;
-      }
-      break;
-    }
-
-    /* parse format specifier */
-    if (!*fmt) break;
-    switch (*fmt++) {
-      case 'e':
-      case 'E':
-      case 'f':
-      case 'g':
-      case 'G':
-        FVAL = va_arg(ap, double);
-        sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
-                altform ? "#" : "", fmt[-1]);
-        if (!haveprec) precision = 6;
-        if (precision > MAXPREC) precision = MAXPREC;
-        sprintf(xbuf, fbuf, precision, FVAL);
-        x = xbuf;
-        len = strlen(x);
-        break;
-
-      case 'i': 
-      case 'd': /* signed decimal integer */
-        if      (lflag) SVAL = va_arg(ap, long);
-        else if (hflag) SVAL = va_arg(ap, short);
-        else            SVAL = va_arg(ap, int);
-        UVAL = (SVAL < 0) ? -SVAL : SVAL;
-
-        if (SVAL < 0)    xbuf[0] = '-';
-        else if (plsign) xbuf[0] = '+';
-        else if (spsign) xbuf[0] = ' ';
-        else             xbuf[0] = 0;
-
-        if (!haveprec) {
-          if (zfill && !ljust) precision = width - !!xbuf[0];
-          else precision = 1;
-          if (precision < 1 + !!xbuf[0]) precision = 1 + !!xbuf[0];
-        }
-        if (precision > MAXPREC) precision = MAXPREC;
-
-        mkint(xbuf + 1, UVAL, 10, 0, precision);
-        x = xbuf + !xbuf[0];
-        len = strlen(x);
-        break;
-
-
-      case 'o': /* unsigned octal integer */
-        if      (lflag) UVAL = va_arg(ap, unsigned long);
-        else if (hflag) UVAL = va_arg(ap, unsigned short);
-        else            UVAL = va_arg(ap, unsigned int);
-
-        xbuf[0] = '0';
-
-        if (!haveprec) {
-          if (zfill && !ljust) precision = width;
-          else precision = 1;
-        }
-        if (precision > MAXPREC) precision = MAXPREC;
-
-        mkint(xbuf + 1, UVAL, 8, 0, precision);
-        x = xbuf + (xbuf[1] == '0' || !altform);
-        len = strlen(x);
-        break;
-
-      case 'u': /* unsigned decimal integer */
-        if      (lflag) UVAL = va_arg(ap, unsigned long);
-        else if (hflag) UVAL = va_arg(ap, unsigned short);
-        else            UVAL = va_arg(ap, unsigned int);
-
-        if (!haveprec) {
-          if (zfill && !ljust) precision = width;
-          else precision = 1;
-        }
-        if (precision > MAXPREC) precision = MAXPREC;
-
-        mkint(xbuf, UVAL, 10, 0, precision);
-        x = xbuf;
-        len = strlen(x);
-        break;
-
-      case 'x': 
-      case 'X': /* unsigned hexadecimal integer */
-        if      (lflag) UVAL = va_arg(ap, unsigned long);
-        else if (hflag) UVAL = va_arg(ap, unsigned short);
-        else            UVAL = va_arg(ap, unsigned int);
-
-        xbuf[0] = '0';
-        xbuf[1] = 'x';
-
-        if (!haveprec) {
-          if (zfill && !ljust) precision = width;
-          else precision = 1;
-        }
-        if (precision > MAXPREC) precision = MAXPREC;
-
-        mkint(xbuf + 2, UVAL, 16, 0, precision);
-        x = xbuf + ((altform && UVAL) ? 0 : 2);
-        len = strlen(x);
-        break;
-
-      case '%': /* literal % */
-        xbuf[0] = '%';
-        xbuf[1] = 0;
-        x = xbuf;
-        len = 1;
-        break;
-
-      case 'c': /* character */
-        xbuf[0] = va_arg(ap, int);
-        xbuf[1] = 0;
-        x = xbuf;
-        len = 1;
-        break;
-
-      case 's': /* string */
-        x = va_arg(ap, char *);
-        if (!x) x = "<null>";
-        len = strlen(x);
-        if (haveprec && precision < len) len = precision;
-        break;
-
-      case 'I': /* IP address:
-         * value is provided as a network-order unsigned long integer
-         * precision specifies max hostname length, as for %s
-         * if precision is explicitly 0, no hostname lookup is done
-         * if 0fill specified, IPaddr fields are 0-filled to 3 digits
-         * if spsign specified, IPaddr fields are space-filled to 3 digits
-         */
-        UVAL = va_arg(ap, unsigned long);
-        ia.s_addr = UVAL;
-        if (haveprec && !precision) he = 0;
-        else he = gethostbyaddr((char *)&ia, 4, AF_INET);
-        if (he) {
-          x = he->h_name;
-          len = strlen(x);
-          if (haveprec && precision < len) len = precision;
-          if (altform)
-            for (y = x; *y; y++) if (isupper(*y)) *y = tolower(*y);
-          else if (plsign)
-            for (y = x; *y; y++) if (islower(*y)) *y = toupper(*y);
-        } else {
-          UVAL = ntohl(UVAL);
-          if      (zfill)  x = "%03u.%03u.%03u.%03u";
-          else if (spsign) x = "%3u.%3u.%3u.%3u";
-          else             x = "%u.%u.%u.%u";
-          sprintf(xbuf, x,
-                  (UVAL & 0xff000000) >> 24, (UVAL & 0x00ff0000) >> 16,
-                  (UVAL & 0x0000ff00) >> 8,  (UVAL & 0x000000ff));
-          x = xbuf;
-          len = strlen(xbuf);
-        }
-        break;
-
-      case 'n': /* report count so far */
-        if (lflag) {
-          lcountp = va_arg(ap, long *);
-          *lcountp = count;
-        } else if (hflag) {
-          hcountp = va_arg(ap, short *);
-          *hcountp = count;
-        } else {
-          countp = va_arg(ap, int *);
-          *countp = count;
-        }
-        continue;
-
-      default: /* unknown specifier */
-        continue;
+       ljust = plsign = spsign = altform = zfill = 0;
+       width = precision = haveprec = 0;
+       hflag = lflag = 0;
+       fmt++;
+
+       /* parse format flags */
+       while (*fmt) {
+           switch (*fmt) {
+           case '-':
+               ljust = 1;
+               fmt++;
+               continue;       /* left justify */
+           case '+':
+               plsign = 1;
+               fmt++;
+               continue;       /* use + or - */
+           case ' ':
+               spsign = 1;
+               fmt++;
+               continue;       /* use space or - */
+           case '#':
+               altform = 1;
+               fmt++;
+               continue;       /* alternate form */
+           case '0':
+               zfill = 1;
+               fmt++;
+               continue;       /* pad with 0 */
+           default:
+               break;
+           }
+           break;
+       }
+
+       /* parse minimum width */
+       if (*fmt == '*') {
+           width = va_arg(ap, int);
+           fmt++;
+       } else
+           while (isdigit(*fmt)) {
+               width = (width * 10) + (*fmt - '0');
+               fmt++;
+           }
+
+       /* parse precision */
+       if (*fmt == '.') {
+           fmt++;
+           haveprec = 1;
+           if (*fmt == '*') {
+               precision = va_arg(ap, int);
+               fmt++;
+           } else
+               while (isdigit(*fmt)) {
+                   precision = (precision * 10) + (*fmt - '0');
+                   fmt++;
+               }
+       }
+
+       /* parse size flags */
+       while (*fmt) {
+           switch (*fmt) {
+           case 'h':
+               hflag = 1;
+               fmt++;
+               continue;       /* short argument */
+           case 'l':
+               lflag += 1;
+               fmt++;
+               continue;       /* long argument */
+           case 'L':
+               lflag = 2;
+               fmt++;
+               continue;       /* long long argument */
+           default:
+               break;
+           }
+           break;
+       }
+
+       /* parse format specifier */
+       if (!*fmt)
+           break;
+       switch (*fmt++) {
+       case 'e':
+       case 'E':
+       case 'f':
+       case 'g':
+       case 'G':
+           FVAL = va_arg(ap, double);
+           sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
+                   altform ? "#" : "", fmt[-1]);
+           if (!haveprec)
+               precision = 6;
+           if (precision > MAXPREC)
+               precision = MAXPREC;
+           sprintf(xbuf, fbuf, precision, FVAL);
+           x = xbuf;
+           len = strlen(x);
+           break;
+
+       case 'i':
+       case 'd':               /* signed decimal integer */
+           if (lflag > 1)
+               SVAL = va_arg(ap, afs_intmax_t);
+           else if (lflag)
+               SVAL = va_arg(ap, long);
+           else if (hflag)
+               SVAL = va_arg(ap, int);
+           else
+               SVAL = va_arg(ap, int);
+           UVAL = (SVAL < 0) ? -SVAL : SVAL;
+
+           if (SVAL < 0)
+               xbuf[0] = '-';
+           else if (plsign)
+               xbuf[0] = '+';
+           else if (spsign)
+               xbuf[0] = ' ';
+           else
+               xbuf[0] = 0;
+
+           if (!haveprec) {
+               if (zfill && !ljust)
+                   precision = width - !!xbuf[0];
+               else
+                   precision = 1;
+               if (precision < 1 + !!xbuf[0])
+                   precision = 1 + !!xbuf[0];
+           }
+           if (precision > MAXPREC)
+               precision = MAXPREC;
+
+           mkint(xbuf + 1, UVAL, 10, 0, precision);
+           x = xbuf + !xbuf[0];
+           len = strlen(x);
+           break;
+
+
+       case 'o':               /* unsigned octal integer */
+           if (lflag > 1)
+               UVAL = va_arg(ap, afs_uintmax_t);
+           else if (lflag)
+               UVAL = va_arg(ap, unsigned long);
+           else if (hflag)
+               UVAL = va_arg(ap, unsigned int);
+           else
+               UVAL = va_arg(ap, unsigned int);
+
+           xbuf[0] = '0';
+
+           if (!haveprec) {
+               if (zfill && !ljust)
+                   precision = width;
+               else
+                   precision = 1;
+           }
+           if (precision > MAXPREC)
+               precision = MAXPREC;
+
+           mkint(xbuf + 1, UVAL, 8, 0, precision);
+           x = xbuf + (xbuf[1] == '0' || !altform);
+           len = strlen(x);
+           break;
+
+       case 'u':               /* unsigned decimal integer */
+           if (lflag > 1)
+               UVAL = va_arg(ap, afs_uintmax_t);
+           else if (lflag)
+               UVAL = va_arg(ap, unsigned long);
+           else if (hflag)
+               UVAL = va_arg(ap, unsigned int);
+           else
+               UVAL = va_arg(ap, unsigned int);
+
+           if (!haveprec) {
+               if (zfill && !ljust)
+                   precision = width;
+               else
+                   precision = 1;
+           }
+           if (precision > MAXPREC)
+               precision = MAXPREC;
+
+           mkint(xbuf, UVAL, 10, 0, precision);
+           x = xbuf;
+           len = strlen(x);
+           break;
+
+       case 'x':
+       case 'X':               /* unsigned hexadecimal integer */
+           if (lflag > 1)
+               UVAL = va_arg(ap, afs_uintmax_t);
+           else if (lflag)
+               UVAL = va_arg(ap, unsigned long);
+           else if (hflag)
+               UVAL = va_arg(ap, unsigned int);
+           else
+               UVAL = va_arg(ap, unsigned int);
+
+           xbuf[0] = '0';
+           xbuf[1] = 'x';
+
+           if (!haveprec) {
+               if (zfill && !ljust)
+                   precision = width;
+               else
+                   precision = 1;
+           }
+           if (precision > MAXPREC)
+               precision = MAXPREC;
+
+           mkint(xbuf + 2, UVAL, 16, 0, precision);
+           x = xbuf + ((altform && UVAL) ? 0 : 2);
+           len = strlen(x);
+           break;
+
+       case '%':               /* literal % */
+           xbuf[0] = '%';
+           xbuf[1] = 0;
+           x = xbuf;
+           len = 1;
+           break;
+
+       case 'c':               /* character */
+           xbuf[0] = va_arg(ap, int);
+           xbuf[1] = 0;
+           x = xbuf;
+           len = 1;
+           break;
+
+       case 's':               /* string */
+           x = va_arg(ap, char *);
+           if (!x)
+               x = "<null>";
+           len = strlen(x);
+           if (haveprec && precision < len)
+               len = precision;
+           break;
+
+       case 'I':               /* IP address:
+                                * value is provided as a network-order unsigned long integer
+                                * precision specifies max hostname length, as for %s
+                                * if precision is explicitly 0, no hostname lookup is done
+                                * if 0fill specified, IPaddr fields are 0-filled to 3 digits
+                                * if spsign specified, IPaddr fields are space-filled to 3 digits
+                                */
+           UVAL = va_arg(ap, unsigned long);
+           ia.s_addr = UVAL;
+           if (haveprec && !precision)
+               he = 0;
+           else
+               he = gethostbyaddr((char *)&ia, 4, AF_INET);
+           if (he) {
+               x = he->h_name;
+               len = strlen(x);
+               if (haveprec && precision < len)
+                   len = precision;
+               if (altform) {
+                   for (y = x; *y; y++)
+                       if (isupper(*y))
+                           *y = tolower(*y);
+               } else if (plsign) {
+                   for (y = x; *y; y++)
+                       if (islower(*y))
+                           *y = toupper(*y);
+               }
+           } else {
+               UVAL = ntohl(UVAL);
+               if (zfill) {
+                   x = "%03u.%03u.%03u.%03u";
+               } else if (spsign) {
+                   x = "%3u.%3u.%3u.%3u";
+               } else {
+                   x = "%u.%u.%u.%u";
+               }
+               sprintf(xbuf, x, (UVAL & 0xff000000) >> 24,
+                       (UVAL & 0x00ff0000) >> 16, (UVAL & 0x0000ff00) >> 8,
+                       (UVAL & 0x000000ff));
+               x = xbuf;
+               len = strlen(xbuf);
+           }
+           break;
+
+       case 'n':               /* report count so far */
+           if (lflag > 1) {
+               llcountp = va_arg(ap, afs_intmax_t *);
+               *llcountp = (afs_intmax_t)count;
+           } else if (lflag) {
+               lcountp = va_arg(ap, long *);
+               *lcountp = (long)count;
+           } else if (hflag) {
+               hcountp = va_arg(ap, short *);
+               *hcountp = (short)count;
+           } else {
+               countp = va_arg(ap, int *);
+               *countp = count;
+           }
+           continue;
+
+       default:                /* unknown specifier */
+           continue;
+       }
+
+       /* render the results */
+       if (len > avail)
+           len = avail;
+       if (!width)
+           width = len;
+       if (width > avail)
+           width = avail;
+       j = width - len;
+       if (j > 0) {
+           avail -= j;
+           count += j;
+       }
+
+       if (!ljust)
+           while (j-- > 0)
+               *p++ = ' ';
+
+       strncpy(p, x, len);
+       avail -= len;
+       count += len;
+       p += len;
+
+       if (ljust)
+           while (j-- > 0)
+               *p++ = ' ';
     }
+    *p = 0;
+    return count;
+}
 
-    /* render the results */
-    if (len > avail)   len = avail;
-    if (!width)        width = len;
-    if (width > avail) width = avail;
-    j = width - len;
-    if (j > 0) {
-      avail -= j;
-      count += j;
-    }
+int
+afs_snprintf(char *p, size_t avail, const char *fmt, ...)
+{
+    va_list ap;
+    int result;
 
-    if (!ljust) while (j-- > 0) *p++ = ' ';
+    va_start(ap, fmt);
+    result = afs_vsnprintf(p, avail, fmt, ap);
+    va_end(ap);
+    return result;
+}
 
-    strncpy(p, x, len);
-    avail -= len;
-    count += len;
-    p += len;
+#if defined(AFS_OSF20_ENV) && !defined(AFS_DUX50_ENV) || defined(AFS_AIX32_ENV) || (defined(AFS_SUN55_ENV) && !defined(AFS_SUN56_ENV)) || !defined(HAVE_VSNPRINTF)
 
-    if (ljust) while (j-- > 0) *p++ = ' ';
-  }
-  *p = 0;
+#ifdef AFS_AIX51_ENV
+int
+vsnprintf(char *p, size_t avail, const char *fmt, va_list ap)
+#else
+void
+vsnprintf(char *p, unsigned int avail, char *fmt, va_list ap)
+#endif
+{
+    int result;
+    result = afs_vsnprintf(p, avail, fmt, ap);
+#ifdef AFS_AIX51_ENV
+    return result;
+#endif
 }
+#endif /* AFS_OSF20_ENV || AFS_AIX32_ENV */
 
+#ifndef AFS_NT40_ENV
+#if defined(AFS_OSF20_ENV) && !defined(AFS_DUX50_ENV) || defined(AFS_AIX32_ENV) || (defined(AFS_SUN55_ENV) && !defined(AFS_SUN56_ENV)) || !defined(HAVE_SNPRINTF)
 
-void snprintf(char *p, unsigned int avail, char *fmt, ...)
+#ifdef AFS_AIX51_ENV
+int
+snprintf(char *p, size_t avail, const char *fmt, ...)
+#else
+void
+snprintf(char *p, unsigned int avail, char *fmt, ...)
+#endif
 {
-  va_list ap;
-
-  va_start(ap, fmt);
-  vsnprintf(p, avail, fmt, ap);
-  va_end(ap);
+    va_list ap;
+    int result;
+
+    va_start(ap, fmt);
+    result = afs_vsnprintf(p, avail, fmt, ap);
+    va_end(ap);
+#ifdef AFS_AIX51_ENV
+    return result;
+#endif
 }
 #endif /* AFS_OSF20_ENV || AFS_AIX32_ENV */
+#endif /* AFS_NT40_ENV */