| /* Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * 1. Redistributions source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of Xilinx nor the names of its contributors may be |
| * used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
| * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <ctype.h> |
| #include <string.h> |
| #include <stdarg.h> |
| |
| extern void outbyte (char); |
| |
| /*----------------------------------------------------*/ |
| /* Use the following parameter passing structure to */ |
| /* make xil_printf re-entrant. */ |
| /*----------------------------------------------------*/ |
| typedef struct params_s { |
| int len; |
| int num1; |
| int num2; |
| char pad_character; |
| int do_padding; |
| int left_flag; |
| } params_t; |
| |
| /*---------------------------------------------------*/ |
| /* The purpose of this routine is to output data the */ |
| /* same as the standard printf function without the */ |
| /* overhead most run-time libraries involve. Usually */ |
| /* the printf brings in many kilobytes of code and */ |
| /* that is unacceptable in most embedded systems. */ |
| /*---------------------------------------------------*/ |
| |
| typedef char* charptr; |
| typedef int (*func_ptr)(int c); |
| |
| /*---------------------------------------------------*/ |
| /* */ |
| /* This routine puts pad characters into the output */ |
| /* buffer. */ |
| /* */ |
| static void padding( const int l_flag, params_t *par) |
| { |
| int i; |
| |
| if (par->do_padding && l_flag && (par->len < par->num1)) |
| for (i=par->len; i<par->num1; i++) |
| outbyte( par->pad_character); |
| } |
| |
| /*---------------------------------------------------*/ |
| /* */ |
| /* This routine moves a string to the output buffer */ |
| /* as directed by the padding and positioning flags. */ |
| /* */ |
| static void outs( charptr lp, params_t *par) |
| { |
| /* pad on left if needed */ |
| par->len = strlen( lp); |
| padding( !(par->left_flag), par); |
| |
| /* Move string to the buffer */ |
| while (*lp && (par->num2)--) |
| outbyte( *lp++); |
| |
| /* Pad on right if needed */ |
| /* CR 439175 - elided next stmt. Seemed bogus. */ |
| /* par->len = strlen( lp); */ |
| padding( par->left_flag, par); |
| } |
| |
| /*---------------------------------------------------*/ |
| /* */ |
| /* This routine moves a number to the output buffer */ |
| /* as directed by the padding and positioning flags. */ |
| /* */ |
| |
| static void outnum( const long n, const long base, params_t *par) |
| { |
| charptr cp; |
| int negative; |
| char outbuf[32]; |
| const char digits[] = "0123456789ABCDEF"; |
| unsigned long num; |
| |
| /* Check if number is negative */ |
| if (base == 10 && n < 0L) { |
| negative = 1; |
| num = -(n); |
| } |
| else{ |
| num = (n); |
| negative = 0; |
| } |
| |
| /* Build number (backwards) in outbuf */ |
| cp = outbuf; |
| do { |
| *cp++ = digits[(int)(num % base)]; |
| } while ((num /= base) > 0); |
| if (negative) |
| *cp++ = '-'; |
| *cp-- = 0; |
| |
| /* Move the converted number to the buffer and */ |
| /* add in the padding where needed. */ |
| par->len = strlen(outbuf); |
| padding( !(par->left_flag), par); |
| while (cp >= outbuf) |
| outbyte( *cp--); |
| padding( par->left_flag, par); |
| } |
| |
| /*---------------------------------------------------*/ |
| /* */ |
| /* This routine gets a number from the format */ |
| /* string. */ |
| /* */ |
| static int getnum( charptr* linep) |
| { |
| int n; |
| charptr cp; |
| |
| n = 0; |
| cp = *linep; |
| while (isdigit(*cp)) |
| n = n*10 + ((*cp++) - '0'); |
| *linep = cp; |
| return(n); |
| } |
| |
| /*---------------------------------------------------*/ |
| /* */ |
| /* This routine operates just like a printf/sprintf */ |
| /* routine. It outputs a set of data under the */ |
| /* control of a formatting string. Not all of the */ |
| /* standard C format control are supported. The ones */ |
| /* provided are primarily those needed for embedded */ |
| /* systems work. Primarily the floaing point */ |
| /* routines are omitted. Other formats could be */ |
| /* added easily by following the examples shown for */ |
| /* the supported formats. */ |
| /* */ |
| |
| /* void esp_printf( const func_ptr f_ptr, |
| const charptr ctrl1, ...) */ |
| void xil_printf( const charptr ctrl1, ...) |
| { |
| |
| int long_flag; |
| int dot_flag; |
| |
| params_t par; |
| |
| char ch; |
| va_list argp; |
| charptr ctrl = ctrl1; |
| |
| va_start( argp, ctrl1); |
| |
| for ( ; *ctrl; ctrl++) { |
| |
| /* move format string chars to buffer until a */ |
| /* format control is found. */ |
| if (*ctrl != '%') { |
| outbyte(*ctrl); |
| continue; |
| } |
| |
| /* initialize all the flags for this format. */ |
| dot_flag = long_flag = par.left_flag = par.do_padding = 0; |
| par.pad_character = ' '; |
| par.num2=32767; |
| |
| try_next: |
| ch = *(++ctrl); |
| |
| if (isdigit(ch)) { |
| if (dot_flag) |
| par.num2 = getnum(&ctrl); |
| else { |
| if (ch == '0') |
| par.pad_character = '0'; |
| |
| par.num1 = getnum(&ctrl); |
| par.do_padding = 1; |
| } |
| ctrl--; |
| goto try_next; |
| } |
| |
| switch (tolower(ch)) { |
| case '%': |
| outbyte( '%'); |
| continue; |
| |
| case '-': |
| par.left_flag = 1; |
| break; |
| |
| case '.': |
| dot_flag = 1; |
| break; |
| |
| case 'l': |
| long_flag = 1; |
| break; |
| |
| case 'd': |
| if (long_flag || ch == 'D') { |
| outnum( va_arg(argp, long), 10L, &par); |
| continue; |
| } |
| else { |
| outnum( va_arg(argp, int), 10L, &par); |
| continue; |
| } |
| case 'x': |
| outnum((long)va_arg(argp, int), 16L, &par); |
| continue; |
| |
| case 's': |
| outs( va_arg( argp, charptr), &par); |
| continue; |
| |
| case 'c': |
| outbyte( va_arg( argp, int)); |
| continue; |
| |
| case '\\': |
| switch (*ctrl) { |
| case 'a': |
| outbyte( 0x07); |
| break; |
| case 'h': |
| outbyte( 0x08); |
| break; |
| case 'r': |
| outbyte( 0x0D); |
| break; |
| case 'n': |
| outbyte( 0x0D); |
| outbyte( 0x0A); |
| break; |
| default: |
| outbyte( *ctrl); |
| break; |
| } |
| ctrl++; |
| break; |
| |
| default: |
| continue; |
| } |
| goto try_next; |
| } |
| va_end( argp); |
| } |
| |
| /*---------------------------------------------------*/ |