/* Copyright (C) Thornwave Labs Inc - All Rights Reserved * Unauthorized copying of this file, via any medium is strictly prohibited * Proprietary and confidential * Written by Razvan Turiac <razvan.turiac@thornwave.com> */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <../src/stdio_internal.h> static const char l_flags[] = "-+ #0"; static const char l_length_chars[] = "hljzt"; static const char l_fs_chars[] = "duxXocs"; //print %u, %x or %X static int32_t fsh_integer(rtprintf_output_handler_t output_handler, void *user, uint32_t val, const char *charset) { int32_t rv = 0; char str[12]; //will fit a 32 bit number char* const str_end = str + sizeof(str); const uint32_t base = strlen(charset); char *ptr = str_end; if (val) { while(val) { *--ptr = charset[val % base]; val /= base; } } else *--ptr = '0'; OUTPUT_CHARS(user, ptr, str_end - ptr); return rv; } //str - string to parse //spec - specifier found //index - the index fo the data to be printed (before the real data we might have the width or/and precision passed as arguments) static inline const char* parse_format_specifier(const char *str, char *spec, uint32_t *index) { const char *ptr = str + 1; //skip over the '%' character *index = 0; //parse flag while(*ptr && strchr(l_flags, *ptr)) ptr++; //parse width if (*ptr == 0) return str; else if (*ptr == '*') { (*index)++; ptr++; } else while (*ptr && strchr("0123456789", *ptr)) ptr++; //parse precision if (*ptr == '.') { ptr++; if (*ptr == 0) return str; else if (*ptr == '*') { (*index)++; ptr++; } else while (*ptr && strchr("0123456789", *ptr)) ptr++; } //parse length if (*ptr && strchr(l_length_chars, *ptr)) ptr++; //parse type if (*ptr && strchr(l_fs_chars, *ptr)) { *spec = *ptr; ptr++; } else return str; return ptr; } int32_t rtiprintf(rtprintf_output_handler_t output_handler, void *user, const char *format, va_list args) { int32_t rv = 0; while(*format) { const char *specifier; ptrdiff_t offset = 0; do { specifier = strchr(format + offset, '%'); offset += 2; }while(specifier && (specifier[1] == '%')); if (specifier) //% char found { //print the string up to the % char const size_t output_size = specifier - format; if (output_size) OUTPUT_CHARS(user, format, output_size); //process the specifier char spec = 0; uint32_t index; const char *new_pos = parse_format_specifier(specifier, &spec, &index); if (new_pos != specifier) { while(index--) va_arg(args, uint32_t); //skip width and/or precision specified as arguments //we have a valid specifier switch(spec) { case 'c': { const char val = va_arg(args, uint32_t); OUTPUT_CHARS(user, &val, 1); }break; case 'd': { int32_t val_signed = va_arg(args, int32_t); if (val_signed < 0) { OUTPUT_CHARS(user, "-", 1); val_signed = -val_signed; } const int32_t rv_temp = fsh_integer(output_handler, user, val_signed, "0123456789"); if (rv_temp < 0) return rv_temp; else rv += rv_temp; }break; case 'u': { const int32_t rv_temp = fsh_integer(output_handler, user, va_arg(args, uint32_t), "0123456789"); if (rv_temp < 0) return rv_temp; else rv += rv_temp; }break; case 'x': { const int32_t rv_temp = fsh_integer(output_handler, user, va_arg(args, uint32_t), "0123456789abcdef"); if (rv_temp < 0) return rv_temp; else rv += rv_temp; }break; case 'X': { const int32_t rv_temp = fsh_integer(output_handler, user, va_arg(args, uint32_t), "0123456789ABCDEF"); if (rv_temp < 0) return rv_temp; else rv += rv_temp; }break; case 's': { const char *str = va_arg(args, const char*); const char *ptr = str; while(*ptr) ptr++; OUTPUT_CHARS(user, str, ptr - str); }break; default: break; } format = new_pos; } else { //invalid specifier so print it OUTPUT_CHARS(user, specifier, 1); format = specifier + 1; } } else { //no % char found //print the remainder of the string const char* str = format; while(*format) format++; OUTPUT_CHARS(user, str, format - str); } } return rv; }