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