home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Libsprintf / Libsprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-15  |  13.6 KB  |  709 lines  |  [TEXT/SPM ]

  1. /*
  2.     libsprintf.c
  3.     
  4.     Stand alone sprintf clone (stand alone meaning that one doesn't need to use the ansi libraries to use this).
  5.     
  6.     Most of this is © Symantec, Inc. (I just had to do a little tinkering to get it to be stand alone...)
  7.     
  8.     06/26/95 - Updated for PPC.
  9. */
  10.  
  11. #include "libsprintf.h"
  12.  
  13. #ifdef _USE_ANSI_ // then use the ansi libraries...
  14.  
  15. #include <stdio.h>
  16. #include <strings.h>
  17.  
  18. #define libsprintf sprintf
  19.  
  20. #else // use our library...
  21.  
  22. // set the following to false to include floating point conversions
  23. #if 1
  24. #define _NOFLOATING_
  25. #endif
  26.  
  27. #include <stdarg.h>
  28.  
  29. #define BUFLEN            512
  30. #define TRUE            1
  31. #define FALSE            0
  32.  
  33. // set the following to 1 to specify register settings, otherwise the
  34. // compiler will try to optimize register settings.
  35. #if 1
  36. #define REGISTER register
  37. #else
  38. #define REGISTER
  39. #endif
  40.  
  41. long s_errno;
  42.  
  43. static struct format {
  44.     unsigned         leftJustify : 1;
  45.     unsigned         forceSign : 1;
  46.     unsigned         altForm : 1;
  47.     unsigned         zeroPad : 1;
  48.     unsigned         havePrecision : 1;
  49.     unsigned         hSize : 1;
  50.     unsigned         lSize : 1;
  51.     unsigned         LSize : 1;
  52.     char            sign;
  53.     char            exponent;
  54.     int                fieldWidth;
  55.     int                precision;
  56. } default_format;
  57.  
  58. #ifndef _NOFLOATING_
  59.  
  60. #include <fp.h>
  61.  
  62. struct LibDecRec {
  63.     decimal    dec;
  64.     /* following fields aren't used by SANE */
  65.     short            min;
  66.     short            dot;
  67.     short            max;
  68. };
  69.  
  70. typedef struct LibDecRec LibDecRec;
  71.  
  72. void libf2d(int, int, struct LibDecRec *, long double);
  73. static void post_conversion(LibDecRec *d);
  74.  
  75. #endif
  76.  
  77. char libstrlen(char* cstr){
  78.     REGISTER char len=0;
  79.     REGISTER char* str=cstr;
  80.     
  81.     if (*str!=0){
  82.         do {
  83.             len++;
  84.             str++;
  85.         } while (*str!=0);
  86.     }
  87.     
  88.     return len;
  89. }
  90.  
  91. void libfixnl(char* buf){
  92.     REGISTER char* cp=buf;
  93.     
  94.     if ((cp==(char*)0)||(*cp==0))
  95.         return;
  96.     
  97.     do {
  98.         if (*cp=='\n')
  99.             *cp=0x06;
  100.         cp++;
  101.     } while (*cp!=0);
  102. }
  103.  
  104. // Has the library been initialized?
  105. static Boolean __gLibSprintfDidInit=false;
  106.  
  107. // static buffers containing strings full of zeros and spaces
  108. static char* __gZeroString;
  109. static char* __gSpaceString;
  110.  
  111. // static variables used by libvsprintf
  112. static char __gFloatConst[]="\6>>>>>>";
  113. static char __gCapDigits[]= "0123456789ABCDEF";
  114. static char __gLowDigits[]= "0123456789abcdef";
  115.  
  116. // Initialization routine to set up the buffers
  117. static void Init_libsprintf(void);
  118. static void Init_libsprintf(void){
  119.     REGISTER short loop;
  120.     
  121.     if (__gLibSprintfDidInit)
  122.         return;
  123.     
  124.     __gZeroString=(char*)NewPtr(BUFLEN);
  125.     __gSpaceString=(char*)NewPtr(BUFLEN);
  126.     
  127.     for (loop=0;loop<BUFLEN;loop++){
  128.         __gZeroString[loop]='0';
  129.         __gSpaceString[loop]=' ';
  130.     }
  131.     
  132.     // re-init default_format
  133.     // this may/may not be necessary (I don't know what some
  134.     // optimizers might be doing; this will ensure correct entries
  135.     
  136.     default_format.leftJustify=FALSE;
  137.     default_format.forceSign=FALSE;
  138.     default_format.altForm=FALSE;
  139.     default_format.zeroPad=FALSE;
  140.     default_format.havePrecision=FALSE;
  141.     default_format.hSize=FALSE;
  142.     default_format.lSize=FALSE;
  143.     default_format.LSize=FALSE;
  144.     default_format.sign=0;
  145.     default_format.exponent=0;
  146.     default_format.fieldWidth=0;
  147.     default_format.precision=0;
  148.     
  149.     s_errno=(long)paramErr;
  150.     
  151.     __gLibSprintfDidInit=true;
  152. }
  153.  
  154. int libsprintf(char *s, const char *fmt, ...){
  155.     return libvsprintf(s, fmt, __va(fmt));
  156. }
  157.  
  158. int libvsprintf(char *cfp,const char *fmt,va_list arg){
  159.     REGISTER int c, i, j, nwritten = 0;
  160.     REGISTER unsigned long n;
  161.     long double x;
  162.     REGISTER char *s;
  163.     REGISTER char* fp=cfp;
  164.     char buf[BUFLEN], *digits, *t;
  165.     char* endbuf;
  166.     struct format F;
  167. #ifndef _NOFLOATING_
  168.     LibDecRec D;
  169. #endif
  170.     
  171.     // only initialize once
  172.     if (!__gLibSprintfDidInit){
  173.         Init_libsprintf();
  174.     }
  175.     
  176.     // only calculate endbuf once
  177.     endbuf=&(buf[BUFLEN]);
  178.     
  179.     for (c = *fmt; c; c = *++fmt) {
  180.         // reset the format
  181.         F = default_format;
  182.         
  183.         if (c != '%'){
  184. #if 1
  185.             s=(char*)fmt;
  186.             
  187.             for (i=0;1;i++){
  188.                 if ((fmt[i]=='%')||(fmt[i]==0)){
  189.                     // i points at a terminator
  190.                     // allow the rest of the function to copy the string n stuff
  191.                     fmt+=(i-1);
  192.                     goto EndOfSwitch;
  193.                 }
  194.             }
  195. #else
  196.             goto copy1;
  197. #endif
  198.         }
  199.         
  200.             /*  decode flags  */
  201.             
  202.         for (;;) {
  203.             c = *++fmt;
  204.             if (c == '-')
  205.                 F.leftJustify = TRUE;
  206.             else if (c == '+')
  207.                 F.forceSign = TRUE;
  208.             else if (c == ' ')
  209.                 F.sign = ' ';
  210.             else if (c == '#')
  211.                 F.altForm = TRUE;
  212.             else if (c == '0')
  213.                 F.zeroPad = TRUE;
  214.             else
  215.                 break;
  216.         }
  217.         
  218.             /*  decode field width  */
  219.             
  220.         if (c == '*') {
  221.             if ((F.fieldWidth = va_arg(arg, int)) < 0) {
  222.                 F.leftJustify = TRUE;
  223.                 F.fieldWidth = -F.fieldWidth;
  224.             }
  225.             c = *++fmt;
  226.         } else {
  227.             for (; c >= '0' && c <= '9'; c = *++fmt)
  228.                 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
  229.         }
  230.         
  231.             /*  decode precision  */
  232.             
  233.         if (c == '.') {
  234.             if ((c = *++fmt) == '*') {
  235.                 F.precision = va_arg(arg, int);
  236.                 c = *++fmt;
  237.             } else {
  238.                 for (; c >= '0' && c <= '9'; c = *++fmt)
  239.                     F.precision = (10 * F.precision) + (c - '0');
  240.             }
  241.             if (F.precision >= 0)
  242.                 F.havePrecision = TRUE;
  243.         }
  244.         
  245.             /* decode size modifiers */
  246.             
  247.         while ((c=='h')||(c=='l')||(c=='L')){
  248.             if (c=='h')
  249.                 F.hSize=TRUE;
  250.             else if (c=='l')
  251.                 F.lSize=TRUE;
  252.             else
  253.                 F.LSize=TRUE;
  254.             
  255.             c=*++fmt;
  256.         }
  257.         
  258.             /*  perform appropriate conversion  */
  259.         
  260.         s =endbuf;
  261.         if (F.leftJustify)
  262.             F.zeroPad = FALSE;
  263.         
  264. conv:    switch (c) {
  265.                 
  266.                 /*  decimal (signed)  */
  267.                 
  268.             case 'd':
  269.             case 'i':
  270.                 if (F.lSize)
  271.                     n = va_arg(arg, long);
  272.                 else
  273.                     n = va_arg(arg, int);
  274.                 if (F.hSize)
  275.                     n = (short) n;
  276.                 if ((long) n < 0) {
  277.                     n = -n;
  278.                     F.sign = '-';
  279.                 } else if (F.forceSign)
  280.                     F.sign = '+';
  281.                 goto decimal;
  282.                 
  283.                 /*  decimal (unsigned)  */
  284.                 
  285.             case 'u':
  286.                 if (F.lSize)
  287.                     n = va_arg(arg, unsigned long);
  288.                 else
  289.                     n = va_arg(arg, unsigned int);
  290.                 if (F.hSize)
  291.                     n = (unsigned short) n;
  292.                 F.sign = 0;
  293.                 goto decimal;
  294.                 
  295.                 /*  decimal (common code)  */
  296.  
  297. decimal:
  298.                 if (!F.havePrecision) {
  299.                     if (F.zeroPad) {
  300.                         F.precision = F.fieldWidth;
  301.                         if (F.sign)
  302.                             --F.precision;
  303.                     }
  304.                     if (F.precision < 1)
  305.                         F.precision = 1;
  306.                 }
  307.                 for (i = 0; n; n /= 10, i++)
  308.                     *--s = n % 10 + '0';
  309.                 if (i<F.precision){
  310.                     j=(F.precision-i);
  311.                     s-=j;
  312.                     BlockMoveData((Ptr)__gZeroString,(Ptr)s,j);
  313.                     i=F.precision;
  314.                 }
  315.                 if (F.sign) {
  316.                     *--s = F.sign;
  317.                     i++;
  318.                 }
  319.                 break;
  320.                 
  321.                 /*  octal (unsigned)  */
  322.                 
  323.             case 'o':
  324.                 if (F.lSize)
  325.                     n = va_arg(arg, unsigned long);
  326.                 else
  327.                     n = va_arg(arg, unsigned int);
  328.                 if (F.hSize)
  329.                     n = (unsigned short) n;
  330.                 if (!F.havePrecision) {
  331.                     if (F.zeroPad)
  332.                         F.precision = F.fieldWidth;
  333.                     if (F.precision < 1)
  334.                         F.precision = 1;
  335.                 }
  336.                 for (i = 0; n; n /= 8, i++)
  337.                     *--s = n % 8 + '0';
  338.                 if (F.altForm && i && *s != '0') {
  339.                     *--s = '0';
  340.                     i++;
  341.                 }
  342.                 if (i<F.precision){
  343.                     j=(F.precision-i);
  344.                     s-=j;
  345.                     BlockMoveData((Ptr)__gZeroString,(Ptr)s,j);
  346.                     i=F.precision;
  347.                 }
  348.                 break;
  349.                 
  350.                 /*  hexadecimal (unsigned)  */
  351.                 
  352.             case 'p': // pointer processing
  353.                 F.havePrecision = F.lSize = TRUE;
  354.                 F.precision = 8;
  355.                 /* ... */
  356.             case 'X':
  357.                 digits = __gCapDigits;
  358.                 goto hexadecimal;
  359.             case 'x':
  360.                 digits =__gLowDigits;
  361.                 /* ... */
  362. hexadecimal:
  363.                 if (F.lSize)
  364.                     n = va_arg(arg, unsigned long);
  365.                 else
  366.                     n = va_arg(arg, unsigned int);
  367.                 if (F.hSize)
  368.                     n = (unsigned short) n;
  369.                 if (!F.havePrecision) {
  370.                     if (F.zeroPad) {
  371.                         F.precision = F.fieldWidth;
  372.                         if (F.altForm)
  373.                             F.precision -= 2;
  374.                     }
  375.                     if (F.precision < 1)
  376.                         F.precision = 1;
  377.                 }
  378.                 for (i = 0; n; n /= 16, i++)
  379.                     *--s = digits[n % 16];
  380.                 if (i<F.precision){
  381.                     j=(F.precision-i);
  382.                     s-=j;
  383.                     BlockMoveData((Ptr)__gZeroString,(Ptr)s,j);
  384.                     i=F.precision;
  385.                 }
  386.                 if (F.altForm) {
  387.                     *--s = c;
  388.                     *--s = '0';
  389.                     i += 2;
  390.                 }
  391.                 break;
  392.                 
  393.  
  394.                 /*  character  */
  395.                 
  396.             case 'c':
  397.                 *--s = va_arg(arg, int);
  398.                 i = 1;
  399.                 break;
  400.                 
  401.                 /*  Error  */
  402.             case 'm':
  403.                 // display the error stored in errno (s_errno);
  404.                 s=buf;
  405.                 i=libsprintf(buf,"%ld",s_errno);
  406.                 break;
  407.                 
  408.                 /*  string  */
  409.                 
  410.             case 's':
  411.                 s = va_arg(arg, char *);
  412.                 i=0;
  413.                 if (F.altForm) {
  414.                     unsigned char* ucp=(unsigned char*)s;
  415.                     unsigned char uc=*ucp;
  416.                     
  417.                     s++;
  418.                     i=(int)0;
  419.                     i+=uc;
  420.                 } else {
  421.                     i = libstrlen(s);
  422.                 }
  423.                 
  424.                 if ((F.havePrecision)&&(i>F.precision))
  425.                     i=F.precision;
  426.                 
  427.                 break;
  428.                 
  429. #ifndef _NOFLOATING_
  430.                 /*  fixed-point  */
  431.  
  432.             case 'f':
  433.                 if (F.LSize)
  434.                     x = va_arg(arg, long double);
  435.                 else
  436.                     x = va_arg(arg, double);
  437.                 if (!F.havePrecision)
  438.                     F.precision = 6;
  439.                 libf2d(1, F.precision, (LibDecRec*)&D, x);
  440.                 D.dot = D.dec.exp + D.dec.sig.length;
  441.                 if ((D.min = D.dot) > 1)
  442.                     D.min = 1;
  443.                 D.max = D.dot + F.precision;
  444.                 if (D.max - D.min > 508)
  445.                     BlockMoveData((Ptr)__gFloatConst,(Ptr)&D.dec.sig, 7);
  446.                 goto floating;
  447.  
  448.                 /*  floating-point  */
  449.                 
  450.             case 'e':
  451.             case 'E':
  452.                 if (F.LSize)
  453.                     x = va_arg(arg, long double);
  454.                 else
  455.                     x = va_arg(arg, double);
  456.                 if (!F.havePrecision)
  457.                     F.precision = 6;
  458.                 F.exponent = c;
  459.                 libf2d(0, D.max = F.precision + 1,  (LibDecRec*)&D, x);
  460.                 D.min = D.dot = 1;
  461.                 D.dec.exp += D.dec.sig.length - 1;
  462.                 goto floating;
  463.                 
  464.                 /*  "general" notation  */
  465.                 
  466.             case 'g':
  467.             case 'G':
  468.                 if (F.LSize)
  469.                     x = va_arg(arg, long double);
  470.                 else
  471.                     x = va_arg(arg, double);
  472.                 if (!F.havePrecision)
  473.                     F.precision = 6;
  474.                 else if (F.precision == 0)
  475.                     F.precision = 1;
  476.                 F.exponent = c - 2;
  477.                 libf2d(0, D.max = F.precision, (LibDecRec*) &D, x);
  478.                 D.min = D.dot = 1;
  479.                 D.dec.exp += D.dec.sig.length - 1;
  480.                 if (D.dec.exp >= -4 && D.dec.exp < F.precision) {
  481.                     F.exponent = 0;
  482.                     if ((D.dot += D.dec.exp) < 1)
  483.                         D.min = D.dot;
  484.                 }
  485.                 if (!F.altForm && D.max > D.dec.sig.length) {
  486.                     if ((D.max = D.dec.sig.length) < D.dot)
  487.                         D.max = D.dot;
  488.                 }
  489.                 goto floating;
  490.                 
  491.                     /*  floating (common code)  */
  492.  
  493. floating:
  494.                 if (D.dec.sig.text[0] > '9') {
  495.                     F.exponent = FALSE;
  496.                     D.dot = 0;
  497.                     D.min = 1;
  498.                     D.max = D.dec.sig.length;
  499.                 }
  500.                 i = 0;
  501.                 if (F.exponent) {
  502.                     n = D.dec.exp < 0 ? -D.dec.exp : D.dec.exp;
  503.                     for (; n; n /= 10, i++)
  504.                         *--s = n % 10 + '0';
  505.                     for (; i < 2; i++)
  506.                         *--s = '0';
  507.                     *--s = D.dec.exp < 0 ? '-' : '+';
  508.                     *--s = F.exponent;
  509.                     i += 2;
  510.                 }
  511.                 j = D.max;
  512.                 if (j == D.dot && !F.altForm)
  513.                     ++D.dot;
  514.                 do {
  515.                     if (j == D.dot) {
  516.                         *--s = '.';
  517.                         i++;
  518.                     }
  519.                     *--s = j > 0 && j <= D.dec.sig.length ? D.dec.sig.text[j-1] : '0';
  520.                 } while (--j >= D.min);
  521.                 i += D.max - j;
  522.                 if (D.dec.sgn)
  523.                     F.sign = '-';
  524.                 else if (F.forceSign)
  525.                     F.sign = '+';
  526.                 if (F.zeroPad) {
  527.                     j = F.fieldWidth;
  528.                     if (F.sign)
  529.                         --j;
  530.                     if (i<j){
  531.                         s -= (j-i);
  532.                         
  533.                         BlockMoveData((Ptr)__gZeroString,(Ptr)s,(j-i));
  534.                         i=j;
  535.                     }
  536.                 }
  537.                 if (F.sign) {
  538.                     *--s = F.sign;
  539.                     i++;
  540.                 }
  541.                 break;
  542. #endif /* _NOFLOATING_ */
  543.                 /*  store # bytes written so far  */
  544.                 
  545.             case 'n':
  546.                 s = (char *)va_arg(arg, void *);
  547.                 if (F.hSize)
  548.                     * (short *) s = nwritten;
  549.                 else if (F.lSize)
  550.                     * (long *) s = nwritten;
  551.                 else
  552.                     * (int *) s = nwritten;
  553.                 continue;
  554.             
  555.                 /*  oops - unknown conversion, abort  */
  556.                 
  557.             default:
  558.                 if (c != '%')
  559.                     goto done;
  560.             copy1:
  561.                 *fp=c;fp++;
  562.                 ++nwritten;
  563.                 continue;
  564.         }
  565.             
  566. EndOfSwitch:
  567.             /*  pad on the left  */
  568.             
  569.         if (i < F.fieldWidth && !F.leftJustify) {
  570.             j=F.fieldWidth-i;
  571.             
  572.             BlockMoveData((Ptr)__gSpaceString,(Ptr)fp,j);
  573.             
  574.             fp+=j;
  575.             nwritten+=j;
  576.             F.fieldWidth=0;
  577.         }
  578.         
  579.             /*  write the converted result  */
  580.         
  581.         BlockMoveData((Ptr)s,(Ptr)fp,i);
  582.         fp+=i;
  583.         nwritten += i;
  584.             
  585.             /*  pad on the right  */
  586.             
  587.         if (i<F.fieldWidth){
  588.             j=F.fieldWidth-i;
  589.             
  590.             BlockMoveData((Ptr)__gSpaceString,(Ptr)fp,j);
  591.             fp+=j;
  592.             nwritten+=j;
  593.         }
  594.     }
  595.     
  596.         /*  all done!  */
  597.         
  598. done:
  599.     *fp=0;
  600.     return nwritten;
  601. }
  602.  
  603. #ifndef _NOFLOATING_
  604.  
  605. static void post_conversion(LibDecRec *d){
  606.     int i;
  607.     /*  strip trailing zeroes  */
  608.  
  609.     for (i = d->dec.sig.length; i > 1 && d->dec.sig.text[i-1] == '0'; --i)
  610.         ++d->dec.exp;
  611.     d->dec.sig.length = i;
  612.         
  613.         /*  format 0, INF, NAN  */
  614.         
  615.     if (d->dec.sig.text[0] == '0') {
  616. /*        d->dec.sgn = 0;             add back to disallow printing "-0"  */
  617.         d->dec.exp = 0;
  618.     }
  619.     else if (d->dec.sig.text[0] == 'I') {
  620.         d->dec.sig.length = 3;
  621.         d->dec.sig.text[1] = 'N';
  622.         d->dec.sig.text[2] = 'F';
  623.     }
  624.     else if (d->dec.sig.text[0] == 'N') {
  625.         d->dec.sig.length = 5;
  626.         d->dec.sig.text[1] = 'A';
  627.         d->dec.sig.text[2] = 'N';
  628.     }
  629. }
  630.  
  631. /* ---------- floating-point conversion ---------- */
  632.  
  633. #if powerc
  634. static void libf2d( int fixed, int precision, LibDecRec *d, long double x){
  635.     struct decform form;
  636.     
  637.     if (precision >= sizeof d->dec.sig)
  638.         precision = sizeof d->dec.sig - 1;
  639.  
  640.     if (fixed)
  641.         form.style = FIXEDDECIMAL;
  642.     else
  643.         form.style = FLOATDECIMAL;
  644.     form.digits = precision;
  645.     /*
  646.         Until the long double data type is really implemented, this must be a call
  647.         to num2dec and not num2decl even though the argument is declared as a long
  648.         double 
  649.     */
  650.     
  651.     num2dec( &form, x, &(d->dec) );
  652.     
  653.         /*  handle fixed-point overflow  */
  654.         
  655.     if (d->dec.sig.text[0] == '?') {
  656.         form.style = FLOATDECIMAL;
  657.         form.digits = sizeof d->dec.sig - 1;
  658.         num2dec( &form, x, &(d->dec));
  659.     }
  660.     post_conversion(d);
  661. #else
  662.  
  663. static void libf2d(int fixed, int precision, LibDecRec *d, long double x){
  664.     struct { char style; short digits; } form;
  665.     REGISTER short *p = (short *) &x;
  666.     
  667.         /*  point to SANE extended  */
  668.  
  669.     #if __option(mc68881) && _NATIVE_FP_
  670.         p[1] = p[0];
  671.     #endif
  672.     #if __option(mc68881) || !_NATIVE_FP_
  673.         p++;
  674.     #endif
  675.     
  676.         /*  convert to decimal record  */
  677.     
  678.     if (precision >= sizeof d->dec.sig)
  679.         precision = sizeof d->dec.sig - 1;
  680.     form.style = fixed;
  681.     form.digits = precision;
  682.     fp68k(&form, p, d, FX2DEC);
  683.     
  684.         /*  handle fixed-point overflow  */
  685.         
  686.     if (d->dec.sig.text[0] == '?') {
  687.         form.style = 0;
  688.         form.digits = sizeof d->dec.sig - 1;
  689.         fp68k(&form, p, d, FX2DEC);
  690.     }
  691.     
  692.     post_conversion(d);    
  693.  
  694. }
  695. #endif // __powerc
  696. #endif // no floating
  697. #endif // use ansi
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.