win-pvdrivers

view xenpci/mingw_extras.c @ 358:c85311cc1aec

fix bug in RtlStringCbPrintfW.
author Andy Grover <andy.grover@oracle.com>
date Wed Jul 02 11:40:56 2008 -0700 (2008-07-02)
parents 429f282ecbb3
children
line source
1 /*
2 * Provide missing std functions needed by the driver but not provided by
3 * MinGW. Code mostly taken from Linux or as noted.
4 *
5 * Remaining code is
6 * Copyright Andy Grover <andy.grover@oracle.com>
7 * and licensed under the GPLv2.
8 */
10 #include "xenpci.h"
12 NTSTATUS
13 RtlStringCbPrintfW(
14 win_wchar_t *dest_str,
15 size_t dest_size,
16 win_wchar_t *format,
17 ...)
18 {
19 va_list args;
20 int len;
21 int i;
22 char tmp_buf[512];
23 NTSTATUS status = STATUS_SUCCESS;
25 if (dest_size > sizeof(tmp_buf))
26 dest_size = sizeof(tmp_buf);
28 /* we don't have a 2-byte version of vsnprintf, so write it to a single-byte
29 array using vsnprintf() and then copy result to the wchar buffer.
30 This should be seldom executed, so this inefficiency should be ok. */
31 va_start(args, format);
32 len = vsnprintf(tmp_buf, sizeof(tmp_buf), (char *)format, args);
33 va_end(args);
35 if (len >= (dest_size * sizeof(win_wchar_t))) {
36 /* output buffer truncated */
37 status = STATUS_BUFFER_OVERFLOW;
38 len = sizeof(tmp_buf) - 1;
39 tmp_buf[len] = '\0';
40 }
42 /* copy byte-string to short_string, incl NULL */
43 for (i = 0; i < (len + 1); i++)
44 {
45 dest_str[i] = tmp_buf[i];
46 }
48 return status;
49 }
51 /* ----- BEGIN Other people's code --------- */
53 /* from arch/x86/boot/string.c, used under GPLv2 */
54 /* Copyright (C) 1991, 1992 Linus Torvalds
55 * Copyright 2007 rPath, Inc. - All Rights Reserved
56 */
57 size_t strnlen(const char *s, size_t maxlen)
58 {
59 const char *es = s;
60 while (*es && maxlen) {
61 es++;
62 maxlen--;
63 }
65 return (es - s);
66 }
68 /* from arch/x86/boot/boot.h, used under GPLv2 */
69 /* Copyright (C) 1991, 1992 Linus Torvalds
70 * Copyright 2007 rPath, Inc. - All Rights Reserved
71 */
72 static int isdigit(int ch)
73 {
74 return (ch >= '0') && (ch <= '9');
75 }
77 /* from K&Rv2 p. 43 */
78 int atoi(const char s[])
79 {
80 int i, n;
82 n = 0;
83 for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
84 n = 10 * n + (s[i] - '0');
85 return n;
86 }
88 /* from linux/lib/vsprintf.c, used under GPLv2 */
89 /* Copyright (C) 1991, 1992 Linus Torvalds
90 * Wirzenius wrote this portably, Torvalds fucked it up :-)
91 */
92 static int skip_atoi(const char **s)
93 {
94 int i=0;
96 while (isdigit(**s))
97 i = i*10 + *((*s)++) - '0';
98 return i;
99 }
101 int snprintf(char * buf, size_t size, const char *fmt, ...)
102 {
103 va_list args;
104 int i;
106 va_start(args, fmt);
107 i = vsnprintf(buf,size,fmt,args);
108 va_end(args);
109 return i;
110 }
112 #define do_div(n,base) ({ \
113 int __res; \
114 __res = ((unsigned long) n) % (unsigned) base; \
115 n = ((unsigned long) n) / (unsigned) base; \
116 __res; })
119 /* Decimal conversion is by far the most typical, and is used
120 * for /proc and /sys data. This directly impacts e.g. top performance
121 * with many processes running. We optimize it for speed
122 * using code from
123 * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
124 * (with permission from the author, Douglas W. Jones). */
126 /* Formats correctly any integer in [0,99999].
127 * Outputs from one to five digits depending on input.
128 * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
129 static char* put_dec_trunc(char *buf, unsigned q)
130 {
131 unsigned d3, d2, d1, d0;
132 d1 = (q>>4) & 0xf;
133 d2 = (q>>8) & 0xf;
134 d3 = (q>>12);
136 d0 = 6*(d3 + d2 + d1) + (q & 0xf);
137 q = (d0 * 0xcd) >> 11;
138 d0 = d0 - 10*q;
139 *buf++ = d0 + '0'; /* least significant digit */
140 d1 = q + 9*d3 + 5*d2 + d1;
141 if (d1 != 0) {
142 q = (d1 * 0xcd) >> 11;
143 d1 = d1 - 10*q;
144 *buf++ = d1 + '0'; /* next digit */
146 d2 = q + 2*d2;
147 if ((d2 != 0) || (d3 != 0)) {
148 q = (d2 * 0xd) >> 7;
149 d2 = d2 - 10*q;
150 *buf++ = d2 + '0'; /* next digit */
152 d3 = q + 4*d3;
153 if (d3 != 0) {
154 q = (d3 * 0xcd) >> 11;
155 d3 = d3 - 10*q;
156 *buf++ = d3 + '0'; /* next digit */
157 if (q != 0)
158 *buf++ = q + '0'; /* most sign. digit */
159 }
160 }
161 }
162 return buf;
163 }
164 /* Same with if's removed. Always emits five digits */
165 static char* put_dec_full(char *buf, unsigned q)
166 {
167 /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
168 /* but anyway, gcc produces better code with full-sized ints */
169 unsigned d3, d2, d1, d0;
170 d1 = (q>>4) & 0xf;
171 d2 = (q>>8) & 0xf;
172 d3 = (q>>12);
174 /* Possible ways to approx. divide by 10 */
175 /* gcc -O2 replaces multiply with shifts and adds */
176 // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
177 // (x * 0x67) >> 10: 1100111
178 // (x * 0x34) >> 9: 110100 - same
179 // (x * 0x1a) >> 8: 11010 - same
180 // (x * 0x0d) >> 7: 1101 - same, shortest code (on i386)
182 d0 = 6*(d3 + d2 + d1) + (q & 0xf);
183 q = (d0 * 0xcd) >> 11;
184 d0 = d0 - 10*q;
185 *buf++ = d0 + '0';
186 d1 = q + 9*d3 + 5*d2 + d1;
187 q = (d1 * 0xcd) >> 11;
188 d1 = d1 - 10*q;
189 *buf++ = d1 + '0';
191 d2 = q + 2*d2;
192 q = (d2 * 0xd) >> 7;
193 d2 = d2 - 10*q;
194 *buf++ = d2 + '0';
196 d3 = q + 4*d3;
197 q = (d3 * 0xcd) >> 11; /* - shorter code */
198 /* q = (d3 * 0x67) >> 10; - would also work */
199 d3 = d3 - 10*q;
200 *buf++ = d3 + '0';
201 *buf++ = q + '0';
202 return buf;
203 }
205 static char* put_dec(char *buf, unsigned long long num)
206 {
207 while (1) {
208 unsigned rem;
209 if (num < 100000)
210 return put_dec_trunc(buf, num);
211 rem = do_div(num, 100000);
212 buf = put_dec_full(buf, rem);
213 }
214 }
217 #define ZEROPAD 1 /* pad with zero */
218 #define SIGN 2 /* unsigned/signed long */
219 #define PLUS 4 /* show plus */
220 #define SPACE 8 /* space if plus */
221 #define LEFT 16 /* left justified */
222 #define SMALL 32 /* Must be 32 == 0x20 */
223 #define SPECIAL 64 /* 0x */
225 static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
226 {
227 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
228 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
230 char tmp[66];
231 char sign;
232 char locase;
233 int need_pfx = ((type & SPECIAL) && base != 10);
234 int i;
236 /* locase = 0 or 0x20. ORing digits or letters with 'locase'
237 * produces same digits or (maybe lowercased) letters */
238 locase = (type & SMALL);
239 if (type & LEFT)
240 type &= ~ZEROPAD;
241 sign = 0;
242 if (type & SIGN) {
243 if ((signed long long) num < 0) {
244 sign = '-';
245 num = - (signed long long) num;
246 size--;
247 } else if (type & PLUS) {
248 sign = '+';
249 size--;
250 } else if (type & SPACE) {
251 sign = ' ';
252 size--;
253 }
254 }
255 if (need_pfx) {
256 size--;
257 if (base == 16)
258 size--;
259 }
261 /* generate full string in tmp[], in reverse order */
262 i = 0;
263 if (num == 0)
264 tmp[i++] = '0';
265 /* Generic code, for any base:
266 else do {
267 tmp[i++] = (digits[do_div(num,base)] | locase);
268 } while (num != 0);
269 */
270 else if (base != 10) { /* 8 or 16 */
271 int mask = base - 1;
272 int shift = 3;
273 if (base == 16) shift = 4;
274 do {
275 tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
276 num >>= shift;
277 } while (num);
278 } else { /* base 10 */
279 i = put_dec(tmp, num) - tmp;
280 }
282 /* printing 100 using %2d gives "100", not "00" */
283 if (i > precision)
284 precision = i;
285 /* leading space padding */
286 size -= precision;
287 if (!(type & (ZEROPAD+LEFT))) {
288 while(--size >= 0) {
289 if (buf < end)
290 *buf = ' ';
291 ++buf;
292 }
293 }
294 /* sign */
295 if (sign) {
296 if (buf < end)
297 *buf = sign;
298 ++buf;
299 }
300 /* "0x" / "0" prefix */
301 if (need_pfx) {
302 if (buf < end)
303 *buf = '0';
304 ++buf;
305 if (base == 16) {
306 if (buf < end)
307 *buf = ('X' | locase);
308 ++buf;
309 }
310 }
311 /* zero or space padding */
312 if (!(type & LEFT)) {
313 char c = (type & ZEROPAD) ? '0' : ' ';
314 while (--size >= 0) {
315 if (buf < end)
316 *buf = c;
317 ++buf;
318 }
319 }
320 /* hmm even more zero padding? */
321 while (i <= --precision) {
322 if (buf < end)
323 *buf = '0';
324 ++buf;
325 }
326 /* actual digits of result */
327 while (--i >= 0) {
328 if (buf < end)
329 *buf = tmp[i];
330 ++buf;
331 }
332 /* trailing space padding */
333 while (--size >= 0) {
334 if (buf < end)
335 *buf = ' ';
336 ++buf;
337 }
338 return buf;
339 }
341 /**
342 * vsnprintf - Format a string and place it in a buffer
343 * @buf: The buffer to place the result into
344 * @size: The size of the buffer, including the trailing null space
345 * @fmt: The format string to use
346 * @args: Arguments for the format string
347 *
348 * The return value is the number of characters which would
349 * be generated for the given input, excluding the trailing
350 * '\0', as per ISO C99. If you want to have the exact
351 * number of characters written into @buf as return value
352 * (not including the trailing '\0'), use vscnprintf(). If the
353 * return is greater than or equal to @size, the resulting
354 * string is truncated.
355 *
356 * Call this function if you are already dealing with a va_list.
357 * You probably want snprintf() instead.
358 */
359 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
360 {
361 int len;
362 unsigned long long num;
363 int i, base;
364 char *str, *end, c;
365 const char *s;
367 int flags; /* flags to number() */
369 int field_width; /* width of output field */
370 int precision; /* min. # of digits for integers; max
371 number of chars for from string */
372 int qualifier; /* 'h', 'l', or 'L' for integer fields */
373 /* 'z' support added 23/7/1999 S.H. */
374 /* 'z' changed to 'Z' --davidm 1/25/99 */
375 /* 't' added for ptrdiff_t */
377 /* Reject out-of-range values early. Large positive sizes are
378 used for unknown buffer sizes. */
379 if ((int) size < 0)
380 return 0;
382 str = buf;
383 end = buf + size;
385 /* Make sure end is always >= buf */
386 if (end < buf) {
387 end = ((void *)-1);
388 size = end - buf;
389 }
391 for (; *fmt ; ++fmt) {
392 if (*fmt != '%') {
393 if (str < end)
394 *str = *fmt;
395 ++str;
396 continue;
397 }
399 /* process flags */
400 flags = 0;
401 repeat:
402 ++fmt; /* this also skips first '%' */
403 switch (*fmt) {
404 case '-': flags |= LEFT; goto repeat;
405 case '+': flags |= PLUS; goto repeat;
406 case ' ': flags |= SPACE; goto repeat;
407 case '#': flags |= SPECIAL; goto repeat;
408 case '0': flags |= ZEROPAD; goto repeat;
409 }
411 /* get field width */
412 field_width = -1;
413 if (isdigit(*fmt))
414 field_width = skip_atoi(&fmt);
415 else if (*fmt == '*') {
416 ++fmt;
417 /* it's the next argument */
418 field_width = va_arg(args, int);
419 if (field_width < 0) {
420 field_width = -field_width;
421 flags |= LEFT;
422 }
423 }
425 /* get the precision */
426 precision = -1;
427 if (*fmt == '.') {
428 ++fmt;
429 if (isdigit(*fmt))
430 precision = skip_atoi(&fmt);
431 else if (*fmt == '*') {
432 ++fmt;
433 /* it's the next argument */
434 precision = va_arg(args, int);
435 }
436 if (precision < 0)
437 precision = 0;
438 }
440 /* get the conversion qualifier */
441 qualifier = -1;
442 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
443 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
444 qualifier = *fmt;
445 ++fmt;
446 if (qualifier == 'l' && *fmt == 'l') {
447 qualifier = 'L';
448 ++fmt;
449 }
450 }
452 /* default base */
453 base = 10;
455 switch (*fmt) {
456 case 'c':
457 if (!(flags & LEFT)) {
458 while (--field_width > 0) {
459 if (str < end)
460 *str = ' ';
461 ++str;
462 }
463 }
464 c = (unsigned char) va_arg(args, int);
465 if (str < end)
466 *str = c;
467 ++str;
468 while (--field_width > 0) {
469 if (str < end)
470 *str = ' ';
471 ++str;
472 }
473 continue;
475 case 's':
476 s = va_arg(args, char *);
477 if ((unsigned long)s < PAGE_SIZE)
478 s = "<NULL>";
480 len = strnlen(s, precision);
482 if (!(flags & LEFT)) {
483 while (len < field_width--) {
484 if (str < end)
485 *str = ' ';
486 ++str;
487 }
488 }
489 for (i = 0; i < len; ++i) {
490 if (str < end)
491 *str = *s;
492 ++str; ++s;
493 }
494 while (len < field_width--) {
495 if (str < end)
496 *str = ' ';
497 ++str;
498 }
499 continue;
501 case 'p':
502 flags |= SMALL;
503 if (field_width == -1) {
504 field_width = 2*sizeof(void *);
505 flags |= ZEROPAD;
506 }
507 str = number(str, end,
508 (unsigned long) va_arg(args, void *),
509 16, field_width, precision, flags);
510 continue;
513 case 'n':
514 /* FIXME:
515 * What does C99 say about the overflow case here? */
516 if (qualifier == 'l') {
517 long * ip = va_arg(args, long *);
518 *ip = (str - buf);
519 } else if (qualifier == 'Z' || qualifier == 'z') {
520 size_t * ip = va_arg(args, size_t *);
521 *ip = (str - buf);
522 } else {
523 int * ip = va_arg(args, int *);
524 *ip = (str - buf);
525 }
526 continue;
528 case '%':
529 if (str < end)
530 *str = '%';
531 ++str;
532 continue;
534 /* integer number formats - set up the flags and "break" */
535 case 'o':
536 base = 8;
537 break;
539 case 'x':
540 flags |= SMALL;
541 case 'X':
542 base = 16;
543 break;
545 case 'd':
546 case 'i':
547 flags |= SIGN;
548 case 'u':
549 break;
551 default:
552 if (str < end)
553 *str = '%';
554 ++str;
555 if (*fmt) {
556 if (str < end)
557 *str = *fmt;
558 ++str;
559 } else {
560 --fmt;
561 }
562 continue;
563 }
564 if (qualifier == 'L')
565 num = va_arg(args, long long);
566 else if (qualifier == 'l') {
567 num = va_arg(args, unsigned long);
568 if (flags & SIGN)
569 num = (signed long) num;
570 } else if (qualifier == 'Z' || qualifier == 'z') {
571 num = va_arg(args, size_t);
572 } else if (qualifier == 't') {
573 num = va_arg(args, ptrdiff_t);
574 } else if (qualifier == 'h') {
575 num = (unsigned short) va_arg(args, int);
576 if (flags & SIGN)
577 num = (signed short) num;
578 } else {
579 num = va_arg(args, unsigned int);
580 if (flags & SIGN)
581 num = (signed int) num;
582 }
583 str = number(str, end, num, base,
584 field_width, precision, flags);
585 }
586 if (size > 0) {
587 if (str < end)
588 *str = '\0';
589 else
590 end[-1] = '\0';
591 }
592 /* the trailing null byte doesn't count towards the total */
593 return str-buf;
594 }
595 /* ----- END Other people's code --------- */