-int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args)
-{
- int len;
- unsigned long num;
- int i, base;
- const char *s;
-
- int flags; /* flags to number() */
-
- int field_width; /* width of output field */
- int precision; /* min. # of digits for integers; max
- number of chars for from string */
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
-
- int count;
-
- for (count=0; *fmt ; ++fmt) {
- if (*fmt != '%') {
- tx_byte(*fmt), count++;
- continue;
- }
-
- /* process flags */
- flags = 0;
- repeat:
- ++fmt; /* this also skips first '%' */
- switch (*fmt) {
- case '-': flags |= LEFT; goto repeat;
- case '+': flags |= PLUS; goto repeat;
- case ' ': flags |= SPACE; goto repeat;
- case '#': flags |= SPECIAL; goto repeat;
- case '0': flags |= ZEROPAD; goto repeat;
- }
-
- /* get field width */
- field_width = -1;
- if (is_digit(*fmt))
- field_width = skip_atoi(&fmt);
- else if (*fmt == '*') {
- ++fmt;
- /* it's the next argument */
- field_width = va_arg(args, int);
- if (field_width < 0) {
- field_width = -field_width;
- flags |= LEFT;
- }
- }
-
- /* get the precision */
- precision = -1;
- if (*fmt == '.') {
- ++fmt;
- if (is_digit(*fmt))
- precision = skip_atoi(&fmt);
- else if (*fmt == '*') {
- ++fmt;
- /* it's the next argument */
- precision = va_arg(args, int);
- }
- if (precision < 0)
- precision = 0;
- }
-
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
- qualifier = *fmt;
- ++fmt;
- }
-
- /* default base */
- base = 10;
-
- switch (*fmt) {
- case 'c':
- if (!(flags & LEFT))
- while (--field_width > 0)
- tx_byte(' '), count++;
- tx_byte((unsigned char) va_arg(args, int)), count++;
- while (--field_width > 0)
- tx_byte(' '), count++;
- continue;
-
- case 's':
- s = va_arg(args, char *);
- if (!s)
- s = "<NULL>";
-
- len = strnlen(s, precision);
-
- if (!(flags & LEFT))
- while (len < field_width--)
- tx_byte(' '), count++;
- for (i = 0; i < len; ++i)
- tx_byte(*s++), count++;
- while (len < field_width--)
- tx_byte(' '), count++;
- continue;
-
- case 'p':
- if (field_width == -1) {
- field_width = 2*sizeof(void *);
- flags |= ZEROPAD;
- }
- count += number(tx_byte,
- (unsigned long) va_arg(args, void *), 16,
- field_width, precision, flags);
- continue;
-
-
- case 'n':
- if (qualifier == 'l') {
- long * ip = va_arg(args, long *);
- *ip = count;
- } else {
- int * ip = va_arg(args, int *);
- *ip = count;
- }
- continue;
-
- case '%':
- tx_byte('%'), count++;
- continue;
-
- /* integer number formats - set up the flags and "break" */
- case 'o':
- base = 8;
- break;
-
- case 'X':
- flags |= LARGE;
- case 'x':
- base = 16;
- break;
-
- case 'd':
- case 'i':
- flags |= SIGN;
- case 'u':
- break;
-
- default:
- tx_byte('%'), count++;
- if (*fmt)
- tx_byte(*fmt), count++;
- else
- --fmt;
- continue;
- }
- if (qualifier == 'l')
- num = va_arg(args, unsigned long);
- else if (qualifier == 'h') {
- num = (unsigned short) va_arg(args, int);
- if (flags & SIGN)
- num = (short) num;
- } else if (flags & SIGN)
- num = va_arg(args, int);
- else
- num = va_arg(args, unsigned int);
- count += number(tx_byte, num, base, field_width, precision, flags);
- }
- return count;
-}
-
-/* FIXME this global makes vsprintf non-reentrant
- */