1/* $NetBSD$ */ 2 3/* OpenLDAP: pkg/ldap/libraries/liblutil/utils.c,v 1.33.2.29 2010/06/10 17:23:20 quanah Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2010 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18#include "portable.h" 19 20#include <stdio.h> 21#include <ac/stdlib.h> 22#include <ac/stdarg.h> 23#include <ac/string.h> 24#include <ac/ctype.h> 25#include <ac/unistd.h> 26#include <ac/time.h> 27#include <ac/errno.h> 28#ifdef HAVE_IO_H 29#include <io.h> 30#endif 31#ifdef HAVE_FCNTL_H 32#include <fcntl.h> 33#endif 34#ifdef _WIN32 35#include <windows.h> 36#endif 37 38#include "lutil.h" 39#include "ldap_defaults.h" 40#include "ldap_pvt.h" 41#include "lber_pvt.h" 42 43#ifdef HAVE_EBCDIC 44int _trans_argv = 1; 45#endif 46 47#ifdef _WIN32 48/* Some Windows versions accept both forward and backslashes in 49 * directory paths, but we always use backslashes when generating 50 * and parsing... 51 */ 52void lutil_slashpath( char *path ) 53{ 54 char *c, *p; 55 56 p = path; 57 while (( c=strchr( p, '/' ))) { 58 *c++ = '\\'; 59 p = c; 60 } 61} 62#endif 63 64char* lutil_progname( const char* name, int argc, char *argv[] ) 65{ 66 char *progname; 67 68 if(argc == 0) { 69 return (char *)name; 70 } 71 72#ifdef HAVE_EBCDIC 73 if (_trans_argv) { 74 int i; 75 for (i=0; i<argc; i++) __etoa(argv[i]); 76 _trans_argv = 0; 77 } 78#endif 79 LUTIL_SLASHPATH( argv[0] ); 80 progname = strrchr ( argv[0], *LDAP_DIRSEP ); 81 progname = progname ? &progname[1] : argv[0]; 82#ifdef _WIN32 83 { 84 size_t len = strlen( progname ); 85 if ( len > 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 ) 86 progname[len - 4] = '\0'; 87 } 88#endif 89 return progname; 90} 91 92#if 0 93size_t lutil_gentime( char *s, size_t smax, const struct tm *tm ) 94{ 95 size_t ret; 96#ifdef HAVE_EBCDIC 97/* We've been compiling in ASCII so far, but we want EBCDIC now since 98 * strftime only understands EBCDIC input. 99 */ 100#pragma convlit(suspend) 101#endif 102 ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm ); 103#ifdef HAVE_EBCDIC 104#pragma convlit(resume) 105 __etoa( s ); 106#endif 107 return ret; 108} 109#endif 110 111size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta ) 112{ 113 size_t ret; 114 char *p; 115 116 if ( smax < 16 ) { /* YYYYmmddHHMMSSZ */ 117 return 0; 118 } 119 120#ifdef HAVE_EBCDIC 121/* We've been compiling in ASCII so far, but we want EBCDIC now since 122 * strftime only understands EBCDIC input. 123 */ 124#pragma convlit(suspend) 125#endif 126 ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm ); 127#ifdef HAVE_EBCDIC 128#pragma convlit(resume) 129 __etoa( s ); 130#endif 131 if ( delta == 0 || ret == 0 ) { 132 return ret; 133 } 134 135 if ( smax < 20 ) { /* YYYYmmddHHMMSS+HHMM */ 136 return 0; 137 } 138 139 p = s + 14; 140 141 if ( delta < 0 ) { 142 p[ 0 ] = '-'; 143 delta = -delta; 144 } else { 145 p[ 0 ] = '+'; 146 } 147 p++; 148 149 snprintf( p, smax - 15, "%02ld%02ld", delta / 3600, 150 ( delta % 3600 ) / 60 ); 151 152 return ret + 4; 153} 154 155int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt ) 156{ 157 static int moffset[12] = { 158 0, 31, 59, 90, 120, 159 151, 181, 212, 243, 160 273, 304, 334 }; 161 int sec; 162 163 tt->tt_usec = tm->tm_usec; 164 165 /* special case 0000/01/01+00:00:00 is returned as zero */ 166 if ( tm->tm_year == -1900 && tm->tm_mon == 0 && tm->tm_mday == 1 && 167 tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0 ) { 168 tt->tt_sec = 0; 169 tt->tt_gsec = 0; 170 return 0; 171 } 172 173 /* tm->tm_year is years since 1900 */ 174 /* calculate days from years since 1970 (epoch) */ 175 tt->tt_sec = tm->tm_year - 70; 176 tt->tt_sec *= 365L; 177 178 /* count leap days in preceding years */ 179 tt->tt_sec += ((tm->tm_year -69) >> 2); 180 181 /* calculate days from months */ 182 tt->tt_sec += moffset[tm->tm_mon]; 183 184 /* add in this year's leap day, if any */ 185 if (((tm->tm_year & 3) == 0) && (tm->tm_mon > 1)) { 186 tt->tt_sec ++; 187 } 188 189 /* add in days in this month */ 190 tt->tt_sec += (tm->tm_mday - 1); 191 192 /* this function can handle a range of about 17408 years... */ 193 /* 86400 seconds in a day, divided by 128 = 675 */ 194 tt->tt_sec *= 675; 195 196 /* move high 7 bits into tt_gsec */ 197 tt->tt_gsec = tt->tt_sec >> 25; 198 tt->tt_sec -= tt->tt_gsec << 25; 199 200 /* get hours */ 201 sec = tm->tm_hour; 202 203 /* convert to minutes */ 204 sec *= 60L; 205 sec += tm->tm_min; 206 207 /* convert to seconds */ 208 sec *= 60L; 209 sec += tm->tm_sec; 210 211 /* add remaining seconds */ 212 tt->tt_sec <<= 7; 213 tt->tt_sec += sec; 214 215 /* return success */ 216 return 0; 217} 218 219int lutil_parsetime( char *atm, struct lutil_tm *tm ) 220{ 221 while (atm && tm) { 222 char *ptr = atm; 223 unsigned i, fracs; 224 225 /* Is the stamp reasonably long? */ 226 for (i=0; isdigit((unsigned char) atm[i]); i++); 227 if (i < sizeof("00000101000000")-1) 228 break; 229 230 /* 231 * parse the time into a struct tm 232 */ 233 /* 4 digit year to year - 1900 */ 234 tm->tm_year = *ptr++ - '0'; 235 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; 236 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; 237 tm->tm_year *= 10; tm->tm_year += *ptr++ - '0'; 238 tm->tm_year -= 1900; 239 /* month 01-12 to 0-11 */ 240 tm->tm_mon = *ptr++ - '0'; 241 tm->tm_mon *=10; tm->tm_mon += *ptr++ - '0'; 242 if (tm->tm_mon < 1 || tm->tm_mon > 12) break; 243 tm->tm_mon--; 244 245 /* day of month 01-31 */ 246 tm->tm_mday = *ptr++ - '0'; 247 tm->tm_mday *=10; tm->tm_mday += *ptr++ - '0'; 248 if (tm->tm_mday < 1 || tm->tm_mday > 31) break; 249 250 /* Hour 00-23 */ 251 tm->tm_hour = *ptr++ - '0'; 252 tm->tm_hour *=10; tm->tm_hour += *ptr++ - '0'; 253 if (tm->tm_hour < 0 || tm->tm_hour > 23) break; 254 255 /* Minute 00-59 */ 256 tm->tm_min = *ptr++ - '0'; 257 tm->tm_min *=10; tm->tm_min += *ptr++ - '0'; 258 if (tm->tm_min < 0 || tm->tm_min > 59) break; 259 260 /* Second 00-61 */ 261 tm->tm_sec = *ptr++ - '0'; 262 tm->tm_sec *=10; tm->tm_sec += *ptr++ - '0'; 263 if (tm->tm_sec < 0 || tm->tm_sec > 61) break; 264 265 /* Fractions of seconds */ 266 if ( *ptr == '.' ) { 267 ptr++; 268 for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) { 269 i*=10; i+= *ptr++ - '0'; 270 fracs++; 271 } 272 tm->tm_usec = i; 273 if (i) { 274 for (i = fracs; i<6; i++) 275 tm->tm_usec *= 10; 276 } 277 } 278 279 /* Must be UTC */ 280 if (*ptr != 'Z') break; 281 282 return 0; 283 } 284 return -1; 285} 286 287/* strcopy is like strcpy except it returns a pointer to the trailing NUL of 288 * the result string. This allows fast construction of catenated strings 289 * without the overhead of strlen/strcat. 290 */ 291char * 292lutil_strcopy( 293 char *a, 294 const char *b 295) 296{ 297 if (!a || !b) 298 return a; 299 300 while ((*a++ = *b++)) ; 301 return a-1; 302} 303 304/* strncopy is like strcpy except it returns a pointer to the trailing NUL of 305 * the result string. This allows fast construction of catenated strings 306 * without the overhead of strlen/strcat. 307 */ 308char * 309lutil_strncopy( 310 char *a, 311 const char *b, 312 size_t n 313) 314{ 315 if (!a || !b || n == 0) 316 return a; 317 318 while ((*a++ = *b++) && n-- > 0) ; 319 return a-1; 320} 321 322/* memcopy is like memcpy except it returns a pointer to the byte past 323 * the end of the result buffer, set to NULL. This allows fast construction 324 * of catenated buffers. Provided for API consistency with lutil_str*copy(). 325 */ 326char * 327lutil_memcopy( 328 char *a, 329 const char *b, 330 size_t n 331) 332{ 333 AC_MEMCPY(a, b, n); 334 return a + n; 335} 336 337#ifndef HAVE_MKSTEMP 338int mkstemp( char * template ) 339{ 340#ifdef HAVE_MKTEMP 341 return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 ); 342#else 343 return -1; 344#endif 345} 346#endif 347 348#ifdef _MSC_VER 349/* Equivalent of MS CRT's _dosmaperr(). 350 * @param lastError[in] Result of GetLastError(). 351 */ 352static errno_t win2errno(DWORD lastError) 353{ 354 const struct { 355 DWORD windows_code; 356 errno_t errno_code; 357 } WIN2ERRNO_TABLE[] = { 358 { ERROR_SUCCESS, 0 }, 359 { ERROR_FILE_NOT_FOUND, ENOENT }, 360 { ERROR_PATH_NOT_FOUND, ENOENT }, 361 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, 362 { ERROR_ACCESS_DENIED, EACCES }, 363 { ERROR_INVALID_HANDLE, EBADF }, 364 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, 365 { ERROR_LOCK_VIOLATION, EACCES }, 366 { ERROR_FILE_EXISTS, EEXIST }, 367 { ERROR_INVALID_PARAMETER, EINVAL }, 368 { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG }, 369 }; 370 const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) / 371sizeof(WIN2ERRNO_TABLE[0]); 372 const errno_t DEFAULT_ERRNO_ERROR = -1; 373 unsigned int i; 374 375 for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) { 376 if (WIN2ERRNO_TABLE[i].windows_code == lastError) { 377 return WIN2ERRNO_TABLE[i].errno_code; 378 } 379 } 380 return DEFAULT_ERRNO_ERROR; 381} 382 383struct dirent { 384 char *d_name; 385}; 386typedef struct DIR { 387 HANDLE dir; 388 struct dirent data; 389 int first; 390 char buf[MAX_PATH+1]; 391} DIR; 392DIR *opendir( char *path ) 393{ 394 char tmp[32768]; 395 int len = strlen(path); 396 DIR *d; 397 HANDLE h; 398 WIN32_FIND_DATA data; 399 400 if (len+3 >= sizeof(tmp)) { 401 errno = ENAMETOOLONG; 402 return NULL; 403 } 404 405 strcpy(tmp, path); 406 tmp[len++] = '\\'; 407 tmp[len++] = '*'; 408 tmp[len] = '\0'; 409 410 h = FindFirstFile( tmp, &data ); 411 412 if ( h == INVALID_HANDLE_VALUE ) { 413 errno = win2errno( GetLastError()); 414 return NULL; 415 } 416 417 d = ber_memalloc( sizeof(DIR) ); 418 if ( !d ) 419 return NULL; 420 d->dir = h; 421 d->data.d_name = d->buf; 422 d->first = 1; 423 strcpy(d->data.d_name, data.cFileName); 424 return d; 425} 426struct dirent *readdir(DIR *dir) 427{ 428 WIN32_FIND_DATA data; 429 430 if (dir->first) { 431 dir->first = 0; 432 } else { 433 if (!FindNextFile(dir->dir, &data)) 434 return NULL; 435 strcpy(dir->data.d_name, data.cFileName); 436 } 437 return &dir->data; 438} 439int closedir(DIR *dir) 440{ 441 FindClose(dir->dir); 442 ber_memfree(dir); 443} 444#endif 445 446/* 447 * Memory Reverse Search 448 */ 449void * 450(lutil_memrchr)(const void *b, int c, size_t n) 451{ 452 if (n != 0) { 453 const unsigned char *s, *bb = b, cc = c; 454 455 for ( s = bb + n; s > bb; ) { 456 if ( *--s == cc ) { 457 return (void *) s; 458 } 459 } 460 } 461 462 return NULL; 463} 464 465int 466lutil_atoix( int *v, const char *s, int x ) 467{ 468 char *next; 469 long i; 470 471 assert( s != NULL ); 472 assert( v != NULL ); 473 474 i = strtol( s, &next, x ); 475 if ( next == s || next[ 0 ] != '\0' ) { 476 return -1; 477 } 478 479 if ( (long)(int)i != i ) { 480 return 1; 481 } 482 483 *v = (int)i; 484 485 return 0; 486} 487 488int 489lutil_atoux( unsigned *v, const char *s, int x ) 490{ 491 char *next; 492 unsigned long u; 493 494 assert( s != NULL ); 495 assert( v != NULL ); 496 497 /* strtoul() has an odd interface */ 498 if ( s[ 0 ] == '-' ) { 499 return -1; 500 } 501 502 u = strtoul( s, &next, x ); 503 if ( next == s || next[ 0 ] != '\0' ) { 504 return -1; 505 } 506 507 if ( (unsigned long)(unsigned)u != u ) { 508 return 1; 509 } 510 511 *v = u; 512 513 return 0; 514} 515 516int 517lutil_atolx( long *v, const char *s, int x ) 518{ 519 char *next; 520 long l; 521 522 assert( s != NULL ); 523 assert( v != NULL ); 524 525 l = strtol( s, &next, x ); 526 if ( next == s || next[ 0 ] != '\0' ) { 527 return -1; 528 } 529 530 *v = l; 531 532 return 0; 533} 534 535int 536lutil_atoulx( unsigned long *v, const char *s, int x ) 537{ 538 char *next; 539 unsigned long ul; 540 541 assert( s != NULL ); 542 assert( v != NULL ); 543 544 /* strtoul() has an odd interface */ 545 if ( s[ 0 ] == '-' ) { 546 return -1; 547 } 548 549 ul = strtoul( s, &next, x ); 550 if ( next == s || next[ 0 ] != '\0' ) { 551 return -1; 552 } 553 554 *v = ul; 555 556 return 0; 557} 558 559/* Multiply an integer by 100000000 and add new */ 560typedef struct lutil_int_decnum { 561 unsigned char *buf; 562 int bufsiz; 563 int beg; 564 int len; 565} lutil_int_decnum; 566 567#define FACTOR1 (100000000&0xffff) 568#define FACTOR2 (100000000>>16) 569 570static void 571scale( int new, lutil_int_decnum *prev, unsigned char *tmp ) 572{ 573 int i, j; 574 unsigned char *in = prev->buf+prev->beg; 575 unsigned int part; 576 unsigned char *out = tmp + prev->bufsiz - prev->len; 577 578 memset( tmp, 0, prev->bufsiz ); 579 if ( prev->len ) { 580 for ( i = prev->len-1; i>=0; i-- ) { 581 part = in[i] * FACTOR1; 582 for ( j = i; part; j-- ) { 583 part += out[j]; 584 out[j] = part & 0xff; 585 part >>= 8; 586 } 587 part = in[i] * FACTOR2; 588 for ( j = i-2; part; j-- ) { 589 part += out[j]; 590 out[j] = part & 0xff; 591 part >>= 8; 592 } 593 } 594 j++; 595 prev->beg += j; 596 prev->len -= j; 597 } 598 599 out = tmp + prev->bufsiz; 600 i = 0; 601 do { 602 i--; 603 new += out[i]; 604 out[i] = new & 0xff; 605 new >>= 8; 606 } while ( new ); 607 i = -i; 608 if ( prev->len < i ) { 609 prev->beg = prev->bufsiz - i; 610 prev->len = i; 611 } 612 AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len ); 613} 614 615/* Convert unlimited length decimal or hex string to binary. 616 * Output buffer must be provided, bv_len must indicate buffer size 617 * Hex input can be "0x1234" or "'1234'H" 618 * 619 * Temporarily modifies the input string. 620 * 621 * Note: High bit of binary form is always the sign bit. If the number 622 * is supposed to be positive but has the high bit set, a zero byte 623 * is prepended. It is assumed that this has already been handled on 624 * any hex input. 625 */ 626int 627lutil_str2bin( struct berval *in, struct berval *out, void *ctx ) 628{ 629 char *pin, *pout, ctmp; 630 char *end; 631 int i, chunk, len, rc = 0, hex = 0; 632 if ( !out || !out->bv_val || out->bv_len < in->bv_len ) 633 return -1; 634 635 pout = out->bv_val; 636 /* Leading "0x" for hex input */ 637 if ( in->bv_len > 2 && in->bv_val[0] == '0' && 638 ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) ) 639 { 640 len = in->bv_len - 2; 641 pin = in->bv_val + 2; 642 hex = 1; 643 } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' && 644 in->bv_val[in->bv_len-2] == '\'' && 645 in->bv_val[in->bv_len-1] == 'H' ) 646 { 647 len = in->bv_len - 3; 648 pin = in->bv_val + 1; 649 hex = 1; 650 } 651 if ( hex ) { 652#define HEXMAX (2 * sizeof(long)) 653 unsigned long l; 654 /* Convert a longword at a time, but handle leading 655 * odd bytes first 656 */ 657 chunk = len % HEXMAX; 658 if ( !chunk ) 659 chunk = HEXMAX; 660 661 while ( len ) { 662 int ochunk; 663 ctmp = pin[chunk]; 664 pin[chunk] = '\0'; 665 errno = 0; 666 l = strtoul( pin, &end, 16 ); 667 pin[chunk] = ctmp; 668 if ( errno ) 669 return -1; 670 ochunk = (chunk + 1)/2; 671 for ( i = ochunk - 1; i >= 0; i-- ) { 672 pout[i] = l & 0xff; 673 l >>= 8; 674 } 675 pin += chunk; 676 pout += ochunk; 677 len -= chunk; 678 chunk = HEXMAX; 679 } 680 out->bv_len = pout - out->bv_val; 681 } else { 682 /* Decimal */ 683 char tmpbuf[64], *tmp; 684 lutil_int_decnum num; 685 int neg = 0; 686 long l; 687 688 len = in->bv_len; 689 pin = in->bv_val; 690 num.buf = (unsigned char *)out->bv_val; 691 num.bufsiz = out->bv_len; 692 num.beg = num.bufsiz-1; 693 num.len = 0; 694 if ( pin[0] == '-' ) { 695 neg = 0xff; 696 len--; 697 pin++; 698 } 699 700#define DECMAX 8 /* 8 digits at a time */ 701 702 /* tmp must be at least as large as outbuf */ 703 if ( out->bv_len > sizeof(tmpbuf)) { 704 tmp = ber_memalloc_x( out->bv_len, ctx ); 705 } else { 706 tmp = tmpbuf; 707 } 708 chunk = len & (DECMAX-1); 709 if ( !chunk ) 710 chunk = DECMAX; 711 712 while ( len ) { 713 ctmp = pin[chunk]; 714 pin[chunk] = '\0'; 715 errno = 0; 716 l = strtol( pin, &end, 10 ); 717 pin[chunk] = ctmp; 718 if ( errno ) { 719 rc = -1; 720 goto decfail; 721 } 722 scale( l, &num, (unsigned char *)tmp ); 723 pin += chunk; 724 len -= chunk; 725 chunk = DECMAX; 726 } 727 /* Negate the result */ 728 if ( neg ) { 729 unsigned char *ptr; 730 731 ptr = num.buf+num.beg; 732 733 /* flip all bits */ 734 for ( i=0; i<num.len; i++ ) 735 ptr[i] ^= 0xff; 736 737 /* add 1, with carry - overflow handled below */ 738 while ( i-- && ! (ptr[i] = (ptr[i] + 1) & 0xff )) ; 739 } 740 /* Prepend sign byte if wrong sign bit */ 741 if (( num.buf[num.beg] ^ neg ) & 0x80 ) { 742 num.beg--; 743 num.len++; 744 num.buf[num.beg] = neg; 745 } 746 if ( num.beg ) 747 AC_MEMCPY( num.buf, num.buf+num.beg, num.len ); 748 out->bv_len = num.len; 749decfail: 750 if ( tmp != tmpbuf ) { 751 ber_memfree_x( tmp, ctx ); 752 } 753 } 754 return rc; 755} 756 757static char time_unit[] = "dhms"; 758 759/* Used to parse and unparse time intervals, not timestamps */ 760int 761lutil_parse_time( 762 const char *in, 763 unsigned long *tp ) 764{ 765 unsigned long t = 0; 766 char *s, 767 *next; 768 int sofar = -1, 769 scale[] = { 86400, 3600, 60, 1 }; 770 771 *tp = 0; 772 773 for ( s = (char *)in; s[ 0 ] != '\0'; ) { 774 unsigned long u; 775 char *what; 776 777 /* strtoul() has an odd interface */ 778 if ( s[ 0 ] == '-' ) { 779 return -1; 780 } 781 782 u = strtoul( s, &next, 10 ); 783 if ( next == s ) { 784 return -1; 785 } 786 787 if ( next[ 0 ] == '\0' ) { 788 /* assume seconds */ 789 t += u; 790 break; 791 } 792 793 what = strchr( time_unit, next[ 0 ] ); 794 if ( what == NULL ) { 795 return -1; 796 } 797 798 if ( what - time_unit <= sofar ) { 799 return -1; 800 } 801 802 sofar = what - time_unit; 803 t += u * scale[ sofar ]; 804 805 s = &next[ 1 ]; 806 } 807 808 *tp = t; 809 return 0; 810} 811 812int 813lutil_unparse_time( 814 char *buf, 815 size_t buflen, 816 unsigned long t ) 817{ 818 int len, i; 819 unsigned long v[ 4 ]; 820 char *ptr = buf; 821 822 v[ 0 ] = t/86400; 823 v[ 1 ] = (t%86400)/3600; 824 v[ 2 ] = (t%3600)/60; 825 v[ 3 ] = t%60; 826 827 for ( i = 0; i < 4; i++ ) { 828 if ( v[i] > 0 || ( i == 3 && ptr == buf ) ) { 829 len = snprintf( ptr, buflen, "%lu%c", v[ i ], time_unit[ i ] ); 830 if ( len < 0 || (unsigned)len >= buflen ) { 831 return -1; 832 } 833 buflen -= len; 834 ptr += len; 835 } 836 } 837 838 return 0; 839} 840 841/* 842 * formatted print to string 843 * 844 * - if return code < 0, the error code returned by vsnprintf(3) is returned 845 * 846 * - if return code > 0, the buffer was not long enough; 847 * - if next is not NULL, *next will be set to buf + bufsize - 1 848 * - if len is not NULL, *len will contain the required buffer length 849 * 850 * - if return code == 0, the buffer was long enough; 851 * - if next is not NULL, *next will point to the end of the string printed so far 852 * - if len is not NULL, *len will contain the length of the string printed so far 853 */ 854int 855lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... ) 856{ 857 va_list ap; 858 int ret; 859 860 assert( buf != NULL ); 861 assert( bufsize > 0 ); 862 assert( fmt != NULL ); 863 864 va_start( ap, fmt ); 865 ret = vsnprintf( buf, bufsize, fmt, ap ); 866 va_end( ap ); 867 868 if ( ret < 0 ) { 869 return ret; 870 } 871 872 if ( len ) { 873 *len = ret; 874 } 875 876 if ( (unsigned) ret >= bufsize ) { 877 if ( next ) { 878 *next = &buf[ bufsize - 1 ]; 879 } 880 881 return 1; 882 } 883 884 if ( next ) { 885 *next = &buf[ ret ]; 886 } 887 888 return 0; 889} 890 891