Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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