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