Subversion Repositories HelenOS

Rev

Rev 2479 | Rev 3347 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
974 cejka 1
/*
2071 jermar 2
 * Copyright (c) 2001-2004 Jakub Jermar
3
 * Copyright (c) 2006 Josef Cejka
974 cejka 4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
12
 * - Redistributions in binary form must reproduce the above copyright
13
 *   notice, this list of conditions and the following disclaimer in the
14
 *   documentation and/or other materials provided with the distribution.
15
 * - The name of the author may not be used to endorse or promote products
16
 *   derived from this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
 
1866 jermar 30
/** @addtogroup libc
1653 cejka 31
 * @{
32
 */
1272 cejka 33
/**
1653 cejka 34
 * @file
1272 cejka 35
 * @brief	Printing functions.
36
 */
37
 
1234 cejka 38
#include <unistd.h>
974 cejka 39
#include <stdio.h>
1234 cejka 40
#include <io/printf_core.h>
1173 cejka 41
#include <ctype.h>
42
#include <string.h>
974 cejka 43
 
1272 cejka 44
#define __PRINTF_FLAG_PREFIX		0x00000001	/**< show prefixes 0x or 0*/
45
#define __PRINTF_FLAG_SIGNED		0x00000002	/**< signed / unsigned number */
46
#define __PRINTF_FLAG_ZEROPADDED	0x00000004	/**< print leading zeroes */
47
#define __PRINTF_FLAG_LEFTALIGNED	0x00000010	/**< align to left */
48
#define __PRINTF_FLAG_SHOWPLUS		0x00000020	/**< always show + sign */
49
#define __PRINTF_FLAG_SPACESIGN		0x00000040	/**< print space instead of plus */
50
#define __PRINTF_FLAG_BIGCHARS		0x00000080	/**< show big characters */
51
#define __PRINTF_FLAG_NEGATIVE		0x00000100	/**< number has - sign */
995 cejka 52
 
1272 cejka 53
#define PRINT_NUMBER_BUFFER_SIZE	(64+5)		/**< Buffer big enought for 64 bit number
1073 cejka 54
							 * printed in base 2, sign, prefix and
55
							 * 0 to terminate string.. (last one is only for better testing 
56
							 * end of buffer by zero-filling subroutine)
57
							 */
1272 cejka 58
/** Enumeration of possible arguments types.
59
 */
1073 cejka 60
typedef enum {
61
	PrintfQualifierByte = 0,
62
	PrintfQualifierShort,
63
	PrintfQualifierInt,
64
	PrintfQualifierLong,
65
	PrintfQualifierLongLong,
66
	PrintfQualifierSizeT,
67
	PrintfQualifierPointer
68
} qualifier_t;
974 cejka 69
 
1272 cejka 70
static char digits_small[] = "0123456789abcdef";	/**< Small hexadecimal characters */
71
static char digits_big[] = "0123456789ABCDEF";		/**< Big hexadecimal characters */
995 cejka 72
 
1234 cejka 73
/** Print count chars from buffer without adding newline
74
 * @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
75
 * @param count 
76
 * @param ps output method and its data
1617 cejka 77
 * @return number of printed characters
1234 cejka 78
 */
2570 jermar 79
static int printf_putnchars(const char * buf, size_t count,
80
    struct printf_spec *ps)
1234 cejka 81
{
1617 cejka 82
	return ps->write((void *)buf, count, ps->data);
1234 cejka 83
}
1173 cejka 84
 
1234 cejka 85
/** Print string without added newline
86
 * @param str string to print
87
 * @param ps write function specification and support data
1617 cejka 88
 * @return number of printed characters
1234 cejka 89
 */
90
static int printf_putstr(const char * str, struct printf_spec *ps)
91
{
92
	size_t count;
93
 
2209 decky 94
	if (str == NULL)
1234 cejka 95
		return printf_putnchars("(NULL)", 6, ps);
96
 
97
	for (count = 0; str[count] != 0; count++);
98
 
2209 decky 99
	if (ps->write((void *) str, count, ps->data) == count)
1234 cejka 100
		return 0;
101
 
102
	return EOF;
103
}
104
 
