1 // Stripped-down primitive printf-style formatting routines,
2 // used in common by printf, sprintf, fprintf, etc.
3 // This code is also used by both the kernel and user programs.
7 #include <inc/string.h>
8 #include <inc/stdarg.h>
12 * Space or zero padding and a field width are supported for the numeric
15 * The special format %e takes an integer error code
16 * and prints a string describing the error.
17 * The integer may be positive or negative,
18 * so that -E_NO_MEM and E_NO_MEM are equivalent.
21 static const char * const error_string
[MAXERROR
+ 1] =
28 "out of environments",
31 "unexpected end of file",
35 * Print a number (base <= 16) in reverse order,
36 * using specified putch function and associated pointer putdat.
39 printnum(void (*putch
)(int, void*), void *putdat
,
40 unsigned long long num
, unsigned base
, int width
, int padc
)
42 // first recursively print all preceding (more significant) digits
44 printnum(putch
, putdat
, num
/ base
, base
, width
- 1, padc
);
46 // print any needed pad characters before first digit
51 // then print this (the least significant) digit
52 putch("0123456789abcdef"[num
% base
], putdat
);
55 // Get an unsigned int of various possible sizes from a varargs list,
56 // depending on the lflag parameter.
57 static unsigned long long
58 getuint(va_list *ap
, int lflag
)
61 return va_arg(*ap
, unsigned long long);
63 return va_arg(*ap
, unsigned long);
65 return va_arg(*ap
, unsigned int);
68 // Same as getuint but signed - can't use getuint
69 // because of sign extension
71 getint(va_list *ap
, int lflag
)
74 return va_arg(*ap
, long long);
76 return va_arg(*ap
, long);
78 return va_arg(*ap
, int);
82 // Main function to format and print a string.
83 void printfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, ...);
86 vprintfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, va_list ap
)
88 register const char *p
;
90 unsigned long long num
;
91 int base
, lflag
, width
, precision
, altflag
;
95 while ((ch
= *(unsigned char *) fmt
++) != '%') {
101 // Process a %-escape sequence
108 switch (ch
= *(unsigned char *) fmt
++) {
110 // flag to pad on the right
115 // flag to pad with 0's instead of spaces
130 for (precision
= 0; ; ++fmt
) {
131 precision
= precision
* 10 + ch
- '0';
133 if (ch
< '0' || ch
> '9')
136 goto process_precision
;
139 precision
= va_arg(ap
, int);
140 goto process_precision
;
153 width
= precision
, precision
= -1;
156 // long flag (doubled for long long)
163 putch(va_arg(ap
, int), putdat
);
168 err
= va_arg(ap
, int);
171 if (err
> MAXERROR
|| (p
= error_string
[err
]) == NULL
)
172 printfmt(putch
, putdat
, "error %d", err
);
174 printfmt(putch
, putdat
, "%s", p
);
179 if ((p
= va_arg(ap
, char *)) == NULL
)
181 if (width
> 0 && padc
!= '-')
182 for (width
-= strnlen(p
, precision
); width
> 0; width
--)
184 for (; (ch
= *p
++) != '\0' && (precision
< 0 || --precision
>= 0); width
--)
185 if (altflag
&& (ch
< ' ' || ch
> '~'))
189 for (; width
> 0; width
--)
195 num
= getint(&ap
, lflag
);
196 if ((long long) num
< 0) {
198 num
= -(long long) num
;
205 num
= getuint(&ap
, lflag
);
211 // Replace this with your code.
212 num
= getuint(&ap
, lflag
);
220 num
= (unsigned long long)
221 (uintptr_t) va_arg(ap
, void *);
225 // (unsigned) hexadecimal
227 num
= getuint(&ap
, lflag
);
230 printnum(putch
, putdat
, num
, base
, width
, padc
);
233 // escaped '%' character
238 // unrecognized escape sequence - just print it literally
241 for (fmt
--; fmt
[-1] != '%'; fmt
--)
249 printfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, ...)
254 vprintfmt(putch
, putdat
, fmt
, ap
);
265 sprintputch(int ch
, struct sprintbuf
*b
)
268 if (b
->buf
< b
->ebuf
)
273 vsnprintf(char *buf
, int n
, const char *fmt
, va_list ap
)
275 struct sprintbuf b
= {buf
, buf
+n
-1, 0};
277 if (buf
== NULL
|| n
< 1)
280 // print the string to the buffer
281 vprintfmt((void*)sprintputch
, &b
, fmt
, ap
);
283 // null terminate the buffer
290 snprintf(char *buf
, int n
, const char *fmt
, ...)
296 rc
= vsnprintf(buf
, n
, fmt
, ap
);