Factor duplicate snprintf code into functions.
authorBruce Momjian <bruce@momjian.us>
Thu, 17 Mar 2005 03:18:14 +0000 (03:18 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 17 Mar 2005 03:18:14 +0000 (03:18 +0000)
src/port/snprintf.c

index e50555df62e7db5f4e3a0c4e34ea3f823138d149..544ab3d78c978b7b596624342be1fdd8b8312b9f 100644 (file)
@@ -65,7 +65,7 @@
  * causing nasty effects.
  **************************************************************/
 
-/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.23 2005/03/16 21:27:23 momjian Exp $";*/
+/*static char _id[] = "$PostgreSQL: pgsql/src/port/snprintf.c,v 1.24 2005/03/17 03:18:14 momjian Exp $";*/
 
 static void dopr(char *buffer, const char *format, va_list args, char *end);
 
@@ -149,16 +149,18 @@ pg_printf(const char *fmt,...)
    return len;
 }
 
-/*
- * dopr(): poor man's version of doprintf
- */
+static int adjust_sign(int is_negative, int forcesign, int *signvalue);
+static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen);
+static void leading_pad(int zpad, int *signvalue, int *padlen, char *end,
+                char **output);
+static void trailing_pad(int *padlen, char *end, char **output);
 
-static void fmtstr(char *value, int ljust, int len, int maxwidth,
+static void fmtstr(char *value, int leftjust, int minlen, int maxwidth,
       char *end, char **output);
-static void fmtnum(int64 value, int base, int dosign, int forcesign,
-      int ljust, int len, int zpad, char *end, char **output);
+static void fmtint(int64 value, int base, int dosign, int forcesign,
+      int leftjust, int minlen, int zpad, char *end, char **output);
 static void fmtfloat(double value, char type, int forcesign,
-      int ljust, int len, int zpad, int precision, int pointflag, char *end,
+      int leftjust, int minlen, int zpad, int precision, int pointflag, char *end,
       char **output);
 static void dostr(char *str, int cut, char *end, char **output);
 static void dopr_outch(int c, char *end, char **output);
@@ -171,6 +173,10 @@ static void dopr_outch(int c, char *end, char **output);
 #define FMTWIDTH   6
 #define FMTLEN     7
 
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
 static void
 dopr(char *buffer, const char *format, va_list args, char *end)
 {
@@ -179,8 +185,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
    int         longflag;
    int         pointflag;
    int         maxwidth;
-   int         ljust;
-   int         len;
+   int         leftjust;
+   int         minlen;
    int         zpad;
    int         forcesign;
    int         i;
@@ -201,8 +207,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
        int64       numvalue;
        double      fvalue;
        int         charvalue;
-       int         ljust;
-       int         len;
+       int         leftjust;
+       int         minlen;
        int         zpad;
        int         maxwidth;
        int         base;
@@ -245,7 +251,7 @@ dopr(char *buffer, const char *format, va_list args, char *end)
        switch (ch)
        {
            case '%':
-               ljust = len = zpad = forcesign = maxwidth = 0;
+               leftjust = minlen = zpad = forcesign = maxwidth = 0;
                longflag = longlongflag = pointflag = 0;
                fmtbegin = format - 1;
                realpos = 0;
@@ -257,13 +263,13 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                    case '\0':
                        goto performpr;
                    case '-':
-                       ljust = 1;
+                       leftjust = 1;
                        goto nextch;
                    case '+':
                        forcesign = 1;
                        goto nextch;
-                   case '0':   /* set zero padding if len not set */
-                       if (len == 0 && !pointflag)
+                   case '0':   /* set zero padding if minlen not set */
+                       if (minlen == 0 && !pointflag)
                            zpad = '0';
                    case '1':
                    case '2':
@@ -276,7 +282,7 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                    case '9':
                        if (!pointflag)
                        {
-                           len = len * 10 + ch - '0';
+                           minlen = minlen * 10 + ch - '0';
                            position = position * 10 + ch - '0';
                        }
                        else
@@ -287,7 +293,7 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        goto nextch;
                    case '$':
                        realpos = position;
-                       len = 0;
+                       minlen = 0;
                        goto nextch;
                    case '*':
                        MemSet(&fmtpar[fmtpos], 0, sizeof(fmtpar[fmtpos]));
@@ -340,8 +346,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].base = 10;
                        fmtpar[fmtpos].dosign = 0;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].func = FMTNUM_U;
                        fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos;
@@ -356,8 +362,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].base = 8;
                        fmtpar[fmtpos].dosign = 0;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].func = FMTNUM_U;
                        fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos;