105
/** Print one character to output
106
 * @param c one character
107
 * @param ps output method
1617 cejka 108
 * @return number of printed characters
1234 cejka 109
 */
110
static int printf_putchar(int c, struct printf_spec *ps)
111
{
112
	unsigned char ch = c;
113
 
1617 cejka 114
	return ps->write((void *) &ch, 1, ps->data);
1234 cejka 115
}
116
 
1173 cejka 117
/** Print one formatted character
118
 * @param c character to print
119
 * @param width 
120
 * @param flags
1617 cejka 121
 * @return number of printed characters
1173 cejka 122
 */
1234 cejka 123
static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
1173 cejka 124
{
125
	int counter = 0;
126
 
127
	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
2570 jermar 128
		/*
129
		 * One space is consumed by the character itself, hence the
130
		 * predecrement.
131
		 */
132
		while (--width > 0) {
1617 cejka 133
			if (printf_putchar(' ', ps) > 0)	
134
				++counter;
1173 cejka 135
		}
136
	}
1617 cejka 137
 
138
	if (printf_putchar(c, ps) > 0)
139
		counter++;
2570 jermar 140
	/*
141
	 * One space is consumed by the character itself, hence the
142
	 * predecrement.
143
	 */
144
	while (--width > 0) {
1617 cejka 145
		if (printf_putchar(' ', ps) > 0)
146
			++counter;
1173 cejka 147
	}
148
 
149
	return ++counter;
150
}
151
 
152
/** Print one string
153
 * @param s string
154
 * @param width 
155
 * @param precision
156
 * @param flags
1617 cejka 157
 * @return number of printed characters
1173 cejka 158
 */
2570 jermar 159
static int print_string(char *s, int width, int precision, uint64_t flags,
160
    struct printf_spec *ps)
1173 cejka 161
{
162
	int counter = 0;
163
	size_t size;
1617 cejka 164
	int retval;
1173 cejka 165
 
166
	if (s == NULL) {
1234 cejka 167
		return printf_putstr("(NULL)", ps);
1173 cejka 168
	}
169
 
170
	size = strlen(s);
171
 
172
	/* print leading spaces */
173
 
174
	if (precision == 0) 
175
		precision = size;
176
 
177
	width -= precision;
178
 
179
	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
180
		while (width-- > 0) { 	
1617 cejka 181
			if (printf_putchar(' ', ps) == 1)	
182
				counter++;
1173 cejka 183
		}
184
	}
185
 
2570 jermar 186
 	if ((retval = printf_putnchars(s, size < precision ? size : precision,
187
	    ps)) < 0) {
1617 cejka 188
		return -counter;
1173 cejka 189
	}
190
 
1617 cejka 191
	counter += retval;	
1173 cejka 192
 
193
	while (width-- > 0) {
1617 cejka 194
		if (printf_putchar(' ', ps) == 1)	
195
			++counter;
1173 cejka 196
	}
197
 
1617 cejka 198
	return counter;
1173 cejka 199
}
200
 
201
 
974 cejka 202
/** Print number in given base
203
 *
204
 * Print significant digits of a number in given
205
 * base.
206
 *
207
 * @param num  Number to print.
1173 cejka 208
 * @param width
209
 * @param precision
974 cejka 210
 * @param base Base to print the number in (should
211
 *             be in range 2 .. 16).
1073 cejka 212
 * @param flags output modifiers
1617 cejka 213
 * @return number of printed characters
974 cejka 214
 *
215
 */
2570 jermar 216
static int print_number(uint64_t num, int width, int precision, int base,
217
    uint64_t flags, struct printf_spec *ps)
