/* Returns bytes written, negative on error */ int vfprintf(rd_t rd, char *fmt, va_list ap, int (*puts_fn)(rd_t,char*), int (*putc_fn)(rd_t,char)) { int total = 0; /* We buffer data here as long as possible, because the actual puts/putc functions tend to be slow * and the fewer calls we can make, the better. */ char holding[32]; int hold_count = 0; const int hold_len = sizeof(holding)/sizeof(holding[0]); holding[0] = '\0'; int ret; while (*fmt) { if (*fmt == '%') { switch (*(++fmt)) { case 'x': { /* Hex */ uint32_t hex = va_arg(ap, uint32_t); char buf[12]; uitoa(hex, buf, 9, 16); ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = puts_fn(rd, buf); if (ret >= 0) { total += ret; } else { return ret; } break; } case 'i': case 'd': { int num = va_arg(ap, int); char buf[9]; /* 7 digits in INT_MAX + '-' and '\0' */ itoa(num, buf, 12, 10); ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = puts_fn(rd, buf); if (ret >= 0) { total += ret; } else { return ret; } break; } case 'u': { uint32_t num = va_arg(ap, uint32_t); char buf[9]; /* 7 digits in INT_MAX + '-' and '\0' */ uitoa(num, buf, 12, 10); ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = puts_fn(rd, buf); if (ret >= 0) { total += ret; } else { return ret; } break; } case 'f': { float num = (float) va_arg(ap, double); char buf[20]; ftoa(num, 0.0001f, buf, 20); ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = puts_fn(rd, buf); if (ret >= 0) { total += ret; } else { return ret; } break; } case 'c': { char letter = (char) va_arg(ap, uint32_t); ret = holding_push(letter, holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } break; } case 's': { char *s = va_arg(ap, char*); ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = puts_fn(rd, s); if (ret >= 0) { total += ret; } else { return ret; } break; } case '%': { /* Just print a % */ ret = holding_push('%', holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } break; } default: { ret = holding_push('%', holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } ret = holding_push(*fmt, holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } } } fmt++; } else { ret = holding_push(*fmt++, holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } } }
} else { return ret; } } } fmt++; } else { ret = holding_push(*fmt++, holding, hold_len, &hold_count, dev); if (ret >= 0) { total += ret; } else { return ret; } } } ret = holding_flush(holding, &hold_count, dev); if (ret >= 0) { total += ret; } else { return ret; } return total; }
} else { return ret; } } } fmt++; } else { ret = holding_push(*fmt++, holding, hold_len, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } } } ret = holding_flush(holding, &hold_count, rd, puts_fn); if (ret >= 0) { total += ret; } else { return ret; } return total; }