/****************************************************************************/ /* */ /* _ P r i n t f M o d u l e */ /* --------------------------- */ /* */ /* This module is called through the single entry point "_printf" to */ /* perform the conversions and output for the library functions: */ /* */ /* printf - Formatted print to standard output */ /* fprintf - Formatted print to stream file */ /* sprintf - Formatted print to string */ /* */ /* The calling routines are logically a part of this module, but are */ /* compiled separately to save space in the user's program when only */ /* one of the library routines is used. */ /* */ /* The following routines are present: */ /* */ /* _printf Internal printf conversion / output */ /* _prnt8 Octal conversion routine */ /* _prntx Hex conversion routine */ /* __conv Decimal ASCII to binary routine */ /* _putstr Output character to string routine */ /* _prnt1 Decimal conversion routine */ /* */ /* The following routines are called: */ /* */ /* strlen Compute length of a string */ /* putc Stream output routine */ /* ftoa Floating point output conversion routine */ /* */ /* */ /* This routine depends on the fact that the argument list is always */ /* composed of LONG data items. */ /* */ /* Configured for Whitesmith's C on VAX. "putc" arguments are */ /* reversed from UNIX. */ /* */ /****************************************************************************/ /* * Include files: */ #include /* just the standard stuff */ /* * Local DEFINEs */ #define HIBIT 31 /* High bit number of LONG */ /* * Local static data: */ /****************************/ MLOCAL BYTE *_ptrbf = 0; /* Buffer Pointer */ MLOCAL BYTE *_ptrst = 0; /* -> File/string (if any) */ MLOCAL BYTE *__fmt = 0; /* Format Pointer */ /****************************/ /***************************************************************************** * * P R I N T F I N T E R N A L R O U T I N E * --------------------------------------------- * * Routine "_printf" is used to handle all "printf" functions, including * "sprintf", and "fprintf". * * Calling Sequence: * * _printf(fd,func,fmt,arg1); * * Where: * * fd Is the file or string pointer. * func Is the function to handle output. * fmt Is the address of the format string. * arg1 Is the address of the first arg. * * * Returns: * * Number of characters output * * Bugs: * * It is assumed that args are contiguous starting at "arg1", and that * all are the same size (LONG), except for floating point. * * *****************************************************************************/ _printf(fd,f,fmt,a1) /****************************/ LONG fd; /* Not really, but ... */ LONG (*f)(); /* Function pointer */ BYTE *fmt; /* -> Format string */ LONG *a1; /* -> Arg list */ { /****************************/ LOCAL BYTE c; /* Format character temp */ LOCAL BYTE *s; /* Output string pointer */ LOCAL BYTE adj; /* Right/left adjust flag */ LOCAL BYTE buf[30]; /* Temporary buffer */ /****************************/ LOCAL LONG *adx; /* Arg Address temporary */ LOCAL LONG x; /* Arg Value temporary */ LOCAL LONG n; /* String Length Temp */ LOCAL LONG m; /* Field Length Temporary */ LOCAL LONG width; /* Field width */ LOCAL LONG prec; /* Precision for "%x.yf" */ LOCAL LONG padchar; /* '0' or ' ' (padding) */ LOCAL DOUBLE zz; /* Floating temporary */ LOCAL DOUBLE *dblptr; /* Floating temp. address */ LOCAL LONG ccount; /* Character count */ EXTERN _putstr(); /* Reference function */ /***************************/ /***************************/ ccount = 0; /* Initially no characters */ _ptrbf = buf; /* Set buffer pointer */ adx = a1; /* Copy address variable */ _ptrst = fd; /* Copy file descriptor */ __fmt = fmt; /* Copy format address */ /***************************/ if(*__fmt == 'L' || *__fmt == 'l') /* Skip long output */ __fmt++; /* conversions */ /* */ /************************************************* */ /* This is the main format conversion loop. Load a character from the */ /* format string. If the character is '%', perform the appropriate */ /* conversion. Otherwise, just output the character. */ /************************************************* */ /* */ while( c = *__fmt++ ) /* Pick up next format char*/ { /* */ if(c != '%') /***************************/ { /* */ (*f)(fd,c); /* If not '%', just output */ ccount++; /* Bump character count */ } /***************************/ else /* It is a '%', */ { /* convert */ x = *adx++; /* x = address of next arg */ /***************************/ if( *__fmt == '-' ) /* Check for left adjust */ { /***************************/ adj = 'l'; /* Is left, set flag */ __fmt++; /* Bump format pointer */ } /* */ else /* Right adjust */ adj = 'r'; /***************************/ /* */ padchar=(*__fmt=='0') ? '0' : ' '; /* Select Pad character */ /***************************/ width = __conv(); /* Convert width (if any) */ /***************************/ if( *__fmt == '.') /* '.' means precision spec*/ { /* */ ++__fmt; /* Bump past '.' */ prec = __conv(); /* Convert precision spec */ } /* */ else /* None specified */ prec = 0; /***************************/ /* */ s = 0; /* Assume no output string */ switch ( c = *__fmt++ ) /* Next char is conversion */ { /* */ case 'D': /* Decimal */ case 'd': /* */ _prt1(x); /* Call decimal print rtn */ break; /* Go do output */ /***************************/ case 'o': /* Octal */ case 'O': /* Print */ _prnt8(x); /* Call octal printer */ break; /* Go do output */ /***************************/ case 'x': /* Hex */ case 'X': /* Print */ _prntx(x); /* Call conversion routine */ break; /* Go do output */ /***************************/ case 'S': /* String */ case 's': /* Output? */ s=x; /* Yes, (easy) */ break; /* Go finish up */ /***************************/ case 'C': /* Character */ case 'c': /* Output? */ *_ptrbf++ = x&0377; /* Just load buffer */ break; /* Go output */ /***************************/ case 'E': /* Floating point? */ case 'e': /* */ case 'F': /* */ case 'f': /* */ dblptr = adx-1; /* Assumes 64 bit float! */ zz = *dblptr; /* Load value */ adx =+ 1; /* Bump past second word */ ftoa (zz, buf, prec, c); /* Call floating conversion*/ prec = 0; /* Fake out padding routine*/ s = buf; /* just like string print */ break; /* Go Output */ /***************************/ default: /* None of the above? */ (*f)(fd,c); /* Just Output */ ccount++; /* Count it. */ adx--; /* Fix arg address */ } /* End switch */ /***************************/ if (s == 0) /* If s = 0, string is in */ { /* "buf", */ *_ptrbf = '\0'; /* Insure termination */ s = buf; /* Load address */ } /***************************/ /* */ n = strlen (s); /* Compute converted length*/ n = (prec 0) /* Pad in front */ { /* */ (*f)(fd,padchar); /* Thusly */ ccount++; /* Count it */ } /* */ /***************************/ while (n--) /* Output Converted */ { /* */ (*f)(fd,*s++); /* Data */ ccount++; /* Count it */ } /* */ /***************************/ while (m-- > 0) /* If left adjust, */ { /* */ (*f)(fd,padchar); /* Pad */ ccount++; /* Count padded characters */ } /***************************/ _ptrbf = buf; /* Reset buffer pointer */ } /* End else */ } /* End while */ if((*f) == _putstr) /* If string output, */ (*f)(fd,'\0'); /* Drop in terminator char */ /***************************/ return(ccount); /* Return appropriate value*/ } /* End _printf */ /***************************/ /****************************************************************************/ /* */ /* _ P R N T 8 P R O C E D U R E */ /* ------------------------------- */ /* */ /* Routine "_prnt8" converts a binary LONG value to octal ascii. */ /* The area at "_ptrbf" is used. */ /* */ /* Calling Sequence: */ /* */ /* _prnt8(n); */ /* */ /* "n" is the number to be converted. */ /* */ /* Returns: */ /* */ /* (none) */ /* */ /****************************************************************************/ VOID _prnt8 (n) /* */ LONG n; /* Number to convert */ { /* */ REG WORD p; /* Counts bits */ REG WORD k; /* Temporary 3-bit value */ REG WORD sw; /* Switch 1 => output */ /****************************/ if (n==0) /* Handle 0 as special case */ { /* */ *_ptrbf++ = '0'; /* Put in one zero */ return; /* And quit */ } /* */ /****************************/ sw = 0; /* Indicate no output yet */ /* */ for (p=HIBIT; p >= 0; p =- 3) /* Use 3 bits at a time */ /* */ if ((k = (n>>p)&07) || sw) /* Need to output yet? */ { /* */ if (p==HIBIT) /* 1st digit has only 2 bits*/ k = k & 02; /* Mask appropriately */ *_ptrbf++ = '0' + k; /* ASCIIfy digit */ sw = 1; /* Set output flag */ } /* End if */ } /* End _prnt8 */ /****************************/ /****************************************************************************/ /* */ /* _ P r n t x F u n c t i o n */ /* ----------------------------- */ /* */ /* The "_prntx" function converts a binary LONG quantity to hex ASCII */ /* and stores the result in "*_ptrbf". Leading zeros are suppressed. */ /* */ /* Calling sequence: */ /* */ /* _prntx(n); */ /* */ /* where "n" is the value to be converted. */ /* */ /* Returns: */ /* */ /* (none) */ /* */ /****************************************************************************/ VOID _prntx (n) /* */ LONG n; /* 32 bits */ { /****************************/ REG LONG d; /* A digit */ REG LONG a; /* Temporary value */ /****************************/ if (a = n>>4) /* Peel off low 4 bits */ _prntx ( a & 0xfffffff); /* If <> 0, print first */ d = n&017; /* Take low four bits */ *_ptrbf++ = d > 9 ? 'A'+d-10 : '0' + d;/* ASCIIfy into buffer */ } /****************************/ /****************************************************************************/ /* */ /* _ _ C o n v F u n c t i o n */ /* ----------------------------- */ /* */ /* Function "__conv" is used to convert a decimal ASCII string in */ /* the format to binary. */ /* */ /* Calling Sequence: */ /* */ /* val = __conv(); */ /* */ /* Returns: */ /* */ /* "val" is the converted value */ /* Zero is returned if no value */ /* */ /****************************************************************************/ LONG __conv() /* */ { /****************************/ REG BYTE c; /* Character temporary */ REG LONG n; /* Accumulator */ /****************************/ n = 0; /* Zero found so far */ while(((c= *__fmt++) >= '0') /* While c is a digit */ && (c <= '9')) /* */ n = n*10+c-'0'; /* Add c to accumulator */ __fmt--; /* Back up format pointer to*/ /* character skipped above */ return(n); /* See, wasn't that simple? */ } /****************************/ /****************************************************************************/ /* */ /* _ P u t s t r F u n c t i o n */ /* ------------------------------- */ /* */ /* Function "_putstr" is used by "sprintf" as the output function */ /* argument to "_printf". A single character is copied to the buffer */ /* at "_ptrst". */ /* */ /* Calling Sequence: */ /* */ /* _putstr(str,chr); */ /* */ /* where "str" is a dummy argument necessary because the other output */ /* functions have two arguments. */ /* */ /* Returns: */ /* */ /* (none) */ /* */ /****************************************************************************/ VOID _putstr(str,chr) /* */ REG BYTE chr; /* The output character */ BYTE *str; /* Dummy argument */ { /****************************/ *_ptrst++ = chr; /* Output the character */ return(0); /* Go back */ } /****************************/ /****************************************************************************/ /* */ /* _ P r t 1 F u n c t i o n */ /* --------------------------- */ /* */ /* Function "_prt1" converts a LONG binary quantity to decimal ASCII */ /* at the buffer pointed to by "_ptrbf". */ /* */ /* Calling Sequence: */ /* */ /* _prt1(n); */ /* */ /* where "n" is the value to be converted. */ /* */ /* Returns: */ /* */ /* (none) */ /* */ /****************************************************************************/ VOID _prt1(n) /* */ REG LONG n; /* Conversion input */ { /****************************/ REG LONG digs[15]; /* store digits here */ REG LONG *dpt; /* Points to last digit */ /****************************/ dpt = digs; /* Initialize digit pointer */ /****************************/ if (n >= 0) /* Fix */ n = -n; /* up */ else /* sign */ *_ptrbf++ = '-'; /* stuff */ /****************************/ for (; n != 0; n = n/10) /* Divide by 10 till zero */ *dpt++ = n%10; /* Store digit (reverse ord)*/ /****************************/ if (dpt == digs) /* Zero value? */ *dpt++ = 0; /* Yes, store 1 zero digit */ /****************************/ while (dpt != digs) /* Now convert to ASCII */ { /* */ --dpt; /* Decrement pointer */ *_ptrbf++ = '0' - *dpt; /* Note digits are negative!*/ } /* */ } /****************************/