974 cejka 218
{
1073 cejka 219
	char *digits = digits_small;
2570 jermar 220
	char d[PRINT_NUMBER_BUFFER_SIZE];	/* this is good enough even for
221
						 * base == 2, prefix and sign */
1073 cejka 222
	char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
1234 cejka 223
	int size = 0; /* size of number with all prefixes and signs */
224
	int number_size; /* size of plain number */
1173 cejka 225
	char sgn;
1617 cejka 226
	int retval;
227
	int counter = 0;
974 cejka 228
 
1073 cejka 229
	if (flags & __PRINTF_FLAG_BIGCHARS) 
230
		digits = digits_big;	
995 cejka 231
 
1073 cejka 232
	*ptr-- = 0; /* Put zero at end of string */
233
 
234
	if (num == 0) {
235
		*ptr-- = '0';
1173 cejka 236
		size++;
1073 cejka 237
	} else {
238
		do {
239
			*ptr-- = digits[num % base];
1173 cejka 240
			size++;
1073 cejka 241
		} while (num /= base);
242
	}
1234 cejka 243
 
244
	number_size = size;
1173 cejka 245
 
2570 jermar 246
	/*
247
	 * Collect sum of all prefixes/signs/... to calculate padding and
248
	 * leading zeroes
249
	 */
1173 cejka 250
	if (flags & __PRINTF_FLAG_PREFIX) {
1073 cejka 251
		switch(base) {
2070 jermar 252
		case 2:	/* Binary formating is not standard, but usefull */
253
			size += 2;
254
			break;
255
		case 8:
256
			size++;
257
			break;
258
		case 16:
259
			size += 2;
260
			break;
1073 cejka 261
		}
262
	}
1173 cejka 263
 
264
	sgn = 0;
1073 cejka 265
	if (flags & __PRINTF_FLAG_SIGNED) {
266
		if (flags & __PRINTF_FLAG_NEGATIVE) {
1173 cejka 267
			sgn = '-';
268
			size++;
1073 cejka 269
		} else if (flags & __PRINTF_FLAG_SHOWPLUS) {
2570 jermar 270
			sgn = '+';
271
			size++;
272
		} else if (flags & __PRINTF_FLAG_SPACESIGN) {
273
			sgn = ' ';
274
			size++;
275
		}
1073 cejka 276
	}
974 cejka 277
 
1073 cejka 278
	if (flags & __PRINTF_FLAG_LEFTALIGNED) {
279
		flags &= ~__PRINTF_FLAG_ZEROPADDED;
280
	}
1173 cejka 281
 
2570 jermar 282
	/*
283
	 * If number is leftaligned or precision is specified then zeropadding
284
	 * is ignored.
285
	 */
1073 cejka 286
	if (flags & __PRINTF_FLAG_ZEROPADDED) {
1173 cejka 287
		if ((precision == 0) && (width > size)) {
1234 cejka 288
			precision = width - size + number_size;
1073 cejka 289
		}
290
	}
1173 cejka 291
 
292
	/* print leading spaces */
2570 jermar 293
 
294
	/* We must print whole number not only a part. */
295
	if (number_size > precision)
1234 cejka 296
		precision = number_size;
1173 cejka 297
 
1234 cejka 298
	width -= precision + size - number_size;
1073 cejka 299
 
1173 cejka 300
	if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
301
		while (width-- > 0) { 	
1617 cejka 302
			if (printf_putchar(' ', ps) == 1)	
303
				counter++;
1173 cejka 304
		}
305
	}
306
 
307
	/* print sign */
308
	if (sgn) {
1617 cejka 309
		if (printf_putchar(sgn, ps) == 1)
310
			counter++;
1173 cejka 311
	}
312
 
313
	/* print prefix */
314
 
