home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Snippets / sscanf / sprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-07  |  9.9 KB  |  387 lines  |  [TEXT/ALFA]

  1. /*
  2. **
  3. ** DOES NOT DO FLOATING POINT!!!! (%f and %g and %e).
  4. **
  5. ** Written by Tim Endres, time@bomb.ice.com
  6. ** With permission to distribute.
  7. **
  8. ** -brent
  9. */
  10.  
  11. #define BUFSIZE 256
  12.  
  13. typedef struct
  14.   {
  15.    char buffer[BUFSIZE];
  16.    int count;
  17.   } bufrec;
  18.  
  19. int sputc();   
  20.  
  21. sprintf(str, fmt, args)
  22. char *str;
  23. char   *fmt;
  24. char   *args;
  25.   {
  26.    bufrec br;
  27.   
  28.     br.buffer[0] = '\0';
  29.     br.count = 1;
  30.    
  31.     _doprnt(fmt, &args, sputc, &br);
  32.     
  33.     strncpy(str, &br.buffer[1], br.count - 1);
  34.     str[br.count - 1] = '\0';
  35.     return (br.count - 1);
  36.   }
  37.  
  38. sputc(br, ch)
  39. bufrec *br;
  40. char ch;
  41.    {
  42.    br->buffer[(br->count)++] = ch;
  43.  }
  44.  
  45. #define MAX_DIGITS     16
  46.  
  47. #define MAX_INTEGER       2147483647
  48. #define INTEGER_HIBIT 0x80000000
  49.  
  50. #define isdigit(x)      ((x) - '0' >= 0 && (x) - '0' <= 9)
  51. #define tonumber(x)     ((x) - '0')
  52. #define todigit(x)      ((x) + '0')
  53.                                        
  54.  
  55. #define max(a,b) ((a) > (b)? (a): (b))
  56. #define min(a,b) ((a) < (b)? (a): (b))
  57.  
  58. int     _doprnt(format, args, func, farg)
  59. char    *format;
  60. char    *args;
  61. int     (*func)();
  62. int     *farg;
  63.     {
  64.         char *cp;
  65.         char *bp, *p;
  66.         int  width, prec;
  67.         char fcode;
  68.  
  69.         int   lzero;
  70.         short length;
  71.         short fplus;
  72.         short fminus;  
  73.         short fblank;  
  74.         short fsharp;
  75.         short fzero;
  76.  
  77.         char *prefix;
  78.                     
  79.         char buf[MAX_DIGITS];
  80.         long val;                
  81.                                     
  82.         char *tab;                     
  83.         int n, hradix, lowbit;
  84.  
  85.      char PlusStr[4];
  86.         char MinusStr[4];
  87.        char SpaceStr[4];
  88.        char EmptyStr[4];
  89.        char UpperHex[20];
  90.       char LowerHex[20];
  91.       char UHexPrefix[4];
  92.      char LHexPrefix[4];
  93.      
  94.         long *longptr;
  95.  
  96.       PlusStr[0] = '+'; PlusStr[1] = '\0';
  97.         MinusStr[0] = '-'; MinusStr[1] = '\0';
  98.       SpaceStr[0] = ' '; SpaceStr[1] = '\0';
  99.       EmptyStr[0] = '\0';
  100.      UHexPrefix[0] = '0'; UHexPrefix[1] = 'X'; UHexPrefix[2] = '\0';
  101.      LHexPrefix[0] = '0'; LHexPrefix[1] = 'x'; LHexPrefix[2] = '\0';
  102.      longptr = (long *)&UpperHex[0];
  103.      *longptr++ = '0123';
  104.         *longptr++ = '4567';
  105.         *longptr++ = '89AB';
  106.         *longptr++ = 'CDEF';
  107.         longptr = (long *)&LowerHex[0];
  108.      *longptr++ = '0123';
  109.         *longptr++ = '4567';
  110.         *longptr++ = '89ab';
  111.         *longptr++ = 'cdef';
  112.  
  113.         cp = format;
  114.  
  115.         while (*cp)
  116.          {
  117.            if (*cp != '%')
  118.              {
  119.                 /* Ordinary (non-%) character */
  120.                 (*func)(farg, *cp++);
  121.                 }
  122.          else {
  123.               /*
  124.               ** % character.
  125.              ** Parse the format specification.
  126.               */
  127.  
  128.               /* Scan the <flags> */
  129.               fzero = fplus = fminus = fblank = fsharp = 0;
  130.  
  131.            scan:
  132.            switch (*++cp)
  133.               {
  134.                case '+':
  135.                        fplus = 1;
  136.                       goto scan;
  137.               case '-':
  138.                        fminus = 1;
  139.                      goto scan;
  140.               case ' ':
  141.                        fblank = 1;
  142.                      goto scan;
  143.               case '#':
  144.               fsharp = 1;
  145.               goto scan;
  146.               case '0':
  147.                        fzero = 1;
  148.                       goto scan;
  149.               }
  150.  
  151.            /* Scan the field width */
  152.           if (*cp == '*')
  153.              {
  154.                width = *(int *)args;
  155.                args += sizeof(int);
  156.                 if (width < 0)
  157.                   {
  158.                    width = -width;
  159.                  fminus = 1;
  160.                  }
  161.                cp++;
  162.                }
  163.            else
  164.                 {
  165.                width = 0;
  166.               while (isdigit (*cp))
  167.                    {
  168.                    n = tonumber (*cp++);
  169.                    width = width * 10 + n;
  170.                  }
  171.                }
  172.  
  173.            /* Scan the precision */
  174.             if (*cp == '.')
  175.              {
  176.                /* '*' instead of digits? */
  177.                 if (*++cp == '*')
  178.                    {
  179.                    prec = *(int *)args; args += sizeof(int);
  180.                    cp++;
  181.                    }
  182.                else
  183.                     {
  184.                    prec = 0;
  185.                    while (isdigit (*cp))
  186.                        {
  187.                        n = tonumber (*cp++);
  188.                        prec = prec * 10 + n;
  189.                        }
  190.                    }
  191.                }
  192.            else
  193.                 prec = -1;
  194.  
  195.           /* Scan the length modifier */
  196.           length = 0;
  197.          
  198.             switch (*cp)
  199.                 {
  200.                case 'l':
  201.                    length = 1;
  202.                  /* No break */
  203.               case 'h':
  204.                    cp++;
  205.                }
  206.  
  207.            lzero = 0;
  208.           prefix = EmptyStr;
  209.  
  210.           switch (fcode = *cp++)
  211.               {
  212.                case 'd':
  213.                case 'u':
  214.                    hradix = 5;
  215.                  goto fixed;
  216.                  
  217.                 case 'D':
  218.                    fcode = 'd';
  219.                     length = 1;
  220.                  hradix = 5;
  221.                  goto fixed;
  222.  
  223.                 case 'o':
  224.                    hradix = 4;
  225.                  goto fixed;
  226.  
  227.                 case 'X':
  228.                case 'x':
  229.                    hradix = 8;
  230.  
  231.                 fixed:
  232.                   /* Establish default precision */
  233.                    if (prec < 0)
  234.                        prec = 1;
  235.  
  236.                    /* Fetch the argument to be printed */
  237.                   if (length)
  238.                      {
  239.                        val = *(long *)args; args += sizeof(long);
  240.                       }
  241.                    else if (fcode == 'd')
  242.                       {
  243.                        val = *(int *)args; args += sizeof(int);
  244.                         }
  245.                    else
  246.                         {
  247.                        val = *(unsigned *)args; args += sizeof(unsigned);
  248.                       }
  249.  
  250.                    /* If signed conversion, establish sign */
  251.                   if (fcode == 'd')
  252.                        {
  253.                        if (val < 0)
  254.                             {
  255.                            prefix = MinusStr;
  256.                           /*
  257.                           **   Negate, checking in
  258.                             **   advance for possible
  259.                            **   overflow.
  260.                           */
  261.                           if (val != INTEGER_HIBIT)
  262.                                val = -val;
  263.                          }
  264.                        else if (fplus)
  265.                          prefix = PlusStr;
  266.                        else if (fblank)
  267.                             prefix = SpaceStr;
  268.                       }
  269.  
  270.                    if (fzero)
  271.                       {
  272.                        int n = width - msstrlen (prefix);
  273.                       if (n > prec)
  274.                            prec = n;
  275.                        }
  276.  
  277.                    /* Set translate table for digits */
  278.                     if (fcode == 'X')
  279.                            tab = UpperHex;
  280.                  else
  281.                             tab = LowerHex;
  282.  
  283.                  /* Develop the digits of the value */
  284.                    p = bp = buf + MAX_DIGITS;
  285.                   while (val) {
  286.                            lowbit = val & 1;
  287.                            val = (val >> 1) & ~INTEGER_HIBIT;
  288.                           *--bp = tab[val % hradix * 2 + lowbit];
  289.                          val = val / hradix;
  290.                  }
  291.  
  292.                    /* Calculate padding zero requirement */
  293.                     lzero = bp - p + prec;
  294.  
  295.                   /* Handle the # flag */
  296.                  if (fsharp && bp != p)
  297.                           switch (fcode) {
  298.                             case 'o':
  299.                                    if (lzero < 1)
  300.                                           lzero = 1;
  301.                                   break;
  302.                           case 'x':
  303.                                    prefix = LHexPrefix;
  304.                                     break;
  305.                           case 'X':
  306.                                    prefix = UHexPrefix;
  307.                                     break;
  308.                           }
  309.  
  310.                    break;
  311.               case 'c':
  312.                    buf[0] = *(int *)args; args += sizeof(int);
  313.                  bp = &buf[0];
  314.                    p = bp + 1;
  315.                  break;
  316.   
  317.                 case 's':
  318.                    bp = *(char **)args; args += sizeof(char **);
  319.                    if (prec < 0)
  320.                        prec = MAX_INTEGER;
  321.                  
  322.                     for (n=0; *bp++ != '\0' && n < prec; n++);
  323.                   
  324.                     p = --bp;
  325.                    bp -= n;
  326.                     break;
  327.   
  328.                 case '\0':
  329.                   cp--;
  330.                    break;
  331.   
  332.                 default:
  333.                     p = bp = &fcode;
  334.                     p++;
  335.                     break;
  336.   
  337.                 }
  338.            
  339.             if (fcode != '\0')
  340.               {
  341.                /* Calculate number of padding blanks */
  342.                 int nblank;
  343.              nblank = width
  344.                       - (p - bp)
  345.                       - (lzero < 0 ? 0 : lzero)
  346.                        - msstrlen(prefix);
  347.  
  348.              /* Blanks on left if required */
  349.                 if (! fminus)
  350.                    while (--nblank >= 0)
  351.                        (*func) (farg,' ');
  352.  
  353.              /* Prefix, if any */
  354.                 while (*prefix != '\0')
  355.                  (*func) (farg, *prefix++);
  356.  
  357.               /* Zeroes on the left */
  358.                 while (--lzero >= 0)
  359.                     (*func) (farg, '0');
  360.                 
  361.                 /* The value itself */
  362.               while (bp < p)
  363.                   (*func) (farg, *bp++);
  364.               
  365.                 /* Blanks on the right if required */
  366.                if (fminus)
  367.                  while (--nblank >= 0)
  368.                        (*func) (farg, ' ');
  369.                 }
  370.            }
  371.        }
  372.  
  373.    return 1;
  374.    }
  375.  
  376. msstrlen(s)  /* msstrlen from K & R */
  377. char *s;
  378.  {
  379.    int n;
  380.   
  381.     for (n=0; *s != '\0'; s++) n++;
  382.  
  383.     return(n);
  384.   }
  385.  
  386.  
  387.