Category : Assembly Language Source Code
Archive   : MSCPOPUP.ZIP
Filename : PRINTF.C

 
Output of file : PRINTF.C contained in archive : MSCPOPUP.ZIP
/* Printf.c - Replaces standard library printf() function.
* This function is currently set up to call wputchar() to display data
* in a window, but can be easily changed to suit any application where
* a general-purpose print function is required.
*
* This printf() function differs from the standard printf() as follows:
* 1. Scientific (exponential) notation is not supported.
* 2. Strings are always left-justified within their print fields and are
* truncated if their length exceeds the width of the print field.
* The construct "%10s" always prints exactly ten characters; if the
* corresponding argument is less than ten characters long, the print
* field is padded on the right with spaces; otherwise, the first ten
* characters of the string are printed. This suited my needs at the
* time I wrote this code, but should be easily modifiable to conform
* with standard C.
* 3. When a field is padded, it is always padded with spaces (not with
* zeroes with the field width begins with a zero).
* 4. Integer output in binary is supported with the "%b" conversion
* character.
* 5. Newlines ('\n') are converted to CR-LF combinations by the printf()
* function.
* 6. Output of floating-point values with zero decimal digits ("%5.0f"
* construct, for example) is not supported.
* 7. True rounding is not supported; instead, the last printed digit after
* the decimal point in a floating-point number is rounded up by one
* if the next digit that would be printed is a 5 or greater, unless
* the last printed digit is a 9 in which case it is left alone.
*/

#include

/* #define INCLUDE_FP to include floating point support in printf();
* leave it out to keep the floating-point library from being brought
* into the program (which seems to make the program size about 13K
* smaller in the case of Microsoft C 4.0, for example).
*/
#define INCLUDE_FP

/* For most PC compilers, the largest long integer is 4294967295; MAX_FIELD
* must equal the length of this number plus three, or 13 in this case.
* It may be made larger if very large floating-point numbers are going
* to be output, as their integer portions are always output as long
* integers (there is currently no support for scientific notation).
*/
#define MAX_FIELD 25 /* Max length of integer in decimal */
/* digits */

#define YES 1
#define NO 0

typedef signed long SIGNED_LONG; /* Use "signed long" for MSC */
typedef unsigned long UNSIGNED_LONG; /* Use "unsigned long" for MSC */

/* For compilers that don't support unsigned long integers, simply define
* SIGNED_LONG and UNSIGNED_LONG as "long".
*/

void wputchar();

wprintf(ctrl, args)
char *ctrl, *args;

{
pf(ctrl, &args, wputchar);
}

pf(ctrl, argptr, out_func)
char *ctrl, *argptr;
void (*out_func)();

{
char c, *p;
long num;
int long_flag, left_jus;
int field_w, prec; /* Field width and precision of */
/* printed numbers */
int i;

#ifdef INCLUDE_FP
double fnum;
#endif

while (c=*ctrl++) {
if (c != '%') {
if (c == '\n')
(*out_func)('\r'); /* Convert \n to \r\n */
(*out_func)(c); /* If not conversion char, */
/* just print it */
}

else { /* Handle conversion character */
long_flag = left_jus = NO;
field_w = prec = 0;

for (;;)
if (*ctrl == '-') { /* Hyphen specifies left */
/* justification */
left_jus=YES;
++ctrl;
}

else if (isdigit(*ctrl)) /* If field width specified, */
field_w = read_num(&ctrl); /* read it. */

else if (*ctrl == '.') { /* If precision specified, */
++ctrl;
prec = read_num(&ctrl); /* read it too. */
}

else if (*ctrl == 'l') { /* Long integer argument flag */
long_flag=YES;
++ctrl;
}

else
break;

switch(*ctrl++) {
case 'c': /* Output a single character */
(*out_func)(*(char *)argptr);
argptr += sizeof(int); /* Char takes up same space as */
/* an int on the stack */
break;

case 's': /* Output a character string */
p = *(char **)argptr;

if (field_w == 0)
out_str(p, out_func);

else {
/* Note that if the field width is actually specified,
* it also determines the precision to which the
* string will be printed; that is, the output field
* will be exactly field_w characters long. This
* differs from the standard C implementation.
*/

while (*p && field_w) {
(*out_func)(*p++);
--field_w;
}
while (field_w--)
(*out_func)(' ');
}

argptr += sizeof(char *);
break;

case 'd': /* Signed integer output */
if (long_flag) {
num = *(long *)argptr;
argptr += sizeof(long);
} else {
num = (long)*(int *)argptr;
argptr += sizeof(int);
}

/* Display a signed decimal number: */
out_num(num, field_w, 0, left_jus, out_func, 10);
break;

case 'u': /* Unsigned integer output */
if (long_flag) {
num = *(long *)argptr;
argptr += sizeof(long);
} else {
num = (long)*(int *)argptr;
argptr += sizeof(int);
}

/* Display an unsigned decimal number: */
out_num(num, field_w, 1, left_jus, out_func, 10);
break;

case 'x': /* Hexadecimal integer output */
if (long_flag) {
num = *(long *)argptr;
argptr += sizeof(long);
} else {
num = (long)*(int *)argptr;
argptr += sizeof(int);
}

/* Output unsigned value in base 16: */
out_num(num, field_w, 1, left_jus, out_func, 16);
break;

case 'o': /* Octal integer output */
if (long_flag) {
num = *(long *)argptr;
argptr += sizeof(long);
} else {
num = (long)*(int *)argptr;
argptr += sizeof(int);
}

/* Output unsigned value in base 8: */
out_num(num, field_w, 1, left_jus, out_func, 8);
break;

case 'b': /* Binary integer output */
if (long_flag) {
num = *(long *)argptr;
argptr += sizeof(long);
} else {
num = (long)*(int *)argptr;
argptr += sizeof(int);
}

/* Output unsigned value in base 2: */
out_num(num, field_w, 1, left_jus, out_func, 2);
break;

#ifdef INCLUDE_FP /* #define INCLUDE_FP to include floating point support */

case 'f': /* Floating-point double- */
/* precision value output */
num = (long)(fnum = *(double *)argptr);
argptr += sizeof(double);

if (prec == 0)
prec = 6; /* Default precision is 6 */

if (fnum < 0)
out_num(-num, field_w-prec-1, 2, left_jus, out_func, 10);
else
out_num(num, field_w-prec-1, 0, left_jus, out_func, 10);

(*out_func)('.'); /* Always output decimal point */
fnum -= num; /* Remove int. portion of fnum */
if (fnum < 0)
fnum = -fnum; /* Make sure remainder is + */

for (i=1; i < prec; ++i) {
(*out_func)((int)(num = (long)(fnum *= 10.0)) + '0');
fnum -= num;
}

if (i > 0) { /* Print the last digit and */
/* round it up, except if it's */
/* a 9, leave it alone (this is */
/* not true rounding) */
num = (long)(fnum *= 10.0);
fnum -= num;
(*out_func)((int)(num +
((fnum >= 0.5 && num != 9) ? '1' : '0')));
}
break;
#endif

default:
(*out_func)(c); /* If not valid conversion */
/* char, just output the char */
break;
}
}
}
}

