www.pudn.com > drdossrc.zip > PRINTF.C


/* 
;    File              : $Workfile: PRINTF.C$ 
; 
;    Description       : 
; 
;    Original Author   : DIGITAL RESEARCH 
; 
;    Last Edited By    : $CALDERA$ 
; 
;-----------------------------------------------------------------------; 
;    Copyright Work of Caldera, Inc. All Rights Reserved. 
;       
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL, 
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC. 
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES 
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF 
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO 
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE 
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE 
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, 
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, 
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, 
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF 
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT 
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND 
;    CIVIL LIABILITY. 
;-----------------------------------------------------------------------; 
; 
;    *** Current Edit History *** 
;    *** End of Current Edit History *** 
; 
;    $Log$ 
; 
;    ENDLOG 
*/ 
 
/* 
 * 26 Apr 88 Modify the Long conversion routine to display all 10 
 *           digits of a 32 bit integer when displayed in decimal 
 * 27 May 88 Added string undefs. 
 * 1? Jun 88 Support for CODE relative messages using the FARPTR routine. 
 * 05 Jun 89 Add EPRINTF routine to display messages on STDERR 
 * 30 Oct 89 dispense with digits & uc_digits in resident portion 
 *  8 Nov 89 Replaced ASCII calculation with to_dec(), etc. as used 
 *           in APPALIB printf module. Much faster (eg dir /l 10% faster). 
 *  8 Jan 90 Added parameter order indexing option. 
 *  6-Mar-90 Watcom C v 7.0 
 * 26-Mar-90 Make _printf CDECL again, otherwise arg processing screws up 
 * 23-May-90 increase printf buffers from 128 to 130 
 * 02-Dec-90 Re-work, to flush buffer on \n to allow large input strings 
 * 28-May-91 local buffer is now on the stack instead of static. Reduces 
 *           resident size by 128 bytes. 
 * 29-Jul-91 Buffer is now a far one, so output redirection to a file works 
 *           on a NOVELL drive when we are in seg FFFF. 
 */ 
 
#include	"defines.h" 
#include	 
 
#if defined(MWC) && defined(strlen) 
#undef strcmp			/* These are defined as macros in string.h */ 
#undef strcpy			/* which are expaneded in line under */ 
#undef strlen			/* Metaware C. These undefs avoid this. */ 
#endif 
 
#include	 
#include	"command.h" 
#include	"dosif.h" 
#include	"global.h" 
 
#define     PRINTF      -1 
#define     EPRINTF     -2 
#define     SPRINTF     -3 
 
EXTERN VOID		c_write		(BYTE *, WORD);	 
EXTERN BYTE FAR * CDECL farptr		(BYTE *); 
EXTERN BOOLEAN		isdigit		(BYTE); 
EXTERN BOOLEAN		err_flag; 
 
/* forward references */ 
MLOCAL UWORD CDECL 	_printf		(BYTE *, UWORD *, UWORD); 
MLOCAL VOID		arg_ptrs	(BYTE FAR *, UWORD *, UWORD **); 
MLOCAL BYTE FAR *	arg_siz		(BYTE FAR *, UBYTE *); 
MLOCAL BYTE FAR *	arg_num		(BYTE FAR *, UWORD *); 
MLOCAL BYTE * 		to_hex		(ULONG, BYTE *, BYTE); 
MLOCAL BYTE *  		to_dec		(ULONG, BYTE *); 
MLOCAL BYTE *  		to_udec		(ULONG, BYTE *); 
 
#define			UPPER_CASE	('A'-10) 
#define			LOWER_CASE	('a'-10) 
 
#define			MAX_ARG_NUM	10	/* max args with order indxs */ 
 
MLOCAL  BYTE FAR	*buff 		= NULLPTR; 
 
/*GLOBAL  BYTE		str[130];*/ 
MLOCAL	BYTE FAR	*str; 
 
GLOBAL WORD CDECL printf(fmt,args) 
BYTE	*fmt; 
UWORD	args; 
{ 
	UWORD	totlen,len; 
	/*BYTE	local_buff[130];*/ 
	UWORD	bufsize; 
 
	/*str = (BYTE FAR *) local_buff;*/ 
	str = gp_far_buff; 
 
	buff = str; 			/* use local buffer for printing */ 
	totlen = _printf (fmt,&args,PRINTF);		/* build up output string */ 
        len=(UWORD) buff - (UWORD) str; 
        if(len)				/* if anything in the buffer   */ 
	    far_write(err_flag ? STDERR:STDOUT, str, len); 
	    				/* then flush it */ 
 
	return totlen+len;			/* Return the String Length	*/ 
 
} 
 
