Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 1
/*
2
 * This code contains changes by
3
 *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4
 *
5
 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6
 * to these changes.
7
 *
8
 *
9
 * Copyright (c) 1980, 1993
10
 * 	The Regents of the University of California.  All rights reserved.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgement:
22
 * 	This product includes software developed by the University of
23
 * 	California, Berkeley and its contributors.
24
 * 4. Neither the name of the University nor the names of its contributors
25
 *    may be used to endorse or promote products derived from this software
26
 *    without specific prior written permission.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
 * SUCH DAMAGE.
39
 *
40
 *
41
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42
 *
43
 * Redistribution and use in source and binary forms, with or without
44
 * modification, are permitted provided that the following conditions
45
 * are met:
46
 *   Redistributions of source code and documentation must retain the
47
 *    above copyright notice, this list of conditions and the following
48
 *    disclaimer.
49
 *   Redistributions in binary form must reproduce the above copyright
50
 *    notice, this list of conditions and the following disclaimer in the
51
 *    documentation and/or other materials provided with the distribution.
52
 *   All advertising materials mentioning features or use of this software
53
 *    must display the following acknowledgement:
54
 *      This product includes software developed or owned by Caldera
55
 *      International, Inc.
56
 *   Neither the name of Caldera International, Inc. nor the names of
57
 *    other contributors may be used to endorse or promote products
58
 *    derived from this software without specific prior written permission.
59
 *
60
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
 */
73
 
74
#ifndef	lint
75
#ifdef	DOSCCS
76
static char sccsid[] = "@(#)printf.c	1.15 (gritter) 12/1/04";
77
#endif
78
#endif
79
 
80
/* from printf.c	7.3 (Berkeley) 6/7/85 */
81
 
82
/* The pwb version this is based on */
83
/* from printf.c:2.2 6/5/79 */
84
 
85
#include "ex.h"
86
 
87
/*
88
 * This version of printf is compatible with the Version 7 C
89
 * printf. The differences are only minor except that this
90
 * printf assumes it is to print through putchar. Version 7
91
 * printf is more general (and is much larger) and includes
92
 * provisions for floating point.
93
 */
94
 
95
static int width, sign, fill;
96
 
97
int vprintf(const char *, va_list);
98
char *p_dconv(long, char *);
99
static int p_emit(char *, char *);
100
 
101
int
102
printf(const char *fmt, ...)
103
{
104
	va_list ap;
105
	int ret;
106
 
107
	va_start(ap, fmt);
108
	ret = vprintf(fmt, ap);
109
	va_end(ap);
110
	return ret;
111
}
112
 
