home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
ddjmag
/
ddj8804.arc
/
HOLUB.ARC
/
HOLUB.LST
< prev
Wrap
File List
|
1980-01-01
|
16KB
|
383 lines
Listing One -- C:/SRC/TOOLS/IDOPRNT.C, Printed 1/10/1988
____________________________________________________________________________
1| #include <stdarg.h> /* ANSI variable-argument defines */
2| #include <dos.h> /* uSoft: defines for FP_OFF and FP_SEG */
3|
4| /* IDOPRNT - integer-only printf/fprintf/sprintf workhorse
5| * function.
6| *
7| * (C) 1988 Allen I. Holub. All rights reserved.
8| *
9| * The following conversions are supported:
10| *
11| * %d %ld decimal, long decimal
12| * %u unsigned (int only, no longs)
13| * %s string
14| * %x %lx hex, long hex
15| * %o %lo octal, long octal
16| * %b %lb binary, long binary (nonstandard)
17| * %p far pointer (in hex XXXX:XXXX)
18| *
19| * Note that it's impossible to get zero fill in the offset
20| * part of a %p conversion. That is 1234:0001 is always
21| * printed as 1234:1. Sorry. The following modifiers are
22| * supported for all conversions:
23| *
24| * %0x zero left fill
25| * %-x left justification in field
26| * %|x centered in field (nonstandard)
27| * %*x field width from first argument
28| *
29| * Precision is supported in strings:
30| *
31| * %X.Ys X-character wide field, print at most Y characters
32| * (even if the string is longer). If X or Y is a *,
33| * the width is taken from the next argument.
34| *
35| * Potential portability problems:
36| *
37| * %p is a FAR pointer. I've used the "far" keyword to
38| * declare it as such and I've used the FP_SEG and FP_OFF
39| * to extract the segment and offset parts of the pointer.
40| * The offset part of a near pointes can be printed by
41| * casting it to an int and using %x.
42| */
43|
44| extern char *ltos(long, char*, int);
45|
46| /*------------------------------------------------------------
47| * Macros to save some code space below. If your compiler
48| * doesn't accept multi-line macros, remove the backslashes
49| * and merge the entire definition onto one line.
50| * These both have horrible side effects. Be careful.
51| *
52| * PAD(fw,filchar,out,op) outputs filchar, fw times. fw = 0.
53| * TOINT(p,x) works like "x = atoi(p);" except p
54| * is advanced past the number.
55| */
56|
57| #define PAD(fw,fc,out,op) while( --(fw) >= 0 ) \
58| (*out)( fc, op )
59|
60| #define TOINT(p,x) while( '0' <= *p && *p <= '9' ) \
61| x = (x * 10) + (*p++ - '0')
62|
63| /*------------------------------------------------------------
64| * INTMASK is a portable way to mask off the bottom N bits
65| * of a long, were N is the width of an int.
66| */
67|
68| #define INTMASK (long)( (unsigned)(~0) )
69|
70| /*------------------------------------------------------------*/
71|
72| void idoprnt( out, o_param, format, args )
73|
74| int (*out)(); /* output subroutine */
75| void *o_param; /* 2nd argument to pass to out() */
76| char *format; /* pointer to format string */
77| va_list args; /* pointer to arguments */
78| {
79| char filchar ; /* Fill character used to pad fields */
80| char nbuf[34]; /* Buffer used to hold converted #s */
81| char *bp ; /* Pointer to current output buffer */
82| int slen ; /* length of string pointe to by bp */
83| int base ; /* Current base (%x=16, %d=10, etc.) */
84| int fldwth ; /* Field width as in %10x */
85| int precision; /* Precision as in %10.10s or %10.3f */
86| int lftjust ; /* 1 = left justifying (ie. %-10d) */
87| int center ; /* 1 = centered (ie. %|10d) */
88| int longf ; /* doing long int (ie. %lx or %X) */
89| long lnum ; /* used to hold numeric arguments */
90| void far *pnum; /* Pointer-sized number */
91|
92| for(; *format ; format++ )
93| {
94| if( *format != '%') /* No conversion, just */
95| { /* print the next char. */
96| (*out)(*format, o_param);
97| }
98| else /* Process a % conversion */
99| {
100| bp = nbuf ;
101| filchar = ' ' ;
102| fldwth = 0 ;
103| lftjust = 0 ;
104| center = 0 ;
105| longf = 0 ;
106| precision = 0 ;
107| slen = 0 ;
108|
109| /* Interpret any modifiers that can precede a
110| * conversion character. (ie %04x , %-10.6s... etc).
111| * if a * is present instead of a field width then
112| * the width is taken from the argument list.
113| */
114|
115| if( *++format == '-') { ++format ; ++lftjust; }
116| if( *format == '|') { ++format ; ++center; }
117| if( *format == '0') { ++format ; filchar = '0'; }
118|
119| if( *format != '*' )
120| TOINT( format, fldwth );
121| else
122| {
123| ++format;
124| fldwth = va_arg(args, int);
125| }
126|
127| if( *format == '.' )
128| {
129| if( *++format != '*' )
130| TOINT( format, precision );
131| else
132| {
133| ++format;
134| precision = va_arg(args, int);
135| }
136| }
137|
138| if( *format == 'l' || *format == 'L' )
139| {
140| ++format;
141| ++longf ;
142| }
143|
144|
145| /* By now we've picked off all the modifiers and
146| * *format is looking at the actual conversion
147| * character. Pick the appropriatly sized argument
148| * off the stack and advanced the pointer (ap) to
149| * point at the next argument.
150| */
151|
152| switch( *format )
153| {
154| default: *bp++ = *format ; break;
155| case 'c': *bp++ = va_arg(args, int ); break;
156| case 's': bp = va_arg(args, char *); break;
157|
158| case 'p':
159| pnum = va_arg(args, void far *);
160| bp = ltos( (unsigned long)FP_SEG(pnum), bp, 16);
161| *bp++ = ':';
162| bp = ltos( (unsigned long)FP_OFF(pnum), bp, 16 );
163| break;
164|
165| case 'u': base = -10 ; goto pnum ;
166| case 'd': base = 10 ; goto pnum ;
167| case 'x': base = 16 ; goto pnum ;
168| case 'b': base = 2 ; goto pnum ;
169| case 'o': base = 8 ;
170| pnum:
171| /* Fetch a long or int sized argument off the
172| * stack as appropriate. If the fetched number
173| * is a base 10 int then mask off the top
174| * bits to prevent sign extension.
175| */
176|
177| if( longf )
178| lnum = va_arg(args, long);
179| else
180| {
181| lnum = (long) va_arg(args, int);
182|
183| if( base == -10 ) /* Unsigned int */
184| {
185| base = 10;
186| lnum &= INTMASK;
187| }
188| else if( base != 10 ) /* Nondecimal int */
189| {
190| lnum &= INTMASK;
191| }
192| }
193|
194| if( lnum < 0L && base == 10 && filchar == '0' )
195| {
196| /* Again, print a - to avoid "000-123."
197| * Only decimal numbers get - signs.
198| */
199|
200| (*out)( '-' ,o_param) ;
201| --fldwth ;
202| lnum = -lnum ;
203| }
204|
205| bp = ltos( lnum, bp, base );
206| break;
207| }
208|
209| /* Terminate the string if necessary and compute
210| * the string length (slen). Bp will point at the
211| * beginning of the output string.
212| */
213|
214| if (*format != 's')
215| {
216| *bp = '\0';
217| slen = bp - nbuf;
218| bp = nbuf;
219| }
220| else
221| {
222| slen = strlen(bp);
223| if( precision && slen > precision )
224| slen = precision;
225| }
226|
227|
228| /* Adjust fldwth to be the amount of padding we need
229| * to fill the buffer out to the specified field
230| * width. Then print leading padding (if we aren't
231| * left justifying), the buffer itself, and any
232| * required trailing padding (if we are left
233| * justifying.
234| */
235|
236| if( (fldwth -= slen) < 0 )
237| fldwth = 0;
238|
239| if( center )
240| {
241| /* Use longf as counter */
242| longf = fldwth/2;
243| PAD( longf, filchar, out, o_param );
244| }
245| else if( !lftjust )
246| PAD( fldwth, filchar, out, o_param );
247|
248| while( --slen >= 0 )
249| (*out)(*bp++,o_param);
250|
251| if( center )
252| {
253| longf = fldwth - fldwth/2;
254| PAD( longf, filchar, out, o_param );
255| }
256| else if( lftjust)
257| PAD( fldwth, filchar, out, o_param );
258|
259| }
260| }
261| }
262|
263| /*------------------------------------------------------------*/
264|
265| #ifdef DEBUG
266|
267| #include <stdio.h>
268|
269| printm( fmt, ... )
270| char *fmt;
271| {
272| extern int fputc();
273| va_list args;
274| va_start(args, fmt);
275| idoprnt( fputc, stdout, fmt, args );
276| }
277|
278| /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
279|
280| main()
281| {
282| printm("should see <0 1 2 3 4 5 6 7>: ");
283| printm(" %d %x %o %ld %lx %lo %c %s\n",
284| 0, 1, 2, 3L, 4L, 5L, '6', "7" );
285|
286| printf("should see: hello world: " );
287| printm("%s %s %c", "hello", "world", '\n' );
288|
289| printm("should see <string> : <%6.6s>\n", "string NO NO" );
290| printm("should see < str> : <%*.*s>\n", 6, 3, "string" );
291| printm("should see <70000> : <%ld>\n", 70000L );
292| printm("should see <fffff> : <%lx>\n",0xfffffL);
293| printm("should see <ffff> : <%x>\n", -1 );
294| printm("should see <-1> : <%ld>\n", -1L );
295| printm("should see <x> : <%c>\n", 'x' );
296| printm("should see < x > : <%|5c>\n", 'x' );
297| printm("should see <a5> : <%x>\n", 0xa5 );
298| printm("should see <765> : <%o>\n", 0765 );
299| printm("should see <1010> : <%b>\n", 0xa );
300| printm("should see < 123> : <%6d>\n", 123 );
301| printm("should see < 456> : <%*d>\n", 6,456 );
302| printm("should see < -123> : <%6d>\n", -123 );
303| printm("should see <123 > : <%-6d>\n", 123 );
304| printm("should see <-123 > : <%-6d>\n", -123 );
305| printm("should see <-00123> : <%06d>\n", -123 );
306| printm("should see <abcd:123>: <%p>\n",
307| (char far *)( 0xabcd0123L) );
308| }
309| #endif
Listing Two -- /SRC/TOOLS/LTOS.C, Printed 1/10/1988
____________________________________________________________________________
1| /* LTOS.C Convert long to string in indicated base.
2| * (C) 1988 Allen I. Holub. All rights reserved.
3| */
4|
5| char *ltos( n, buf, base )
6| unsigned long n ;
7| char *buf ;
8| int base ;
9| {
10| /* Convert long to string. Prints in hex, decimal, octal,
11| * or binary.
12| * "n" is the number to be converted
13| * "buf" is the output buffer.
14| * "base" is the base (16, 10, 8 or 2).
15| *
16| * The output string is null terminated and a pointer to the
17| * null terminator is returned.
18| *
19| * The number is put into an array one digit at a time as
20| * it's translated. The array is filled with the digits
21| * reversed (ie. the \0 goes in first, then the rightmost
22| * digit, etc.) and then is reversed in place before
23| * returning.
24| *
25| * This routine is much like the unix() ltoa except that
26| * it returns a pointer to the end of the string.
27| */
28|
29| register char *bp = buf;
30| register int minus = 0;
31| char *endp;
32|
33| if( base < 2 || base > 16 )
34| return 0;
35|
36| if( base == 10 && (long)n < 0 ) /* If the number is negative */
37| { /* and we're in base 10, set */
38| minus++ ; /* minus to true and make it */
39| n = -( (long)n ); /* positive. */
40| }
41|
42| *bp = '\0' ; /* Have to put the null in now */
43| /* because the array is being */
44| /* filled in reverse order. */
45| do {
46| *++bp = "0123456789abcdef" [ n % base ];
47| n /= base;
48|
49| } while( n );
50|
51| if( minus )
52| *++bp = '-';
53|
54| for( endp = bp; bp > buf ;) /* Reverse string in place */
55| {
56| minus = *bp; /* Use minus for temporary */
57| *bp -- = *buf; /* storage. */
58| *buf++ = minus;
59| }
60|
61| return endp; /* Return pointer to terminating null */
62| }