GLOBAL WORD CDECL eprintf(fmt,args) 
BYTE	*fmt; 
UWORD	args; 
{ 
	UWORD	totlen, len; 
	BYTE	local_buff[130]; 
 
	str = (BYTE FAR *) local_buff; 
 
	buff = str; 			/* use local buffer for printing */ 
        err_flag = TRUE; 
	totlen = _printf (fmt,&args,EPRINTF);		/* build up output string */ 
        len = buff-str; 
        if(len)	{			/* if anything in the buffer   */ 
            far_write(STDERR,str,len); 
 	} 
	err_flag = FALSE; 
 
	return totlen+len;			/* Return the String Length	*/ 
 
} 
 
GLOBAL WORD CDECL fprintf(handle, fmt, args) 
UWORD	handle; 
BYTE	*fmt; 
UWORD	args; 
{ 
	UWORD	totlen,len; 
	UWORD	bufsize; 
	 
	str = gp_far_buff; 
 
	buff = str; 			/* use local buffer for printing */ 
	totlen =_printf (fmt,&args,handle);		/* build up output string */ 
        len = (UWORD) buff - (UWORD) str; 
        if(len)				/* if anything in the buffer   */ 
	    far_write(handle, str, len);	/* then flush it */ 
 
	return totlen+len;			/* Return the String Length	*/ 
 
} 
 
GLOBAL WORD CDECL sprintf(strg, fmt, args) 
BYTE	*strg; 
BYTE	*fmt; 
UWORD	args; 
{ 
	buff = (BYTE FAR *) strg;		/* Point buffer at String	*/ 
	return _printf (fmt,&args,SPRINTF); 	/* Generate the String		*/ 
} 
 
