pcs/sprintf.c

539 lines
18 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* =====> SPRINTF.C */
/* TIPC Scheme '84 Runtime Support - C Compatible I/O Routines
(C) Copyright 1984,1985 by Texas Instruments Incorporated.
All rights reserved.
Author: John C. Jensen
Installation: Texas Instruments Incorporated, Dallas, Texas
Division: Central Research Laboratories
Cost Center: Computer Science Laboratory
Project: Computer Architecture Branch
Date Written: 7 December 1984
Last Modification: 10 September 1985 by Rusty Haddock
*/
#include "scheme.h"
/************************************************************************/
/* Main Print Driver - printf */
/* */
/* Acknowledgement: This routines perform formatted output functions */
/* similar to that of the Lattice C compiler. */
/* Some of the following descriptions are */
/* excerpted from the Lattice 8086/8088 C Compiler */
/* manual. */
/* */
/* Description: The control string (format statement) contains */
/* ordinary characters, which are sent without */
/* modification to the standard output port, and */
/* format specifiers of the form: */
/* */
/* %-m.plX */
/* */
/* where (1) the optional "-" indicates the field */
/* is to be left justified (right justified is the */
/* default); (2) the optional "m" field is a */
/* decimal number specifying a minimum field width;*/
/* (3) the optional ".p" field is the character '.'*/
/* followed by a decimal number specifying the */
/* precision of a floating point image or the */
/* maximum number of characters to be printed from */
/* a string; (4) the optional "l" (letter ell) */
/* indicates that the item to be formatted is */
/* "long"; and (5) "X" is one of the format type */
/* indicators from the following list: */
/* */
/* d -- decimal signed integer */
/* u -- decimal unsigned integer */
/* x -- hexadecimal integer */
/* o -- octal integer */
/* s -- character string */
/* c -- single character */
/* f -- fixed decimal floating point */
/* e -- exponential floating point */
/* g -- use "e" or "f", whichever is shorter */
/* */
/* The format type must be specified in lower case.*/
/* Characters in the control string which are not */
/* part of a format specified are sent to the */
/* output port; a % may be sent by using the */
/* sequence %%. See the Kernighan and Ritchie */
/* text for a more detailed explanation of the */
/* formatted output functions. */
/************************************************************************/
/* working variables visible to all output routines in this module */
static int auto_CR = TRUE; /* flag for inserting a "carriage return"
whenever a "line feed" is encountered */
static int field_width = 0;/* width (number of characters) of format field */
static int leading_zeros = FALSE; /* indicates if leading zeros desired */
static int left_justified = FALSE; /* indicates if field left justified */
static int long_object = FALSE; /* indicates if a data item is "long" */
static int precision = 0; /* the precision of a floating point image, or
the maximum number of character to be printed
from a string */
static char digit[16] = {'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F'};
char *concat_str(); /* concatenate two character strings */
char *copy_str(); /* make copy of a character string */
char *fmt_hex(); /* format a hexadecimal value */
char *fmt_int(); /* format a signed integer value */
char *fmt_long(); /* format a long signed integer value */
char *fmt_unsigned(); /* format an unsigned integer value */
char *getmem(); /* Lattice C's memory allocation routine */
printf(fmt, data)
char *fmt; /* the "format statement" describing the I/O */
int data; /* the first data object to be printed */
{
char *buffer; /* temporary output buffer for converted values */
int *next; /* pointer to the next object to be printed */
double *next_float; /* pointer to the next floating point object */
long *next_long; /* pointer to the next long object to be printed */
ENTER(printf);
/* set the default port address for the I/O operation */
ssetadr(ADJPAGE(OUT_PAGE), OUT_DISP);
next = &data; /* create a pointer to the next object to print */
/* Continue output until format is exhausted */
while (*fmt)
{
if (*fmt == '%')
{
buffer = NULL;
leading_zeros = FALSE;
left_justified = FALSE;
long_object = FALSE;
field_width = 0;
precision = 0;
fmt++; /* advance pointer to next character in format */
/* test if field is to be left justified */
if (*fmt == '-')
{
left_justified = TRUE;
fmt++;
}
/* test for request for leading zeros ('0' follows the '%') */
if (*fmt == '0')
{
leading_zeros = TRUE;
fmt++;
}
/* determine the field width, if specified */
while (isdigit(*fmt))
{
field_width = (field_width * 10) + *fmt - '0';
fmt++;
}
/* test for a "precision" field */
if (*fmt == '.')
{
fmt++;
while (isdigit(*fmt))
{
precision = (precision * 10) + *fmt - '0';
fmt++;
}
} /* end: if (*fmt == '.') */
/* test for a "long" object */
if (*fmt == 'l')
{
long_object = TRUE;
fmt++;
}
/* decode the format specifier */
switch (*fmt)
{
case 'c': /* single character */
prtf_character(*next);
next++;
break;
case 'd': /* decimal signed integer */
if (long_object)
{
next_long = (long *) next;
buffer = fmt_long(*next_long);
next++;
}
else
{
buffer = fmt_int(*next);
}
next++;
break;
case 'e':
case 'f':
case 'g': /* Floating-point numbers */
next_float = (double *) next;
fmt_float(*next_float,*fmt);
next += 4;
break;
/***** WATCH OUT!!! Lattice C allows nested comments!!!
case 'o': /* octal integer */
prtf_string("<%o not implemented>");
next++;
break;
*****/
case 's': /* character string */
prtf_string(*next);
next++;
break;
case 'u': /* decimal unsigned integer */
if (long_object)
{
prtf_string("<long objects not implemented>");
next++;
}
else
{
buffer = fmt_unsigned(*next);
}
next++;
break;
case 'x': /* hexadecimal integer */
if (long_object)
{
prtf_string("<long objects not implemented>");
next++;
}
else
{
buffer = fmt_hex(*next);
}
next++;
break;
case '%': /* the percent sign itself */
outchar('%');
break;
case '\0': /* unexpected end of format specification */
prtf_string("<unexpected end of format>\n");
fmt--;
break;
default: /* unexpected format specifier */
outchar('%');
outchar(*fmt);
prtf_string("< invalid format specifier>", 0, 0, 0);
break;
} /* end: switch (*fmt) */
if (buffer)
{
prtf_string(buffer);
rlsstr(buffer);
}
}
else /* just a character to print (not a % formatting directive) */
{
outchar(*fmt);
}
fmt++; /* advance pointer to next character in format */
} /* end: while (*fmt) */
/* reset format control variables to permit calls to sub-entry points */
leading_zeros = FALSE;
left_justified = FALSE;
long_object = FALSE;
field_width = 0;
precision = 0;
}
/************************************************************************/
/* Print a single character */
/************************************************************************/
prtf_character(ch)
char ch;
{
/*%%int i; /* our old favorite index variable */*/
if (field_width)
{
if (left_justified)
{
outchar(ch);
pad_with_blanks(field_width - 1);
}
else /* right justified */
{
pad_with_blanks(field_width - 1);
outchar(ch);
}
}
else outchar(ch); /* just print the single character */
} /* end of function: prtf_character(ch) */
/************************************************************************/
/* Print a character string */
/************************************************************************/
prtf_string(string)
char *string;
{
int i; /* our old favorite index variable */
int len = 0; /* the actual length of the character string */
/* determine string length (search for '\0' end-of-string mark) */
while (string[len]) len++;
/* if precision field specified, reduce "len" if too long */
if (precision && precision < len) len = precision;
/* output string with appropriate justification */
if (left_justified)
{
for (i = 0; i < len; i++) outchar(string[i]);
pad_with_blanks(field_width - len);
}
else /* right justified */
{
pad_with_blanks(field_width - len);
for (i = 0; i < len; i++) outchar(string[i]);
}
}
/************************************************************************/
/* Format a floating point number */
/************************************************************************/
fmt_float(value,type)
double value;
char type;
{
char buf[32];
int siz;
siz = ((type=='g')? (outrange(value)) : (type=='e'));
siz = makeflo(value,buf,precision,siz);
buf[siz] = '\0';
prtf_string(buf);
} /* end of function: fmt_float(value,type) */
/************************************************************************/
/* Format a signed decimal integer */
/************************************************************************/
char *fmt_int(value)
int value;
{
long lvalue;
lvalue = value;
return(fmt_long(lvalue));
/*****
char buffer[100]; /* buffer to hold characters of converted value */
int digit_count = 0; /* count of significant digits */
int i,j; /* index variables */
int negative = FALSE; /* flag to indicate sign of number */
/* test the sign of the integer-- if negative, record that fact */
if (value < 0)
{
negative = TRUE;
value = -value;
field_width--;
}
/* convert the integer to ASCII */
i = sizeof(buffer) - 1;
buffer[i--] = '\0'; /* insert end of string indicator */
do {
buffer[i--] = digit[value % 10];
value /= 10;
digit_count++;
} while (value);
/* if leading zeros are required, insert said */
if (leading_zeros)
{
for (j = digit_count; j < field_width; j++)
buffer[i--] = '0';
}
/* if negative, insert a '-' sign */
if (negative)
{
buffer[i--] = '-';
}
/* return the formatted integer */
return(copy_str(buffer+i+1));
*****/
} /* end of function: char *fmt_int(value) */
/************************************************************************/
/* Format a long signed decimal integer */
/************************************************************************/
char *fmt_long(value)
long value;
{
char buffer[100]; /* buffer to hold characters of converted value */
int digit_count = 0; /* count of significant digits */
int i,j; /* index variables */
int negative = FALSE; /* flag to indicate sign of number */
/* test the sign of the integer-- if negative, record that fact */
if (value < 0)
{
negative = TRUE;
value = -value;
field_width--;
}
/* convert the integer to ASCII */
i = sizeof(buffer) - 1;
buffer[i--] = '\0'; /* insert end of string indicator */
do {
buffer[i--] = digit[value % 10];
value /= 10;
digit_count++;
} while (value);
/* if leading zeros are required, insert said */
if (leading_zeros)
{
for (j = digit_count; j < field_width; j++)
buffer[i--] = '0';
}
/* if negative, insert a '-' sign */
if (negative)
{
buffer[i--] = '-';
}
/* return the formatted integer */
return(copy_str(buffer+i+1));
} /* end of function: char *fmt_long(value) */
/************************************************************************/
/* Format an unsigned decimal integer */
/************************************************************************/
char *fmt_unsigned(value)
unsigned value;
{
int i,j; /* index variables */
char buffer[100]; /* buffer to hold characters of converted value */
int digit_count = 0; /* count of significant digits */
/* convert the integer to ASCII */
i = sizeof(buffer) - 1;
buffer[i--] = '\0'; /* insert end of string indicator */
do {
buffer[i--] = digit[value % 10];
value /= 10;
digit_count++;
} while (value);
/* if leading zeros are required, insert said */
if (leading_zeros)
{
for (j = digit_count; j < field_width; j++)
buffer[i--] = '0';
}
/* return the formatted unsigned integer */
return(copy_str(buffer+i+1));
} /* end of function: char *fmt_unsigned(value) */
/************************************************************************/
/* Format a hexadecimal integer */
/************************************************************************/
char *fmt_hex(value)
unsigned value;
{
int i,j; /* index variables */
char buffer[100]; /* buffer to hold characters of converted value */
int digit_count = 0; /* count of significant digits */
/* convert the integer to ASCII */
i = sizeof(buffer) - 1;
buffer[i--] = '\0'; /* insert end of string indicator */
do {
buffer[i--] = digit[value & 0xf];
value = value >> 4;
digit_count++;
} while (value);
/* if leading zeros are required, insert said */
if (leading_zeros)
{
for (j = digit_count; j < field_width; j++)
buffer[i--] = '0';
}
/* return the hexadecimal integer value */
return(copy_str(buffer+i+1));
} /* end of function: char *fmt_hex(value) */
/************************************************************************/
/* Pad with blanks */
/************************************************************************/
pad_with_blanks(number)
int number; /* the number of blanks to output */
{
int i; /* index variable */
/* spew out the appropriate number of blanks */
for (i = 0; i < number; i++) outchar(' ');
} /* end of function: pad_with_blanks */
/************************************************************************/
/* Create copy of a character string */
/************************************************************************/
char *copy_str(string)
char *string;
{
char *ret_str;
ENTER(copy_str);
if (!(ret_str = getmem(strlen(string)+1))) getmem_error(rtn_name);
else
{
strcpy(ret_str, string);
}
return(ret_str);
}
/************************************************************************/
/* Create concatenation of two character strings */
/************************************************************************/
char *concat_str(str1,str2)
char *str1,*str2;
{
ENTER(concat_str);
char *ret_str;
if (!(ret_str = getmem(strlen(str1) + strlen(str2) + 1)))
getmem_error(rtn_name);
else
{
strcpy(ret_str, str1);
strcat(ret_str, str2);
}
return(ret_str);
}