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