MLOCAL UWORD CDECL 	_printf(fmt_near, args, type) 
BYTE		*fmt_near; 
UWORD	   	*args; 
UWORD        type; 
{ 
	BYTE FAR *fmt; 
	WORD rjust;			/* if string/number is right justified */ 
	WORD maxwidth, width; 
	BOOLEAN	long_arg;		/* true if next argument is long */ 
	ULONG value; 
	UWORD uvalue; 
	WORD i, k; 
	BYTE FAR *cp; 
	BYTE c, filler; 
	BYTE s[40], *sp; 
	LONG *lp; 
	UWORD *arg_list[MAX_ARG_NUM]; 
	UWORD arg_idx; 
        UWORD totlen=0; 
 
	fmt = farptr(fmt_near);		/* get full address of format string */ 
	arg_ptrs(fmt, args, arg_list);	/* init table of argument addresses */ 
 
	while ((c = *fmt++) != 0)	/* scan format string */ 
	{ 
	    if (c == '%') {		/* formatting code found */ 
		    s[14] = 0; 
		    rjust = YES; 
		    filler = ' '; 
		    maxwidth = 0x7fff; 
 
		    fmt = arg_num(fmt, &arg_idx);	/* get argument index */ 
		    if (arg_idx < MAX_ARG_NUM) {	/* valid index? */ 
		        fmt++;			/*  yes - skip '%' */ 
		        args = arg_list[arg_idx];	/* lookup address of arg */ 
		    } 
 
		    if ((c = *fmt) == '-') {	/* string is left justified */ 
		        rjust = NO;		/*   ... not right justified */ 
		        c = *fmt++;		/* get the next character */ 
		    } 
 
		    if (c == '0')		/* if leading zeroes desired */ 
		        filler = '0';	/*    use '0' instead of ' ' */ 
 
		    if (*fmt == '*') {	/* if formatting width is parameter */ 
		            			/*    then get it from parameters */ 
		        width = (WORD)*args++; 
		        fmt++;		/* skip the asterisk */ 
		        c = *fmt++;		/* get next character */ 
		    } 
		    else			/* get full width */ 
		        for (width = 0; (c = *fmt++) >= '0' && c <= '9'; ) 
			        width = width*10 + c - '0'; 
 
		    if (c == '.') {		/* if decimal places specified */ 
		        if (*fmt == '*') {	/* if width is a parameter */ 
			        maxwidth = (WORD)*args++; 
			        fmt++;		/* skip the asterisk */ 
			        c = *fmt++;	/* get next character */ 
		        } 
		        else		/* get decimal places */ 
			        for (maxwidth = 0; (c = *fmt++) >= '0' && c <= '9' ;) 
			            maxwidth = maxwidth*10 + c - '0'; 
		    } 
 
			/* "%ld", "%lu", "lx" specified */ 
		    long_arg = (c == 'l');	/* is the argument supplied long? */ 
		    if (long_arg)		/* if long argument */ 
		        c = *fmt++;		/* then skip the 'l' character */ 
 
		    switch (c)	{ 
		        case 'd':		/* signed argument */ 
		            if (!long_arg) 
			            value = (WORD) *args++; 
		            else { 
			            lp = (LONG *) args; 
			            value = *lp++; 
			            args = (UWORD *) lp; 
		            } 
		            break; 
 
		    case 'u':		/* unsigned argument */ 
		    case 'x': 
		    case 'X': 
		        if (!long_arg) 
			        value = (UWORD) *args++; 
		        else { 
			        lp = (LONG *) args; 
			        value = (ULONG) *lp++; 
			        args = (UWORD *) lp; 
		        } 
		        break; 
 
		    default:			/* "%s", "%c" */ 
		        uvalue = (UWORD) *args++;	/* get string address of char */ 
		    } 
 
 
		    switch (c) {		/* now convert to ASCII */ 
		        case 'd':		/* signed decimal */ 
		    	    sp = to_dec(value, s+14); 
		    	    break; 
 
		        case 'u':		/* unsigned decimal */ 
		    	    sp = to_udec(value, s+14); 
		    	    break; 
 
		        case 'x':		/* unsigned hexadecimal, lower case */ 
		    	    sp = to_hex(value, s+14, LOWER_CASE); 
		    	    break; 
 
		        case 'X':		/* unsigned hexadecimal, upper case */ 
		            sp = to_hex(value, s+14, UPPER_CASE); 
		            break; 
 
		        case 's':		/* string -- could be far */ 
		            cp = farptr((BYTE *)uvalue); 
		            for (i=0; cp[i] != '\0'; i++) 
		                ; 
		            goto havelen; 
 
		        case 'c': 
		            c = uvalue; 
					/* drop into "default:" */ 
		        default:			/* normal characters */ 
		            sp = s+13; 
		            *sp = c; 
		            break; 
		    } 
 
		    i = (s+14) - sp;	/* work out length of string */ 
		    cp = (BYTE FAR *) sp;	/* convert to FAR pointer */ 
 
havelen: 
		    if (i > maxwidth) 
		        i = maxwidth; 
			 
		    if (rjust) { 
		        while (width-- > i) 
			    *buff++ = filler; 
		    } 
 
		    for (k = 0; *cp && k < maxwidth; ++k) { 
		        if (*cp == '\n') 
			        *buff++ = '\r'; 
		        *buff++ = *cp++; 
		    } 
 
		    if (!rjust)	{	/* if right justified */ 
		        while (width-- > i) 
			        *buff++ = ' '; 
		    } 
	    } 
	    else if (c == '\n')	{	/* expand newline to CR,LF then flush the buffer */ 
		    *buff++ = '\r'; 
		    *buff++ = '\n'; 
                if (type!=SPRINTF) { 
                    /* Flush the buffer */ 
	            *buff = '\0';		/* terminate the string	*/ 
                    switch (type) { 
                        case PRINTF: 
	                    far_write(err_flag ? STDERR:STDOUT,str, 
			    		(UWORD) buff - (UWORD) str); 
                            break; 
                        case EPRINTF: 
	                    far_write(STDERR, str, buff-str); 
                            break; 
                        default: 
	                    far_write(type, str, buff-str);	 
                            break; 
                    } /*ENDSWITCH*/ 
                    totlen+=buff-str; 
                    buff=str; 
                } 
	    } 
	    else  
		    *buff++ = c; 
	} 
	*buff = '\0';		/* terminate the string	*/ 
        return totlen+=buff-str; 
} 
 
 
 
/* Initialise the table of pointers to all arguments (ptr_list). 
   The ptr_list table will not be filled in unless the format 
   string (fmt) contains parameter order indexes. */ 
 
MLOCAL VOID arg_ptrs(fmt, args, ptr_list) 
REG BYTE FAR	*fmt;			/* ASCIIZ format string */ 
UWORD		*args;			/* pointer to first argument */ 
UWORD	   	*ptr_list[];		/* list of pointers to all arguments */ 
{ 
UWORD		arg_cnt;		/* running count of parameters found */ 
UWORD		num; 
UBYTE		size_list[MAX_ARG_NUM];	/* number bytes in each argument */ 
UWORD		i; 
 
 
    /* Read through format string to determine the size of each argument. */ 
    for (arg_cnt = 0; ; ) 
    { 
    	while (*fmt && *fmt != '%')	/* find the next parameter */ 
	    fmt++; 
 
	if (!*fmt)			/* patameter found? */ 
	    break;			/*  no - exit loop */ 
	fmt++;				/* skip '%' */ 
 
	if (*fmt == '%')		/* "%%" escape for percent? */ 
	{ 
	    fmt++;			/*  yes - skip second '%' */ 
	    continue;			/*  and look for next parameter */ 
	} 
 
	fmt = arg_num(fmt, &num);	/* get this argument's index */ 
	if (num >= MAX_ARG_NUM)		/* arg index present and valid? */ 
	    break;			/*  no - go no further */ 
 
					/* record this argument's size */ 
	fmt = arg_siz(fmt, &size_list[num]); 
	arg_cnt++;			/* one more argument found */ 
    } 
 
 
    /* Loop once for each argument found in format string, filling in 
       the offset for that argument in the size_list table. */ 
    for (i = 0; i < arg_cnt; i++) 
    { 
    	ptr_list[i] = args;			/* record the address of arg */ 
	args += (UWORD)(size_list[i]);		/* update ptr by size of arg */ 
    } 
} 
 
 
 
