home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / http_bpr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-29  |  14.0 KB  |  591 lines

  1. /*
  2.  * printf() style routines stolen from FastCGI
  3.  * Copyright (c) 1996 Open Market, Inc.
  4.  */
  5.  
  6. /*
  7.  * Modified to work with Apache buffering routines by Ben Laurie
  8.  * <ben@algroup.co.uk>.
  9.  *
  10.  * Modifications Copyright (C) 1996 Ben Laurie.
  11.  *
  12.  * History:
  13.  * 18 May 1996 Initial revision [Ben Laurie]
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <stdarg.h>
  19. #include <string.h>
  20. #ifndef QNX
  21. #include <memory.h>
  22. #endif
  23. #include <assert.h>
  24. #include <math.h>
  25. #include "alloc.h"
  26. #include "buff.h"
  27.  
  28. #if !defined(max)
  29. #define max(a,b)    (a > b ? a : b)
  30. #endif
  31.  
  32. #define LONG_DOUBLE    long double
  33.  
  34. #define FALSE    0
  35. #define TRUE    1
  36.  
  37. #define PRINTF_BUFFLEN 100
  38.     /*
  39.      * More than sufficient space for all unmodified conversions
  40.      * except %s and %f.
  41.      */
  42. #define FMT_BUFFLEN 25
  43.     /*
  44.      * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop
  45.      */
  46.  
  47. /*
  48.  * Copy n characters from *srcPtr to *destPtr, then increment
  49.  * both *srcPtr and *destPtr by n.
  50.  */
  51. static void CopyAndAdvance(char **destPtr, const char **srcPtr, int n)
  52.     {
  53.     char *dest = *destPtr;
  54.     const char *src = *srcPtr;
  55.     int i;
  56.     
  57.     for (i = 0; i < n; i++)
  58.         *dest++ = *src++;
  59.     *destPtr = dest;
  60.     *srcPtr = src;
  61.     }
  62.  
  63. int vbprintf(BUFF *bp, const char *format, va_list arg)
  64.     {
  65.     const char *f,*fStop,*percentPtr,*p;
  66.     char *fmtBuffPtr, *buffPtr;
  67.     int op, performedOp, sizeModifier, buffLen, specifierLength;
  68.     int fastPath, n, buffReqd, minWidth, precision, exp;
  69.     int buffCount = 0;
  70.     int auxBuffLen = 0;
  71.     char *auxBuffPtr = NULL;
  72.     int streamCount = 0;
  73.     char fmtBuff[FMT_BUFFLEN];
  74.     char buff[PRINTF_BUFFLEN];
  75.  
  76.     int intArg;
  77.     short shortArg;
  78.     long longArg;
  79.     unsigned unsignedArg;
  80.     unsigned long uLongArg;
  81.     unsigned short uShortArg;
  82.     char *charPtrArg = NULL;
  83.     void *voidPtrArg;
  84.     int *intPtrArg;
  85.     long *longPtrArg;
  86.     short *shortPtrArg;
  87.     double doubleArg = 0.0;
  88.     LONG_DOUBLE lDoubleArg = 0.0;
  89.  
  90.     fmtBuff[0] = '%';
  91.     f=format;
  92.     fStop = f + strlen(f);
  93.     while (f != fStop)
  94.     {
  95.         percentPtr = memchr(f, '%', fStop - f);
  96.         if(percentPtr == NULL) percentPtr = fStop;
  97.         if(percentPtr != f)
  98.         {
  99.             if(bwrite(bp,f,percentPtr - f) < 0)
  100.         goto ErrorReturn;
  101.             streamCount += percentPtr - f;
  102.             f = percentPtr;
  103.             if(f == fStop)
  104.         break;
  105.         }
  106.         fastPath = TRUE;
  107.         /*
  108.          * The following loop always executes either once or twice.
  109.          */
  110.         for (;;)
  111.         {
  112.             if(fastPath)
  113.         {
  114.                 /*
  115.                  * Fast path: Scan optimistically, hoping that no flags,
  116.                  * minimum field width, or precision are specified.
  117.                  * Use the preallocated buffer, which is large enough
  118.                  * for all fast path cases.  If the conversion specifier
  119.                  * is really more complex, run the loop a second time
  120.                  * using the slow path.
  121.                  * Note that fast path execution of %s bypasses the buffer
  122.                  * and %f is not attempted on the fast path due to
  123.                  * its large buffering requirements.
  124.                  */
  125.                 op = percentPtr[1];
  126.                 switch(op)
  127.             {
  128.             case 'l':
  129.             case 'L':
  130.                 case 'h':
  131.             sizeModifier = op;
  132.             op = percentPtr[2];
  133.             fmtBuff[1] = sizeModifier;
  134.             fmtBuff[2] = op;
  135.             fmtBuff[3] = '\0';
  136.             specifierLength = 3;
  137.             break;
  138.             default:
  139.             sizeModifier = ' ';
  140.             fmtBuff[1] = op;
  141.             fmtBuff[2] = '\0';
  142.             specifierLength = 2;
  143.             break;
  144.             }
  145.                 buffPtr = buff;
  146.                 buffLen = PRINTF_BUFFLEN;
  147.         }
  148.         else
  149.         {
  150.                 /*
  151.                  * Slow path: Scan the conversion specifier and construct
  152.                  * a new format string, compute an upper bound on the
  153.                  * amount of buffering that sprintf will require,
  154.                  * and allocate a larger buffer if necessary.
  155.                  */
  156.                 p = percentPtr + 1;
  157.                 fmtBuffPtr = &fmtBuff[1];
  158.                 /*
  159.                  * Scan flags
  160.                  */
  161.                 n = strspn(p, "-0+ #");
  162.                 if(n > 5)
  163.             goto ErrorReturn;
  164.                 CopyAndAdvance(&fmtBuffPtr, &p, n);
  165.  
  166.         /* Optimiser bug in SCO 5 - p is not advanced here under -O2.
  167.          * -K noinline fixes it. Ben.
  168.          */
  169.  
  170.                 /*
  171.                  * Scan minimum field width
  172.                  */
  173.                 n = strspn(p, "0123456789");
  174.                 if(n == 0)
  175.             {
  176.                     if(*p == '*')
  177.             {
  178.                         minWidth = va_arg(arg, int);
  179.                         if(abs(minWidth) > 999999) goto ErrorReturn;
  180.             /*
  181.              * The following use of strlen rather than the
  182.              * value returned from sprintf is because SUNOS4
  183.              * returns a char * instead of an int count.
  184.              */
  185.             sprintf(fmtBuffPtr, "%d", minWidth);
  186.                         fmtBuffPtr += strlen(fmtBuffPtr);
  187.                         p++;
  188.             }
  189.             else
  190.                         minWidth = 0;
  191.             }
  192.         else if(n <= 6)
  193.             {
  194.                     minWidth = strtol(p, NULL, 10);
  195.                     CopyAndAdvance(&fmtBuffPtr, &p, n);
  196.             }
  197.         else
  198.                     goto ErrorReturn;
  199.                 /*
  200.                  * Scan precision
  201.                  */
  202.             if(*p == '.')
  203.             {
  204.                     p++;
  205.                     n = strspn(p, "0123456789");
  206.                     if(n == 0)
  207.             {
  208.                         if(*p == '*')
  209.                 {
  210.                             precision = va_arg(arg, int);
  211.                             if(precision < 0) precision = 0;
  212.                             if(precision > 999999) goto ErrorReturn;
  213.                 /*
  214.                  * The following use of strlen rather than the
  215.                  * value returned from sprintf is because SUNOS4
  216.                  * returns a char * instead of an int count.
  217.                  */
  218.                 sprintf(fmtBuffPtr, ".%d", precision);
  219.                 fmtBuffPtr += strlen(fmtBuffPtr);
  220.                             p++;
  221.                 }
  222.             else
  223.                             precision = 0;
  224.             }
  225.             else if(n <= 6)
  226.             {
  227.                         precision = strtol(p, NULL, 10);
  228.             *fmtBuffPtr++='.';
  229.                         CopyAndAdvance(&fmtBuffPtr, &p, n);
  230.             }
  231.             else
  232.                         goto ErrorReturn;
  233.             }
  234.         else
  235.                     precision = -1;
  236.                 /*
  237.                  * Scan size modifier and conversion operation
  238.                  */
  239.                 switch(*p)
  240.             {
  241.             case 'l':
  242.                 case 'L':
  243.                 case 'h':
  244.             sizeModifier = *p;
  245.             CopyAndAdvance(&fmtBuffPtr, &p, 1);
  246.             break;
  247.             
  248.         default:
  249.             sizeModifier = ' ';
  250.             break;
  251.             }
  252.                 op = *p;
  253.                 CopyAndAdvance(&fmtBuffPtr, &p, 1);
  254.                 assert(fmtBuffPtr - fmtBuff < FMT_BUFFLEN);
  255.                 *fmtBuffPtr = '\0';
  256.         /*
  257.         bwrite(bp,"[",1);
  258.         bwrite(bp,fmtBuff,strlen(fmtBuff));
  259.         bwrite(bp,"]",1);
  260.         */
  261.                 specifierLength = p - percentPtr;
  262.                 /*
  263.                  * Bound the required buffer size.  For s and f
  264.                  * conversions this requires examining the argument.
  265.                  */
  266.                 switch(op)
  267.             {
  268.             case 'd':
  269.                 case 'i':
  270.                 case 'u':
  271.                 case 'o':
  272.                 case 'x':
  273.                 case 'X':
  274.                 case 'c':
  275.                 case 'p':
  276.             buffReqd = max(precision, 46);
  277.             break;
  278.  
  279.         case 's':
  280.             charPtrArg = va_arg(arg, char *);
  281.             if(precision == -1)
  282.             buffReqd = strlen(charPtrArg);
  283.             else
  284.             {
  285.             p = memchr(charPtrArg, '\0', precision);
  286.             buffReqd=(p == NULL) ? precision : p - charPtrArg;
  287.             }
  288.             break;
  289.  
  290.             case 'f':
  291.             switch(sizeModifier)
  292.             {
  293.             case ' ':
  294.                 doubleArg = va_arg(arg, double);
  295.             frexp(doubleArg, &exp);
  296.             break;
  297.  
  298.             case 'L':
  299.                 lDoubleArg = va_arg(arg, LONG_DOUBLE);
  300.             frexp(lDoubleArg, &exp);
  301.             break;
  302.  
  303.             default:
  304.                 goto ErrorReturn;
  305.                         }
  306.             if(precision == -1)
  307.             precision = 6;
  308.             buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0);
  309.             break;
  310.                 
  311.         case 'e':
  312.             case 'E':
  313.             case 'g':
  314.             case 'G':
  315.             if(precision == -1)
  316.             precision = 6;
  317.             buffReqd = precision + 8;
  318.             break;
  319.  
  320.             case 'n':
  321.             case '%':
  322.             default:
  323.             goto ErrorReturn;
  324.             }
  325.                 buffReqd = max(buffReqd + 10, minWidth);
  326.                 /*
  327.                  * Allocate the buffer
  328.                  */
  329.             if(buffReqd <= PRINTF_BUFFLEN)
  330.             {
  331.                     buffPtr = buff;
  332.             buffLen = PRINTF_BUFFLEN;
  333.             }
  334.         else
  335.             {
  336.                     if(auxBuffPtr == NULL || buffReqd > auxBuffLen)
  337.             {
  338.                 if(auxBuffPtr != NULL) free(auxBuffPtr);
  339.                         auxBuffPtr = malloc(buffReqd);
  340.                         auxBuffLen = buffReqd;
  341.                         if(auxBuffPtr == NULL)
  342.                 goto ErrorReturn;
  343.             }
  344.                     buffPtr = auxBuffPtr;
  345.             buffLen = auxBuffLen;
  346.             }
  347.         }
  348.             /*
  349.              * This giant switch statement requires the following variables
  350.              * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff.
  351.              * When fastPath == FALSE and op == 's' or 'f', the argument
  352.              * has been read into charPtrArg, doubleArg, or lDoubleArg.
  353.              * The statement produces the boolean performedOp, TRUE iff
  354.              * the op/sizeModifier were executed and argument consumed;
  355.              * if performedOp, the characters written into buffPtr[]
  356.              * and the character count buffCount (== EOF meaning error).
  357.              *
  358.              * The switch cases are arranged in the same order as in the
  359.              * description of fprintf in section 15.11 of Harbison and Steele.
  360.              */
  361.             performedOp = TRUE;
  362.             switch(op)
  363.         {
  364.         case 'd':
  365.         case 'i':
  366.             switch(sizeModifier)
  367.             {
  368.         case ' ':
  369.             intArg = va_arg(arg, int);
  370.             sprintf(buffPtr, fmtBuff, intArg);
  371.             buffCount = strlen(buffPtr);
  372.             break;
  373.         
  374.         case 'l':
  375.             longArg = va_arg(arg, long);
  376.             sprintf(buffPtr, fmtBuff, longArg);
  377.             buffCount = strlen(buffPtr);
  378.             break;
  379.                 
  380.         case 'h':
  381.             shortArg = va_arg(arg, short);
  382.             sprintf(buffPtr, fmtBuff, shortArg);
  383.             buffCount = strlen(buffPtr);
  384.             break;
  385.         
  386.         default:
  387.             goto ErrorReturn;
  388.                 }
  389.         break;
  390.  
  391.         case 'u':
  392.         case 'o':
  393.         case 'x':
  394.         case 'X':
  395.         switch(sizeModifier)
  396.             {
  397.         case ' ':
  398.             unsignedArg = va_arg(arg, unsigned);
  399.             sprintf(buffPtr, fmtBuff, unsignedArg);
  400.             buffCount = strlen(buffPtr);
  401.             break;
  402.         
  403.         case 'l':
  404.             uLongArg = va_arg(arg, unsigned long);
  405.             sprintf(buffPtr, fmtBuff, uLongArg);
  406.             buffCount = strlen(buffPtr);
  407.             break;
  408.         
  409.         case 'h':
  410.             uShortArg = va_arg(arg, unsigned short);
  411.             sprintf(buffPtr, fmtBuff, uShortArg);
  412.             buffCount = strlen(buffPtr);
  413.             break;
  414.         
  415.         default:
  416.             goto ErrorReturn;
  417.                     }
  418.         break;
  419.  
  420.         case 'c':
  421.         switch(sizeModifier)
  422.             {
  423.         case ' ':
  424.             intArg = va_arg(arg, int);
  425.             sprintf(buffPtr, fmtBuff, intArg);
  426.             buffCount = strlen(buffPtr);
  427.             break;
  428.  
  429.         case 'l':
  430.             /*
  431.              * XXX: Allowed by ISO C Amendment 1, but
  432.              * many platforms don't yet support wint_t
  433.              */
  434.             goto ErrorReturn;
  435.  
  436.         default:
  437.             goto ErrorReturn;
  438.                     }
  439.         break;
  440.  
  441.         case 's':
  442.         switch(sizeModifier)
  443.             {
  444.         case ' ':
  445.             if(fastPath)
  446.             {
  447.             buffPtr = va_arg(arg, char *);
  448.             buffCount = strlen(buffPtr);
  449.             buffLen = buffCount + 1;
  450.             }
  451.             else
  452.             {
  453.             sprintf(buffPtr, fmtBuff, charPtrArg);
  454.             buffCount = strlen(buffPtr);
  455.             }
  456.             break;
  457.  
  458.         case 'l':
  459.             /*
  460.              * XXX: Don't know how to convert a sequence
  461.              * of wide characters into a byte stream, or
  462.              * even how to predict the buffering required.
  463.              */
  464.             goto ErrorReturn;
  465.  
  466.         default:
  467.             goto ErrorReturn;
  468.                     }
  469.         break;
  470.  
  471.         case 'p':
  472.         if(sizeModifier != ' ')
  473.             goto ErrorReturn;
  474.         voidPtrArg = va_arg(arg, void *);
  475.         sprintf(buffPtr, fmtBuff, voidPtrArg);
  476.         buffCount = strlen(buffPtr);
  477.         break;
  478.  
  479.         case 'n':
  480.         switch(sizeModifier)
  481.             {
  482.         case ' ':
  483.             intPtrArg = va_arg(arg, int *);
  484.             *intPtrArg = streamCount;
  485.             break;
  486.  
  487.         case 'l':
  488.             longPtrArg = va_arg(arg, long *);
  489.             *longPtrArg = streamCount;
  490.             break;
  491.  
  492.         case 'h':
  493.             shortPtrArg = va_arg(arg, short *);
  494.             *shortPtrArg = streamCount;
  495.             break;
  496.  
  497.         default:
  498.             goto ErrorReturn;
  499.                 }
  500.         buffCount = 0;
  501.         break;
  502.  
  503.         case 'f':
  504.         if(fastPath)
  505.             {
  506.             performedOp = FALSE;
  507.             break;
  508.             }
  509.  
  510.         switch(sizeModifier)
  511.             {
  512.         case ' ':
  513.             sprintf(buffPtr, fmtBuff, doubleArg);
  514.             buffCount = strlen(buffPtr);
  515.             break;
  516.  
  517.         case 'L':
  518.             sprintf(buffPtr, fmtBuff, lDoubleArg);
  519.             buffCount = strlen(buffPtr);
  520.             break;
  521.  
  522.         default:
  523.             goto ErrorReturn;
  524.                     }
  525.         break;
  526.         /* FIXME: Used to flow through here? Should it? Ben */
  527.  
  528.         case 'e':
  529.         case 'E':
  530.         case 'g':
  531.         case 'G':
  532.         switch(sizeModifier)
  533.             {
  534.         case ' ':
  535.             doubleArg = va_arg(arg, double);
  536.             sprintf(buffPtr, fmtBuff, doubleArg);
  537.             buffCount = strlen(buffPtr);
  538.             break;
  539.  
  540.         case 'L':
  541.             lDoubleArg = va_arg(arg, LONG_DOUBLE);
  542.             sprintf(buffPtr, fmtBuff, lDoubleArg);
  543.             buffCount = strlen(buffPtr);
  544.             break;
  545.  
  546.         default:
  547.             goto ErrorReturn;
  548.                     }
  549.         break;
  550.  
  551.         case '%':
  552.         if(sizeModifier != ' ')
  553.             goto ErrorReturn;
  554.         buff[0] = '%';
  555.         buffCount = 1;
  556.         break;
  557.  
  558.         case '\0':
  559.         goto ErrorReturn;
  560.  
  561.         default:
  562.         performedOp = FALSE;
  563.         break;
  564.         } /* switch(op) */
  565.  
  566.             if(performedOp)
  567.         break;
  568.             if(!fastPath)
  569.         goto ErrorReturn;
  570.             fastPath = FALSE;
  571.         } /* for (;;) */
  572.         assert(buffCount < buffLen);
  573.         if(buffCount > 0)
  574.         {
  575.             if(bwrite(bp,buffPtr,buffCount) < 0)
  576.                 goto ErrorReturn;
  577.             streamCount += buffCount;
  578.         }
  579.     else if(buffCount < 0)
  580.             goto ErrorReturn;
  581.         f += specifierLength;
  582.     } /* while(f != fStop) */
  583.     goto NormalReturn;
  584. ErrorReturn:
  585.     streamCount = -1;
  586. NormalReturn:
  587.     if(auxBuffPtr != NULL)
  588.     free(auxBuffPtr);
  589.     return streamCount;
  590.     }
  591.