bunscho@cs.vu.nl (Bunschoten Jacob Pieter) (12/04/87)
/* This version of doprintf.c can handle %% and optional arguments.
%% is recognized and printf("%%") gives a single %
printf("%*c",12,'a'); gives 11 spaces and then 'a'
modification made by Jacob P. Bunschoten
%-*.* works now too (JPB)
*/
#include "../include/stdio.h"
#define MAXDIGITS 12
#define PRIVATE static
#define IS_DIGIT(X) ('0' <= (X) && (X) <= '9')
/* This is the same as varargs , on BSD systems */
#define GET_ARG(arglist,mode) ((mode *)(arglist += sizeof(mode)))[-1]
_doprintf(fp, format, args)
FILE *fp;
register char *format;
int args;
{
register char *vl;
int r,
w1, w2,
sign;
long l;
char c;
char *s;
char padchar;
char a[MAXDIGITS];
vl = (char *) args;
while ( *format != '\0') {
if ( *format != '%' ) {
putc( *format++, fp );
continue;
}
format++; /* % seen */
if (*format == '%') { /* %% seen */
putc(*format++, fp);
continue;
}
w1 = 0;
w2 = 0;
sign = 1;
padchar = ' ';
if ( *format == '-' ) {
sign = -1;
format++;
}
if ( *format == '0') {
padchar = '0';
format++;
}
if ( IS_DIGIT(*format) || *format == '*') {
if (*format == '*') {
w1 = (int) GET_ARG(vl, int);
w1 *= sign;
format++;
} else {
while ( IS_DIGIT( *format )) {
w1 *= 10 ;
w1 += sign * ( *format - '0' );
format++;
}
}
}
if ( *format == '.'){
format++;
if ( IS_DIGIT( *format) || *format == '*') {
if (*format == '*') {
w2 = (int) GET_ARG(vl, int);
format++;
} else {
while ( IS_DIGIT( *format )) {
w2 *= 10;
w2 += *format - '0';
format++;
}
}
}
}
switch (*format) {
case 'd':
l = (long) GET_ARG(vl, int);
r = 10;
break;
case 'u':
l = (long) GET_ARG(vl, int);
l = l & 0xFFFF;
r = 10;
break;
case 'o':
l = (long) GET_ARG(vl, int);
if (l < 0) l = l & 0xFFFF;
r = 8;
break;
case 'x':
l = (long) GET_ARG(vl, int);
if (l < 0) l = l & 0xFFFF;
r = 16;
break;
case 'D':
l = (long) GET_ARG(vl, long);
r = 10;
break;
case 'O':
l = (long) GET_ARG(vl, long);
r = 8;
break;
case 'X':
l = (long) GET_ARG(vl, long);
r = 16;
break;
case 'c':
c = (char) GET_ARG(vl, int);
/* char's are casted back to int's */
a[0] = c; /* set c into a string */
a[1] = '\0';
_printit(a,w1,w2,padchar,strlen(a),fp);
format++;
continue;
case 's':
s = GET_ARG(vl, char *);
_printit(s,w1,w2,padchar,strlen(s),fp);
format++;
continue;
default:
putc('%',fp); /* why */
putc(*format++,fp);
continue;
}
_bintoascii (l, r, a);
_printit(a,w1,w2,padchar,strlen(a),fp);
format++;
}
}
PRIVATE _bintoascii (num, radix, a)
long num;
int radix;
char *a;
{
char b[MAXDIGITS];
int hit, negative;
register int n, i;
negative = 0;
if (num == 0) {
a[0] = '0';
a[1] = '\0';
return;
}
if (radix == 10) {
if (num < 0) {num = -num; negative++;}
}
for (n = 0; n < MAXDIGITS; n++)
b[n] = 0;
n = 0;
do {
if (radix == 10) {
b[n] = num % 10;
num = (num - b[n]) / 10;
}
if (radix == 8) {
b[n] = num & 0x7;
num = (num >> 3) & 0x1FFFFFFF;
}
if (radix == 16) {
b[n] = num & 0xF;
num = (num >> 4) & 0x0FFFFFFF;
}
n++;
}
while (num != 0);
/* Convert to ASCII. */
hit = 0;
for (i = n - 1; i >= 0; i--) {
if (b[i] == 0 && hit == 0) {
b[i] = ' ';
}
else {
if (b[i] < 10)
b[i] += '0';
else
b[i] += 'A' - 10;
hit++;
}
}
if (negative)
b[n++] = '-';
for(i = n - 1 ; i >= 0 ; i-- )
*a++ = b[i];
*a = '\0';
}
PRIVATE _printit(str, w1, w2, padchar, length, file)
char *str;
int w1, w2;
char padchar;
int length;
FILE *file;
{
int len2 = length;
int temp;
if ( w2 > 0 && length > w2)
len2 = w2;
temp = len2;
if ( w1 > 0 )
while ( w1-- > len2 )
putc(padchar,file);
while ( *str && ( len2-- != 0 ))
putc(*str++, file);
if ( w1 < 0 )
if ( padchar == '0' ){
putc('.',file);
w1++;
}
while ( w1++ < -temp )
putc(padchar,file);
}