home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 109.lha / PD_C / lib / format.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  16KB  |  388 lines

  1. /**************************************************************************/
  2. /***     format.c: format routines                                             ***/
  3. /***     Author:             Christopher M. Caldwell of IO Software, Inc.      ***/
  4. /***     Created:  09-Jul-86                                         ***/
  5. /***     "Do with as ye may"                                                   ***/
  6. /**************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <ctype.h>
  10.  
  11. #define PF_COUNT   0
  12. #define PF_ARRAY   1
  13. #define PF_PUTC              2
  14. #define then
  15. #define TRUE                 1
  16. #define FALSE                0
  17.  
  18. static char *al;
  19. extern char *malloc();
  20.  
  21. int lcase(c)       char c;             { return( isupper(c) ? tolower(c) : c ); }
  22. int ucase(c)       char c;             { return( islower(c) ? toupper(c) : c ); }
  23. int digtobin(c)    char c;             { return( c<='9' ? c-'0' : lcase(c)-'a'+10 ); }
  24. char bintodig(i)int i;                 { return ( i<=9 ? i+'0' : i+'a'-10 ); }
  25.  
  26. int isbase( c, b )
  27. /*       Return TRUE if character c is digit of base b.  Similar to isdigit,
  28.          but allows bases with letters and won't except "9" in base 8, etc.
  29. */
  30.     char c;
  31.     int b;
  32.     {
  33.     if( !isdigit(c) && !isalpha(c) )
  34.       then return FALSE;
  35.       else return( c<='9' ? (c-'0'<b) : (lcase(c)-'a'<b-10) );
  36.     }
  37.  
  38. int cformat(fmt,arglist)               char *fmt; int arglist;
  39. /*       Return number of characters generated by "printing" fmt.  Used by
  40.          things that need to malloc space for strings.
  41. */
  42.     {
  43.     int pf_count;
  44.     al = (char *)&arglist;
  45.     pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  46.     return pf_count;
  47.     }
  48.  
  49. int cxformat(fmt,arglist)              char *fmt, *arglist;
  50. /*       Same as above but argument list is pointed to by second argument */
  51.     {
  52.     int pf_count;
  53.     al = arglist;
  54.     pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  55.     return pf_count;
  56.     }
  57.  
  58. char *mformat(fmt,arglist)             char *fmt; int arglist;
  59. /*       Return pointer to malloced array of characters    */
  60.     {
  61.     int pf_count;
  62.     char *res;
  63.     al = (char *)&arglist;
  64.     pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  65.     if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
  66.     al = (char *)&arglist;
  67.     pf( fmt, PF_ARRAY, NULL, res, NULL );
  68.     return res;
  69.     }
  70.  
  71. char *mxformat(fmt,arglist)            char *fmt, *arglist;
  72. /*       Same as above but argument list is pointed to by second argument */
  73.     {
  74.     int pf_count;
  75.     char *res;
  76.     al = arglist;
  77.     pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  78.     if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
  79.     al = arglist;
  80.     pf( fmt, PF_ARRAY, NULL, res, NULL );
  81.     return res;
  82.     }
  83.  
  84. char *sformat(res,fmt,arglist)                   char *fmt, *res; int arglist;
  85. /*       Return pointer to malloced array of characters if res==NULL,
  86.          else fill array res with characters.
  87. */
  88.     {
  89.     int pf_count;
  90.     if( res==NULL )
  91.       then
  92.          {
  93.          al = (char *)&arglist;
  94.          pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  95.          if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
  96.          }
  97.     al = (char *)&arglist;
  98.     pf( fmt, PF_ARRAY, NULL, res, NULL );
  99.     return res;
  100.     }
  101.  
  102. char *sxformat(res,fmt,arglist)                  char *fmt, *res, *arglist;
  103. /*       Same as above but argument list is pointed to by second argument */
  104.     {
  105.     int pf_count;
  106.     if( res==NULL )
  107.       then
  108.          {
  109.          al = arglist;
  110.          pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
  111.          if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
  112.          }
  113.     al = arglist;
  114.     pf( fmt, PF_ARRAY, NULL, res, NULL );
  115.     return res;
  116.     }
  117.  
  118. int format(fmt,arglist)                          char *fmt; int arglist;
  119. /*       Print characters to standard out. */
  120.     {
  121.     al = (char *)&arglist;
  122.     return pf( fmt, PF_PUTC, NULL, NULL, stdout );
  123.     }
  124.  
  125. int xformat(fmt,arglist)               char *fmt, *arglist;
  126. /*       Same as above but argument list is pointed to by second argument */
  127.     {
  128.     al = arglist;
  129.     return pf( fmt, PF_PUTC, NULL, NULL, stdout );
  130.     }
  131.  
  132. int fformat(outfile,fmt,arglist)       FILE *outfile; char *fmt; int arglist;
  133. /*       Print characters to specified file stream. */
  134.     {
  135.     al = (char *)&arglist;
  136.     return pf( fmt, PF_PUTC, NULL, NULL, outfile );
  137.     }
  138.  
  139. int fxformat(outfile,fmt,arglist)      FILE *outfile; char *fmt, *arglist;
  140. /*       Same as above but argument list is pointed to by second argument */
  141.     {
  142.     al = arglist;
  143.     return pf( fmt, PF_PUTC, NULL, NULL, outfile );
  144.     }
  145.  
  146. #define NEXT(mode) ((mode *)(al += sizeof(mode)))[-1]
  147.  
  148. static int pf( fs, pf_func, pf_count, pf_addr, pf_file )
  149. /*       This routine is called to parse the format string.  If pf_func
  150.          is PF_COUNT, that would be generated is returned.  If pf_func
  151.          is PF_ARRAY, an array is filled.  If pf_func is PF_FILE, characters
  152.          are sent to the stream pf_file.
  153. */
  154.     char *fs;
  155.     int pf_func;
  156.     int *pf_count;
  157.     char *pf_addr;
  158.     FILE *pf_file;
  159.     {
  160.     int pf_right, pf_left, pf_center, pf_dec, pf_max;
  161.     int pf_base, pf_iter, pf_pad, pf_unsigned;
  162.     char *pf_string, pf_char;
  163.     int pf_int;
  164.     long pf_long;
  165.     double pf_double;
  166.     double pnum;
  167.     int ind;
  168.     char t, c, buf[512], *cp;
  169.     int bufcnt;
  170.     int pbase;
  171.     int nm;
  172.     char *saveal;
  173.  
  174.     while( c = *fs++ )
  175.          if( c != '{' || (t = *fs++) == '{' )
  176.            then
  177.              switch( pf_func )
  178.                    {
  179.                    case PF_COUNT:      (*pf_count)++;                break;
  180.                    case PF_ARRAY:      *pf_addr++ = c;               break;
  181.                    case PF_PUTC:       if( putc(c,pf_file) == EOF )
  182.                                          then return EOF;
  183.                                          else break;
  184.                    }
  185.            else
  186.              {
  187.              pf_right        = 0;
  188.              pf_left         = 0;
  189.              pf_center       = 0;
  190.              pf_dec          = 6;
  191.              pf_max          = 0;
  192.              pf_base         = 10;
  193.              pf_iter         = 1;
  194.              pf_pad          = ' ';
  195.              pf_unsigned     = FALSE;
  196.              switch( t )
  197.                    {
  198.                    case 'S': pf_string = NEXT(char *);               break;
  199.                    case 's': pf_string = NEXT(char *);               break;
  200.                    case 'c': pf_char             = NEXT(int);                  break;
  201.                    case 'i': pf_int              = NEXT(int);                  break;
  202.                    case 'l': pf_long             = NEXT(long);                 break;
  203.                    case 'f': pf_double = NEXT(double);               break;
  204.         default: /* $$$ added during port to Amiga */
  205.                    break;
  206.                    }
  207.              while( (c = *fs++) != '}' )
  208.                    {
  209.                    nm = 0;
  210.                    pbase = 10;
  211.                    if( !isbase(*fs,pbase) )
  212.                      then nm = NEXT(int);
  213.                      else
  214.                        {
  215.                        while( TRUE )
  216.                              {
  217.                              while( isbase(*fs,pbase) )
  218.                                  nm = pbase*nm + digtobin(*fs++);
  219.                              if( nm<2 || nm>36 || *fs!='_' ) then break;
  220.                              pbase = nm;
  221.                              fs++;
  222.                              }
  223.                        }
  224.                    switch( c )
  225.                        {
  226.                        case 'r':       pf_right = nm;                break;
  227.                        case 'l':       pf_left = nm;                 break;
  228.                        case 'c':       pf_center = nm;               break;
  229.                        case '.':       pf_dec = nm;                  break;
  230.                        case 'm':       pf_max = nm;                  break;
  231.                        case 'b':       pf_base = nm;                 break;
  232.                        case 'n':       pf_iter = nm;                 break;
  233.                        case 'p':       pf_pad = nm;                  break;
  234.                        case 'u':       pf_unsigned = nm;   break;
  235.                        }
  236.                    }
  237.              bufcnt = 0;
  238.              switch( t )
  239.                    {
  240.                    case 's': if( pf_string == NULL )
  241.                                          then cp = "(null)";
  242.                                          else cp = pf_string;
  243.                                        bufcnt = strlen( cp );
  244.                                        break;
  245.  
  246.                    case 'S': saveal = al;
  247.                                        pf(pf_string,PF_COUNT,&bufcnt,NULL,NULL);
  248.                                        al = saveal;
  249.                                        cp = malloc( bufcnt+1 );
  250.                                        pf(pf_string,PF_ARRAY,NULL,cp,NULL);
  251.                                        break;
  252.  
  253.                    case 'c': buf[bufcnt++] = pf_char;
  254.                                        cp = buf;
  255.                                        break;
  256.  
  257.                    case 'i': pf_char = ( pf_int < 0 );
  258.                                        if( pf_int >= 0 || !pf_unsigned )
  259.                                          then
  260.                                            {
  261.                                            do  {
  262.                                                  buf[100-(++bufcnt)]
  263.                                                      = bintodig( abs(pf_int%pf_base) );
  264.                                                  pf_int /= pf_base;
  265.                                                  } while( pf_int != 0 );
  266.                                            if(pf_char) then buf[100-(++bufcnt)]='-';
  267.                                            cp = buf;
  268.                                            cp += (100 - bufcnt);
  269.                                            }
  270.                                          else
  271.                                            {
  272.                                            c = pf_int & 1;
  273.                                            pf_int >>= 1;
  274.                                            pf_int &= (1<<(sizeof(pf_int)-1));
  275.                                            c = c + ((pf_int%(pf_base>>1)) << 1);
  276.                                            pf_int /= (pf_base>>1);
  277.                                            buf[100-(++bufcnt)] = bintodig( c );
  278.                                            while( pf_int != 0 )
  279.                                                  {
  280.                                                  buf[100-(++bufcnt)]
  281.                                                      = bintodig( abs(pf_int%pf_base) );
  282.                                                  pf_int /= pf_base;
  283.                                                  }
  284.                                            cp = buf;
  285.                                            cp += (100 - bufcnt);
  286.                                            }
  287.                                        break;
  288.  
  289.                    case 'l': pf_char = ( pf_long < 0 );
  290.                                        if( pf_long >= 0 || !pf_unsigned )
  291.                                          then
  292.                                            {
  293.                                            do  {
  294.                                                  buf[100-(++bufcnt)] = bintodig(
  295.                                                      abs((int)(pf_long%pf_base)) );
  296.                                                  pf_long /= pf_base;
  297.                                                  } while( pf_long != 0 );
  298.                                            if(pf_char) then buf[100-(++bufcnt)]='-';
  299.                                            cp = buf;
  300.                                            cp += (100 - bufcnt);
  301.                                            }
  302.                                          else
  303.                                            {
  304.                                            c = pf_long & 1;
  305.                                            pf_long >>= 1;
  306.                                            pf_long &= (1<<(sizeof(pf_long)-1));
  307.                                            c = c + ((pf_long%(pf_base>>1)) << 1);
  308.                                            pf_long /= (pf_base>>1);
  309.                                            buf[100-(++bufcnt)] = bintodig( c );
  310.                                            while( pf_long != 0 )
  311.                                                  {
  312.                                                  buf[100-(++bufcnt)] = bintodig(
  313.                                                      abs((int)(pf_long%pf_base)) );
  314.                                                  pf_long /= pf_base;
  315.                                                  }
  316.                                            cp = buf;
  317.                                            cp += (100 - bufcnt);
  318.                                            }
  319.                                        break;
  320.  
  321.                    case 'f': if( pf_double < 0 )
  322.                                          then
  323.                                            {
  324.                                            buf[bufcnt++] = '-';
  325.                                            pf_double = -pf_double;
  326.                                            }
  327.                                        ind = 0;
  328.                                        for(pnum=1.0; pnum<=pf_double; pnum*=pf_base)
  329.                                            ind--;
  330.                                        pnum /= pf_base;
  331.                                        do  {
  332.                                            if( ind++ == 0 ) then buf[bufcnt++]='.';
  333.                                            c = (int)(pf_double/pnum);
  334.                                            buf[bufcnt++] = bintodig( c );
  335.                                            pf_double -= (pnum*c);
  336.                                            pnum /= pf_base;
  337.                                            } while( ind < pf_dec );
  338.                                        cp = buf;
  339.                                        break;
  340.                    }
  341.              if( bufcnt > pf_max && pf_max > 0 ) then bufcnt = pf_max;
  342.              if( pf_center > 0 )
  343.                then
  344.                    {
  345.                    pf_left = ( pf_center - bufcnt ) / 2;
  346.                    pf_right = pf_center - pf_left - bufcnt;
  347.                    }
  348.                else
  349.                    {
  350.                    pf_left -= bufcnt;
  351.                    pf_right -= bufcnt;
  352.                    }
  353.              while( pf_iter-- > 0 )
  354.                    {
  355.                    for( ind=0; ind<pf_right; ind++ )
  356.                        switch( pf_func )
  357.                              {
  358.                              case PF_COUNT:      (*pf_count)++;                break;
  359.                              case PF_ARRAY:      *pf_addr++ = pf_pad;          break;
  360.                              case PF_PUTC:       if( putc(pf_pad,pf_file) == EOF )
  361.                                                    then return EOF;
  362.                                                    else break;
  363.                              }
  364.                    for( ind=0; ind<bufcnt; ind++ )
  365.                        switch( pf_func )
  366.                              {
  367.                              case PF_COUNT:      (*pf_count)++;                break;
  368.                              case PF_ARRAY:      *pf_addr++ = cp[ind];         break;
  369.                              case PF_PUTC:       if( putc(cp[ind],pf_file) == EOF )
  370.                                                    then return EOF;
  371.                                                    else break;
  372.                              }
  373.                    for( ind=0; ind<pf_left; ind++ )
  374.                        switch( pf_func )
  375.                              {
  376.                              case PF_COUNT:      (*pf_count)++;                break;
  377.                              case PF_ARRAY:      *pf_addr++ = pf_pad;          break;
  378.                              case PF_PUTC:       if( putc(pf_pad,pf_file) == EOF )
  379.                                                    then return EOF;
  380.                                                    else break;
  381.                              }
  382.                    }
  383.              if( t == 'S' ) then free( cp );
  384.              }
  385.     if( pf_func == PF_ARRAY ) then *pf_addr = 0;
  386.     return 0;
  387.     }
  388.