home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************/
- /*** format.c: format routines ***/
- /*** Author: Christopher M. Caldwell of IO Software, Inc. ***/
- /*** Created: 09-Jul-86 ***/
- /*** "Do with as ye may" ***/
- /**************************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
-
- #define PF_COUNT 0
- #define PF_ARRAY 1
- #define PF_PUTC 2
- #define then
- #define TRUE 1
- #define FALSE 0
-
- static char *al;
- extern char *malloc();
-
- int lcase(c) char c; { return( isupper(c) ? tolower(c) : c ); }
- int ucase(c) char c; { return( islower(c) ? toupper(c) : c ); }
- int digtobin(c) char c; { return( c<='9' ? c-'0' : lcase(c)-'a'+10 ); }
- char bintodig(i)int i; { return ( i<=9 ? i+'0' : i+'a'-10 ); }
-
- int isbase( c, b )
- /* Return TRUE if character c is digit of base b. Similar to isdigit,
- but allows bases with letters and won't except "9" in base 8, etc.
- */
- char c;
- int b;
- {
- if( !isdigit(c) && !isalpha(c) )
- then return FALSE;
- else return( c<='9' ? (c-'0'<b) : (lcase(c)-'a'<b-10) );
- }
-
- int cformat(fmt,arglist) char *fmt; int arglist;
- /* Return number of characters generated by "printing" fmt. Used by
- things that need to malloc space for strings.
- */
- {
- int pf_count;
- al = (char *)&arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- return pf_count;
- }
-
- int cxformat(fmt,arglist) char *fmt, *arglist;
- /* Same as above but argument list is pointed to by second argument */
- {
- int pf_count;
- al = arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- return pf_count;
- }
-
- char *mformat(fmt,arglist) char *fmt; int arglist;
- /* Return pointer to malloced array of characters */
- {
- int pf_count;
- char *res;
- al = (char *)&arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
- al = (char *)&arglist;
- pf( fmt, PF_ARRAY, NULL, res, NULL );
- return res;
- }
-
- char *mxformat(fmt,arglist) char *fmt, *arglist;
- /* Same as above but argument list is pointed to by second argument */
- {
- int pf_count;
- char *res;
- al = arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
- al = arglist;
- pf( fmt, PF_ARRAY, NULL, res, NULL );
- return res;
- }
-
- char *sformat(res,fmt,arglist) char *fmt, *res; int arglist;
- /* Return pointer to malloced array of characters if res==NULL,
- else fill array res with characters.
- */
- {
- int pf_count;
- if( res==NULL )
- then
- {
- al = (char *)&arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
- }
- al = (char *)&arglist;
- pf( fmt, PF_ARRAY, NULL, res, NULL );
- return res;
- }
-
- char *sxformat(res,fmt,arglist) char *fmt, *res, *arglist;
- /* Same as above but argument list is pointed to by second argument */
- {
- int pf_count;
- if( res==NULL )
- then
- {
- al = arglist;
- pf( fmt, PF_COUNT, &pf_count, NULL, NULL );
- if( (res=malloc(pf_count+1)) == NULL ) then return NULL;
- }
- al = arglist;
- pf( fmt, PF_ARRAY, NULL, res, NULL );
- return res;
- }
-
- int format(fmt,arglist) char *fmt; int arglist;
- /* Print characters to standard out. */
- {
- al = (char *)&arglist;
- return pf( fmt, PF_PUTC, NULL, NULL, stdout );
- }
-
- int xformat(fmt,arglist) char *fmt, *arglist;
- /* Same as above but argument list is pointed to by second argument */
- {
- al = arglist;
- return pf( fmt, PF_PUTC, NULL, NULL, stdout );
- }
-
- int fformat(outfile,fmt,arglist) FILE *outfile; char *fmt; int arglist;
- /* Print characters to specified file stream. */
- {
- al = (char *)&arglist;
- return pf( fmt, PF_PUTC, NULL, NULL, outfile );
- }
-
- int fxformat(outfile,fmt,arglist) FILE *outfile; char *fmt, *arglist;
- /* Same as above but argument list is pointed to by second argument */
- {
- al = arglist;
- return pf( fmt, PF_PUTC, NULL, NULL, outfile );
- }
-
- #define NEXT(mode) ((mode *)(al += sizeof(mode)))[-1]
-
- static int pf( fs, pf_func, pf_count, pf_addr, pf_file )
- /* This routine is called to parse the format string. If pf_func
- is PF_COUNT, that would be generated is returned. If pf_func
- is PF_ARRAY, an array is filled. If pf_func is PF_FILE, characters
- are sent to the stream pf_file.
- */
- char *fs;
- int pf_func;
- int *pf_count;
- char *pf_addr;
- FILE *pf_file;
- {
- int pf_right, pf_left, pf_center, pf_dec, pf_max;
- int pf_base, pf_iter, pf_pad, pf_unsigned;
- char *pf_string, pf_char;
- int pf_int;
- long pf_long;
- double pf_double;
- double pnum;
- int ind;
- char t, c, buf[512], *cp;
- int bufcnt;
- int pbase;
- int nm;
- char *saveal;
-
- while( c = *fs++ )
- if( c != '{' || (t = *fs++) == '{' )
- then
- switch( pf_func )
- {
- case PF_COUNT: (*pf_count)++; break;
- case PF_ARRAY: *pf_addr++ = c; break;
- case PF_PUTC: if( putc(c,pf_file) == EOF )
- then return EOF;
- else break;
- }
- else
- {
- pf_right = 0;
- pf_left = 0;
- pf_center = 0;
- pf_dec = 6;
- pf_max = 0;
- pf_base = 10;
- pf_iter = 1;
- pf_pad = ' ';
- pf_unsigned = FALSE;
- switch( t )
- {
- case 'S': pf_string = NEXT(char *); break;
- case 's': pf_string = NEXT(char *); break;
- case 'c': pf_char = NEXT(int); break;
- case 'i': pf_int = NEXT(int); break;
- case 'l': pf_long = NEXT(long); break;
- case 'f': pf_double = NEXT(double); break;
- default: /* $$$ added during port to Amiga */
- break;
- }
- while( (c = *fs++) != '}' )
- {
- nm = 0;
- pbase = 10;
- if( !isbase(*fs,pbase) )
- then nm = NEXT(int);
- else
- {
- while( TRUE )
- {
- while( isbase(*fs,pbase) )
- nm = pbase*nm + digtobin(*fs++);
- if( nm<2 || nm>36 || *fs!='_' ) then break;
- pbase = nm;
- fs++;
- }
- }
- switch( c )
- {
- case 'r': pf_right = nm; break;
- case 'l': pf_left = nm; break;
- case 'c': pf_center = nm; break;
- case '.': pf_dec = nm; break;
- case 'm': pf_max = nm; break;
- case 'b': pf_base = nm; break;
- case 'n': pf_iter = nm; break;
- case 'p': pf_pad = nm; break;
- case 'u': pf_unsigned = nm; break;
- }
- }
- bufcnt = 0;
- switch( t )
- {
- case 's': if( pf_string == NULL )
- then cp = "(null)";
- else cp = pf_string;
- bufcnt = strlen( cp );
- break;
-
- case 'S': saveal = al;
- pf(pf_string,PF_COUNT,&bufcnt,NULL,NULL);
- al = saveal;
- cp = malloc( bufcnt+1 );
- pf(pf_string,PF_ARRAY,NULL,cp,NULL);
- break;
-
- case 'c': buf[bufcnt++] = pf_char;
- cp = buf;
- break;
-
- case 'i': pf_char = ( pf_int < 0 );
- if( pf_int >= 0 || !pf_unsigned )
- then
- {
- do {
- buf[100-(++bufcnt)]
- = bintodig( abs(pf_int%pf_base) );
- pf_int /= pf_base;
- } while( pf_int != 0 );
- if(pf_char) then buf[100-(++bufcnt)]='-';
- cp = buf;
- cp += (100 - bufcnt);
- }
- else
- {
- c = pf_int & 1;
- pf_int >>= 1;
- pf_int &= (1<<(sizeof(pf_int)-1));
- c = c + ((pf_int%(pf_base>>1)) << 1);
- pf_int /= (pf_base>>1);
- buf[100-(++bufcnt)] = bintodig( c );
- while( pf_int != 0 )
- {
- buf[100-(++bufcnt)]
- = bintodig( abs(pf_int%pf_base) );
- pf_int /= pf_base;
- }
- cp = buf;
- cp += (100 - bufcnt);
- }
- break;
-
- case 'l': pf_char = ( pf_long < 0 );
- if( pf_long >= 0 || !pf_unsigned )
- then
- {
- do {
- buf[100-(++bufcnt)] = bintodig(
- abs((int)(pf_long%pf_base)) );
- pf_long /= pf_base;
- } while( pf_long != 0 );
- if(pf_char) then buf[100-(++bufcnt)]='-';
- cp = buf;
- cp += (100 - bufcnt);
- }
- else
- {
- c = pf_long & 1;
- pf_long >>= 1;
- pf_long &= (1<<(sizeof(pf_long)-1));
- c = c + ((pf_long%(pf_base>>1)) << 1);
- pf_long /= (pf_base>>1);
- buf[100-(++bufcnt)] = bintodig( c );
- while( pf_long != 0 )
- {
- buf[100-(++bufcnt)] = bintodig(
- abs((int)(pf_long%pf_base)) );
- pf_long /= pf_base;
- }
- cp = buf;
- cp += (100 - bufcnt);
- }
- break;
-
- case 'f': if( pf_double < 0 )
- then
- {
- buf[bufcnt++] = '-';
- pf_double = -pf_double;
- }
- ind = 0;
- for(pnum=1.0; pnum<=pf_double; pnum*=pf_base)
- ind--;
- pnum /= pf_base;
- do {
- if( ind++ == 0 ) then buf[bufcnt++]='.';
- c = (int)(pf_double/pnum);
- buf[bufcnt++] = bintodig( c );
- pf_double -= (pnum*c);
- pnum /= pf_base;
- } while( ind < pf_dec );
- cp = buf;
- break;
- }
- if( bufcnt > pf_max && pf_max > 0 ) then bufcnt = pf_max;
- if( pf_center > 0 )
- then
- {
- pf_left = ( pf_center - bufcnt ) / 2;
- pf_right = pf_center - pf_left - bufcnt;
- }
- else
- {
- pf_left -= bufcnt;
- pf_right -= bufcnt;
- }
- while( pf_iter-- > 0 )
- {
- for( ind=0; ind<pf_right; ind++ )
- switch( pf_func )
- {
- case PF_COUNT: (*pf_count)++; break;
- case PF_ARRAY: *pf_addr++ = pf_pad; break;
- case PF_PUTC: if( putc(pf_pad,pf_file) == EOF )
- then return EOF;
- else break;
- }
- for( ind=0; ind<bufcnt; ind++ )
- switch( pf_func )
- {
- case PF_COUNT: (*pf_count)++; break;
- case PF_ARRAY: *pf_addr++ = cp[ind]; break;
- case PF_PUTC: if( putc(cp[ind],pf_file) == EOF )
- then return EOF;
- else break;
- }
- for( ind=0; ind<pf_left; ind++ )
- switch( pf_func )
- {
- case PF_COUNT: (*pf_count)++; break;
- case PF_ARRAY: *pf_addr++ = pf_pad; break;
- case PF_PUTC: if( putc(pf_pad,pf_file) == EOF )
- then return EOF;
- else break;
- }
- }
- if( t == 'S' ) then free( cp );
- }
- if( pf_func == PF_ARRAY ) then *pf_addr = 0;
- return 0;
- }
-