source: trunk/libs/newlib/src/libgloss/microblaze/xil_printf.c @ 546

Last change on this file since 546 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.7 KB
Line 
1/* Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *
7 * 1.  Redistributions source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of Xilinx nor the names of its contributors may be
15 * used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <ctype.h>
32#include <string.h>
33#include <stdarg.h>
34
35extern void outbyte (char);
36
37/*----------------------------------------------------*/
38/* Use the following parameter passing structure to   */
39/* make xil_printf re-entrant.                        */
40/*----------------------------------------------------*/
41typedef struct params_s {
42    int len;
43    int num1;
44    int num2;
45    char pad_character;
46    int do_padding;
47    int left_flag;
48} params_t;
49
50/*---------------------------------------------------*/
51/* The purpose of this routine is to output data the */
52/* same as the standard printf function without the  */
53/* overhead most run-time libraries involve. Usually */
54/* the printf brings in many kilobytes of code and   */
55/* that is unacceptable in most embedded systems.    */
56/*---------------------------------------------------*/
57
58typedef char* charptr;
59typedef int (*func_ptr)(int c);
60
61/*---------------------------------------------------*/
62/*                                                   */
63/* This routine puts pad characters into the output  */
64/* buffer.                                           */
65/*                                                   */
66static void padding( const int l_flag, params_t *par)
67{
68    int i;
69
70    if (par->do_padding && l_flag && (par->len < par->num1))
71        for (i=par->len; i<par->num1; i++)
72            outbyte( par->pad_character);
73}
74
75/*---------------------------------------------------*/
76/*                                                   */
77/* This routine moves a string to the output buffer  */
78/* as directed by the padding and positioning flags. */
79/*                                                   */
80static void outs( charptr lp, params_t *par)
81{
82    /* pad on left if needed                         */
83    par->len = strlen( lp);
84    padding( !(par->left_flag), par);
85
86    /* Move string to the buffer                     */
87    while (*lp && (par->num2)--)
88        outbyte( *lp++);
89
90    /* Pad on right if needed                        */
91    /* CR 439175 - elided next stmt. Seemed bogus.   */
92    /* par->len = strlen( lp);                       */
93    padding( par->left_flag, par);
94}
95
96/*---------------------------------------------------*/
97/*                                                   */
98/* This routine moves a number to the output buffer  */
99/* as directed by the padding and positioning flags. */
100/*                                                   */
101
102static void outnum( const long n, const long base, params_t *par)
103{
104    charptr cp;
105    int negative;
106    char outbuf[32];
107    const char digits[] = "0123456789ABCDEF";
108    unsigned long num;
109
110    /* Check if number is negative                   */
111    if (base == 10 && n < 0L) {
112        negative = 1;
113        num = -(n);
114    }
115    else{
116        num = (n);
117        negative = 0;
118    }
119   
120    /* Build number (backwards) in outbuf            */
121    cp = outbuf;
122    do {
123        *cp++ = digits[(int)(num % base)];
124    } while ((num /= base) > 0);
125    if (negative)
126        *cp++ = '-';
127    *cp-- = 0;
128
129    /* Move the converted number to the buffer and   */
130    /* add in the padding where needed.              */
131    par->len = strlen(outbuf);
132    padding( !(par->left_flag), par);
133    while (cp >= outbuf)
134        outbyte( *cp--);
135    padding( par->left_flag, par);
136}
137
138/*---------------------------------------------------*/
139/*                                                   */
140/* This routine gets a number from the format        */
141/* string.                                           */
142/*                                                   */
143static int getnum( charptr* linep)
144{
145    int n;
146    charptr cp;
147
148    n = 0;
149    cp = *linep;
150    while (isdigit(*cp))
151        n = n*10 + ((*cp++) - '0');
152    *linep = cp;
153    return(n);
154}
155
156/*---------------------------------------------------*/
157/*                                                   */
158/* This routine operates just like a printf/sprintf  */
159/* routine. It outputs a set of data under the       */
160/* control of a formatting string. Not all of the    */
161/* standard C format control are supported. The ones */
162/* provided are primarily those needed for embedded  */
163/* systems work. Primarily the floaing point         */
164/* routines are omitted. Other formats could be      */
165/* added easily by following the examples shown for  */
166/* the supported formats.                            */
167/*                                                   */
168
169/* void esp_printf( const func_ptr f_ptr,
170   const charptr ctrl1, ...) */
171void xil_printf( const charptr ctrl1, ...)
172{
173
174    int long_flag;
175    int dot_flag;
176
177    params_t par;
178
179    char ch;
180    va_list argp;
181    charptr ctrl = ctrl1;
182
183    va_start( argp, ctrl1);
184
185    for ( ; *ctrl; ctrl++) {
186
187        /* move format string chars to buffer until a  */
188        /* format control is found.                    */
189        if (*ctrl != '%') {
190            outbyte(*ctrl);
191            continue;
192        }
193
194        /* initialize all the flags for this format.   */
195        dot_flag   = long_flag = par.left_flag = par.do_padding = 0;
196        par.pad_character = ' ';
197        par.num2=32767;
198
199 try_next:
200        ch = *(++ctrl);
201
202        if (isdigit(ch)) {
203            if (dot_flag)
204                par.num2 = getnum(&ctrl);
205            else {
206                if (ch == '0')
207                    par.pad_character = '0';
208
209                par.num1 = getnum(&ctrl);
210                par.do_padding = 1;
211            }
212            ctrl--;
213            goto try_next;
214        }
215
216        switch (tolower(ch)) {
217            case '%':
218                outbyte( '%');
219                continue;
220
221            case '-':
222                par.left_flag = 1;
223                break;
224
225            case '.':
226                dot_flag = 1;
227                break;
228
229            case 'l':
230                long_flag = 1;
231                break;
232
233            case 'd':
234                if (long_flag || ch == 'D') {
235                    outnum( va_arg(argp, long), 10L, &par);
236                    continue;
237                }
238                else {
239                    outnum( va_arg(argp, int), 10L, &par);
240                    continue;
241                }
242            case 'x':
243                outnum((long)va_arg(argp, int), 16L, &par);
244                continue;
245
246            case 's':
247                outs( va_arg( argp, charptr), &par);
248                continue;
249
250            case 'c':
251                outbyte( va_arg( argp, int));
252                continue;
253
254            case '\\':
255                switch (*ctrl) {
256                    case 'a':
257                        outbyte( 0x07);
258                        break;
259                    case 'h':
260                        outbyte( 0x08);
261                        break;
262                    case 'r':
263                        outbyte( 0x0D);
264                        break;
265                    case 'n':
266                        outbyte( 0x0D);
267                        outbyte( 0x0A);
268                        break;
269                    default:
270                        outbyte( *ctrl);
271                        break;
272                }
273                ctrl++;
274                break;
275
276            default:
277                continue;
278        }
279        goto try_next;
280    }
281    va_end( argp);
282}
283
284/*---------------------------------------------------*/
Note: See TracBrowser for help on using the repository browser.