| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- /*
- * Copyright (c) 2008 Travis Geiselbrecht
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include <debug.h>
- #include <limits.h>
- #include <stdarg.h>
- #include <sys/types.h>
- #include <printf.h>
- #include <string.h>
- void putc(char c)
- {
- return _dputc(c);
- }
- int puts(const char *str)
- {
- return _dputs(str);
- }
- int getc(char *c)
- {
- return dgetc(c, true);
- }
- int printf(const char *fmt, ...)
- {
- int err;
- va_list ap;
- va_start(ap, fmt);
- err = _dvprintf(fmt, ap);
- va_end(ap);
- return err;
- }
- int sprintf(char *str, const char *fmt, ...)
- {
- int err;
- va_list ap;
- va_start(ap, fmt);
- err = vsprintf(str, fmt, ap);
- va_end(ap);
- return err;
- }
- int snprintf(char *str, size_t len, const char *fmt, ...)
- {
- int err;
- va_list ap;
- va_start(ap, fmt);
- err = vsnprintf(str, len, fmt, ap);
- va_end(ap);
- return err;
- }
- #define LONGFLAG 0x00000001
- #define LONGLONGFLAG 0x00000002
- #define HALFFLAG 0x00000004
- #define HALFHALFFLAG 0x00000008
- #define SIZETFLAG 0x00000010
- #define ALTFLAG 0x00000020
- #define CAPSFLAG 0x00000040
- #define SHOWSIGNFLAG 0x00000080
- #define SIGNEDFLAG 0x00000100
- #define LEFTFORMATFLAG 0x00000200
- #define LEADZEROFLAG 0x00000400
- static char *longlong_to_string(char *buf, unsigned long long n, int len, uint flag)
- {
- int pos = len;
- int negative = 0;
- if ((flag & SIGNEDFLAG) && (long long)n < 0) {
- negative = 1;
- n = -n;
- }
- buf[--pos] = 0;
- /* only do the math if the number is >= 10 */
- while (n >= 10) {
- int digit = n % 10;
- n /= 10;
- buf[--pos] = digit + '0';
- }
- buf[--pos] = n + '0';
- if (negative)
- buf[--pos] = '-';
- else if ((flag & SHOWSIGNFLAG))
- buf[--pos] = '+';
- return &buf[pos];
- }
- static char *longlong_to_hexstring(char *buf, unsigned long long u, int len, uint flag)
- {
- int pos = len;
- static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- const char *table;
- if ((flag & CAPSFLAG))
- table = hextable_caps;
- else
- table = hextable;
- buf[--pos] = 0;
- do {
- unsigned int digit = u % 16;
- u /= 16;
- buf[--pos] = table[digit];
- } while (u != 0);
- return &buf[pos];
- }
- int vsprintf(char *str, const char *fmt, va_list ap)
- {
- return vsnprintf(str, INT_MAX, fmt, ap);
- }
- int vsnprintf(char *str, size_t len, const char *fmt, va_list ap)
- {
- char c;
- unsigned char uc;
- const char *s;
- unsigned long long n;
- void *ptr;
- int flags;
- unsigned int format_num;
- size_t chars_written = 0;
- char num_buffer[32];
- #define OUTPUT_CHAR(c) do { (*str++ = c); chars_written++; if (chars_written + 1 >= len) goto done; } while(0)
- #define OUTPUT_CHAR_NOLENCHECK(c) do { (*str++ = c); chars_written++; } while(0)
- if (len == 0)
- return 0;
- for (;;) {
- /* handle regular chars that aren't format related */
- while ((c = *fmt++) != 0) {
- if (c == '%')
- break; /* we saw a '%', break and start parsing format */
- OUTPUT_CHAR(c);
- }
- /* make sure we haven't just hit the end of the string */
- if (c == 0)
- break;
- /* reset the format state */
- flags = 0;
- format_num = 0;
- next_format:
- /* grab the next format character */
- c = *fmt++;
- if (c == 0)
- break;
- switch (c) {
- case '0'...'9':
- if (c == '0' && format_num == 0)
- flags |= LEADZEROFLAG;
- format_num *= 10;
- format_num += c - '0';
- goto next_format;
- case '.':
- /* XXX for now eat numeric formatting */
- goto next_format;
- case '%':
- OUTPUT_CHAR('%');
- break;
- case 'c':
- uc = va_arg(ap, unsigned int);
- OUTPUT_CHAR(uc);
- break;
- case 's':
- s = va_arg(ap, const char *);
- if (s == 0)
- s = "<null>";
- goto _output_string;
- case '-':
- flags |= LEFTFORMATFLAG;
- goto next_format;
- case '+':
- flags |= SHOWSIGNFLAG;
- goto next_format;
- case '#':
- flags |= ALTFLAG;
- goto next_format;
- case 'l':
- if (flags & LONGFLAG)
- flags |= LONGLONGFLAG;
- flags |= LONGFLAG;
- goto next_format;
- case 'h':
- if (flags & HALFFLAG)
- flags |= HALFHALFFLAG;
- flags |= HALFFLAG;
- goto next_format;
- case 'z':
- flags |= SIZETFLAG;
- goto next_format;
- case 'D':
- flags |= LONGFLAG;
- /* fallthrough */
- case 'i':
- case 'd':
- n = (flags & LONGLONGFLAG) ? va_arg(ap, long long) :
- (flags & LONGFLAG) ? va_arg(ap, long) :
- (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) :
- (flags & HALFFLAG) ? (short)va_arg(ap, int) :
- (flags & SIZETFLAG) ? va_arg(ap, ssize_t) :
- va_arg(ap, int);
- flags |= SIGNEDFLAG;
- s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags);
- goto _output_string;
- case 'U':
- flags |= LONGFLAG;
- /* fallthrough */
- case 'u':
- n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
- (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
- (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
- (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
- (flags & SIZETFLAG) ? va_arg(ap, size_t) :
- va_arg(ap, unsigned int);
- s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags);
- goto _output_string;
- case 'p':
- flags |= LONGFLAG | ALTFLAG;
- goto hex;
- case 'X':
- flags |= CAPSFLAG;
- /* fallthrough */
- hex:
- case 'x':
- n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
- (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
- (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
- (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
- (flags & SIZETFLAG) ? va_arg(ap, size_t) :
- va_arg(ap, unsigned int);
- s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags);
- if (flags & ALTFLAG) {
- OUTPUT_CHAR('0');
- OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x');
- }
- goto _output_string;
- case 'n':
- ptr = va_arg(ap, void *);
- if (flags & LONGLONGFLAG)
- *(long long *)ptr = chars_written;
- else if (flags & LONGFLAG)
- *(long *)ptr = chars_written;
- else if (flags & HALFHALFFLAG)
- *(signed char *)ptr = chars_written;
- else if (flags & HALFFLAG)
- *(short *)ptr = chars_written;
- else if (flags & SIZETFLAG)
- *(size_t *)ptr = chars_written;
- else
- *(int *)ptr = chars_written;
- break;
- default:
- OUTPUT_CHAR('%');
- OUTPUT_CHAR(c);
- break;
- }
- /* move on to the next field */
- continue;
- /* shared output code */
- _output_string:
- if (flags & LEFTFORMATFLAG) {
- /* left justify the text */
- uint count = 0;
- while (*s != 0) {
- OUTPUT_CHAR(*s++);
- count++;
- }
- /* pad to the right (if necessary) */
- for (; format_num > count; format_num--)
- OUTPUT_CHAR(' ');
- } else {
- /* right justify the text (digits) */
- size_t string_len = strlen(s);
- char outchar = (flags & LEADZEROFLAG) ? '0' : ' ';
- for (; format_num > string_len; format_num--)
- OUTPUT_CHAR(outchar);
- /* output the string */
- while (*s != 0)
- OUTPUT_CHAR(*s++);
- }
- continue;
- }
- done:
- /* null terminate */
- OUTPUT_CHAR_NOLENCHECK('\0');
- chars_written--; /* don't count the null */
- #undef OUTPUT_CHAR
- #undef OUTPUT_CHAR_NOLENCHECK
- return chars_written;
- }
|