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