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
getopt(int argc,char ** argv,char * args)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         return -1;
138 }
139 #endif
140 
141 #define ISPATHSEPARATOR(x) ((x == '/') || (x == '\\'))
142 
143 #ifdef HAVE_BASENAME
144 #ifndef PATH_MAX
145   #define PATH_MAX 5000
146 #endif
147 
148 char *
basename(char * path)149 basename(char *path)
150 {
151   static char singledot[] = ".";
152   static char result[PATH_MAX];
153   char *p, *lastp;
154   size_t len;
155 
156   /*
157    * If `path' is a null pointer or points to an empty string,
158    * return a pointer to the string ".".
159    */
160   if ((path == NULL) || (*path == '\0'))
161     return (singledot);
162 
163   /* Strip trailing slashes, if any. */
164   lastp = path + strlen(path) - 1;
165   while (lastp != path && ISPATHSEPARATOR(*lastp))
166     lastp--;
167 
168   /* Now find the beginning of this (final) component. */
169   p = lastp;
170   while (p != path && !ISPATHSEPARATOR(*(p - 1)))
171     p--;
172 
173   /* ...and copy the result into the result buffer. */
174   len = (lastp - p) + 1 /* last char */;
175   if (len > (PATH_MAX - 1))
176     len = PATH_MAX - 1;
177 
178   memcpy(result, p, len);
179   result[len] = '\0';
180 
181   return (result);
182 }
183 #endif
184 
185 #if !defined(HAVE_MKSTEMP) && !defined(WIN32)
186 int
mkstemp(char * path)187 mkstemp(char *path)
188 {
189   char *start, *trv;
190   unsigned int pid;
191 
192   /* To guarantee multiple calls generate unique names even if
193      the file is not created. 676 different possibilities with 7
194      or more X's, 26 with 6 or less. */
195   static char xtra[2] = "aa";
196   int xcnt = 0;
197 
198   pid = getpid();
199 
200   /* Move to end of path and count trailing X's. */
201   for (trv = path; *trv; ++trv)
202     if (*trv == 'X')
203       xcnt++;
204     else
205       xcnt = 0;
206 
207   /* Use at least one from xtra.  Use 2 if more than 6 X's. */
208   if (*(trv - 1) == 'X')
209     *--trv = xtra[0];
210   if (xcnt > 6 && *(trv - 1) == 'X')
211     *--trv = xtra[1];
212 
213   /* Set remaining X's to pid digits with 0's to the left. */
214   while (*--trv == 'X') {
215     *trv = (pid % 10) + '0';
216     pid /= 10;
217   }
218 
219   /* update xtra for next call. */
220   if (xtra[0] != 'z')
221     xtra[0]++;
222   else {
223     xtra[0] = 'a';
224     if (xtra[1] != 'z')
225       xtra[1]++;
226     else
227       xtra[1] = 'a';
228   }
229 
230   return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
231 }
232 #endif
233 
234 #ifdef HAVE_FFS
235 int
ffs(int x)236 ffs(int x)
237 {
238   int r = 1;
239   if (!x) return 0;
240   if (!(x & 0xffff)) { x >>= 16; r += 16; }
241   if (!(x &   0xff)) { x >>= 8;  r += 8;  }
242   if (!(x &    0xf)) { x >>= 4;  r += 4;  }
243   if (!(x &      3)) { x >>= 2;  r += 2;  }
244   if (!(x &      1)) { x >>= 1;  r += 1;  }
245 
246   return r;
247 }
248 #endif
249 
250 /*
251  * Copyright Patrick Powell 1995
252  * This code is based on code written by Patrick Powell (papowell@astart.com)
253  * It may be used for any purpose as long as this notice remains intact
254  * on all source code distributions
255  */
256 
257 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
258 
259 static void
260 dopr(char *buffer, size_t maxlen, const char *format, va_list args);
261 
262 static void
263 fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
264     int min, int max);
265 
266 static void
267 fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
268     int min, int max, int flags);
269 
270 static void
271 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
272     int min, int max, int flags);
273 
274 static void
275 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
276 
277 /*
278  * dopr(): poor man's version of doprintf
279  */
280 
281 /* format read states */
282 #define DP_S_DEFAULT 0
283 #define DP_S_FLAGS   1
284 #define DP_S_MIN     2
285 #define DP_S_DOT     3
286 #define DP_S_MAX     4
287 #define DP_S_MOD     5
288 #define DP_S_CONV    6
289 #define DP_S_DONE    7
290 
291 /* format flags - Bits */
292 #define DP_F_MINUS  (1 << 0)
293 #define DP_F_PLUS   (1 << 1)
294 #define DP_F_SPACE  (1 << 2)
295 #define DP_F_NUM    (1 << 3)
296 #define DP_F_ZERO   (1 << 4)
297 #define DP_F_UP     (1 << 5)
298 #define DP_F_UNSIGNED   (1 << 6)
299 
300 /* Conversion Flags */
301 #define DP_C_SHORT     1
302 #define DP_C_LONG      2
303 #define DP_C_LDOUBLE   3
304 #define DP_C_LONG_LONG 4
305 
306 #define char_to_int(p) (p - '0')
307 #define abs_val(p) (p < 0 ? -p : p)
308 
309 
310 static void
dopr(char * buffer,size_t maxlen,const char * format,va_list args)311 dopr(char *buffer, size_t maxlen, const char *format, va_list args)
312 {
313   char *strvalue, ch;
314   long value;
315   long double fvalue;
316   int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
317   size_t currlen = 0;
318 
319   ch = *format++;
320 
321   while (state != DP_S_DONE) {
322     if ((ch == '\0') || (currlen >= maxlen))
323       state = DP_S_DONE;
324 
325     switch(state) {
326     case DP_S_DEFAULT:
327       if (ch == '%')
328         state = DP_S_FLAGS;
329       else
330         dopr_outch(buffer, &currlen, maxlen, ch);
331       ch = *format++;
332       break;
333     case DP_S_FLAGS:
334       switch (ch) {
335       case '-':
336         flags |= DP_F_MINUS;
337         ch = *format++;
338         break;
339       case '+':
340         flags |= DP_F_PLUS;
341         ch = *format++;
342         break;
343       case ' ':
344         flags |= DP_F_SPACE;
345         ch = *format++;
346         break;
347       case '#':
348         flags |= DP_F_NUM;
349         ch = *format++;
350         break;
351       case '0':
352         flags |= DP_F_ZERO;
353         ch = *format++;
354         break;
355       default:
356         state = DP_S_MIN;
357         break;
358       }
359       break;
360     case DP_S_MIN:
361       if (isdigit((unsigned char)ch)) {
362         min = 10 * min + char_to_int (ch);
363         ch = *format++;
364       } else if (ch == '*') {
365         min = va_arg (args, int);
366         ch = *format++;
367         state = DP_S_DOT;
368       } else
369         state = DP_S_DOT;
370       break;
371     case DP_S_DOT:
372       if (ch == '.') {
373         state = DP_S_MAX;
374         ch = *format++;
375       } else
376         state = DP_S_MOD;
377       break;
378     case DP_S_MAX:
379       if (isdigit((unsigned char)ch)) {
380         if (max < 0)
381           max = 0;
382         max = 10 * max + char_to_int(ch);
383         ch = *format++;
384       } else if (ch == '*') {
385         max = va_arg (args, int);
386         ch = *format++;
387         state = DP_S_MOD;
388       } else
389         state = DP_S_MOD;
390       break;
391     case DP_S_MOD:
392       switch (ch) {
393       case 'h':
394         cflags = DP_C_SHORT;
395         ch = *format++;
396         break;
397       case 'l':
398         cflags = DP_C_LONG;
399         ch = *format++;
400         if (ch == 'l') {
401           cflags = DP_C_LONG_LONG;
402           ch = *format++;
403         }
404         break;
405       case 'q':
406         cflags = DP_C_LONG_LONG;
407         ch = *format++;
408         break;
409       case 'L':
410         cflags = DP_C_LDOUBLE;
411         ch = *format++;
412         break;
413       default:
414         break;
415       }
416       state = DP_S_CONV;
417       break;
418     case DP_S_CONV:
419       switch (ch) {
420       case 'd':
421       case 'i':
422         if (cflags == DP_C_SHORT)
423           value = va_arg(args, int);
424         else if (cflags == DP_C_LONG)
425           value = va_arg(args, long int);
426         else if (cflags == DP_C_LONG_LONG)
427           value = va_arg (args, long long);
428         else
429           value = va_arg (args, int);
430         fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
431         break;
432       case 'o':
433         flags |= DP_F_UNSIGNED;
434         if (cflags == DP_C_SHORT)
435           value = va_arg(args, unsigned int);
436         else if (cflags == DP_C_LONG)
437           value = va_arg(args, unsigned long int);
438         else if (cflags == DP_C_LONG_LONG)
439           value = va_arg(args, unsigned long long);
440         else
441           value = va_arg(args, unsigned int);
442         fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
443         break;
444       case 'u':
445         flags |= DP_F_UNSIGNED;
446         if (cflags == DP_C_SHORT)
447           value = va_arg(args, unsigned int);
448         else if (cflags == DP_C_LONG)
449           value = va_arg(args, unsigned long int);
450         else if (cflags == DP_C_LONG_LONG)
451           value = va_arg(args, unsigned long long);
452         else
453           value = va_arg(args, unsigned int);
454         fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
455         break;
456       case 'X':
457         flags |= DP_F_UP;
458       case 'x':
459         flags |= DP_F_UNSIGNED;
460         if (cflags == DP_C_SHORT)
461           value = va_arg(args, unsigned int);
462         else if (cflags == DP_C_LONG)
463           value = va_arg(args, unsigned long int);
464         else if (cflags == DP_C_LONG_LONG)
465           value = va_arg(args, unsigned long long);
466         else
467           value = va_arg(args, unsigned int);
468         fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
469         break;
470       case 'f':
471         if (cflags == DP_C_LDOUBLE)
472           fvalue = va_arg(args, long double);
473         else
474           fvalue = va_arg(args, double);
475         /* um, floating point? */
476         fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
477         break;
478       case 'E':
479         flags |= DP_F_UP;
480       case 'e':
481         if (cflags == DP_C_LDOUBLE)
482           fvalue = va_arg(args, long double);
483         else
484           fvalue = va_arg(args, double);
485         break;
486       case 'G':
487         flags |= DP_F_UP;
488       case 'g':
489         if (cflags == DP_C_LDOUBLE)
490           fvalue = va_arg(args, long double);
491         else
492           fvalue = va_arg(args, double);
493         break;
494       case 'c':
495         dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
496         break;
497       case 's':
498         strvalue = va_arg(args, char *);
499         if (max < 0)
500           max = maxlen; /* ie, no max */
501         fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
502         break;
503       case 'p':
504         strvalue = va_arg(args, void *);
505         fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
506         break;
507       case 'n':
508         if (cflags == DP_C_SHORT) {
509           short int *num;
510           num = va_arg(args, short int *);
511           *num = currlen;
512         } else if (cflags == DP_C_LONG) {
513           long int *num;
514           num = va_arg(args, long int *);
515           *num = currlen;
516         } else if (cflags == DP_C_LONG_LONG) {
517           long long *num;
518           num = va_arg(args, long long *);
519           *num = currlen;
520         } else {
521           int *num;
522           num = va_arg(args, int *);
523           *num = currlen;
524         }
525         break;
526       case '%':
527         dopr_outch(buffer, &currlen, maxlen, ch);
528         break;
529       case 'w': /* not supported yet, treat as next char */
530         ch = *format++;
531         break;
532       default: /* Unknown, skip */
533       break;
534       }
535       ch = *format++;
536       state = DP_S_DEFAULT;
537       flags = cflags = min = 0;
538       max = -1;
539       break;
540     case DP_S_DONE:
541       break;
542     default: /* hmm? */
543       break; /* some picky compilers need this */
544     }
545   }
546   if (currlen < maxlen - 1)
547     buffer[currlen] = '\0';
548   else
549     buffer[maxlen - 1] = '\0';
550 }
551 
552 static void
fmtstr(char * buffer,size_t * currlen,size_t maxlen,char * value,int flags,int min,int max)553 fmtstr(char *buffer, size_t *currlen, size_t maxlen,
554     char *value, int flags, int min, int max)
555 {
556   int cnt = 0, padlen, strln;     /* amount to pad */
557 
558   if (value == 0)
559     value = "<NULL>";
560 
561   for (strln = 0; value[strln]; ++strln); /* strlen */
562   padlen = min - strln;
563   if (padlen < 0)
564     padlen = 0;
565   if (flags & DP_F_MINUS)
566     padlen = -padlen; /* Left Justify */
567 
568   while ((padlen > 0) && (cnt < max)) {
569     dopr_outch(buffer, currlen, maxlen, ' ');
570     --padlen;
571     ++cnt;
572   }
573   while (*value && (cnt < max)) {
574     dopr_outch(buffer, currlen, maxlen, *value++);
575     ++cnt;
576   }
577   while ((padlen < 0) && (cnt < max)) {
578     dopr_outch(buffer, currlen, maxlen, ' ');
579     ++padlen;
580     ++cnt;
581   }
582 }
583 
584 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
585 
586 static void
fmtint(char * buffer,size_t * currlen,size_t maxlen,long value,int base,int min,int max,int flags)587 fmtint(char *buffer, size_t *currlen, size_t maxlen,
588     long value, int base, int min, int max, int flags)
589 {
590   unsigned long uvalue;
591   char convert[20];
592   int signvalue = 0, place = 0, caps = 0;
593   int spadlen = 0; /* amount to space pad */
594   int zpadlen = 0; /* amount to zero pad */
595 
596 #define PADMAX(x,y) ((x) > (y) ? (x) : (y))
597 
598   if (max < 0)
599     max = 0;
600 
601   uvalue = value;
602 
603   if (!(flags & DP_F_UNSIGNED)) {
604     if (value < 0) {
605       signvalue = '-';
606       uvalue = -value;
607     } else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
608       signvalue = '+';
609     else if (flags & DP_F_SPACE)
610       signvalue = ' ';
611   }
612 
613   if (flags & DP_F_UP)
614     caps = 1; /* Should characters be upper case? */
615   do {
616     convert[place++] =
617         (caps ? "0123456789ABCDEF" : "0123456789abcdef")
618         [uvalue % (unsigned)base];
619     uvalue = (uvalue / (unsigned)base );
620   } while (uvalue && (place < 20));
621   if (place == 20)
622     place--;
623   convert[place] = 0;
624 
625   zpadlen = max - place;
626   spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);
627   if (zpadlen < 0)
628     zpadlen = 0;
629   if (spadlen < 0)
630     spadlen = 0;
631   if (flags & DP_F_ZERO) {
632     zpadlen = PADMAX(zpadlen, spadlen);
633     spadlen = 0;
634   }
635   if (flags & DP_F_MINUS)
636     spadlen = -spadlen; /* Left Justifty */
637 
638   /* Spaces */
639   while (spadlen > 0) {
640     dopr_outch(buffer, currlen, maxlen, ' ');
641     --spadlen;
642   }
643 
644   /* Sign */
645   if (signvalue)
646     dopr_outch(buffer, currlen, maxlen, signvalue);
647 
648   /* Zeros */
649   if (zpadlen > 0) {
650     while (zpadlen > 0) {
651       dopr_outch(buffer, currlen, maxlen, '0');
652       --zpadlen;
653     }
654   }
655 
656   /* Digits */
657   while (place > 0)
658     dopr_outch(buffer, currlen, maxlen, convert[--place]);
659 
660   /* Left Justified spaces */
661   while (spadlen < 0) {
662     dopr_outch (buffer, currlen, maxlen, ' ');
663     ++spadlen;
664   }
665 }
666 
667 static long double
pow10(int exp)668 pow10(int exp)
669 {
670   long double result = 1;
671 
672   while (exp) {
673     result *= 10;
674     exp--;
675   }
676 
677   return result;
678 }
679 
680 static long
round(long double value)681 round(long double value)
682 {
683   long intpart = value;
684 
685   value -= intpart;
686   if (value >= 0.5)
687     intpart++;
688 
689   return intpart;
690 }
691 
692 static void
fmtfp(char * buffer,size_t * currlen,size_t maxlen,long double fvalue,int min,int max,int flags)693 fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
694       int min, int max, int flags)
695 {
696   char iconvert[20], fconvert[20];
697   int signvalue = 0, iplace = 0, fplace = 0;
698   int padlen = 0; /* amount to pad */
699   int zpadlen = 0, caps = 0;
700   long intpart, fracpart;
701   long double ufvalue;
702 
703   /*
704    * AIX manpage says the default is 0, but Solaris says the default
705    * is 6, and sprintf on AIX defaults to 6
706    */
707   if (max < 0)
708     max = 6;
709 
710   ufvalue = abs_val(fvalue);
711 
712   if (fvalue < 0)
713     signvalue = '-';
714   else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
715     signvalue = '+';
716   else if (flags & DP_F_SPACE)
717     signvalue = ' ';
718 
719   intpart = ufvalue;
720 
721   /*
722    * Sorry, we only support 9 digits past the decimal because of our
723    * conversion method
724    */
725   if (max > 9)
726     max = 9;
727 
728   /* We "cheat" by converting the fractional part to integer by
729    * multiplying by a factor of 10
730    */
731   fracpart = round((pow10 (max)) * (ufvalue - intpart));
732 
733   if (fracpart >= pow10 (max)) {
734     intpart++;
735     fracpart -= pow10 (max);
736   }
737 
738   /* Convert integer part */
739   do {
740     iconvert[iplace++] =
741         (caps ? "0123456789ABCDEF" : "0123456789abcdef")
742         [intpart % 10];
743     intpart = (intpart / 10);
744   } while(intpart && (iplace < 20));
745   if (iplace == 20)
746     iplace--;
747   iconvert[iplace] = 0;
748 
749   /* Convert fractional part */
750   do {
751     fconvert[fplace++] =
752         (caps ? "0123456789ABCDEF" : "0123456789abcdef")
753         [fracpart % 10];
754     fracpart = (fracpart / 10);
755   } while(fracpart && (fplace < 20));
756   if (fplace == 20)
757     fplace--;
758   fconvert[fplace] = 0;
759 
760   /* -1 for decimal point, another -1 if we are printing a sign */
761   padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
762   zpadlen = max - fplace;
763   if (zpadlen < 0)
764     zpadlen = 0;
765   if (padlen < 0)
766     padlen = 0;
767   if (flags & DP_F_MINUS)
768     padlen = -padlen; /* Left Justifty */
769 
770   if ((flags & DP_F_ZERO) && (padlen > 0)) {
771     if (signvalue) {
772       dopr_outch(buffer, currlen, maxlen, signvalue);
773       --padlen;
774       signvalue = 0;
775     }
776     while (padlen > 0) {
777       dopr_outch(buffer, currlen, maxlen, '0');
778       --padlen;
779     }
780   }
781   while (padlen > 0) {
782     dopr_outch(buffer, currlen, maxlen, ' ');
783     --padlen;
784   }
785   if (signvalue)
786     dopr_outch(buffer, currlen, maxlen, signvalue);
787 
788   while (iplace > 0)
789     dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
790 
791   /*
792    * Decimal point.  This should probably use locale to find the
793    * correct char to print out.
794    */
795   dopr_outch(buffer, currlen, maxlen, '.');
796 
797   while (fplace > 0)
798     dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
799 
800   while (zpadlen > 0) {
801     dopr_outch(buffer, currlen, maxlen, '0');
802     --zpadlen;
803   }
804 
805   while (padlen < 0) {
806     dopr_outch(buffer, currlen, maxlen, ' ');
807     ++padlen;
808   }
809 }
810 
811 static void
dopr_outch(char * buffer,size_t * currlen,size_t maxlen,char c)812 dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
813 {
814   if (*currlen < maxlen)
815     buffer[(*currlen)++] = c;
816 }
817 #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
818 
819 #ifndef HAVE_VSNPRINTF
820 int
vsnprintf(char * str,size_t count,const char * fmt,va_list args)821 vsnprintf(char *str, size_t count, const char *fmt, va_list args)
822 {
823   str[0] = 0;
824   dopr(str, count, fmt, args);
825 
826   return(strlen(str));
827 }
828 #endif /* !HAVE_VSNPRINTF */
829 
830 #ifndef HAVE_SNPRINTF
831 int
snprintf(char * str,size_t count,const char * fmt,...)832 snprintf(char *str,size_t count,const char *fmt,...)
833 {
834   va_list ap;
835 
836   va_start(ap, fmt);
837   (void) vsnprintf(str, count, fmt, ap);
838   va_end(ap);
839 
840   return(strlen(str));
841 }
842 
843 #endif /* !HAVE_SNPRINTF */
844