285 lines
8.7 KiB
C
285 lines
8.7 KiB
C
/* 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);
|
|
}
|
|
|
|
/*---------------------------------------------------*/
|