123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * string.c
- *
- * String manipulation functions.
- *
- * Written & released by Keir Fraser <keir.xen@gmail.com>
- *
- * This is free and unencumbered software released into the public domain.
- * See the file COPYING for more details, or visit <http://unlicense.org>.
- */
- static void do_putch(char **p, char *end, char c)
- {
- if (*p < end)
- **p = c;
- (*p)++;
- }
- int vsnprintf(char *str, size_t size, const char *format, va_list ap)
- {
- unsigned int x, flags;
- int width;
- char c, *p = str, *end = p + size - 1, tmp[12], *q;
- while ((c = *format++) != '\0') {
- if (c != '%') {
- do_putch(&p, end, c);
- continue;
- }
- flags = width = 0;
- #define BASE (31u << 0)
- #define UPPER ( 1u << 8)
- #define SIGN ( 1u << 9)
- #define ALTERNATE ( 1u << 10)
- #define ZEROPAD ( 1u << 11)
- #define CHAR ( 1u << 12)
- #define SHORT ( 1u << 13)
- more:
- switch (c = *format++) {
- case '*':
- width = va_arg(ap, unsigned int);
- goto more;
- case '#':
- flags |= ALTERNATE;
- goto more;
- case '0':
- flags |= ZEROPAD;
- goto more;
- case '1'...'9':
- width = c-'0';
- while (((c = *format) >= '0') && (c <= '9')) {
- width = width*10 + c-'0';
- format++;
- }
- goto more;
- case 'h':
- if ((c = *format) == 'h') {
- flags |= CHAR;
- format++;
- } else {
- flags |= SHORT;
- }
- goto more;
- case 'o':
- flags |= 8;
- break;
- case 'd':
- case 'i':
- flags |= SIGN;
- case 'u':
- flags |= 10;
- break;
- case 'X':
- flags |= UPPER;
- case 'x':
- case 'p':
- flags |= 16;
- break;
- case 's':
- q = va_arg(ap, char *);
- while ((c = *q++) != '\0') {
- do_putch(&p, end, c);
- width--;
- }
- while (width-- > 0)
- do_putch(&p, end, ' ');
- continue;
- case 'c':
- c = va_arg(ap, unsigned int);
- default:
- do_putch(&p, end, c);
- continue;
- }
- x = va_arg(ap, unsigned int);
- if (flags & CHAR) {
- if (flags & SIGN)
- x = (char)x;
- else
- x = (unsigned char)x;
- } else if (flags & SHORT) {
- if (flags & SIGN)
- x = (short)x;
- else
- x = (unsigned short)x;
- }
- if ((flags & SIGN) && ((int)x < 0)) {
- if (flags & ZEROPAD) {
- do_putch(&p, end, '-');
- flags &= ~SIGN;
- }
- width--;
- x = -x;
- } else {
- flags &= ~SIGN;
- }
- if (flags & ALTERNATE) {
- if (((flags & BASE) == 8) || ((flags & BASE) == 16)) {
- do_putch(&p, end, '0');
- width--;
- }
- if ((flags & BASE) == 16) {
- do_putch(&p, end, 'x');
- width--;
- }
- }
- if (x == 0) {
- q = tmp;
- *q++ = '0';
- } else {
- for (q = tmp; x; q++, x /= (flags&BASE))
- *q = ((flags & UPPER)
- ? "0123456789ABCDEF"
- : "0123456789abcdef") [x % (flags&BASE)];
- }
- while (width-- > (q-tmp))
- do_putch(&p, end, (flags & ZEROPAD) ? '0' : ' ');
- if (flags & SIGN)
- do_putch(&p, end, '-');
- while (q != tmp)
- do_putch(&p, end, *--q);
- };
- if (p <= end)
- *p = '\0';
- else if (str <= end)
- *end = '\0';
- return p - str;
- }
- int snprintf(char *str, size_t size, const char *format, ...)
- {
- va_list ap;
- int n;
- va_start(ap, format);
- n = vsnprintf(str, size, format, ap);
- va_end(ap);
- return n;
- }
- /*
- * Local variables:
- * mode: C
- * c-file-style: "Linux"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
|