1/* 2 * snpf.c -- snprintf() empulation functions for lsof library 3 * 4 * V. Abell 5 * Purdue University Computing Center 6 */ 7 8/* 9 * Copyright 2000 Purdue Research Foundation, West Lafayette, Indiana 10 * 47907. All rights reserved. 11 * 12 * Written by Victor A. Abell 13 * 14 * This software is not subject to any license of the American Telephone 15 * and Telegraph Company or the Regents of the University of California. 16 * 17 * This software has been adapted from snprintf.c in sendmail 8.9.3. It 18 * is subject to the sendmail copyright statements listed below, and the 19 * sendmail licensing terms stated in the sendmail LICENSE file comment 20 * section of this file. 21 * 22 * Permission is granted to anyone to use this software for any purpose on 23 * any computer system, and to alter it and redistribute it freely, subject 24 * to the following restrictions: 25 * 26 * 1. Neither the authors nor Purdue University are responsible for any 27 * consequences of the use of this software. 28 * 29 * 2. The origin of this software must not be misrepresented, either by 30 * explicit claim or by omission. Credit to the authors and Purdue 31 * University must appear in documentation and sources. 32 * 33 * 3. Altered versions must be plainly marked as such, and must not be 34 * misrepresented as being the original software. 35 * 36 * 4. This notice may not be removed or altered. 37 */ 38 39#include "../machine.h" 40 41#ifdef USE_LIB_SNPF 42 43/* 44 * Sendmail copyright statements: 45 * 46 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 47 * Copyright (c) 1997 Eric P. Allman. All rights reserved. 48 * Copyright (c) 1988, 1993 49 * The Regents of the University of California. All rights reserved. 50 * 51 * By using this file, you agree to the terms and conditions set 52 * forth in the LICENSE file which can be found at the top level of 53 * the sendmail distribution. 54 * 55 * The LICENSE file may be found in the following comment section. 56 */ 57 58 59/* 60 * Begin endmail LICENSE file. 61 62 SENDMAIL LICENSE 63 64The following license terms and conditions apply, unless a different 65license is obtained from Sendmail, Inc., 1401 Park Avenue, Emeryville, CA 6694608, or by electronic mail at license@sendmail.com. 67 68License Terms: 69 70Use, Modification and Redistribution (including distribution of any 71modified or derived work) in source and binary forms is permitted only if 72each of the following conditions is met: 73 741. Redistributions qualify as "freeware" or "Open Source Software" under 75 one of the following terms: 76 77 (a) Redistributions are made at no charge beyond the reasonable cost of 78 materials and delivery. 79 80 (b) Redistributions are accompanied by a copy of the Source Code or by an 81 irrevocable offer to provide a copy of the Source Code for up to three 82 years at the cost of materials and delivery. Such redistributions 83 must allow further use, modification, and redistribution of the Source 84 Code under substantially the same terms as this license. For the 85 purposes of redistribution "Source Code" means the complete source 86 code of sendmail including all modifications. 87 88 Other forms of redistribution are allowed only under a separate royalty- 89 free agreement permitting such redistribution subject to standard 90 commercial terms and conditions. A copy of such agreement may be 91 obtained from Sendmail, Inc. at the above address. 92 932. Redistributions of source code must retain the copyright notices as they 94 appear in each source code file, these license terms, and the 95 disclaimer/limitation of liability set forth as paragraph 6 below. 96 973. Redistributions in binary form must reproduce the Copyright Notice, 98 these license terms, and the disclaimer/limitation of liability set 99 forth as paragraph 6 below, in the documentation and/or other materials 100 provided with the distribution. For the purposes of binary distribution 101 the "Copyright Notice" refers to the following language: 102 "Copyright (c) 1998 Sendmail, Inc. All rights reserved." 103 1044. Neither the name of Sendmail, Inc. nor the University of California nor 105 the names of their contributors may be used to endorse or promote 106 products derived from this software without specific prior written 107 permission. The name "sendmail" is a trademark of Sendmail, Inc. 108 1095. All redistributions must comply with the conditions imposed by the 110 University of California on certain embedded code, whose copyright 111 notice and conditions for redistribution are as follows: 112 113 (a) Copyright (c) 1988, 1993 The Regents of the University of 114 California. All rights reserved. 115 116 (b) Redistribution and use in source and binary forms, with or without 117 modification, are permitted provided that the following conditions 118 are met: 119 120 (i) Redistributions of source code must retain the above copyright 121 notice, this list of conditions and the following disclaimer. 122 123 (ii) Redistributions in binary form must reproduce the above 124 copyright notice, this list of conditions and the following 125 disclaimer in the documentation and/or other materials provided 126 with the distribution. 127 128 (iii) All advertising materials mentioning features or use of this 129 software must display the following acknowledgement: "This 130 product includes software developed by the University of 131 California, Berkeley and its contributors." 132 133 (iv) Neither the name of the University nor the names of its 134 contributors may be used to endorse or promote products derived 135 from this software without specific prior written permission. 136 1376. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY 138 SENDMAIL, INC. AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 139 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 140 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 141 NO EVENT SHALL SENDMAIL, INC., THE REGENTS OF THE UNIVERSITY OF 142 CALIFORNIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 143 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 144 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 145 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 146 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 147 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 148 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 149 150(Version 8.6, last updated 6/24/1998) 151 152 * End endmail LICENSE file. 153 */ 154 155 156/* 157 * If "ll" format support is not possible -- e.g., the long long type isn't 158 * supported -- define HAS_NO_LONG_LONG. 159 */ 160 161# ifndef lint 162static char copyright[] = 163"@(#) Copyright 2000 Purdue Research Foundation.\nAll rights reserved.\n"; 164# endif /* !defined(lint) */ 165 166#include <varargs.h> 167 168#if defined(__STDC__) 169#define _PROTOTYPE(function, params) function params 170#else /* !defined(__STDC__) */ 171#define _PROTOTYPE(function, params) function() 172#endif /* defined(__STDC__) */ 173 174 175/* 176** SNPRINTF, VSNPRINT -- counted versions of printf 177** 178** These versions have been grabbed off the net. They have been 179** cleaned up to compile properly and support for .precision and 180** %lx has been added. 181*/ 182 183/************************************************************** 184 * Original: 185 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 186 * A bombproof version of doprnt (dopr) included. 187 * Sigh. This sort of thing is always nasty do deal with. Note that 188 * the version here does not include floating point... 189 * 190 * snprintf() is used instead of sprintf() as it does limit checks 191 * for string length. This covers a nasty loophole. 192 * 193 * The other functions are there to prevent NULL pointers from 194 * causing nast effects. 195 **************************************************************/ 196 197/*static char _id[] = "$Id: snpf.c,v 1.5 2008/10/21 16:13:23 abe Exp $";*/ 198 199 200/* 201 * Local function prototypes 202 */ 203 204_PROTOTYPE(static void dopr,(char *bp, char *ep, char *fmt, va_list args)); 205_PROTOTYPE(static void dopr_outch,(char **bp, char *ep, int c)); 206_PROTOTYPE(static void dostr,(char **bp, char *ep, char *str, int)); 207 208# if !defined(HAS_NO_LONG_LONG) 209_PROTOTYPE(static void fmtllnum,(char **bp, char *ep, long long value, 210 int base, int dosign, int ljust, int len, 211 int zpad)); 212# endif /* !defined(HAS_NO_LONG_LONG) */ 213 214_PROTOTYPE(static void fmtnum,(char **bp, char *ep, long value, int base, 215 int dosign, int ljust, int len, int zpad)); 216_PROTOTYPE(static void fmtstr,(char **bp, char *ep, char *value, int ljust, 217 int len, int zpad, 218 int maxwidth)); 219 220 221/* 222 * Local variables 223 */ 224 225static int Length; 226 227 228/* 229 * snpf() -- count-controlled sprintf() 230 */ 231 232int 233snpf(va_alist) 234 va_dcl /* requires at least three arguments: 235 * bp = receiving buffer pointer 236 * ct = length of buffer 237 * fmt = format string 238 */ 239{ 240 va_list args; 241 char *bp, *fmt; 242 int ct, len; 243 244 va_start(args); 245 bp = va_arg(args, char *); 246 ct = va_arg(args, int); 247 fmt = va_arg(args, char *); 248 len = vsnpf(bp, ct, fmt, args); 249 va_end(args); 250 return(len); 251} 252 253 254/* 255 * vsnpf() -- count-controlled vsprintf() 256 */ 257 258int 259vsnpf(str, count, fmt, args) 260 char *str; /* result buffer */ 261 int count; /* size of buffer */ 262 char *fmt; /* format */ 263 va_list args; /* variable length argument list */ 264{ 265 char *ep = str + count - 1; 266 267 *str = '\0'; 268 (void) dopr(str, ep, fmt, args); 269 if (count > 0) 270 *ep = '\0'; 271 return(Length); 272} 273 274 275/* 276 * dopr() -- poor man's version of doprintf 277 */ 278 279 280static void 281dopr(bp, ep, fmt, args) 282 char *bp; /* buffer start */ 283 char *ep; /* buffer end (start + length - 1) */ 284 char *fmt; /* format */ 285 va_list args; /* variable length argument list */ 286{ 287 int ch; 288 char ebuf[64]; 289 int ebufl = (int)(sizeof(ebuf) - 1); 290 long value; 291 int longflag = 0; 292 int longlongflag = 0; 293 int pointflag = 0; 294 int maxwidth = 0; 295 char *strvalue; 296 int ljust; 297 int len; 298 int zpad; 299 int zxflag = 0; 300 301# if !defined(HAS_NO_LONG_LONG) 302 long long llvalue; 303# endif /* !defined(HAS_NO_LONG_LONG) */ 304 305 Length = 0; 306 while((ch = *fmt++)) { 307 switch (ch) { 308 case '%': 309 ljust = len = zpad = zxflag = maxwidth = 0; 310 longflag = longlongflag = pointflag = 0; 311 312nextch: 313 314 ch = *fmt++; 315 switch (ch) { 316 case '\0': 317 dostr(&bp, ep, "**end of format**" , 0); 318 return; 319 case '-': 320 ljust = 1; 321 goto nextch; 322 case '0': /* set zero padding if len not set */ 323 if ((len == 0) && !pointflag) 324 zpad = '0'; 325 case '1': 326 case '2': 327 case '3': 328 case '4': 329 case '5': 330 case '6': 331 case '7': 332 case '8': 333 case '9': 334 if (pointflag) 335 maxwidth = (maxwidth * 10) + (int)(ch - '0'); 336 else 337 len = (len * 10) + (int)(ch - '0'); 338 goto nextch; 339 case '*': 340 if (pointflag) 341 maxwidth = va_arg(args, int); 342 else 343 len = va_arg(args, int); 344 goto nextch; 345 case '#': 346 zxflag = 1; 347 goto nextch; 348 case '.': 349 pointflag = 1; 350 goto nextch; 351 case 'l': 352 if (longflag) { 353 longflag = 0; 354 longlongflag = 1; 355 goto nextch; 356 } 357 longflag = 1; 358 goto nextch; 359 case 'u': 360 case 'U': 361 if (longlongflag) { 362 363# if !defined(HAS_NO_LONG_LONG) 364 llvalue = va_arg(args, long long); 365 (void) fmtllnum(&bp,ep,llvalue,10,0,ljust,len,zpad); 366# else /* defined(HAS_NO_LONG_LONG) */ 367 (void) strncpy(ebuf, "ll is unsupported", ebufl); 368 ebuf[(int)ebufl] = '\0'; 369 (void) dostr(&bp, ep, ebuf, 0); 370# endif /* !defined(HAS_NO_LONG_LONG) */ 371 372 break; 373 } 374 if (longflag) 375 value = va_arg(args, long); 376 else 377 value = va_arg(args, int); 378 (void) fmtnum(&bp, ep, value, 10,0, ljust, len, zpad); 379 break; 380 case 'o': 381 case 'O': 382 if (longlongflag) { 383 384# if !defined(HAS_NO_LONG_LONG) 385 llvalue = va_arg(args, long long); 386 (void) fmtllnum(&bp,ep,llvalue,8,0,ljust,len,zpad); 387# else /* defined(HAS_NO_LONG_LONG) */ 388 (void) strncpy(ebuf, "ll is unsupported", ebufl); 389 ebuf[(int)ebufl] = '\0'; 390 (void) dostr(&bp, ep, ebuf, 0); 391# endif /* !defined(HAS_NO_LONG_LONG) */ 392 393 break; 394 } 395 if (longflag) 396 value = va_arg(args, long); 397 else 398 value = va_arg(args, int); 399 (void) fmtnum(&bp, ep, value, 8,0, ljust, len, zpad); 400 break; 401 case 'd': 402 case 'D': 403 if (longlongflag) { 404 405# if !defined(HAS_NO_LONG_LONG) 406 llvalue = va_arg(args, long long); 407 (void) fmtllnum(&bp,ep,llvalue,10,1,ljust,len,zpad); 408# else /* defined(HAS_NO_LONG_LONG) */ 409 (void) strncpy(ebuf, "ll is unsupported", ebufl); 410 ebuf[(int)ebufl] = '\0'; 411 (void) dostr(&bp, ep, ebuf, 0); 412# endif /* !defined(HAS_NO_LONG_LONG) */ 413 414 break; 415 } 416 if (longflag) 417 value = va_arg(args, long); 418 else 419 value = va_arg(args, int); 420 (void) fmtnum(&bp, ep, value, 10,1, ljust, len, zpad); 421 break; 422 case 'x': 423 if (longlongflag) { 424 425# if !defined(HAS_NO_LONG_LONG) 426 llvalue = va_arg(args, long long); 427 if (zxflag && llvalue) { 428 (void) dostr(&bp, ep, "0x", 0); 429 if (len >= 2) 430 len -= 2; 431 } 432 (void) fmtllnum(&bp,ep,llvalue,16,0,ljust,len,zpad); 433# else /* defined(HAS_NO_LONG_LONG) */ 434 (void) strncpy(ebuf, "ll is unsupported", ebufl); 435 ebuf[(int)ebufl] = '\0'; 436 (void) dostr(&bp, ep, ebuf, 0); 437# endif /* !defined(HAS_NO_LONG_LONG) */ 438 439 break; 440 } 441 if (longflag) 442 value = va_arg(args, long); 443 else 444 value = va_arg(args, int); 445 if (zxflag && value) { 446 (void) dostr(&bp, ep, "0x", 0); 447 if (len >= 2) 448 len -= 2; 449 } 450 (void) fmtnum(&bp, ep, value, 16,0, ljust, len, zpad); 451 break; 452 case 'X': 453 if (longlongflag) { 454 455# if !defined(HAS_NO_LONG_LONG) 456 llvalue = va_arg(args, long long); 457 if (zxflag && llvalue) { 458 (void) dostr(&bp, ep, "0x", 0); 459 if (len >= 2) 460 len -= 2; 461 } 462 (void) fmtllnum(&bp,ep,llvalue,-16,0,ljust,len,zpad); 463# else /* defined(HAS_NO_LONG_LONG) */ 464 (void) strncpy(ebuf, "ll is unsupported", ebufl); 465 ebuf[(int)ebufl] = '\0'; 466 (void) dostr(&bp, ep, ebuf, 0); 467# endif /* !defined(HAS_NO_LONG_LONG) */ 468 469 break; 470 } 471 if (longflag) 472 value = va_arg(args, long); 473 else 474 value = va_arg(args, int); 475 if (zxflag && value) { 476 (void) dostr(&bp, ep, "0x", 0); 477 if (len >= 2) 478 len -= 2; 479 } 480 (void) fmtnum(&bp, ep, value,-16,0, ljust, len, zpad); 481 break; 482 case 's': 483 strvalue = va_arg(args, char *); 484 if (maxwidth > 0 || !pointflag) { 485 if (pointflag && len > maxwidth) 486 len = maxwidth; /* Adjust padding */ 487 (void) fmtstr(&bp, ep, strvalue, ljust, len, zpad, 488 maxwidth); 489 } 490 break; 491 case 'c': 492 ch = va_arg(args, int); 493 dopr_outch(&bp, ep, ch); 494 break; 495 case '%': 496 (void) dopr_outch(&bp, ep, ch); 497 continue; 498 default: 499 ebuf[0] = ch; 500 (void) strncpy(&ebuf[1], " is unsupported", ebufl); 501 ebuf[(int)ebufl] = '\0'; 502 (void) dostr(&bp, ep, ebuf, 0); 503 } 504 break; 505 default: 506 (void) dopr_outch(&bp, ep, ch); 507 break; 508 } 509 } 510 *bp = '\0'; 511} 512 513 514# if !defined(HAS_NO_LONG_LONG) 515/* 516 * fmtllnum() -- format long long number for output 517 */ 518 519static void 520fmtllnum(bp, ep, value, base, dosign, ljust, len, zpad) 521 char **bp; /* current buffer pointer */ 522 char *ep; /* end of buffer (-1) */ 523 long long value; /* number to format */ 524 int base; /* number base */ 525 int dosign; /* sign request */ 526 int ljust; /* left justfication request */ 527 int len; /* length request */ 528 int zpad; /* zero padding request */ 529{ 530 int signvalue = 0; 531 unsigned long long uvalue; 532 char convert[20]; 533 int place = 0; 534 int padlen = 0; /* amount to pad */ 535 int caps = 0; 536 537 uvalue = value; 538 if (dosign) { 539 if (value < 0) { 540 signvalue = '-'; 541 uvalue = -value; 542 } 543 } 544 if (base < 0) { 545 caps = 1; 546 base = -base; 547 } 548 do { 549 convert[place++] = 550 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 551 [uvalue % (unsigned)base]; 552 uvalue = (uvalue / (unsigned)base); 553 } while (uvalue && (place < (int)(sizeof(convert) - 1))); 554 convert[place] = 0; 555 padlen = len - place; 556 if (padlen < 0) 557 padlen = 0; 558 if(ljust) 559 padlen = -padlen; 560 if (zpad && padlen > 0) { 561 if (signvalue) { 562 (void) dopr_outch(bp, ep, signvalue); 563 --padlen; 564 signvalue = 0; 565 } 566 while (padlen > 0) { 567 (void) dopr_outch(bp, ep, zpad); 568 --padlen; 569 } 570 } 571 while (padlen > 0) { 572 (void) dopr_outch(bp, ep, ' '); 573 --padlen; 574 } 575 if (signvalue) 576 (void) dopr_outch(bp, ep, signvalue); 577 while (place > 0) 578 (void) dopr_outch(bp, ep, convert[--place]); 579 while (padlen < 0) { 580 (void) dopr_outch(bp, ep, ' '); 581 ++padlen; 582 } 583} 584# endif /* !defined(HAS_NO_LONG_LONG) */ 585 586 587/* 588 * fmtnum() -- format number for output 589 */ 590 591static void 592fmtnum(bp, ep, value, base, dosign, ljust, len, zpad) 593 char **bp; /* current buffer pointer */ 594 char *ep; /* end of buffer (-1) */ 595 long value; /* number to format */ 596 int base; /* number base */ 597 int dosign; /* sign request */ 598 int ljust; /* left justfication request */ 599 int len; /* length request */ 600 int zpad; /* zero padding request */ 601{ 602 int signvalue = 0; 603 unsigned long uvalue; 604 char convert[20]; 605 int place = 0; 606 int padlen = 0; /* amount to pad */ 607 int caps = 0; 608 609 uvalue = value; 610 if (dosign) { 611 if (value < 0) { 612 signvalue = '-'; 613 uvalue = -value; 614 } 615 } 616 if (base < 0) { 617 caps = 1; 618 base = -base; 619 } 620 do { 621 convert[place++] = 622 (caps ? "0123456789ABCDEF" : "0123456789abcdef") 623 [uvalue % (unsigned)base]; 624 uvalue = (uvalue / (unsigned)base); 625 } while (uvalue && (place < (int)(sizeof(convert) - 1))); 626 convert[place] = 0; 627 padlen = len - place; 628 if (padlen < 0) 629 padlen = 0; 630 if(ljust) 631 padlen = -padlen; 632 if (zpad && padlen > 0) { 633 if (signvalue) { 634 (void) dopr_outch(bp, ep, signvalue); 635 --padlen; 636 signvalue = 0; 637 } 638 while (padlen > 0) { 639 (void) dopr_outch(bp, ep, zpad); 640 --padlen; 641 } 642 } 643 while (padlen > 0) { 644 (void) dopr_outch(bp, ep, ' '); 645 --padlen; 646 } 647 if (signvalue) 648 (void) dopr_outch(bp, ep, signvalue); 649 while (place > 0) 650 (void) dopr_outch(bp, ep, convert[--place]); 651 while (padlen < 0) { 652 (void) dopr_outch(bp, ep, ' '); 653 ++padlen; 654 } 655} 656 657 658/* 659 * fmtstr() -- format string for output 660 */ 661 662static void 663fmtstr(bp, ep, value, ljust, len, zpad, maxwidth) 664 char **bp; /* current buffer pointer */ 665 char *ep; /* end of buffer (-1) */ 666 char *value; /* string to format */ 667 int ljust; /* left justification request */ 668 int len; /* length request */ 669 int zpad; /* zero padding request */ 670 int maxwidth; /* maximum width request */ 671{ 672 int padlen, strlen; /* amount to pad */ 673 674 if (value == 0) 675 value = "<NULL>"; 676 for (strlen = 0; value[strlen]; ++ strlen) /* strlen() */ 677 ; 678 if ((strlen > maxwidth) && maxwidth) 679 strlen = maxwidth; 680 padlen = len - strlen; 681 if (padlen < 0) 682 padlen = 0; 683 if (ljust) 684 padlen = -padlen; 685 while (padlen > 0) { 686 (void) dopr_outch(bp, ep, ' '); 687 --padlen; 688 } 689 (void) dostr(bp, ep, value, maxwidth); 690 while (padlen < 0) { 691 (void) dopr_outch(bp, ep, ' '); 692 ++padlen; 693 } 694} 695 696 697/* 698 * dostr() -- do string output 699 */ 700 701static void 702dostr(bp, ep, str, cut) 703 char **bp; /* current buffer pointer */ 704 char *ep; /* end of buffer (-1) */ 705 char *str; /* string to output */ 706 int cut; /* limit on amount of string to output: 707 * 0 == no limit */ 708{ 709 int f; 710 711 f = cut ? 1 : 0; 712 while (*str) { 713 if (f) { 714 if (cut-- > 0) 715 (void) dopr_outch(bp, ep, *str); 716 } else 717 (void) dopr_outch(bp, ep, *str); 718 str++; 719 } 720} 721 722 723/* 724 * dopr_outch() -- output a character (or two) 725 */ 726 727static void 728dopr_outch(bp, ep, c) 729 char **bp; /* current buffer pointer */ 730 char *ep; /* end of buffer (-1) */ 731 int c; /* character to output */ 732{ 733 register char *cp = *bp; 734 735 if (iscntrl(c) && c != '\n' && c != '\t') { 736 c = '@' + (c & 0x1F); 737 if (cp < ep) 738 *cp++ = '^'; 739 Length++; 740 } 741 if (cp < ep) 742 *cp++ = c; 743 *bp = cp; 744 Length++; 745} 746 747#else /* !defined(USE_LIB_SNPF) */ 748char snpf_d1[] = "d"; char *snpf_d2 = snpf_d1; 749#endif /* defined(USE_LIB_SNPF) */ 750