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