315
	if (flags & __PRINTF_FLAG_PREFIX) {
316
		switch(base) {
2070 jermar 317
		case 2:	/* Binary formating is not standard, but usefull */
318
			if (printf_putchar('0', ps) == 1)
319
				counter++;
320
			if (flags & __PRINTF_FLAG_BIGCHARS) {
321
				if (printf_putchar('B', ps) == 1)
1617 cejka 322
					counter++;
2070 jermar 323
			} else {
324
				if (printf_putchar('b', ps) == 1)
1617 cejka 325
					counter++;
2070 jermar 326
			}
327
			break;
328
		case 8:
329
			if (printf_putchar('o', ps) == 1)
330
				counter++;
331
			break;
332
		case 16:
333
			if (printf_putchar('0', ps) == 1)
334
				counter++;
335
			if (flags & __PRINTF_FLAG_BIGCHARS) {
336
				if (printf_putchar('X', ps) == 1)
1617 cejka 337
					counter++;
2070 jermar 338
			} else {
339
				if (printf_putchar('x', ps) == 1)
340
					counter++;
341
			}
342
			break;
1173 cejka 343
		}
344
	}
345
 
346
	/* print leading zeroes */
1234 cejka 347
	precision -= number_size;
1173 cejka 348
	while (precision-- > 0) { 	
1617 cejka 349
		if (printf_putchar('0', ps) == 1)
350
			counter++;
1173 cejka 351
	}
352
 
353
 
354
	/* print number itself */
355
 
1617 cejka 356
	if ((retval = printf_putstr(++ptr, ps)) > 0) {
357
		counter += retval;
358
	}
1173 cejka 359
 
360
	/* print ending spaces */
361
 
362
	while (width-- > 0) { 	
1617 cejka 363
		if (printf_putchar(' ', ps) == 1)	
364
			counter++;
1173 cejka 365
	}
366
 
1617 cejka 367
	return counter;
974 cejka 368
}
369
 
370
 
1272 cejka 371
/** Print formatted string.
974 cejka 372
 *
2570 jermar 373
 * Print string formatted according to the fmt parameter and variadic arguments.
374
 * Each formatting directive must have the following form:
1272 cejka 375
 * 
376
 * 	\% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
974 cejka 377
 *
1272 cejka 378
 * FLAGS:@n
379
 * 	- "#" Force to print prefix.
2570 jermar 380
 * 	For conversion \%o the prefix is 0, for %x and \%X prefixes are 0x and
381
 *	0X and for conversion \%b the prefix is 0b.
1272 cejka 382
 *
383
 * 	- "-"	Align to left.
384
 *
385
 * 	- "+"	Print positive sign just as negative.
386
 *
2570 jermar 387
 * 	- " "	If the printed number is positive and "+" flag is not set,
388
 *		print space in place of sign.
1272 cejka 389
 *
2570 jermar 390
 * 	- "0"	Print 0 as padding instead of spaces. Zeroes are placed between
391
 *		sign and the rest of the number. This flag is ignored if "-"
392
 *		flag is specified.
1199 cejka 393
 * 
1272 cejka 394
 * WIDTH:@n
2570 jermar 395
 * 	- Specify minimal width of printed argument. If it is bigger, width is
396
 *	  ignored. If width is specified with a "*" character instead of number,
397
 *	  width is taken from parameter list. And integer parameter is expected
398
 *	  before parameter for processed conversion specification. If this value
399
 *	  is negative its absolute value is taken and the "-" flag is set.
974 cejka 400
 *
1272 cejka 401
 * PRECISION:@n
402
 * 	- Value precision. For numbers it specifies minimum valid numbers.
2570 jermar 403
 *	  Smaller numbers are printed with leading zeroes. Bigger numbers are
404
 *	  not affected. Strings with more than precision characters are cut off.
405
 *	  Just as with width, an "*" can be used used instead of a number. An
406
 *	  integer value is then expected in parameters. When both width and
407
 *	  precision are specified using "*", the first parameter is used for
408
 *	  width and the second one for precision.
1199 cejka 409
 * 
1272 cejka 410
 * TYPE:@n
411
 * 	- "hh"	Signed or unsigned char.@n
412
 * 	- "h"	Signed or usigned short.@n
413
 * 	- ""	Signed or usigned int (default value).@n
414
 * 	- "l"	Signed or usigned long int.@n
415
 * 	- "ll"	Signed or usigned long long int.@n
416
 * 	- "z"	Type size_t.@n
1199 cejka 417
 * 
418
 * 
1272 cejka 419
 * CONVERSION:@n
420
 * 	- %	Print percentile character itself.
974 cejka 421
 *
1272 cejka 422
 * 	- c	Print single character.
974 cejka 423
 *
2570 jermar 424
 * 	- s	Print zero terminated string. If a NULL value is passed as
425
 *		value, "(NULL)" is printed instead.
1199 cejka 426
 * 
2570 jermar 427
 * 	- P, p	Print value of a pointer. Void * value is expected and it is
428
 *		printed in hexadecimal notation with prefix (as with '\%#X' or
429
 *		'\%#x' for 32bit or '\%#X' or '\%#x' for 64bit long pointers).
974 cejka 430
 *
2570 jermar 431
 * 	- b	Print value as unsigned binary number. Prefix is not printed by
432
 *		default. (Nonstandard extension.)
1199 cejka 433
 * 
2570 jermar 434
 * 	- o	Print value as unsigned octal number. Prefix is not printed by
435
 *		default. 
974 cejka 436
 *
2570 jermar 437
 * 	- d, i	Print signed decimal number. There is no difference between d
438
 *		and i conversion.
974 cejka 439
 *
1272 cejka 440
 * 	- u	Print unsigned decimal number.
974 cejka 441
 *
2570 jermar 442
 * 	- X, x	Print hexadecimal number with upper- or lower-case. Prefix is
443
 *		not printed by default.
1199 cejka 444
 * 
2570 jermar 445
 * All other characters from fmt except the formatting directives are printed in
446
 * verbatim.
974 cejka 447
 *
448
 * @param fmt Formatting NULL terminated string.
1272 cejka 449
 * @return Number of printed characters or negative value on failure.
974 cejka 450
 */
