1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * All rights reserved.
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
8 *
9 * Contributors:
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
12
13 #include <stdbool.h>
14 #include <compiler.h>
15 #include "stdio.h"
16 #include "stdlib.h"
17 #include "string.h"
18 #include "ctype.h"
19
20 static const unsigned long long convert[] = {
21 0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
22 0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
23 };
24
25 static int
print_str_fill(char ** buffer,size_t bufsize,char * sizec,const char * str,char c)26 print_str_fill(char **buffer, size_t bufsize, char *sizec,
27 const char *str, char c)
28 {
29 size_t i, sizei, len;
30 char *bstart = *buffer;
31
32 sizei = strtoul(sizec, NULL, 10);
33 len = strlen(str);
34 if (sizei > len) {
35 for (i = 0;
36 (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
37 i++) {
38 **buffer = c;
39 *buffer += 1;
40 }
41 }
42 return 1;
43 }
44
45 static int
print_str(char ** buffer,size_t bufsize,const char * str)46 print_str(char **buffer, size_t bufsize, const char *str)
47 {
48 char *bstart = *buffer;
49 size_t i;
50
51 for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) {
52 **buffer = str[i];
53 *buffer += 1;
54 }
55 return 1;
56 }
57
58 static unsigned int __attrconst
print_intlen(unsigned long value,unsigned short int base)59 print_intlen(unsigned long value, unsigned short int base)
60 {
61 int i = 0;
62
63 while (value > 0) {
64 value /= base;
65 i++;
66 }
67 if (i == 0)
68 i = 1;
69 return i;
70 }
71
72 static int
print_itoa(char ** buffer,size_t bufsize,unsigned long value,unsigned short base,bool upper)73 print_itoa(char **buffer, size_t bufsize, unsigned long value,
74 unsigned short base, bool upper)
75 {
76 const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
77 char c;
78 int i, len;
79
80 if(base <= 2 || base > 16)
81 return 0;
82
83 len = i = print_intlen(value, base);
84
85 /* Don't print to buffer if bufsize is not enough. */
86 if (len > bufsize)
87 return 0;
88
89 do {
90 c = zeichen[value % base];
91 if (upper)
92 c = toupper(c);
93
94 (*buffer)[--i] = c;
95 value /= base;
96 } while(value);
97
98 *buffer += len;
99
100 return 1;
101 }
102
103
104
105 static int
print_fill(char ** buffer,size_t bufsize,char * sizec,unsigned long size,unsigned short int base,char c,int optlen)106 print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size,
107 unsigned short int base, char c, int optlen)
108 {
109 int i, sizei, len;
110 char *bstart = *buffer;
111
112 sizei = strtoul(sizec, NULL, 10);
113 len = print_intlen(size, base) + optlen;
114 if (sizei > len) {
115 for (i = 0;
116 (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
117 i++) {
118 **buffer = c;
119 *buffer += 1;
120 }
121 }
122
123 return 0;
124 }
125
126
127 static int
print_format(char ** buffer,size_t bufsize,const char * format,void * var)128 print_format(char **buffer, size_t bufsize, const char *format, void *var)
129 {
130 char *start;
131 unsigned int i = 0, length_mod = sizeof(int);
132 unsigned long value = 0;
133 unsigned long signBit;
134 char *form, sizec[32];
135 char sign = ' ';
136 bool upper = false;
137
138 form = (char *) format;
139 start = *buffer;
140
141 form++;
142 if(*form == '0' || *form == '.') {
143 sign = '0';
144 form++;
145 }
146
147 while ((*form != '\0') && ((*buffer - start) < bufsize)) {
148 switch(*form) {
149 case 'u':
150 case 'd':
151 case 'i':
152 sizec[i] = '\0';
153 value = (unsigned long) var;
154 signBit = 0x1ULL << (length_mod * 8 - 1);
155 if ((*form != 'u') && (signBit & value)) {
156 **buffer = '-';
157 *buffer += 1;
158 value = (-(unsigned long)value) & convert[length_mod];
159 }
160 print_fill(buffer, bufsize - (*buffer - start),
161 sizec, value, 10, sign, 0);
162 print_itoa(buffer, bufsize - (*buffer - start),
163 value, 10, upper);
164 break;
165 case 'X':
166 upper = true;
167 /* fallthrough */
168 case 'x':
169 sizec[i] = '\0';
170 value = (unsigned long) var & convert[length_mod];
171 print_fill(buffer, bufsize - (*buffer - start),
172 sizec, value, 16, sign, 0);
173 print_itoa(buffer, bufsize - (*buffer - start),
174 value, 16, upper);
175 break;
176 case 'O':
177 case 'o':
178 sizec[i] = '\0';
179 value = (long int) var & convert[length_mod];
180 print_fill(buffer, bufsize - (*buffer - start),
181 sizec, value, 8, sign, 0);
182 print_itoa(buffer, bufsize - (*buffer - start),
183 value, 8, upper);
184 break;
185 case 'p':
186 sizec[i] = '\0';
187 print_fill(buffer, bufsize - (*buffer - start),
188 sizec, (unsigned long) var, 16, ' ', 2);
189 print_str(buffer, bufsize - (*buffer - start),
190 "0x");
191 print_itoa(buffer, bufsize - (*buffer - start),
192 (unsigned long) var, 16, upper);
193 break;
194 case 'c':
195 sizec[i] = '\0';
196 print_fill(buffer, bufsize - (*buffer - start),
197 sizec, 1, 10, ' ', 0);
198 **buffer = (unsigned long) var;
199 *buffer += 1;
200 break;
201 case 's':
202 sizec[i] = '\0';
203 print_str_fill(buffer,
204 bufsize - (*buffer - start), sizec,
205 (char *) var, ' ');
206
207 print_str(buffer, bufsize - (*buffer - start),
208 (char *) var);
209 break;
210 case 'l':
211 form++;
212 if(*form == 'l') {
213 length_mod = sizeof(long long int);
214 } else {
215 form--;
216 length_mod = sizeof(long int);
217 }
218 break;
219 case 'h':
220 form++;
221 if(*form == 'h') {
222 length_mod = sizeof(signed char);
223 } else {
224 form--;
225 length_mod = sizeof(short int);
226 }
227 break;
228 case 'z':
229 length_mod = sizeof(size_t);
230 break;
231 default:
232 if(*form >= '0' && *form <= '9')
233 sizec[i++] = *form;
234 }
235 form++;
236 }
237
238
239 return (long int) (*buffer - start);
240 }
241
242
243 /*
244 * The vsnprintf function prints a formatted strings into a buffer.
245 * BUG: buffer size checking does not fully work yet
246 */
247 int
vsnprintf(char * buffer,size_t bufsize,const char * format,va_list arg)248 vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
249 {
250 char *ptr, *bstart;
251
252 bstart = buffer;
253 ptr = (char *) format;
254
255 /*
256 * Return from here if size passed is zero, otherwise we would
257 * overrun buffer while setting NULL character at the end.
258 */
259 if (!buffer || !bufsize)
260 return 0;
261
262 /* Leave one space for NULL character */
263 bufsize--;
264
265 while(*ptr != '\0' && (buffer - bstart) < bufsize)
266 {
267 if(*ptr == '%') {
268 char formstr[20];
269 int i=0;
270
271 do {
272 formstr[i] = *ptr;
273 ptr++;
274 i++;
275 } while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X'
276 || *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%'
277 || *ptr == 'O' || *ptr == 'o' ));
278 formstr[i++] = *ptr;
279 formstr[i] = '\0';
280 if(*ptr == '%') {
281 *buffer++ = '%';
282 } else {
283 print_format(&buffer,
284 bufsize - (buffer - bstart),
285 formstr, va_arg(arg, void *));
286 }
287 ptr++;
288 } else {
289
290 *buffer = *ptr;
291
292 buffer++;
293 ptr++;
294 }
295 }
296
297 *buffer = '\0';
298
299 return (buffer - bstart);
300 }
301