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",
32 "no free space on disk",
33 "too many files are open",
34 "file or block not found",
36 "file already exists",
37 "file is not a valid executable",
41 * Print a number (base <= 16) in reverse order,
42 * using specified putch function and associated pointer putdat.
45 printnum(void (*putch
)(int, void*), void *putdat
,
46 unsigned long long num
, unsigned base
, int width
, int padc
)
48 // first recursively print all preceding (more significant) digits
50 printnum(putch
, putdat
, num
/ base
, base
, width
- 1, padc
);
52 // print any needed pad characters before first digit
57 // then print this (the least significant) digit
58 putch("0123456789abcdef"[num
% base
], putdat
);
61 // Get an unsigned int of various possible sizes from a varargs list,
62 // depending on the lflag parameter.
63 static unsigned long long
64 getuint(va_list *ap
, int lflag
)
67 return va_arg(*ap
, unsigned long long);
69 return va_arg(*ap
, unsigned long);
71 return va_arg(*ap
, unsigned int);
74 // Same as getuint but signed - can't use getuint
75 // because of sign extension
77 getint(va_list *ap
, int lflag
)
80 return va_arg(*ap
, long long);
82 return va_arg(*ap
, long);
84 return va_arg(*ap
, int);
88 // Main function to format and print a string.
89 void printfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, ...);
92 vprintfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, va_list ap
)
94 register const char *p
;
96 unsigned long long num
;
97 int base
, lflag
, width
, precision
, altflag
;
101 while ((ch
= *(unsigned char *) fmt
++) != '%') {
107 // Process a %-escape sequence
114 switch (ch
= *(unsigned char *) fmt
++) {
116 // flag to pad on the right
121 // flag to pad with 0's instead of spaces
136 for (precision
= 0; ; ++fmt
) {
137 precision
= precision
* 10 + ch
- '0';
139 if (ch
< '0' || ch
> '9')
142 goto process_precision
;
145 precision
= va_arg(ap
, int);
146 goto process_precision
;
159 width
= precision
, precision
= -1;
162 // long flag (doubled for long long)
169 putch(va_arg(ap
, int), putdat
);
174 err
= va_arg(ap
, int);
177 if (err
> MAXERROR
|| (p
= error_string
[err
]) == NULL
)
178 printfmt(putch
, putdat
, "error %d", err
);
180 printfmt(putch
, putdat
, "%s", p
);
185 if ((p
= va_arg(ap
, char *)) == NULL
)
187 if (width
> 0 && padc
!= '-')
188 for (width
-= strnlen(p
, precision
); width
> 0; width
--)
190 for (; (ch
= *p
++) != '\0' && (precision
< 0 || --precision
>= 0); width
--)
191 if (altflag
&& (ch
< ' ' || ch
> '~'))
195 for (; width
> 0; width
--)
201 num
= getint(&ap
, lflag
);
202 if ((long long) num
< 0) {
204 num
= -(long long) num
;
211 num
= getuint(&ap
, lflag
);
217 // Replace this with your code.
218 num
= getuint(&ap
, lflag
);
226 num
= (unsigned long long)
227 (uintptr_t) va_arg(ap
, void *);
231 // (unsigned) hexadecimal
233 num
= getuint(&ap
, lflag
);
236 printnum(putch
, putdat
, num
, base
, width
, padc
);
239 // escaped '%' character
244 // unrecognized escape sequence - just print it literally
247 for (fmt
--; fmt
[-1] != '%'; fmt
--)
255 printfmt(void (*putch
)(int, void*), void *putdat
, const char *fmt
, ...)
260 vprintfmt(putch
, putdat
, fmt
, ap
);
271 sprintputch(int ch
, struct sprintbuf
*b
)
274 if (b
->buf
< b
->ebuf
)
279 vsnprintf(char *buf
, int n
, const char *fmt
, va_list ap
)
281 struct sprintbuf b
= {buf
, buf
+n
-1, 0};
283 if (buf
== NULL
|| n
< 1)
286 // print the string to the buffer
287 vprintfmt((void*)sprintputch
, &b
, fmt
, ap
);
289 // null terminate the buffer
296 snprintf(char *buf
, int n
, const char *fmt
, ...)
302 rc
= vsnprintf(buf
, n
, fmt
, ap
);