/* Determine the size in bytes (siz) of the argument that corresponds to the  
   given format string (fmt). Return a pointer to the character following 
   the last in the format string. For example... 
 
	fmt	       siz 
   	%d		2 
	%ld		4 
	%*d		4 
*/ 
 
MLOCAL BYTE FAR * arg_siz(fmt, siz) 
REG BYTE FAR	*fmt;			/* printf argument format string */ 
UBYTE		*siz;			/* returned argument size, in bytes */ 
{ 
 
    *siz = 0;				/* argument size not yet known */ 
 
    if (*fmt != '%') 
    	return fmt;			/* format string must begin with '%' */ 
    fmt++;				/* skip '%' */ 
 
    if (*fmt == '#')			/* ignore various formatting ctrls */ 
	fmt++; 
    if (*fmt == '-') 
	fmt++; 
    if (*fmt == '0') 
	fmt++; 
 
    if (*fmt == '*') 
    {					/* width argument also on stack */ 
	*siz += sizeof(WORD);		/* width argument is a WORD */ 
	fmt++; 
    } 
    else				/* ignore any static width control */ 
	while (*fmt >= '0' && *fmt <= '9') 
	    fmt++; 
 
    if (*fmt == '.') 
    { 
	fmt++; 
	if (*fmt == '*') 
	{				/* 2nd width argument on stack */ 
	    *siz += sizeof(WORD); 
	    fmt++; 
	} 
	else				/* ignore any static width control */ 
	    while (*fmt >= '0' && *fmt <= '9') 
	    	fmt++; 
    } 
 
    if (*fmt == 'l') 
    { 
    	*siz += sizeof(LONG); 
	fmt++; 
    } 
    else 
	*siz += sizeof(WORD);		/* assume sizeof(WORD)==sizeof(BYTE *) */ 
 
    return ++fmt;			/* skip final char: 'd', 's', etc. */ 
} 
 
 
 
/* Determine the index number (num) of the argument given by the format 
   string (fmt). If the format string does not have a valid index number 
   num is set to MAX_ARG_NUM. Return a pointer to the character following 
   the last in the index number. For example... 
 
	fmt		num		returned pointer to... 
	3%4d		3		'%' 
	4d		MAX_ARG_NUM	'4' 
	%		MAX_ARG_NUM	'%' 
*/ 
 
MLOCAL BYTE FAR * arg_num(fmt, num) 
BYTE FAR	*fmt; 
UWORD	   	*num; 
{ 
REG BYTE FAR	*cp; 
REG UWORD	n; 
 
 
    *num = MAX_ARG_NUM;			/* argument index not yet known */ 
 
    cp = fmt; 
    if (!isdigit(*cp))			/* at least one digit expected */ 
	return fmt; 
					/* extract index number */ 
    for (n = 0; *cp >= '0' && *cp <= '9'; cp++) 
	n = n * 10 + *cp - '0'; 
 
    if (*cp != '%') 
    	return fmt;			/* number must be terminated by '%' */ 
 
    *num = n;				/* record the index number */ 
    return cp;				/* return pointer to last '%' */ 
} 
 
 
 
MLOCAL BYTE * to_hex(n, s, hex_base) 
ULONG  		n; 
BYTE   		*s; 
BYTE		hex_base;	/* 'a'-10 for lowercase, 'A'-10 uppercase */ 
{ 
REG UBYTE	i; 
 
    do 
    { 
	i = (UBYTE)n & 0x0F; 
	*--s = (i > 9) ? (hex_base + i) : ('0' + i); 
	n >>= 4; 
    } 
    while (n != 0); 
 
    return s; 
} 
 
 
 
MLOCAL BYTE * to_dec(n, s) 
ULONG  		n; 
BYTE   		*s; 
{ 
    if ((LONG)n < 0) 
    { 
	s = to_udec(0 - (LONG)n, s); 
	*--s = '-';			/* preceed number with sign */ 
	return s; 
    } 
    else 
	return to_udec(n, s); 
} 
 
 
 
MLOCAL BYTE * to_udec(n, s) 
ULONG  		n; 
BYTE   		*s; 
{ 
    do 
    { 
	*--s = '0' + (n % 10); 
	n /= 10; 
    }  
    while (n != 0); 
 
    return s; 
}