out_num(num, field_w, uns_flag, left_jus, out_func, radix)
UNSIGNED_LONG num; /* See note on long ints below */
int field_w; /* Minimum field width of */
/* output number */
int uns_flag; /* =0 for signed value, 1 for */
/* unsigned value, 2 to force */
/* generation of minus sign */
int left_jus; /* =YES to left-justify number */
int (*out_func)(); /* Pointer to the output func. */
int radix; /* Base to output number in */

{
char digit[MAX_FIELD]; /* Holds the string of ASCII */
/* digits to be output */
char dig; /* Holds a single digit */
int neg_flag = NO; /* =YES if num is negative */
SIGNED_LONG snum; /* See note below */
int i; /* General-purpose */
char *p; /* Ditto */

/* The following code is included for compilers that support both signed
* and unsigned long integers so that the full range of unsigned long
* values may be printed (e.g. 0 through 4,294,967,295 on most PC
* compilers)
*/

if (uns_flag == 0) { /* If signed number output */
snum = (SIGNED_LONG)num; /* num => signed representation */
if (snum < 0) { /* If negative, make positive */
num = (UNSIGNED_LONG)(-snum); /* Put pos. value back into num */
neg_flag = YES;
}
}
else if (uns_flag == 2) /* Force a minus sign */
neg_flag = YES;

digit[MAX_FIELD-1]='\0';
for (i=0; i < MAX_FIELD-1; ++i)
digit[i]=' '; /* Set entire print field to */
/* spaces with an ending zero */

p = &digit[MAX_FIELD-1]; /* Point to end of output */
/* buffer (character string */
/* will be built backwards) */

do { /* Convert number to ASCII */
if ((dig = num % radix) < 10) /* If digit is a number */
*--p = dig + '0';
else
*--p = dig - 10 + 'A'; /* Else display as letter A-F */
num /= radix;
} while (num != 0);

if (neg_flag) /* Store minus sign if any */
*--p = '-';

i = &digit[MAX_FIELD-1] - p; /* Compute the number of digits */
/* in the number to be printed */
if (left_jus) {
out_str(p, out_func); /* Print digit string */
field_w -= i; /* Subtract digits just printed */
/* from field width */
while (field_w-- > 0)
(*out_func)(' '); /* Print remaining spaces */

} else { /* Right-justify the number */
field_w -= i; /* Subtract digits printed */
while (field_w-- > 0)
(*out_func)(' '); /* Pad field on the left */
out_str(p, out_func); /* And output the number */
}
}

/* The following function reads a base 10 ASCII number, updates *ptr to point
* to the character following the number, and returns the number.
*/

read_num(ptr)
char **ptr;

{
char c;
int num=0;

while (isdigit(c=**ptr)) {
num = num * 10 + c - '0';
++*ptr;
}

return(num);
}

out_str(string, out_func)
char *string;
int (*out_func)();

{
int i;

while (i=*string++)
(*out_func)(i);
}


  3 Responses to “Category : Assembly Language Source Code
Archive   : MSCPOPUP.ZIP
Filename : PRINTF.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/