113
int
114
vprintf(const char *fmt, va_list ap)
115
{
116
	int	cnt = 0;
117
	int fcode;
118
	int prec;
119
	int length,mask1,nbits,n,m;
120
	long int mask2, num;
121
	register char *bptr;
122
	char *ptr;
123
	char buf[134];
124
 
125
	for (;;) {
126
		/* process format string first */
127
		while (nextc(fcode,fmt,m), fmt+=m, fcode!='%') {
128
			/* ordinary (non-%) character */
129
			if (fcode=='\0')
130
				return cnt;
131
			putchar(fcode);
132
			cnt += m;
133
		}
134
		/* length modifier: -1 for h, 1 for l, 0 for none */
135
		length = 0;
136
		/* check for a leading - sign */
137
		sign = 0;
138
		if (*fmt == '-') {
139
			sign++;
140
			fmt++;
141
		}
142
		/* a '0' may follow the - sign */
143
		/* this is the requested fill character */
144
		fill = 1;
145
		if (*fmt == '0') {
146
			fill--;
147
			fmt++;
148
		}
149
 
150
		/* Now comes a digit string which may be a '*' */
151
		if (*fmt == '*') {
152
			width = va_arg(ap, int);
153
			if (width < 0) {
154
				width = -width;
155
				sign = !sign;
156
			}
157
			fmt++;
158
		}
159
		else {
160
			width = 0;
161
			while (*fmt>='0' && *fmt<='9')
162
				width = width * 10 + (*fmt++ - '0');
163
		}
164
 
165
		/* maybe a decimal point followed by more digits (or '*') */
166
		if (*fmt=='.') {
167
			if (*++fmt == '*') {
168
				prec = va_arg(ap, int);
169
				fmt++;
170
			}
171
			else {
172
				prec = 0;
173
				while (*fmt>='0' && *fmt<='9')
174
					prec = prec * 10 + (*fmt++ - '0');
175
			}
176
		}
177
		else
178
			prec = -1;
179
 
180
		/*
181
		 * At this point, "sign" is nonzero if there was
182
		 * a sign, "fill" is 0 if there was a leading
183
		 * zero and 1 otherwise, "width" and "prec"
184
		 * contain numbers corresponding to the digit
185
		 * strings before and after the decimal point,
186
		 * respectively, and "fmt" addresses the next
187
		 * character after the whole mess. If there was
188
		 * no decimal point, "prec" will be -1.
189
		 */
190
		switch (*fmt) {
191
			case 'L':
192
			case 'l':
193
				length = 2;
194
				/* no break!! */
195
			case 'h':
196
			case 'H':
197
				length--;
198
				fmt++;
199
				break;
200
		}
201
 
202
		/*
203
		 * At exit from the following switch, we will
204
		 * emit the characters starting at "bptr" and
205
		 * ending at "ptr"-1, unless fcode is '\0'.
206
		 */
207
		switch (nextc(fcode, fmt, m), fmt += m, fcode) {
208
			/* process characters and strings first */
209
			case 'c':
210
				buf[0] = va_arg(ap, int);
211
				ptr = bptr = &buf[0];
212
				if (buf[0] != '\0')
213
					ptr++;
214
				break;
215
			case 's':
216
				bptr = va_arg(ap,char *);
217
				if (bptr==0)
218
					bptr = catgets(catd, 1, 248,
219
							"(null pointer)");
220
				if (prec < 0)
221
					prec = LRGINT;
222
				for (n=0; *bptr++ && n < prec; n++) ;
223
				ptr = --bptr;
224
				bptr -= n;
225
				break;
226
			case 'O':
227
				length = 1;
228
				fcode = 'o';
229
				/* no break */
230
			case 'o':
231
			case 'X':
232
			case 'x':
233
				if (length > 0)
234
					num = va_arg(ap,long);
235
				else
236
					num = (unsigned)va_arg(ap,int);
237
				if (fcode=='o') {
238
					mask1 = 0x7;
239
					mask2 = 0x1fffffffL;
240
					nbits = 3;
241
				}
242
				else {
243
					mask1 = 0xf;
244
					mask2 = 0x0fffffffL;
245
					nbits = 4;
246
				}
247
				n = (num!=0);
248
				bptr = buf + MAXOCT + 3;
249
				/* shift and mask for speed */
250
				do
251
				    if (((int) num & mask1) < 10)
252
					*--bptr = ((int) num & mask1) + 060;
253
				    else
254
					*--bptr = ((int) num & mask1) + 0127;
255
				while (num = (num >> nbits) & mask2);
256
 
257
				if (fcode=='o') {
258
					if (n)
259
						*--bptr = '0';
260
				}
261
				else
262
					if (!sign && fill <= 0) {
263
						putchar('0');
264
						putchar(fcode);
265
						width -= 2;
266
					}
267
					else {
268
						*--bptr = fcode;
269
						*--bptr = '0';
270
					}
271
				ptr = buf + MAXOCT + 3;
272
				break;
273
			case 'D':
274
			case 'U':
275
			case 'I':
276
				length = 1;
277
				fcode = fcode + 'a' - 'A';
278
				/* no break */
279
			case 'd':
280
			case 'i':
281
			case 'u':
282
				if (length > 0)
283
					num = va_arg(ap,long);
284
				else {
285
					n = va_arg(ap,int);
286
					if (fcode=='u')
287
						num = (unsigned) n;
288
					else
289
						num = (long) n;
290
				}
291
				if (n = (fcode != 'u' && num < 0))
292
					num = -num;
293
				/* now convert to digits */
294
				bptr = p_dconv(num, buf);
295
				if (n)
296
					*--bptr = '-';
297
				if (fill == 0)
298
					fill = -1;
299
				ptr = buf + MAXDIGS + 1;
300
				break;
301
			default:
302
				/* not a control character, 
303
				 * print it.
304
				 */
305
				ptr = bptr = (char *)&fmt[-m];
306
				ptr++;
307
				break;
308
			}
309
			if (fcode != '\0')
310
				cnt += p_emit(bptr,ptr);
311
	}
312
}
313
 