@@ -372,8 +378,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].base = 10;
                        fmtpar[fmtpos].dosign = 1;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].func = FMTNUM;
                        fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos;
@@ -387,8 +393,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].base = 16;
                        fmtpar[fmtpos].dosign = 0;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].func = FMTNUM_U;
                        fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos;
@@ -402,8 +408,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].base = -16;
                        fmtpar[fmtpos].dosign = 1;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].func = FMTNUM_U;
                        fmtpar[fmtpos].realpos = realpos ? realpos : fmtpos;
@@ -412,8 +418,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                    case 's':
                        fmtpar[fmtpos].fmtbegin = fmtbegin;
                        fmtpar[fmtpos].fmtend = format;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].maxwidth = maxwidth;
                        fmtpar[fmtpos].func = FMTSTR;
@@ -436,8 +442,8 @@ dopr(char *buffer, const char *format, va_list args, char *end)
                        fmtpar[fmtpos].fmtend = format;
                        fmtpar[fmtpos].type = ch;
                        fmtpar[fmtpos].forcesign = forcesign;
-                       fmtpar[fmtpos].ljust = ljust;
-                       fmtpar[fmtpos].len = len;
+                       fmtpar[fmtpos].leftjust = leftjust;
+                       fmtpar[fmtpos].minlen = minlen;
                        fmtpar[fmtpos].zpad = zpad;
                        fmtpar[fmtpos].precision = precision;
                        fmtpar[fmtpos].pointflag = pointflag;
@@ -499,11 +505,27 @@ performpr:
                fmtparptr[i]->charvalue = va_arg(args, int);
                break;
            case FMTLEN:
-               if (i + 1 < fmtpos && fmtparptr[i + 1]->func != FMTWIDTH)
-                   fmtparptr[i + 1]->len = va_arg(args, int);
-               /* For "%*.*f", use the second arg */
-               if (i + 2 < fmtpos && fmtparptr[i + 1]->func == FMTWIDTH)
-                   fmtparptr[i + 2]->len = va_arg(args, int);
+               {
+                   int minlen = va_arg(args, int);
+                   int leftjust = 0;
+
+                   if (minlen < 0)
+                   {
+                       minlen = -minlen;
+                       leftjust = 1;
+                   }
+                   if (i + 1 < fmtpos && fmtparptr[i + 1]->func != FMTWIDTH)
+                   {
+                       fmtparptr[i + 1]->minlen = minlen;
+                       fmtparptr[i + 1]->leftjust |= leftjust;
+                   }
+                   /* For "%*.*f", use the second arg */
+                   if (i + 2 < fmtpos && fmtparptr[i + 1]->func == FMTWIDTH)
+                   {
+                       fmtparptr[i + 2]->minlen = minlen;
+                       fmtparptr[i + 2]->leftjust |= leftjust;
+                   }
+               }
                break;
            case FMTWIDTH:
                if (i + 1 < fmtpos)
@@ -530,21 +552,21 @@ performpr:
                switch (fmtparptr[i]->func)
                {
                    case FMTSTR:
-                       fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
-                              fmtparptr[i]->len, fmtparptr[i]->maxwidth,
+                       fmtstr(fmtparptr[i]->value, fmtparptr[i]->leftjust,
+                              fmtparptr[i]->minlen, fmtparptr[i]->maxwidth,
                               end, &output);
                        break;
                    case FMTNUM:
                    case FMTNUM_U:
-                       fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
+                       fmtint(fmtparptr[i]->numvalue, fmtparptr[i]->base,
                               fmtparptr[i]->dosign, fmtparptr[i]->forcesign,
-                              fmtparptr[i]->ljust, fmtparptr[i]->len,
+                              fmtparptr[i]->leftjust, fmtparptr[i]->minlen,
                               fmtparptr[i]->zpad, end, &output);
                        break;
                    case FMTFLOAT:
                        fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
-                              fmtparptr[i]->forcesign, fmtparptr[i]->ljust,
-                              fmtparptr[i]->len, fmtparptr[i]->zpad,
+                              fmtparptr[i]->forcesign, fmtparptr[i]->leftjust,
+                              fmtparptr[i]->minlen, fmtparptr[i]->zpad,
                               fmtparptr[i]->precision, fmtparptr[i]->pointflag,
                               end, &output);
                        break;
