5f2b3128c13445533901cd75f2dfbd230d4fa22c
[visor] / libvisor / src / viprintf.c
1 #include "vilibc.h"
2
3 enum {
4         OUT_BUF
5 };
6
7 static int intern_printf(int out, char *buf, unsigned long sz, const char *fmt, va_list ap);
8 static void bwrite(int out, char *buf, unsigned long buf_sz, char *str, int sz);
9
10 int sprintf(char *buf, const char *fmt, ...)
11 {
12         int res;
13         va_list ap;
14
15         va_start(ap, fmt);
16         res = intern_printf(OUT_BUF, buf, 0, fmt, ap);
17         va_end(ap);
18         return res;
19 }
20
21 int vsprintf(char *buf, const char *fmt, va_list ap)
22 {
23         return intern_printf(OUT_BUF, buf, 0, fmt, ap);
24 }
25
26 int snprintf(char *buf, unsigned long sz, const char *fmt, ...)
27 {
28         int res;
29         va_list ap;
30
31         va_start(ap, fmt);
32         res = intern_printf(OUT_BUF, buf, sz, fmt, ap);
33         va_end(ap);
34         return res;
35 }
36
37 int vsnprintf(char *buf, unsigned long sz, const char *fmt, va_list ap)
38 {
39         return intern_printf(OUT_BUF, buf, sz, fmt, ap);
40 }
41
42 /* intern_printf provides all the functionality needed by all the printf
43  * variants.
44  * - buf: optional buffer onto which the formatted results are written. If null
45  *   then the output goes to the terminal through putchar calls. This is used
46  *   by the (v)sprintf variants which write to an array of char.
47  * - sz: optional maximum size of the output, 0 means unlimited. This is used
48  *   by the (v)snprintf variants to avoid buffer overflows.
49  * The rest are obvious, format string and variable argument list.
50  */
51 static char *convc = "dioxXucsfeEgGpn%";
52
53 #define IS_CONV(c)      strchr(convc, c)
54
55 #define BUF(x)  ((x) ? (x) + cnum : (x))
56 #define SZ(x)   ((x) ? (x) - cnum : (x))
57
58 static int intern_printf(int out, char *buf, unsigned long sz, const char *fmt, va_list ap)
59 {
60         char conv_buf[32];
61         char *str;
62         int i, slen;
63         const char *fstart = 0;
64
65         /* state */
66         int cnum = 0;
67         int base = 10;
68         int alt = 0;
69         int fwidth = 0;
70         int padc = ' ';
71         int sign = 0;
72         int left_align = 0;
73         int hex_caps = 0;
74         int unsig = 0;
75         int num, unum;
76
77         while(*fmt) {
78                 if(*fmt == '%') {
79                         fstart = fmt++;
80                         continue;
81                 }
82
83                 if(fstart) {
84                         if(IS_CONV(*fmt)) {
85                                 switch(*fmt) {
86                                 case 'X':
87                                         hex_caps = 1;
88
89                                 case 'x':
90                                 case 'p':
91                                         base = 16;
92
93                                         if(alt) {
94                                                 bwrite(out, BUF(buf), SZ(sz), "0x", 2);
95                                                 cnum += 2;
96                                         }
97
98                                 case 'u':
99                                         unsig = 1;
100
101                                         if(0) {
102                                 case 'o':
103                                                 base = 8;
104
105                                                 if(alt) {
106                                                         bwrite(out, BUF(buf), SZ(sz), "0", 1);
107                                                         cnum++;
108                                                 }
109                                         }
110
111                                 case 'd':
112                                 case 'i':
113                                         if(unsig) {
114                                                 unum = va_arg(ap, unsigned int);
115                                                 utoa(unum, conv_buf, base);
116                                         } else {
117                                                 num = va_arg(ap, int);
118                                                 itoa(num, conv_buf, base);
119                                         }
120                                         if(hex_caps) {
121                                                 for(i=0; conv_buf[i]; i++) {
122                                                         conv_buf[i] = toupper(conv_buf[i]);
123                                                 }
124                                         }
125
126                                         slen = strlen(conv_buf);
127
128                                         if(left_align) {
129                                                 if(!unsig && sign && num >= 0) {
130                                                         bwrite(out, BUF(buf), SZ(sz), "+", 1);
131                                                         cnum++;
132                                                 }
133                                                 bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
134                                                 cnum += slen;
135                                                 padc = ' ';
136                                         }
137                                         for(i=slen; i<fwidth; i++) {
138                                                 bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
139                                                 cnum++;
140                                         }
141                                         if(!left_align) {
142                                                 if(!unsig && sign && num >= 0) {
143                                                         bwrite(out, BUF(buf), SZ(sz), "+", 1);
144                                                         cnum++;
145                                                 }
146                                                 bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
147                                                 cnum += slen;
148                                         }
149                                         break;
150
151                                 case 'c':
152                                         {
153                                                 char c = va_arg(ap, int);
154                                                 bwrite(out, BUF(buf), SZ(sz), &c, 1);
155                                                 cnum++;
156                                         }
157                                         break;
158
159                                 case 's':
160                                         str = va_arg(ap, char*);
161                                         slen = strlen(str);
162
163                                         if(left_align) {
164                                                 bwrite(out, BUF(buf), SZ(sz), str, slen);
165                                                 cnum += slen;
166                                                 padc = ' ';
167                                         }
168                                         for(i=slen; i<fwidth; i++) {
169                                                 bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
170                                                 cnum++;
171                                         }
172                                         if(!left_align) {
173                                                 bwrite(out, BUF(buf), SZ(sz), str, slen);
174                                                 cnum += slen;
175                                         }
176                                         break;
177
178                                 case 'n':
179                                         *va_arg(ap, int*) = cnum;
180                                         break;
181
182                                 default:
183                                         break;
184                                 }
185
186                                 /* restore default conversion state */
187                                 base = 10;
188                                 alt = 0;
189                                 fwidth = 0;
190                                 padc = ' ';
191                                 hex_caps = 0;
192
193                                 fstart = 0;
194                                 fmt++;
195                         } else {
196                                 switch(*fmt) {
197                                 case '#':
198                                         alt = 1;
199                                         break;
200
201                                 case '+':
202                                         sign = 1;
203                                         break;
204
205                                 case '-':
206                                         left_align = 1;
207                                         break;
208
209                                 case 'l':
210                                 case 'L':
211                                         break;
212
213                                 case '0':
214                                         padc = '0';
215                                         break;
216
217                                 default:
218                                         if(isdigit(*fmt)) {
219                                                 const char *fw = fmt;
220                                                 while(*fmt && isdigit(*fmt)) fmt++;
221
222                                                 fwidth = atoi(fw);
223                                                 continue;
224                                         }
225                                 }
226                                 fmt++;
227                         }
228                 } else {
229                         bwrite(out, BUF(buf), SZ(sz), (char*)fmt++, 1);
230                         cnum++;
231                 }
232         }
233
234         return cnum;
235 }
236
237 /* bwrite is called by intern_printf to transparently handle writing into a
238  * buffer or to the terminal
239  */
240 static void bwrite(int out, char *buf, unsigned long buf_sz, char *str, int sz)
241 {
242         int i;
243
244         if(out == OUT_BUF) {
245                 if(buf_sz && buf_sz <= sz) sz = buf_sz;
246                 buf[sz] = 0;
247                 memcpy(buf, str, sz);
248         }
249 }