/* tab space = 4 */ /********************************************************************* * DISCLAIMER: * * The software supplied by Renesas Technology America Inc. is * * intended and supplied for use on Renesas Technology products. * * This software is owned by Renesas Technology America, Inc. or * * Renesas Technology Corporation and is protected under applicable * * copyright laws. All rights are reserved. * * * * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, * * IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO IMPLIED * * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * * APPLY TO THIS SOFTWARE. RENESAS TECHNOLOGY AMERICA, INC. AND * * AND RENESAS TECHNOLOGY CORPORATION RESERVE THE RIGHT, WITHOUT * * NOTICE, TO MAKE CHANGES TO THIS SOFTWARE. NEITHER RENESAS * * TECHNOLOGY AMERICA, INC. NOR RENESAS TECHNOLOGY CORPORATION SHALL, * * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR * * CONSEQUENTIAL DAMAGES FOR ANY REASON WHATSOEVER ARISING OUT OF THE * * USE OR APPLICATION OF THIS SOFTWARE. * *********************************************************************/ /*----------------------------------------------------------------------------- FILE NAME: simple_printf.c ----------- DESCRIPTION: Simplified printf and sprintf. (float and signed values no supported) ----------- DETAILS: ------------------ Revision History ------------------ 1.6 April 7, 2007 Changed "..." access over to using standard "va_" macros for compatibility with other compilers. 1.5 July 16, 2006 Initialized local "s" in _print_out() in order to suppress compiler warning. 1.4 April 28, 2006 ROM/RAM reductions. Also NC30WA V.5.40 compatable. 1.3 Feb 21, 2006 Combined printf and sprintf functions 1.2 Nov 15, 2005 Fixed bug when using "%lx" or %lX 1.1 Sept 8, 2005 Fixed bug when using "%Ld" Fixed bug for sprintf (did not add NULL at end) 1.0 ??, 2005 Initial Version -----------------------------------------------------------------------------*/ #include <stdio.h> #include <stdarg.h> #if defined NC308 #define FAR _far #elif defined NC30 #define FAR _far #else #define FAR #endif enum { UI, UH, UL, SI, SH, SL }; enum { LEFT_SPACE, PREFIX, ZERO_PAD, VALUE_TXT, RIGHT_SPACE, OUT_DONE}; static const struct { char c[2]; char size; } prefix[]= { {{0,0},0}, /* 0: default, no prefix */ {{'-',0},1}, /* 1: minus sign */ {{'+',0},1}, /* 2: plus sign */ {{' ',0},1}, /* 3: space */ {{'0','x'},2}, /* 4: hex 0x */ {{'0','X'},2}, /* 5: hex 0X */ }; /* Function Prototypes */ int _print_out(char FAR *s, const char FAR *format, va_list sp); int sprintf(char FAR *s, const char FAR *format, ...) { int return_count; va_list sp; va_start(sp, format); return_count = _print_out(s, format, sp); va_end(sp); return (return_count); } int printf(const char FAR *format, ...) { int return_count; va_list sp; va_start(sp, format); return_count = _print_out(NULL, format, sp); va_end(sp); return (return_count); } int _print_out(char FAR *s, const char FAR *format, va_list sp) { int total = 0; char tmp_buf[12]; /* maximum tmp_buf usage is 12 in %d */ /* Loop through format string */ while ( *format ) /* loop till hit NULL */ { unsigned char tmp_char, index, out_state; unsigned char left_justify = 0; /* set default to right justify */ unsigned char prefix_select = 0; /* set default prefix to none */ int min_width = 0; /* set default field min_width to 0 */ int precision = 0; /* set default precision to 0 */ unsigned char size_type = UI; /* set default type to unsigned int */ char const FAR * str_ptr = tmp_buf; /* set default string source to buffer */ union { unsigned long UL; signed long SL; } value; int str_len = 0; tmp_buf[0] = 0; if ( *format == '%' ) /* start of escape characters */ { out_state = PREFIX; do { format++; /* point to next character */ /* Decode the flags */ switch (*format) { case '0': precision = -1; /* if precision not explicitly set, this will zero fill min_width */ break; case '#': prefix_select = 4; /* exact prefix will be determined during type decode */ break; case '+': prefix_select = 2; /* this will be overriden if number is negative */ break; case ' ': prefix_select = 3; /* this will be overriden if number is negative */ break; case '-': left_justify = 1; /* left justification */ break; default: out_state = OUT_DONE; /* no flags left */ break; } } while( out_state != OUT_DONE ); /* check for minimum width */ index = 0; while ( (*format >= '0') && (*format <= '9') ) { min_width = (min_width * index * 10) + (*format - '0'); index++; format++; } /* check for precision */ if (*format == '.') { format++; index = 0; while ( (*format >= '0') && (*format <= '9') ) { precision = (precision * index * 10) + (*format - '0'); index++; format++; } } /* check for size specifier */ switch(*format) { case 'h': size_type = UH; format++; break; case 'l': size_type = UL; format++; break; default: break; } /* check which type of varaible to print */ switch(*format) { case '%': { /* output a '%' */ tmp_buf[0] = '%'; tmp_buf[1] = 0; str_len = 1; break; } case 'c': { /* output a single character */ tmp_buf[0] = (char)va_arg(sp, int); tmp_buf[1] = 0; str_len = 1; break; } case 'd': case 'i': size_type += SI; /* flow through to decimal processing */ case 'u': { /* output decimal value from stack */ static const unsigned long base10[] = {1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1}; /* convert all data types to long to ease later processing */ switch (size_type) { default: case UI: value.UL = (unsigned long)va_arg(sp, unsigned int); break; case SI: value.SL = (signed long)va_arg(sp, signed int); break; case UH: value.UL = (unsigned long)(unsigned short)va_arg(sp, unsigned int); break; case SH: value.SL = (signed long)(signed short)va_arg(sp, signed int); break; case UL: case SL: value.UL = va_arg(sp, unsigned long); break; } /* convert signed values to positive as necessary and set prefix appropriately */ if (size_type >= SI) { if (value.SL < 0) { value.SL = -value.SL; prefix_select = 1; } } /* write out decimal values to buffer...after suppressing zeros */ for (index = 0; index < 10; index++) { tmp_char = (unsigned char)(value.UL/base10[index]); value.UL -= tmp_char * base10[index]; tmp_buf[str_len] = tmp_char + '0'; if ((tmp_char != 0) || (str_len !=0)) str_len++; } if (str_len == 0) str_len = 1; /* if value was zero, we need to increment length */ tmp_buf[str_len] = 0; break; } case 'X': if (prefix_select != 0) prefix_select++; /* fall through to processing */ case 'x': { /* output hex value from stack */ static const char ascii_table_lower[] = "0123456789abcdef"; static const char ascii_table_upper[] = "0123456789ABCDEF"; static const char hex_shift[] = { 28, 24, 20, 16, 12, 8, 4, 0}; /* convert all data types to long to ease later processing */ switch (size_type) { default: case UI: case SI: value.UL = (unsigned long)va_arg(sp, unsigned int); break; case UH: case SH: value.UL = (unsigned long)(unsigned short)va_arg(sp, unsigned int); break; case UL: case SL: value.UL = va_arg(sp, unsigned long); break; } /* write out hex values to buffer...after suppressing initial zeros */ for (index = 0; index < 8; index++) { tmp_char = (unsigned char)(value.UL >> hex_shift[index]) & 0x0F; tmp_buf[str_len] = (*format == 'x') ? ascii_table_lower[tmp_char] : ascii_table_upper[tmp_char]; if ((tmp_char != 0) || (str_len !=0)) str_len++; } if (str_len == 0) str_len = 1; /* if value was zero, we need to increment length */ tmp_buf[str_len] = 0; break; } case 's': case 'S': { /* Add string from stack */ char const FAR * t_str_ptr; str_ptr = t_str_ptr = va_arg(sp, char FAR *); while(*t_str_ptr) /* find string length */ { str_len++; t_str_ptr++; } break; } default: { /* non-processed format...inform user and try not to crash */ static const char err_msg[]="!!NG!!"; static const char err_fmt[]=" "; str_ptr = err_msg; str_len = (int)sizeof(err_msg)-1; format=err_fmt; break; } } /* switch end */ } /* escape processing end */ else { /* pass through Standard ASCII */ index = 0; if( *format == '\n') /* Add CR to LF */ tmp_buf[str_len++] = '\r'; tmp_buf[str_len++] = *format; tmp_buf[str_len] = 0; } /* if numeric format default precision = 0 if width specified set precision to width-prefix size if zero pad if precision specified set precision to it set precision to str_len if str_len is greater space = min_width - precision - prefix size if greater than zero if left justify, space to right, else space to left, if string format if precision > 0, use to truncate string */ out_state=LEFT_SPACE; /* if precision is -1, field has been requested to zero pad */ if (precision == -1) precision = min_width - prefix[prefix_select].size; if ((precision > 0) && (*format == 's')) { /* requesting string truncation... */ if (str_len > precision) str_len = precision; /* zero precision to prevent zero padding */ precision = 0; } /* precision now equals number of zero pads */ precision = precision - str_len; /* min_width now equals number of spaces to add...left_justify will control at beginning or end of min_width */ min_width = (min_width - str_len) - prefix[prefix_select].size; min_width -= (precision > 0) ? precision : 0; do { tmp_char = 0; switch (out_state) { case LEFT_SPACE: { if ((min_width > 0) && (left_justify == 0)) { tmp_char = ' '; min_width--; } else { /* advance state */ index = 0; out_state = PREFIX; } break; } case PREFIX: { tmp_char = prefix[prefix_select].c[index++]; if (index >= prefix[prefix_select].size) { /* advance state */ out_state = ZERO_PAD; } break; } case ZERO_PAD: { if (precision > 0) { tmp_char = '0'; precision--; } else { /* advance state */ precision = 0; out_state = VALUE_TXT; } break; } case VALUE_TXT: { tmp_char = str_ptr[precision++]; /* use precision for indexing because is type "int" */ if (precision >= str_len) { /* advance state */ out_state = RIGHT_SPACE; } break; } case RIGHT_SPACE: { if (min_width > 0) { tmp_char = ' '; min_width--; } else { /* advance state */ out_state = OUT_DONE; } break; } default: { /* output complete */ out_state = OUT_DONE; break; } } if (tmp_char != 0) { if(s != NULL) *s++ = tmp_char; else (void)putchar(tmp_char); total++; } } while (out_state!=OUT_DONE); format++; } /* while format */ /* Insert NULL at the end of the string */ if(s != NULL) *s = 0; return total; }