1234 cejka 451
int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
974 cejka 452
{
2570 jermar 453
	/* i is the index of the currently processed char from fmt */
454
	int i = 0;
455
	/* j is the index to the first not printed nonformating character */
456
	int j = 0;
457
 
1073 cejka 458
	int end;
2570 jermar 459
	int counter;	/* counter of printed characters */
460
	int retval;	/* used to store return values from called functions */
1073 cejka 461
	char c;
1444 cejka 462
	qualifier_t qualifier;	/* type of argument */
2570 jermar 463
	int base;	/* base in which will be a numeric parameter printed */
1444 cejka 464
	uint64_t number; /* argument value */
2570 jermar 465
	size_t	size;	/* byte size of integer parameter */
1173 cejka 466
	int width, precision;
995 cejka 467
	uint64_t flags;
974 cejka 468
 
469
	counter = 0;
1173 cejka 470
 
974 cejka 471
	while ((c = fmt[i])) {
992 jermar 472
		/* control character */
974 cejka 473
		if (c == '%' ) { 
992 jermar 474
			/* print common characters if any processed */	
974 cejka 475
			if (i > j) {
2570 jermar 476
				if ((retval = printf_putnchars(&fmt[j],
477
				    (size_t)(i - j), ps)) < 0) { /* error */
1616 palkovsky 478
					goto minus_out;
974 cejka 479
				}
480
				counter += retval;
481
			}
1073 cejka 482
 
483
			j = i;
995 cejka 484
			/* parse modifiers */
485
			flags = 0;
1073 cejka 486
			end = 0;
487
 
488
			do {
489
				++i;
490
				switch (c = fmt[i]) {
2570 jermar 491
				case '#':
492
					flags |= __PRINTF_FLAG_PREFIX;
493
					break;
494
				case '-':
495
					flags |= __PRINTF_FLAG_LEFTALIGNED;
496
					break;
497
				case '+':
498
					flags |= __PRINTF_FLAG_SHOWPLUS;
499
					break;
500
				case ' ':
501
					flags |= __PRINTF_FLAG_SPACESIGN;
502
					break;
503
				case '0':
504
					flags |= __PRINTF_FLAG_ZEROPADDED;
505
					break;
506
				default:
507
					end = 1;
1073 cejka 508
				};	
509
 
510
			} while (end == 0);	
1173 cejka 511
 
512
			/* width & '*' operator */
513
			width = 0;
514
			if (isdigit(fmt[i])) {
515
				while (isdigit(fmt[i])) {
516
					width *= 10;
517
					width += fmt[i++] - '0';
518
				}
519
			} else if (fmt[i] == '*') {
520
				/* get width value from argument list*/
521
				i++;
522
				width = (int)va_arg(ap, int);
523
				if (width < 0) {
2570 jermar 524
					/* negative width sets '-' flag */
1173 cejka 525
					width *= -1;
526
					flags |= __PRINTF_FLAG_LEFTALIGNED;
527
				}
528
			}
529
 
530
			/* precision and '*' operator */	
531
			precision = 0;
532
			if (fmt[i] == '.') {
533
				++i;
534
				if (isdigit(fmt[i])) {
535
					while (isdigit(fmt[i])) {
536
						precision *= 10;
537
						precision += fmt[i++] - '0';
538
					}
539
				} else if (fmt[i] == '*') {
2570 jermar 540
					/* get precision value from argument */
1173 cejka 541
					i++;
542
					precision = (int)va_arg(ap, int);
543
					if (precision < 0) {
2570 jermar 544
						/* negative precision ignored */
1173 cejka 545
						precision = 0;
546
					}
547
				}
548
			}
1073 cejka 549
 
550
			switch (fmt[i++]) {
2570 jermar 551
			/** @todo unimplemented qualifiers:
2070 jermar 552
			 * t ptrdiff_t - ISO C 99
553
			 */
554
			case 'h':	/* char or short */
555
				qualifier = PrintfQualifierShort;
556
				if (fmt[i] == 'h') {
557
					i++;
558
					qualifier = PrintfQualifierByte;
559
				}
560
				break;
561
			case 'l':	/* long or long long*/
562
				qualifier = PrintfQualifierLong;
563
				if (fmt[i] == 'l') {
564
					i++;
565
					qualifier = PrintfQualifierLongLong;
566
				}
567
				break;
568
			case 'z':	/* size_t */
569
				qualifier = PrintfQualifierSizeT;
570
				break;
571
			default:
2570 jermar 572
				/* set default type */
573
				qualifier = PrintfQualifierInt;
2070 jermar 574
				--i;
995 cejka 575
			}	
1073 cejka 576
 
577
			base = 10;
578
 
974 cejka 579
			switch (c = fmt[i]) {
580
 
2570 jermar 581
			/*
582
			 * String and character conversions.
583
			 */
2070 jermar 584
			case 's':
2570 jermar 585
				if ((retval = print_string(va_arg(ap, char*),
586
				    width, precision, flags, ps)) < 0) {
2070 jermar 587
					goto minus_out;
588
				}
974 cejka 589
 
2070 jermar 590
				counter += retval;
591
				j = i + 1; 
592
				goto next_char;
593
			case 'c':
594
				c = va_arg(ap, unsigned int);
2570 jermar 595
				retval = print_char(c, width, flags, ps);
596
				if (retval < 0) {
2070 jermar 597
					goto minus_out;
598
				}
974 cejka 599
 
2070 jermar 600
				counter += retval;
601
				j = i + 1;
602
				goto next_char;
603
 
604
			/* 
605
			 * Integer values
2570 jermar 606
			 */
2070 jermar 607
			case 'P': /* pointer */
608
			       	flags |= __PRINTF_FLAG_BIGCHARS;
609
			case 'p':
610
				flags |= __PRINTF_FLAG_PREFIX;
611
				base = 16;
612
				qualifier = PrintfQualifierPointer;
613
				break;	
614
			case 'b': 
615
				base = 2;
616
				break;
617
			case 'o':
618
				base = 8;
619
				break;
620
			case 'd':
621
			case 'i':
622
				flags |= __PRINTF_FLAG_SIGNED;  
623
			case 'u':
624
				break;
625
			case 'X':
626
				flags |= __PRINTF_FLAG_BIGCHARS;
627
			case 'x':
628
				base = 16;
629
				break;
630
			/* percentile itself */
631
			case '%': 
632
				j = i;
633
				goto next_char;
634
			/*
2570 jermar 635
			 * Bad formatting.
636
			 */
2070 jermar 637
			default:
2570 jermar 638
				/*
639
				 * Unknown format. Now, j is the index of '%',
640
				 * so we will print the whole bad format
641
				 * sequence.
2070 jermar 642
				 */
643
				goto next_char;		
1073 cejka 644
			}
645
 
646
 
2570 jermar 647
			/* Print integers */
1073 cejka 648
			switch (qualifier) {
2070 jermar 649
			case PrintfQualifierByte:
650
				size = sizeof(unsigned char);
651
				number = (uint64_t)va_arg(ap, unsigned int);
652
				break;
653
			case PrintfQualifierShort:
654
				size = sizeof(unsigned short);
655
				number = (uint64_t)va_arg(ap, unsigned int);
656
				break;
657
			case PrintfQualifierInt:
658
				size = sizeof(unsigned int);
659
				number = (uint64_t)va_arg(ap, unsigned int);
660
				break;
661
			case PrintfQualifierLong:
662
				size = sizeof(unsigned long);
663
				number = (uint64_t)va_arg(ap, unsigned long);
664
				break;
665
			case PrintfQualifierLongLong:
666
				size = sizeof(unsigned long long);
2570 jermar 667
				number = (uint64_t)va_arg(ap,
668
				    unsigned long long);
2070 jermar 669
				break;
670
			case PrintfQualifierPointer:
671
				size = sizeof(void *);
2570 jermar 672
				number = (uint64_t)(unsigned long)va_arg(ap,
673
				    void *);
2070 jermar 674
				break;
675
			case PrintfQualifierSizeT:
676
				size = sizeof(size_t);
677
				number = (uint64_t)va_arg(ap, size_t);
678
				break;
679
			default: /* Unknown qualifier */
680
				goto minus_out;
1073 cejka 681
 
974 cejka 682
			}
1073 cejka 683
 
684
			if (flags & __PRINTF_FLAG_SIGNED) {
2570 jermar 685
				if (number & (0x1 << (size * 8 - 1))) {
1073 cejka 686
					flags |= __PRINTF_FLAG_NEGATIVE;
687
 
688
					if (size == sizeof(uint64_t)) {
689
						number = -((int64_t)number);
690
					} else {
691
						number = ~number;
2570 jermar 692
						number &=
693
						    ~(0xFFFFFFFFFFFFFFFFll <<
694
						    (size * 8));
1073 cejka 695
						number++;
696
					}
697
				}
698
			}
699
 
2570 jermar 700
			if ((retval = print_number(number, width, precision,
701
			    base, flags, ps)) < 0 ) {
1616 palkovsky 702
				goto minus_out;
2570 jermar 703
			}
1073 cejka 704
 
705
			counter += retval;
706
			j = i + 1;
974 cejka 707
		}	
1073 cejka 708
next_char:
709
 
974 cejka 710
		++i;
711
	}
712
 
975 cejka 713
	if (i > j) {
2570 jermar 714
		retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps);
715
		if (retval < 0) { /* error */
1616 palkovsky 716
			goto minus_out;
975 cejka 717
		}
718
		counter += retval;
719
	}
720
 
974 cejka 721
	return counter;
1616 palkovsky 722
minus_out:
723
	return -counter;
974 cejka 724
}
725
 
1866 jermar 726
/** @}
1653 cejka 727
 */