@@ -574,7 +596,7 @@ nochar:
 }
 
 static void
-fmtstr(char *value, int ljust, int len, int maxwidth, char *end,
+fmtstr(char *value, int leftjust, int minlen, int maxwidth, char *end,
       char **output)
 {
    int         padlen,
@@ -582,185 +604,90 @@ fmtstr(char *value, int ljust, int len, int maxwidth, char *end,
 
    if (value == NULL)
        value = "<NULL>";
+
    vallen = strlen(value);
-   if (vallen > maxwidth && maxwidth)
+   if (maxwidth && vallen > maxwidth)
        vallen = maxwidth;
-   if (len < 0)
-   {
-       /* this could happen with a "*" width spec */
-       ljust = 1;
-       len = -len;
-   }
-   padlen = len - vallen;
-   if (padlen < 0)
-       padlen = 0;
-   if (ljust)
-       padlen = -padlen;
+
+   adjust_padlen(minlen, vallen, leftjust, &padlen);
+
    while (padlen > 0)
    {
        dopr_outch(' ', end, output);
        --padlen;
    }
    dostr(value, maxwidth, end, output);
-   while (padlen < 0)
-   {
-       dopr_outch(' ', end, output);
-       ++padlen;
-   }
+
+   trailing_pad(&padlen, end, output);
 }
 
 static void
-fmtnum(int64 value, int base, int dosign, int forcesign, int ljust,
-      int len, int zpad, char *end, char **output)
+fmtint(int64 value, int base, int dosign, int forcesign, int leftjust,
+      int minlen, int zpad, char *end, char **output)
 {
    int         signvalue = 0;
-   uint64      uvalue;
    char        convert[64];
-   int         place = 0;
+   int         vallen = 0;
    int         padlen = 0;     /* amount to pad */
    int         caps = 0;
 
-   /*
-    * DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
-    * value, base, dosign, ljust, len, zpad ));
-    */
-   uvalue = value;
-   if (dosign)
-   {
-       if (value < 0)
-       {
-           signvalue = '-';
-           uvalue = -value;
-       }
-       else if (forcesign)
-           signvalue = '+';
-   }
+   /* Handle +/- and %X (uppercase hex) */
+   if (dosign && adjust_sign((value < 0), forcesign, &signvalue))
+           value = -value;
    if (base < 0)
    {
        caps = 1;
        base = -base;
    }
+
+   /* make integer string */
    do
    {
-       convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
-           [uvalue % (unsigned) base];
-       uvalue = (uvalue / (unsigned) base);
-   } while (uvalue);
-   convert[place] = 0;
+       convert[vallen++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+           [value % (unsigned) base];
+       value = (value / (unsigned) base);
+   } while (value);
+   convert[vallen] = 0;
 
-   if (len < 0)
-   {
-       /* this could happen with a "*" width spec */
-       ljust = 1;
-       len = -len;
-   }
-   padlen = len - place;
-   if (padlen < 0)
-       padlen = 0;
-   if (ljust)
-       padlen = -padlen;
-
-   /*
-    * DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
-    * convert,place,signvalue,padlen));
-    */
-   if (zpad && padlen > 0)
-   {
-       if (signvalue)
-       {
-           dopr_outch(signvalue, end, output);
-           --padlen;
-           signvalue = 0;
-       }
-       while (padlen > 0)
-       {
-           dopr_outch(zpad, end, output);
-           --padlen;
-       }
-   }
-   while (padlen > 0)
-   {
-       dopr_outch(' ', end, output);
-       --padlen;
-   }
-   if (signvalue)
-       dopr_outch(signvalue, end, output);
-   while (place > 0)
-       dopr_outch(convert[--place], end, output);
-   while (padlen < 0)
-   {
-       dopr_outch(' ', end, output);
-       ++padlen;
-   }
+   adjust_padlen(minlen, vallen, leftjust, &padlen);
+
+   leading_pad(zpad, &signvalue, &padlen, end, output);
+   
+   while (vallen > 0)
+       dopr_outch(convert[--vallen], end, output);
+
+   trailing_pad(&padlen, end, output);
 }
 
 static void
-fmtfloat(double value, char type, int forcesign, int ljust,
-        int len, int zpad, int precision, int pointflag, char *end,
+fmtfloat(double value, char type, int forcesign, int leftjust,
+        int minlen, int zpad, int precision, int pointflag, char *end,
         char **output)
 {
    int         signvalue = 0;
-   double      uvalue;
+   int         vallen;
    char        fmt[32];
    char        convert[512];
    int         padlen = 0;     /* amount to pad */
 
-   uvalue = value;
    /* we rely on regular C library's sprintf to do the basic conversion */
    if (pointflag)
        sprintf(fmt, "%%.%d%c", precision, type);
    else
        sprintf(fmt, "%%%c", type);
 
-   if (value < 0)
-   {
-       signvalue = '-';
-       uvalue = -value;
-   }
-   else if (forcesign)
-       signvalue = '+';
+   if (adjust_sign((value < 0), forcesign, &signvalue))
+           value = -value;
 
-   sprintf(convert, fmt, uvalue);
+   vallen = sprintf(convert, fmt, value);
 
-   if (len < 0)
-   {
-       /* this could happen with a "*" width spec */
-       ljust = 1;
-       len = -len;
-   }
-   padlen = len - strlen(convert);
-   if (padlen < 0)
-       padlen = 0;
-   if (ljust)
-       padlen = -padlen;
+   adjust_padlen(minlen, vallen, leftjust, &padlen);
+
+   leading_pad(zpad, &signvalue, &padlen, end, output);
 
-   if (zpad && padlen > 0)
-   {
-       if (signvalue)
-       {
-           dopr_outch(signvalue, end, output);
-           --padlen;
-           signvalue = 0;
-       }
-       while (padlen > 0)
-       {
-           dopr_outch(zpad, end, output);
-           --padlen;
-       }
-   }
-   while (padlen > 0)
-   {
-       dopr_outch(' ', end, output);
-       --padlen;
-   }
-   if (signvalue)
-       dopr_outch(signvalue, end, output);
    dostr(convert, 0, end, output);
-   while (padlen < 0)
-   {
-       dopr_outch(' ', end, output);
-       ++padlen;
-   }
+
+   trailing_pad(&padlen, end, output);
 }
 
 static void
@@ -788,3 +715,73 @@ dopr_outch(int c, char *end, char **output)
    if (end == 0 || *output < end)
        *(*output)++ = c;
 }
+
+
+static int
+adjust_sign(int is_negative, int forcesign, int *signvalue)
+{
+   if (is_negative)
+   {
+       *signvalue = '-';
+       return true;
+   }
+   else if (forcesign)
+       *signvalue = '+';
+   return false;
+}
+
+
+static void
+adjust_padlen(int minlen, int vallen, int leftjust, int *padlen)
+{
+   *padlen = minlen - vallen;
+   if (*padlen < 0)
+       *padlen = 0;
+   if (leftjust)
+       *padlen = -*padlen;
+}
+
+
+static void
+leading_pad(int zpad, int *signvalue, int *padlen, char *end, char **output)
+{
+   if (*padlen > 0 && zpad)
+   {
+       if (*signvalue)
+       {
+           dopr_outch(*signvalue, end, output);
+           --*padlen;
+           *signvalue = 0;
+       }
+       while (*padlen > 0)
+       {
+           dopr_outch(zpad, end, output);
+           --*padlen;
+       }
+   }
+   while (*padlen > 0 + (*signvalue != 0))
+   {
+       dopr_outch(' ', end, output);
+       --*padlen;
+   }
+   if (*signvalue)
+   {
+       dopr_outch(*signvalue, end, output);
+       if (*padlen > 0)
+           --*padlen;
+       if (padlen < 0)
+           ++padlen;
+   }
+}
+
+
+static void
+trailing_pad(int *padlen, char *end, char **output)
+{
+   while (*padlen < 0)
+   {
+       dopr_outch(' ', end, output);
+       ++*padlen;
+   }
+}
+