]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/compat.c
StdLib: Fix some build problems and obscure bugs.
[mirror_edk2.git] / StdLib / LibC / Uefi / compat.c
CommitLineData
d7ce7006 1/*\r
2 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>\r
3 * All rights reserved.\r
4 *\r
5 * Redistribution and use in source and binary forms, with or without\r
6 * modification, are permitted provided that the following conditions\r
7 * are met:\r
8 * 1. Redistributions of source code must retain the above copyright\r
9 * notice, this list of conditions and the following disclaimer.\r
10 * 2. Redistributions in binary form must reproduce the above copyright\r
11 * notice, this list of conditions and the following disclaimer in the\r
12 * documentation and/or other materials provided with the distribution.\r
13 * 3. The name of the author may not be used to endorse or promote products\r
14 * derived from this software without specific prior written permission.\r
15 *\r
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\r
19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\r
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
26 *\r
27 * $Id: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $\r
28\r
29 * Copyright (c) 1997, 2002 The NetBSD Foundation, Inc.\r
30 * All rights reserved.\r
31 *\r
32 * This code is derived from software contributed to The NetBSD Foundation\r
33 * by Klaus Klein and Jason R. Thorpe.\r
34 *\r
35 * Redistribution and use in source and binary forms, with or without\r
36 * modification, are permitted provided that the following conditions\r
37 * are met:\r
38 * 1. Redistributions of source code must retain the above copyright\r
39 * notice, this list of conditions and the following disclaimer.\r
40 * 2. Redistributions in binary form must reproduce the above copyright\r
41 * notice, this list of conditions and the following disclaimer in the\r
42 * documentation and/or other materials provided with the distribution.\r
43 * 3. All advertising materials mentioning features or use of this software\r
44 * must display the following acknowledgement:\r
45 * This product includes software developed by the NetBSD\r
46 * Foundation, Inc. and its contributors.\r
47 * 4. Neither the name of The NetBSD Foundation nor the names of its\r
48 * contributors may be used to endorse or promote products derived\r
49 * from this software without specific prior written permission.\r
50 *\r
51 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
61 * POSSIBILITY OF SUCH DAMAGE.\r
62 *\r
63 * $NetBSD: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $\r
64\r
65 * Copyright (c) 1987, 1993\r
66 * The Regents of the University of California. All rights reserved.\r
67 *\r
68 * Redistribution and use in source and binary forms, with or without\r
69 * modification, are permitted provided that the following conditions\r
70 * are met:\r
71 * 1. Redistributions of source code must retain the above copyright\r
72 * notice, this list of conditions and the following disclaimer.\r
73 * 2. Redistributions in binary form must reproduce the above copyright\r
74 * notice, this list of conditions and the following disclaimer in the\r
75 * documentation and/or other materials provided with the distribution.\r
76 * 3. Neither the name of the University nor the names of its contributors\r
77 * may be used to endorse or promote products derived from this software\r
78 * without specific prior written permission.\r
79 *\r
80 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\r
81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
82 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
83 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\r
84 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
85 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
86 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
87 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
90 * SUCH DAMAGE.\r
91 *\r
92 * $NetBSD: compat.c,v 1.1.1.1 2008/08/24 05:33:08 gmcgarry Exp $\r
93 */\r
94#include <LibConfig.h>\r
95#include <string.h>\r
96#include <fcntl.h>\r
41b152c5 97#include <sys/syslimits.h>\r
d7ce7006 98\r
99#ifndef HAVE_GETOPT\r
100char *optarg;\r
101int optind = 1;\r
102int\r
103getopt(int argc, char **argv, char *args)\r
104{\r
105 size_t n;\r
106 size_t nlen = strlen(args);\r
107 char cmd;\r
108 char rv;\r
109\r
110 if (argv[optind] && *argv[optind] == '-') {\r
111 cmd = *(argv[optind] + 1);\r
112\r
113 for (n = 0; n < nlen; n++) {\r
114 if (args[n] == ':')\r
115 continue;\r
116 if (args[n] == cmd) {\r
117 rv = *(argv[optind] + 1);\r
118 if (args[n+1] == ':') {\r
119 if (*(argv[optind] + 2) != '\0') {\r
120 optarg = argv[optind] + 2;\r
121 optind += 1;\r
122 } else {\r
123 optarg = argv[optind + 1];\r
124 optind += 2;\r
125 }\r
126 if (!optarg)\r
127 optarg="";\r
128 return rv;\r
129 } else {\r
130 optarg = NULL;\r
131 optind += 1;\r
132 return rv;\r
133 }\r
134 }\r
135 }\r
136 }\r
d7ce7006 137 return -1;\r
138}\r
139#endif\r
140\r
d7ce7006 141#define ISPATHSEPARATOR(x) ((x == '/') || (x == '\\'))\r
d7ce7006 142\r
5c5e4a12 143#ifdef HAVE_BASENAME\r
d7ce7006 144#ifndef PATH_MAX\r
5c5e4a12 145 #define PATH_MAX 5000\r
d7ce7006 146#endif\r
147\r
148char *\r
149basename(char *path)\r
150{\r
151 static char singledot[] = ".";\r
152 static char result[PATH_MAX];\r
153 char *p, *lastp;\r
154 size_t len;\r
155\r
156 /*\r
157 * If `path' is a null pointer or points to an empty string,\r
158 * return a pointer to the string ".".\r
159 */\r
160 if ((path == NULL) || (*path == '\0'))\r
161 return (singledot);\r
162\r
163 /* Strip trailing slashes, if any. */\r
164 lastp = path + strlen(path) - 1;\r
165 while (lastp != path && ISPATHSEPARATOR(*lastp))\r
166 lastp--;\r
167\r
168 /* Now find the beginning of this (final) component. */\r
169 p = lastp;\r
170 while (p != path && !ISPATHSEPARATOR(*(p - 1)))\r
171 p--;\r
172\r
173 /* ...and copy the result into the result buffer. */\r
174 len = (lastp - p) + 1 /* last char */;\r
175 if (len > (PATH_MAX - 1))\r
176 len = PATH_MAX - 1;\r
177\r
178 memcpy(result, p, len);\r
179 result[len] = '\0';\r
180\r
181 return (result);\r
182}\r
183#endif\r
184\r
185#if !defined(HAVE_MKSTEMP) && !defined(WIN32)\r
186int\r
187mkstemp(char *path)\r
188{\r
189 char *start, *trv;\r
190 unsigned int pid;\r
191\r
192 /* To guarantee multiple calls generate unique names even if\r
193 the file is not created. 676 different possibilities with 7\r
194 or more X's, 26 with 6 or less. */\r
195 static char xtra[2] = "aa";\r
196 int xcnt = 0;\r
197\r
198 pid = getpid();\r
199\r
200 /* Move to end of path and count trailing X's. */\r
201 for (trv = path; *trv; ++trv)\r
202 if (*trv == 'X')\r
203 xcnt++;\r
204 else\r
205 xcnt = 0;\r
206\r
207 /* Use at least one from xtra. Use 2 if more than 6 X's. */\r
208 if (*(trv - 1) == 'X')\r
209 *--trv = xtra[0];\r
210 if (xcnt > 6 && *(trv - 1) == 'X')\r
211 *--trv = xtra[1];\r
212\r
213 /* Set remaining X's to pid digits with 0's to the left. */\r
214 while (*--trv == 'X') {\r
215 *trv = (pid % 10) + '0';\r
216 pid /= 10;\r
217 }\r
218\r
219 /* update xtra for next call. */\r
220 if (xtra[0] != 'z')\r
221 xtra[0]++;\r
222 else {\r
223 xtra[0] = 'a';\r
224 if (xtra[1] != 'z')\r
225 xtra[1]++;\r
226 else\r
227 xtra[1] = 'a';\r
228 }\r
229\r
230 return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);\r
231}\r
232#endif\r
233\r
5c5e4a12 234#ifdef HAVE_FFS\r
d7ce7006 235int\r
236ffs(int x)\r
237{\r
238 int r = 1;\r
239 if (!x) return 0;\r
240 if (!(x & 0xffff)) { x >>= 16; r += 16; }\r
241 if (!(x & 0xff)) { x >>= 8; r += 8; }\r
242 if (!(x & 0xf)) { x >>= 4; r += 4; }\r
243 if (!(x & 3)) { x >>= 2; r += 2; }\r
244 if (!(x & 1)) { x >>= 1; r += 1; }\r
245\r
246 return r;\r
247}\r
248#endif\r
249\r
250/*\r
251 * Copyright Patrick Powell 1995\r
252 * This code is based on code written by Patrick Powell (papowell@astart.com)\r
253 * It may be used for any purpose as long as this notice remains intact\r
254 * on all source code distributions\r
255 */\r
256\r
257#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)\r
258\r
259static void\r
260dopr(char *buffer, size_t maxlen, const char *format, va_list args);\r
261\r
262static void\r
263fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,\r
264 int min, int max);\r
265\r
266static void\r
267fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,\r
268 int min, int max, int flags);\r
269\r
270static void\r
271fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,\r
272 int min, int max, int flags);\r
273\r
274static void\r
275dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);\r
276\r
277/*\r
278 * dopr(): poor man's version of doprintf\r
279 */\r
280\r
281/* format read states */\r
282#define DP_S_DEFAULT 0\r
283#define DP_S_FLAGS 1\r
284#define DP_S_MIN 2\r
285#define DP_S_DOT 3\r
286#define DP_S_MAX 4\r
287#define DP_S_MOD 5\r
288#define DP_S_CONV 6\r
289#define DP_S_DONE 7\r
290\r
291/* format flags - Bits */\r
292#define DP_F_MINUS (1 << 0)\r
293#define DP_F_PLUS (1 << 1)\r
294#define DP_F_SPACE (1 << 2)\r
295#define DP_F_NUM (1 << 3)\r
296#define DP_F_ZERO (1 << 4)\r
297#define DP_F_UP (1 << 5)\r
298#define DP_F_UNSIGNED (1 << 6)\r
299\r
300/* Conversion Flags */\r
301#define DP_C_SHORT 1\r
302#define DP_C_LONG 2\r
303#define DP_C_LDOUBLE 3\r
304#define DP_C_LONG_LONG 4\r
305\r
306#define char_to_int(p) (p - '0')\r
307#define abs_val(p) (p < 0 ? -p : p)\r
308\r
309\r
310static void\r
311dopr(char *buffer, size_t maxlen, const char *format, va_list args)\r
312{\r
313 char *strvalue, ch;\r
314 long value;\r
315 long double fvalue;\r
316 int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;\r
317 size_t currlen = 0;\r
318\r
319 ch = *format++;\r
320\r
321 while (state != DP_S_DONE) {\r
322 if ((ch == '\0') || (currlen >= maxlen))\r
323 state = DP_S_DONE;\r
324\r
325 switch(state) {\r
326 case DP_S_DEFAULT:\r
327 if (ch == '%')\r
328 state = DP_S_FLAGS;\r
329 else\r
330 dopr_outch(buffer, &currlen, maxlen, ch);\r
331 ch = *format++;\r
332 break;\r
333 case DP_S_FLAGS:\r
334 switch (ch) {\r
335 case '-':\r
336 flags |= DP_F_MINUS;\r
337 ch = *format++;\r
338 break;\r
339 case '+':\r
340 flags |= DP_F_PLUS;\r
341 ch = *format++;\r
342 break;\r
343 case ' ':\r
344 flags |= DP_F_SPACE;\r
345 ch = *format++;\r
346 break;\r
347 case '#':\r
348 flags |= DP_F_NUM;\r
349 ch = *format++;\r
350 break;\r
351 case '0':\r
352 flags |= DP_F_ZERO;\r
353 ch = *format++;\r
354 break;\r
355 default:\r
356 state = DP_S_MIN;\r
357 break;\r
358 }\r
359 break;\r
360 case DP_S_MIN:\r
361 if (isdigit((unsigned char)ch)) {\r
362 min = 10 * min + char_to_int (ch);\r
363 ch = *format++;\r
364 } else if (ch == '*') {\r
365 min = va_arg (args, int);\r
366 ch = *format++;\r
367 state = DP_S_DOT;\r
368 } else\r
369 state = DP_S_DOT;\r
370 break;\r
371 case DP_S_DOT:\r
372 if (ch == '.') {\r
373 state = DP_S_MAX;\r
374 ch = *format++;\r
375 } else\r
376 state = DP_S_MOD;\r
377 break;\r
378 case DP_S_MAX:\r
379 if (isdigit((unsigned char)ch)) {\r
380 if (max < 0)\r
381 max = 0;\r
382 max = 10 * max + char_to_int(ch);\r
383 ch = *format++;\r
384 } else if (ch == '*') {\r
385 max = va_arg (args, int);\r
386 ch = *format++;\r
387 state = DP_S_MOD;\r
388 } else\r
389 state = DP_S_MOD;\r
390 break;\r
391 case DP_S_MOD:\r
392 switch (ch) {\r
393 case 'h':\r
394 cflags = DP_C_SHORT;\r
395 ch = *format++;\r
396 break;\r
397 case 'l':\r
398 cflags = DP_C_LONG;\r
399 ch = *format++;\r
400 if (ch == 'l') {\r
401 cflags = DP_C_LONG_LONG;\r
402 ch = *format++;\r
403 }\r
404 break;\r
405 case 'q':\r
406 cflags = DP_C_LONG_LONG;\r
407 ch = *format++;\r
408 break;\r
409 case 'L':\r
410 cflags = DP_C_LDOUBLE;\r
411 ch = *format++;\r
412 break;\r
413 default:\r
414 break;\r
415 }\r
416 state = DP_S_CONV;\r
417 break;\r
418 case DP_S_CONV:\r
419 switch (ch) {\r
420 case 'd':\r
421 case 'i':\r
422 if (cflags == DP_C_SHORT)\r
423 value = va_arg(args, int);\r
424 else if (cflags == DP_C_LONG)\r
425 value = va_arg(args, long int);\r
426 else if (cflags == DP_C_LONG_LONG)\r
427 value = va_arg (args, long long);\r
428 else\r
429 value = va_arg (args, int);\r
430 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);\r
431 break;\r
432 case 'o':\r
433 flags |= DP_F_UNSIGNED;\r
434 if (cflags == DP_C_SHORT)\r
435 value = va_arg(args, unsigned int);\r
436 else if (cflags == DP_C_LONG)\r
437 value = va_arg(args, unsigned long int);\r
438 else if (cflags == DP_C_LONG_LONG)\r
439 value = va_arg(args, unsigned long long);\r
440 else\r
441 value = va_arg(args, unsigned int);\r
442 fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);\r
443 break;\r
444 case 'u':\r
445 flags |= DP_F_UNSIGNED;\r
446 if (cflags == DP_C_SHORT)\r
447 value = va_arg(args, unsigned int);\r
448 else if (cflags == DP_C_LONG)\r
449 value = va_arg(args, unsigned long int);\r
450 else if (cflags == DP_C_LONG_LONG)\r
451 value = va_arg(args, unsigned long long);\r
452 else\r
453 value = va_arg(args, unsigned int);\r
454 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);\r
455 break;\r
456 case 'X':\r
457 flags |= DP_F_UP;\r
458 case 'x':\r
459 flags |= DP_F_UNSIGNED;\r
460 if (cflags == DP_C_SHORT)\r
461 value = va_arg(args, unsigned int);\r
462 else if (cflags == DP_C_LONG)\r
463 value = va_arg(args, unsigned long int);\r
464 else if (cflags == DP_C_LONG_LONG)\r
465 value = va_arg(args, unsigned long long);\r
466 else\r
467 value = va_arg(args, unsigned int);\r
468 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);\r
469 break;\r
470 case 'f':\r
471 if (cflags == DP_C_LDOUBLE)\r
472 fvalue = va_arg(args, long double);\r
473 else\r
474 fvalue = va_arg(args, double);\r
475 /* um, floating point? */\r
476 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);\r
477 break;\r
478 case 'E':\r
479 flags |= DP_F_UP;\r
480 case 'e':\r
481 if (cflags == DP_C_LDOUBLE)\r
482 fvalue = va_arg(args, long double);\r
483 else\r
484 fvalue = va_arg(args, double);\r
485 break;\r
486 case 'G':\r
487 flags |= DP_F_UP;\r
488 case 'g':\r
489 if (cflags == DP_C_LDOUBLE)\r
490 fvalue = va_arg(args, long double);\r
491 else\r
492 fvalue = va_arg(args, double);\r
493 break;\r
494 case 'c':\r
495 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));\r
496 break;\r
497 case 's':\r
498 strvalue = va_arg(args, char *);\r
499 if (max < 0)\r
500 max = maxlen; /* ie, no max */\r
501 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);\r
502 break;\r
503 case 'p':\r
504 strvalue = va_arg(args, void *);\r
505 fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);\r
506 break;\r
507 case 'n':\r
508 if (cflags == DP_C_SHORT) {\r
509 short int *num;\r
510 num = va_arg(args, short int *);\r
511 *num = currlen;\r
512 } else if (cflags == DP_C_LONG) {\r
513 long int *num;\r
514 num = va_arg(args, long int *);\r
515 *num = currlen;\r
516 } else if (cflags == DP_C_LONG_LONG) {\r
517 long long *num;\r
518 num = va_arg(args, long long *);\r
519 *num = currlen;\r
520 } else {\r
521 int *num;\r
522 num = va_arg(args, int *);\r
523 *num = currlen;\r
524 }\r
525 break;\r
526 case '%':\r
527 dopr_outch(buffer, &currlen, maxlen, ch);\r
528 break;\r
529 case 'w': /* not supported yet, treat as next char */\r
530 ch = *format++;\r
531 break;\r
532 default: /* Unknown, skip */\r
533 break;\r
534 }\r
535 ch = *format++;\r
536 state = DP_S_DEFAULT;\r
537 flags = cflags = min = 0;\r
538 max = -1;\r
539 break;\r
540 case DP_S_DONE:\r
541 break;\r
542 default: /* hmm? */\r
543 break; /* some picky compilers need this */\r
544 }\r
545 }\r
546 if (currlen < maxlen - 1)\r
547 buffer[currlen] = '\0';\r
548 else\r
549 buffer[maxlen - 1] = '\0';\r
550}\r
551\r
552static void\r
553fmtstr(char *buffer, size_t *currlen, size_t maxlen,\r
554 char *value, int flags, int min, int max)\r
555{\r
556 int cnt = 0, padlen, strln; /* amount to pad */\r
557\r
558 if (value == 0)\r
559 value = "<NULL>";\r
560\r
561 for (strln = 0; value[strln]; ++strln); /* strlen */\r
562 padlen = min - strln;\r
563 if (padlen < 0)\r
564 padlen = 0;\r
565 if (flags & DP_F_MINUS)\r
566 padlen = -padlen; /* Left Justify */\r
567\r
568 while ((padlen > 0) && (cnt < max)) {\r
569 dopr_outch(buffer, currlen, maxlen, ' ');\r
570 --padlen;\r
571 ++cnt;\r
572 }\r
573 while (*value && (cnt < max)) {\r
574 dopr_outch(buffer, currlen, maxlen, *value++);\r
575 ++cnt;\r
576 }\r
577 while ((padlen < 0) && (cnt < max)) {\r
578 dopr_outch(buffer, currlen, maxlen, ' ');\r
579 ++padlen;\r
580 ++cnt;\r
581 }\r
582}\r
583\r
584/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */\r
585\r
586static void\r
587fmtint(char *buffer, size_t *currlen, size_t maxlen,\r
588 long value, int base, int min, int max, int flags)\r
589{\r
590 unsigned long uvalue;\r
591 char convert[20];\r
592 int signvalue = 0, place = 0, caps = 0;\r
593 int spadlen = 0; /* amount to space pad */\r
594 int zpadlen = 0; /* amount to zero pad */\r
595\r
596#define PADMAX(x,y) ((x) > (y) ? (x) : (y))\r
597\r
598 if (max < 0)\r
599 max = 0;\r
600\r
601 uvalue = value;\r
602\r
603 if (!(flags & DP_F_UNSIGNED)) {\r
604 if (value < 0) {\r
605 signvalue = '-';\r
606 uvalue = -value;\r
607 } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */\r
608 signvalue = '+';\r
609 else if (flags & DP_F_SPACE)\r
610 signvalue = ' ';\r
611 }\r
612\r
613 if (flags & DP_F_UP)\r
614 caps = 1; /* Should characters be upper case? */\r
615 do {\r
616 convert[place++] =\r
617 (caps ? "0123456789ABCDEF" : "0123456789abcdef")\r
618 [uvalue % (unsigned)base];\r
619 uvalue = (uvalue / (unsigned)base );\r
620 } while (uvalue && (place < 20));\r
621 if (place == 20)\r
622 place--;\r
623 convert[place] = 0;\r
624\r
625 zpadlen = max - place;\r
626 spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);\r
627 if (zpadlen < 0)\r
628 zpadlen = 0;\r
629 if (spadlen < 0)\r
630 spadlen = 0;\r
631 if (flags & DP_F_ZERO) {\r
632 zpadlen = PADMAX(zpadlen, spadlen);\r
633 spadlen = 0;\r
634 }\r
635 if (flags & DP_F_MINUS)\r
636 spadlen = -spadlen; /* Left Justifty */\r
637\r
638 /* Spaces */\r
639 while (spadlen > 0) {\r
640 dopr_outch(buffer, currlen, maxlen, ' ');\r
641 --spadlen;\r
642 }\r
643\r
644 /* Sign */\r
645 if (signvalue)\r
646 dopr_outch(buffer, currlen, maxlen, signvalue);\r
647\r
648 /* Zeros */\r
649 if (zpadlen > 0) {\r
650 while (zpadlen > 0) {\r
651 dopr_outch(buffer, currlen, maxlen, '0');\r
652 --zpadlen;\r
653 }\r
654 }\r
655\r
656 /* Digits */\r
657 while (place > 0)\r
658 dopr_outch(buffer, currlen, maxlen, convert[--place]);\r
659\r
660 /* Left Justified spaces */\r
661 while (spadlen < 0) {\r
662 dopr_outch (buffer, currlen, maxlen, ' ');\r
663 ++spadlen;\r
664 }\r
665}\r
666\r
667static long double\r
668pow10(int exp)\r
669{\r
670 long double result = 1;\r
671\r
672 while (exp) {\r
673 result *= 10;\r
674 exp--;\r
675 }\r
676\r
677 return result;\r
678}\r
679\r
680static long\r
681round(long double value)\r
682{\r
683 long intpart = value;\r
684\r
685 value -= intpart;\r
686 if (value >= 0.5)\r
687 intpart++;\r
688\r
689 return intpart;\r
690}\r
691\r
692static void\r
693fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,\r
694 int min, int max, int flags)\r
695{\r
696 char iconvert[20], fconvert[20];\r
697 int signvalue = 0, iplace = 0, fplace = 0;\r
698 int padlen = 0; /* amount to pad */\r
699 int zpadlen = 0, caps = 0;\r
700 long intpart, fracpart;\r
701 long double ufvalue;\r
702\r
703 /*\r
704 * AIX manpage says the default is 0, but Solaris says the default\r
705 * is 6, and sprintf on AIX defaults to 6\r
706 */\r
707 if (max < 0)\r
708 max = 6;\r
709\r
710 ufvalue = abs_val(fvalue);\r
711\r
712 if (fvalue < 0)\r
713 signvalue = '-';\r
714 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */\r
715 signvalue = '+';\r
716 else if (flags & DP_F_SPACE)\r
717 signvalue = ' ';\r
718\r
719 intpart = ufvalue;\r
720\r
721 /*\r
722 * Sorry, we only support 9 digits past the decimal because of our\r
723 * conversion method\r
724 */\r
725 if (max > 9)\r
726 max = 9;\r
727\r
728 /* We "cheat" by converting the fractional part to integer by\r
729 * multiplying by a factor of 10\r
730 */\r
731 fracpart = round((pow10 (max)) * (ufvalue - intpart));\r
732\r
733 if (fracpart >= pow10 (max)) {\r
734 intpart++;\r
735 fracpart -= pow10 (max);\r
736 }\r
737\r
738 /* Convert integer part */\r
739 do {\r
740 iconvert[iplace++] =\r
741 (caps ? "0123456789ABCDEF" : "0123456789abcdef")\r
742 [intpart % 10];\r
743 intpart = (intpart / 10);\r
744 } while(intpart && (iplace < 20));\r
745 if (iplace == 20)\r
746 iplace--;\r
747 iconvert[iplace] = 0;\r
748\r
749 /* Convert fractional part */\r
750 do {\r
751 fconvert[fplace++] =\r
752 (caps ? "0123456789ABCDEF" : "0123456789abcdef")\r
753 [fracpart % 10];\r
754 fracpart = (fracpart / 10);\r
755 } while(fracpart && (fplace < 20));\r
756 if (fplace == 20)\r
757 fplace--;\r
758 fconvert[fplace] = 0;\r
759\r
760 /* -1 for decimal point, another -1 if we are printing a sign */\r
761 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);\r
762 zpadlen = max - fplace;\r
763 if (zpadlen < 0)\r
764 zpadlen = 0;\r
765 if (padlen < 0)\r
766 padlen = 0;\r
767 if (flags & DP_F_MINUS)\r
768 padlen = -padlen; /* Left Justifty */\r
769\r
770 if ((flags & DP_F_ZERO) && (padlen > 0)) {\r
771 if (signvalue) {\r
772 dopr_outch(buffer, currlen, maxlen, signvalue);\r
773 --padlen;\r
774 signvalue = 0;\r
775 }\r
776 while (padlen > 0) {\r
777 dopr_outch(buffer, currlen, maxlen, '0');\r
778 --padlen;\r
779 }\r
780 }\r
781 while (padlen > 0) {\r
782 dopr_outch(buffer, currlen, maxlen, ' ');\r
783 --padlen;\r
784 }\r
785 if (signvalue)\r
786 dopr_outch(buffer, currlen, maxlen, signvalue);\r
787\r
788 while (iplace > 0)\r
789 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);\r
790\r
791 /*\r
792 * Decimal point. This should probably use locale to find the\r
793 * correct char to print out.\r
794 */\r
795 dopr_outch(buffer, currlen, maxlen, '.');\r
796\r
797 while (fplace > 0)\r
798 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);\r
799\r
800 while (zpadlen > 0) {\r
801 dopr_outch(buffer, currlen, maxlen, '0');\r
802 --zpadlen;\r
803 }\r
804\r
805 while (padlen < 0) {\r
806 dopr_outch(buffer, currlen, maxlen, ' ');\r
807 ++padlen;\r
808 }\r
809}\r
810\r
811static void\r
812dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)\r
813{\r
814 if (*currlen < maxlen)\r
815 buffer[(*currlen)++] = c;\r
816}\r
817#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */\r
818\r
819#ifndef HAVE_VSNPRINTF\r
820int\r
821vsnprintf(char *str, size_t count, const char *fmt, va_list args)\r
822{\r
823 str[0] = 0;\r
824 dopr(str, count, fmt, args);\r
825\r
826 return(strlen(str));\r
827}\r
828#endif /* !HAVE_VSNPRINTF */\r
829\r
830#ifndef HAVE_SNPRINTF\r
831int\r
832snprintf(char *str,size_t count,const char *fmt,...)\r
833{\r
834 va_list ap;\r
835\r
836 va_start(ap, fmt);\r
837 (void) vsnprintf(str, count, fmt, ap);\r
838 va_end(ap);\r
839\r
840 return(strlen(str));\r
841}\r
842\r
843#endif /* !HAVE_SNPRINTF */\r