314
/* p_dconv converts the unsigned long integer "value" to
315
 * printable decimal and places it in "buffer", right-justified.
316
 * The value returned is the address of the first non-zero character,
317
 * or the address of the last character if all are zero.
318
 * The result is NOT null terminated, and is MAXDIGS characters long,
319
 * starting at buffer[1] (to allow for insertion of a sign).
320
 *
321
 * This program assumes it is running on 2's complement machine
322
 * with reasonable overflow treatment.
323
 */
324
char *
325
p_dconv(long value, char *buffer)
326
{
327
	register char *bp;
328
	register int svalue;
329
	int n;
330
	long lval;
331
 
332
	bp = buffer;
333
 
334
	/* zero is a special case */
335
	if (value == 0) {
336
		bp += MAXDIGS;
337
		*bp = '0';
338
		return(bp);
339
	}
340
 
341
	/* develop the leading digit of the value in "n" */
342
	n = 0;
343
	while (value < 0) {
344
		value -= BIG;	/* will eventually underflow */
345
		n++;
346
	}
347
	while (value >= BIG && (lval = value - BIG) >= 0) {
348
		value = lval;
349
		n++;
350
	}
351
 
352
	/* stash it in buffer[1] to allow for a sign */
353
	bp[1] = n + '0';
354
	/*
355
	 * Now develop the rest of the digits. Since speed counts here,
356
	 * we do it in two loops. The first gets "value" down until it
357
	 * is no larger than LRGINT. The second one uses integer divides
358
	 * rather than long divides to speed it up.
359
	 */
360
	bp += MAXDIGS + 1;
361
	while (value > LRGINT) {
362
		*--bp = (int)(value % 10) + '0';
363
		value /= 10;
364
	}
365
 
366
	/* cannot lose precision */
367
	svalue = value;
368
	while (svalue > 0) {
369
		*--bp = (svalue % 10) + '0';
370
		svalue /= 10;
371
	}
372
 
373
	/* fill in intermediate zeroes if needed */
374
	if (buffer[1] != '0') {
375
		while (bp > buffer + 2)
376
			*--bp = '0';
377
		--bp;
378
	}
379
	return(bp);
380
}
381
 
382
/*
383
 * This program sends string "s" to putchar. The character after
384
 * the end of "s" is given by "send". This allows the size of the
385
 * field to be computed; it is stored in "alen". "width" contains the
386
 * user specified length. If width<alen, the width will be taken to
387
 * be alen. "sign" is zero if the string is to be right-justified
388
 * in the field, nonzero if it is to be left-justified. "fill" is
389
 * 0 if the string is to be padded with '0', positive if it is to be
390
 * padded with ' ', and negative if an initial '-' should appear before
391
 * any padding in right-justification (to avoid printing "-3" as
392
 * "000-3" where "-0003" was intended).
393
 */
394
static int 
395
p_emit(register char *s, char *send)
396
{
397
	char cfill;
398
	register int alen;
399
	int npad;
400
	int	cnt = 0;
401
	int	c, m;
402
 
403
	alen = send - s;
404
	if (alen > width)
405
		width = alen;
406
	cfill = fill>0? ' ': '0';
407
 
408
	/* we may want to print a leading '-' before anything */
409
	if (*s == '-' && fill < 0) {
410
		putchar(*s++);
411
		cnt++;
412
		alen--;
413
		width--;
414
	}
415
	npad = width - alen;
416
 
417
	/* emit any leading pad characters */
418
	if (!sign)
419
		while (--npad >= 0) {
420
			putchar(cfill);
421
			cnt++;
422
		}
423
 
424
	/* emit the string itself */
425
	while (--alen >= 0) {
426
		nextc(c, s, m);
427
		s += m;
428
		putchar(c);
429
		cnt += m;
430
		alen -= m-1;
431
	}
432
 
433
	/* emit trailing pad characters */
434
	if (sign)
435
		while (--npad >= 0) {
436
			putchar(cfill);
437
			cnt++;
438
		}
439
	return cnt;
440
}