950687beff1be039bec8eca702c8fb2c2cca8bb7
[openwrt.git] / target / image / generic / lzma-loader / src / print.c
1 /*
2  * Copyright (C) 2001 MontaVista Software Inc.
3  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4  *
5  * This program is free software; you can redistribute  it and/or modify it
6  * under  the terms of  the GNU General  Public License as published by the
7  * Free Software Foundation;  either version 2 of the  License, or (at your
8  * option) any later version.
9  *
10  */
11
12 #include        "print.h"
13
14 /* macros */
15 #define         IsDigit(x)      ( ((x) >= '0') && ((x) <= '9') )
16 #define         Ctod(x)         ( (x) - '0')
17
18 /* forward declaration */
19 extern int PrintChar(char *, char, int, int);
20 extern int PrintString(char *, char *, int, int);
21 extern int PrintNum(char *, unsigned long, int, int, int, int, char, int);
22
23 /* private variable */
24 static const char theFatalMsg[] = "fatal error in lp_Print!";
25
26 /* -*-
27  * A low level printf() function.
28  */
29 void
30 lp_Print(void (*output)(void *, char *, int), 
31          void * arg,
32          char *fmt, 
33          va_list ap)
34 {
35
36 #define         OUTPUT(arg, s, l)  \
37   { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
38        (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
39     } else { \
40       (*output)(arg, s, l); \
41     } \
42   }
43     
44     char buf[LP_MAX_BUF];
45
46     char c;
47     char *s;
48     long int num;
49
50     int longFlag;
51     int negFlag;
52     int width;
53     int prec;
54     int ladjust;
55     char padc;
56
57     int length;
58
59     for(;;) {
60         { 
61             /* scan for the next '%' */
62             char *fmtStart = fmt;
63             while ( (*fmt != '\0') && (*fmt != '%')) {
64                 fmt ++;
65             }
66
67             /* flush the string found so far */
68             OUTPUT(arg, fmtStart, fmt-fmtStart);
69
70             /* are we hitting the end? */
71             if (*fmt == '\0') break;
72         }
73
74         /* we found a '%' */
75         fmt ++;
76         
77         /* check for long */
78         if (*fmt == 'l') {
79             longFlag = 1;
80             fmt ++;
81         } else {
82             longFlag = 0;
83         }
84
85         /* check for other prefixes */
86         width = 0;
87         prec = -1;
88         ladjust = 0;
89         padc = ' ';
90
91         if (*fmt == '-') {
92             ladjust = 1;
93             fmt ++;
94         }
95
96         if (*fmt == '0') {
97             padc = '0';
98             fmt++;
99         }
100
101         if (IsDigit(*fmt)) {
102             while (IsDigit(*fmt)) {
103                 width = 10 * width + Ctod(*fmt++);
104             }
105         }
106
107         if (*fmt == '.') {
108             fmt ++;
109             if (IsDigit(*fmt)) {
110                 prec = 0;
111                 while (IsDigit(*fmt)) {
112                     prec = prec*10 + Ctod(*fmt++);
113                 }
114             }
115         }
116
117
118         /* check format flag */
119         negFlag = 0;
120         switch (*fmt) {
121          case 'b':
122             if (longFlag) { 
123                 num = va_arg(ap, long int); 
124             } else { 
125                 num = va_arg(ap, int);
126             }
127             length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
128             OUTPUT(arg, buf, length);
129             break;
130
131          case 'd':
132          case 'D':
133             if (longFlag) { 
134                 num = va_arg(ap, long int);
135             } else { 
136                 num = va_arg(ap, int); 
137             }
138             if (num < 0) {
139                 num = - num;
140                 negFlag = 1;
141             }
142             length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
143             OUTPUT(arg, buf, length);
144             break;
145
146          case 'o':
147          case 'O':
148             if (longFlag) { 
149                 num = va_arg(ap, long int);
150             } else { 
151                 num = va_arg(ap, int); 
152             }
153             length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
154             OUTPUT(arg, buf, length);
155             break;
156
157          case 'u':
158          case 'U':
159             if (longFlag) { 
160                 num = va_arg(ap, long int);
161             } else { 
162                 num = va_arg(ap, int); 
163             }
164             length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
165             OUTPUT(arg, buf, length);
166             break;
167             
168          case 'x':
169             if (longFlag) { 
170                 num = va_arg(ap, long int);
171             } else { 
172                 num = va_arg(ap, int); 
173             }
174             length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
175             OUTPUT(arg, buf, length);
176             break;
177
178          case 'X':
179             if (longFlag) { 
180                 num = va_arg(ap, long int);
181             } else { 
182                 num = va_arg(ap, int); 
183             }
184             length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
185             OUTPUT(arg, buf, length);
186             break;
187
188          case 'c':
189             c = (char)va_arg(ap, int);
190             length = PrintChar(buf, c, width, ladjust);
191             OUTPUT(arg, buf, length);
192             break;
193
194          case 's':
195             s = (char*)va_arg(ap, char *);
196             length = PrintString(buf, s, width, ladjust);
197             OUTPUT(arg, buf, length);
198             break;
199
200          case '\0':
201             fmt --;
202             break;
203
204          default:
205             /* output this char as it is */
206             OUTPUT(arg, fmt, 1);
207         }       /* switch (*fmt) */
208
209         fmt ++;
210     }           /* for(;;) */
211
212     /* special termination call */
213     OUTPUT(arg, "\0", 1);
214 }
215
216
217 /* --------------- local help functions --------------------- */
218 int
219 PrintChar(char * buf, char c, int length, int ladjust)
220 {
221     int i;
222     
223     if (length < 1) length = 1;
224     if (ladjust) {
225         *buf = c;
226         for (i=1; i< length; i++) buf[i] = ' ';
227     } else {
228         for (i=0; i< length-1; i++) buf[i] = ' ';
229         buf[length - 1] = c;
230     }
231     return length;
232 }
233
234 int
235 PrintString(char * buf, char* s, int length, int ladjust)
236 {
237     int i;
238     int len=0;
239     char* s1 = s;
240     while (*s1++) len++;
241     if (length < len) length = len;
242
243     if (ladjust) {
244         for (i=0; i< len; i++) buf[i] = s[i];
245         for (i=len; i< length; i++) buf[i] = ' ';
246     } else {
247         for (i=0; i< length-len; i++) buf[i] = ' ';
248         for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
249     }
250     return length;
251 }
252
253 int
254 PrintNum(char * buf, unsigned long u, int base, int negFlag, 
255          int length, int ladjust, char padc, int upcase)
256 {
257     /* algorithm :
258      *  1. prints the number from left to right in reverse form.
259      *  2. fill the remaining spaces with padc if length is longer than
260      *     the actual length
261      *     TRICKY : if left adjusted, no "0" padding.
262      *              if negtive, insert  "0" padding between "0" and number.
263      *  3. if (!ladjust) we reverse the whole string including paddings
264      *  4. otherwise we only reverse the actual string representing the num.
265      */
266
267     int actualLength =0;
268     char *p = buf;
269     int i;
270
271     do {
272         int tmp = u %base;
273         if (tmp <= 9) {
274             *p++ = '0' + tmp;
275         } else if (upcase) {
276             *p++ = 'A' + tmp - 10;
277         } else {
278             *p++ = 'a' + tmp - 10;
279         }
280         u /= base;
281     } while (u != 0);
282
283     if (negFlag) {
284         *p++ = '-';
285     }
286
287     /* figure out actual length and adjust the maximum length */
288     actualLength = p - buf;
289     if (length < actualLength) length = actualLength;
290
291     /* add padding */
292     if (ladjust) {
293         padc = ' ';
294     }
295     if (negFlag && !ladjust && (padc == '0')) {
296         for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
297         buf[length -1] = '-';
298     } else {
299         for (i = actualLength; i< length; i++) buf[i] = padc;
300     }
301             
302
303     /* prepare to reverse the string */
304     {
305         int begin = 0;
306         int end;
307         if (ladjust) {
308             end = actualLength - 1;
309         } else {
310             end = length -1;
311         }
312
313         while (end > begin) {
314             char tmp = buf[begin];
315             buf[begin] = buf[end];
316             buf[end] = tmp;
317             begin ++;
318             end --;
319         }
320     }
321
322     /* adjust the string pointer */
323     return length;
324 }