Back to index

openldap  2.4.31
utils.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <limits.h>
00019 #include <stdio.h>
00020 #include <ac/stdlib.h>
00021 #include <ac/stdarg.h>
00022 #include <ac/string.h>
00023 #include <ac/ctype.h>
00024 #include <ac/unistd.h>
00025 #include <ac/time.h>
00026 #include <ac/errno.h>
00027 #ifdef HAVE_IO_H
00028 #include <io.h>
00029 #endif
00030 #ifdef HAVE_FCNTL_H
00031 #include <fcntl.h>
00032 #endif
00033 #ifdef _WIN32
00034 #include <windows.h>
00035 #endif
00036 
00037 #include "lutil.h"
00038 #include "ldap_defaults.h"
00039 #include "ldap_pvt.h"
00040 #include "lber_pvt.h"
00041 
00042 #ifdef HAVE_EBCDIC
00043 int _trans_argv = 1;
00044 #endif
00045 
00046 #ifdef _WIN32
00047 /* Some Windows versions accept both forward and backslashes in
00048  * directory paths, but we always use backslashes when generating
00049  * and parsing...
00050  */
00051 void lutil_slashpath( char *path )
00052 {
00053        char *c, *p;
00054 
00055        p = path;
00056        while (( c=strchr( p, '/' ))) {
00057               *c++ = '\\';
00058               p = c;
00059        }
00060 }
00061 #endif
00062 
00063 char* lutil_progname( const char* name, int argc, char *argv[] )
00064 {
00065        char *progname;
00066 
00067        if(argc == 0) {
00068               return (char *)name;
00069        }
00070 
00071 #ifdef HAVE_EBCDIC
00072        if (_trans_argv) {
00073               int i;
00074               for (i=0; i<argc; i++) __etoa(argv[i]);
00075               _trans_argv = 0;
00076        }
00077 #endif
00078        LUTIL_SLASHPATH( argv[0] );
00079        progname = strrchr ( argv[0], *LDAP_DIRSEP );
00080        progname = progname ? &progname[1] : argv[0];
00081 #ifdef _WIN32
00082        {
00083               size_t len = strlen( progname );
00084               if ( len > 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 )
00085                      progname[len - 4] = '\0';
00086        }
00087 #endif
00088        return progname;
00089 }
00090 
00091 #if 0
00092 size_t lutil_gentime( char *s, size_t smax, const struct tm *tm )
00093 {
00094        size_t ret;
00095 #ifdef HAVE_EBCDIC
00096 /* We've been compiling in ASCII so far, but we want EBCDIC now since
00097  * strftime only understands EBCDIC input.
00098  */
00099 #pragma convlit(suspend)
00100 #endif
00101        ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
00102 #ifdef HAVE_EBCDIC
00103 #pragma convlit(resume)
00104        __etoa( s );
00105 #endif
00106        return ret;
00107 }
00108 #endif
00109 
00110 size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta )
00111 {
00112        size_t ret;
00113        char   *p;
00114 
00115        if ( smax < 16 ) {   /* YYYYmmddHHMMSSZ */
00116               return 0;
00117        }
00118 
00119 #ifdef HAVE_EBCDIC
00120 /* We've been compiling in ASCII so far, but we want EBCDIC now since
00121  * strftime only understands EBCDIC input.
00122  */
00123 #pragma convlit(suspend)
00124 #endif
00125        ret = strftime( s, smax, "%Y%m%d%H%M%SZ", tm );
00126 #ifdef HAVE_EBCDIC
00127 #pragma convlit(resume)
00128        __etoa( s );
00129 #endif
00130        if ( delta == 0 || ret == 0 ) {
00131               return ret;
00132        }
00133 
00134        if ( smax < 20 ) {   /* YYYYmmddHHMMSS+HHMM */
00135               return 0;
00136        }
00137 
00138        p = s + 14;
00139 
00140        if ( delta < 0 ) {
00141               p[ 0 ] = '-';
00142               delta = -delta;
00143        } else {
00144               p[ 0 ] = '+';
00145        }
00146        p++;
00147 
00148        snprintf( p, smax - 15, "%02ld%02ld", delta / 3600,
00149                      ( delta % 3600 ) / 60 );
00150 
00151        return ret + 4;
00152 }
00153 
00154 int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt )
00155 {
00156        static int moffset[12] = {
00157               0, 31, 59, 90, 120,
00158               151, 181, 212, 243,
00159               273, 304, 334 }; 
00160        int sec;
00161 
00162        tt->tt_usec = tm->tm_usec;
00163 
00164        /* special case 0000/01/01+00:00:00 is returned as zero */
00165        if ( tm->tm_year == -1900 && tm->tm_mon == 0 && tm->tm_mday == 1 &&
00166               tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0 ) {
00167               tt->tt_sec = 0;
00168               tt->tt_gsec = 0;
00169               return 0;
00170        }
00171 
00172        /* tm->tm_year is years since 1900 */
00173        /* calculate days from years since 1970 (epoch) */ 
00174        tt->tt_sec = tm->tm_year - 70; 
00175        tt->tt_sec *= 365L; 
00176 
00177        /* count leap days in preceding years */ 
00178        tt->tt_sec += ((tm->tm_year -69) >> 2); 
00179 
00180        /* calculate days from months */ 
00181        tt->tt_sec += moffset[tm->tm_mon]; 
00182 
00183        /* add in this year's leap day, if any */ 
00184        if (((tm->tm_year & 3) == 0) && (tm->tm_mon > 1)) { 
00185               tt->tt_sec ++; 
00186        } 
00187 
00188        /* add in days in this month */ 
00189        tt->tt_sec += (tm->tm_mday - 1); 
00190 
00191        /* this function can handle a range of about 17408 years... */
00192        /* 86400 seconds in a day, divided by 128 = 675 */
00193        tt->tt_sec *= 675;
00194 
00195        /* move high 7 bits into tt_gsec */
00196        tt->tt_gsec = tt->tt_sec >> 25;
00197        tt->tt_sec -= tt->tt_gsec << 25;
00198 
00199        /* get hours */ 
00200        sec = tm->tm_hour; 
00201 
00202        /* convert to minutes */ 
00203        sec *= 60L; 
00204        sec += tm->tm_min; 
00205 
00206        /* convert to seconds */ 
00207        sec *= 60L; 
00208        sec += tm->tm_sec; 
00209        
00210        /* add remaining seconds */
00211        tt->tt_sec <<= 7;
00212        tt->tt_sec += sec;
00213 
00214        /* return success */
00215        return 0; 
00216 }
00217 
00218 int lutil_parsetime( char *atm, struct lutil_tm *tm )
00219 {
00220        while (atm && tm) {
00221               char *ptr = atm;
00222               unsigned i, fracs;
00223 
00224               /* Is the stamp reasonably long? */
00225               for (i=0; isdigit((unsigned char) atm[i]); i++);
00226               if (i < sizeof("00000101000000")-1)
00227                      break;
00228 
00229               /*
00230                * parse the time into a struct tm
00231                */
00232               /* 4 digit year to year - 1900 */
00233               tm->tm_year = *ptr++ - '0';
00234               tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
00235               tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
00236               tm->tm_year *= 10; tm->tm_year += *ptr++ - '0';
00237               tm->tm_year -= 1900;
00238               /* month 01-12 to 0-11 */
00239               tm->tm_mon = *ptr++ - '0';
00240               tm->tm_mon *=10; tm->tm_mon += *ptr++ - '0';
00241               if (tm->tm_mon < 1 || tm->tm_mon > 12) break;
00242               tm->tm_mon--;
00243 
00244               /* day of month 01-31 */
00245               tm->tm_mday = *ptr++ - '0';
00246               tm->tm_mday *=10; tm->tm_mday += *ptr++ - '0';
00247               if (tm->tm_mday < 1 || tm->tm_mday > 31) break;
00248 
00249               /* Hour 00-23 */
00250               tm->tm_hour = *ptr++ - '0';
00251               tm->tm_hour *=10; tm->tm_hour += *ptr++ - '0';
00252               if (tm->tm_hour < 0 || tm->tm_hour > 23) break;
00253 
00254               /* Minute 00-59 */
00255               tm->tm_min = *ptr++ - '0';
00256               tm->tm_min *=10; tm->tm_min += *ptr++ - '0';
00257               if (tm->tm_min < 0 || tm->tm_min > 59) break;
00258 
00259               /* Second 00-61 */
00260               tm->tm_sec = *ptr++ - '0';
00261               tm->tm_sec *=10; tm->tm_sec += *ptr++ - '0';
00262               if (tm->tm_sec < 0 || tm->tm_sec > 61) break;
00263 
00264               /* Fractions of seconds */
00265               if ( *ptr == '.' ) {
00266                      ptr++;
00267                      for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) {
00268                             i*=10; i+= *ptr++ - '0';
00269                             fracs++;
00270                      }
00271                      tm->tm_usec = i;
00272                      if (i) {
00273                             for (i = fracs; i<6; i++)
00274                                    tm->tm_usec *= 10;
00275                      }
00276               }
00277 
00278               /* Must be UTC */
00279               if (*ptr != 'Z') break;
00280 
00281               return 0;
00282        }
00283        return -1;
00284 }
00285 
00286 /* strcopy is like strcpy except it returns a pointer to the trailing NUL of
00287  * the result string. This allows fast construction of catenated strings
00288  * without the overhead of strlen/strcat.
00289  */
00290 char *
00291 lutil_strcopy(
00292        char *a,
00293        const char *b
00294 )
00295 {
00296        if (!a || !b)
00297               return a;
00298        
00299        while ((*a++ = *b++)) ;
00300        return a-1;
00301 }
00302 
00303 /* strncopy is like strcpy except it returns a pointer to the trailing NUL of
00304  * the result string. This allows fast construction of catenated strings
00305  * without the overhead of strlen/strcat.
00306  */
00307 char *
00308 lutil_strncopy(
00309        char *a,
00310        const char *b,
00311        size_t n
00312 )
00313 {
00314        if (!a || !b || n == 0)
00315               return a;
00316        
00317        while ((*a++ = *b++) && n-- > 0) ;
00318        return a-1;
00319 }
00320 
00321 /* memcopy is like memcpy except it returns a pointer to the byte past
00322  * the end of the result buffer, set to NULL. This allows fast construction
00323  * of catenated buffers.  Provided for API consistency with lutil_str*copy().
00324  */
00325 char *
00326 lutil_memcopy(
00327        char *a,
00328        const char *b,
00329        size_t n
00330 )
00331 {
00332        AC_MEMCPY(a, b, n);
00333        return a + n;
00334 }
00335 
00336 #ifndef HAVE_MKSTEMP
00337 int mkstemp( char * template )
00338 {
00339 #ifdef HAVE_MKTEMP
00340        return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 );
00341 #else
00342        return -1;
00343 #endif
00344 }
00345 #endif
00346 
00347 #ifdef _MSC_VER
00348 /* Equivalent of MS CRT's _dosmaperr().
00349  * @param lastError[in] Result of GetLastError().
00350  */
00351 static errno_t win2errno(DWORD lastError)
00352 {
00353        const struct { 
00354               DWORD   windows_code;
00355               errno_t errno_code;
00356        } WIN2ERRNO_TABLE[] = {
00357               { ERROR_SUCCESS, 0 },
00358               { ERROR_FILE_NOT_FOUND, ENOENT },
00359               { ERROR_PATH_NOT_FOUND, ENOENT },
00360               { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
00361               { ERROR_ACCESS_DENIED, EACCES },
00362               { ERROR_INVALID_HANDLE, EBADF },
00363               { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
00364               { ERROR_LOCK_VIOLATION, EACCES },
00365               { ERROR_FILE_EXISTS, EEXIST },
00366               { ERROR_INVALID_PARAMETER, EINVAL },
00367               { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG },
00368        };
00369        const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) /
00370 sizeof(WIN2ERRNO_TABLE[0]);
00371        const errno_t DEFAULT_ERRNO_ERROR = -1;
00372        unsigned int i;
00373 
00374        for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) {
00375               if (WIN2ERRNO_TABLE[i].windows_code == lastError) {
00376                      return WIN2ERRNO_TABLE[i].errno_code;
00377               }
00378        }
00379        return DEFAULT_ERRNO_ERROR;
00380 }
00381 
00382 struct dirent {
00383        char *d_name;
00384 };
00385 typedef struct DIR {
00386        HANDLE dir;
00387        struct dirent data;
00388        int first;
00389        char buf[MAX_PATH+1];
00390 } DIR;
00391 DIR *opendir( char *path )
00392 {
00393        char tmp[32768];
00394        int len = strlen(path);
00395        DIR *d;
00396        HANDLE h;
00397        WIN32_FIND_DATA data;
00398        
00399        if (len+3 >= sizeof(tmp)) {
00400               errno = ENAMETOOLONG;
00401               return NULL;
00402        }
00403 
00404        strcpy(tmp, path);
00405        tmp[len++] = '\\';
00406        tmp[len++] = '*';
00407        tmp[len] = '\0';
00408 
00409        h = FindFirstFile( tmp, &data );
00410 
00411        if ( h == INVALID_HANDLE_VALUE ) {
00412               errno = win2errno( GetLastError());
00413               return NULL;
00414        }
00415 
00416        d = ber_memalloc( sizeof(DIR) );
00417        if ( !d )
00418               return NULL;
00419        d->dir = h;
00420        d->data.d_name = d->buf;
00421        d->first = 1;
00422        strcpy(d->data.d_name, data.cFileName);
00423        return d;
00424 }
00425 struct dirent *readdir(DIR *dir)
00426 {
00427        WIN32_FIND_DATA data;
00428 
00429        if (dir->first) {
00430               dir->first = 0;
00431        } else {
00432               if (!FindNextFile(dir->dir, &data))
00433                      return NULL;
00434               strcpy(dir->data.d_name, data.cFileName);
00435        }
00436        return &dir->data;
00437 }
00438 int closedir(DIR *dir)
00439 {
00440        FindClose(dir->dir);
00441        ber_memfree(dir);
00442 }
00443 #endif
00444 
00445 /*
00446  * Memory Reverse Search
00447  */
00448 void *
00449 (lutil_memrchr)(const void *b, int c, size_t n)
00450 {
00451        if (n != 0) {
00452               const unsigned char *s, *bb = b, cc = c;
00453 
00454               for ( s = bb + n; s > bb; ) {
00455                      if ( *--s == cc ) {
00456                             return (void *) s;
00457                      }
00458               }
00459        }
00460 
00461        return NULL;
00462 }
00463 
00464 int
00465 lutil_atoix( int *v, const char *s, int x )
00466 {
00467        char          *next;
00468        long          i;
00469 
00470        assert( s != NULL );
00471        assert( v != NULL );
00472 
00473        i = strtol( s, &next, x );
00474        if ( next == s || next[ 0 ] != '\0' ) {
00475               return -1;
00476        }
00477 
00478        if ( (long)(int)i != i ) {
00479               return 1;
00480        }
00481 
00482        *v = (int)i;
00483 
00484        return 0;
00485 }
00486 
00487 int
00488 lutil_atoux( unsigned *v, const char *s, int x )
00489 {
00490        char          *next;
00491        unsigned long u;
00492 
00493        assert( s != NULL );
00494        assert( v != NULL );
00495 
00496        /* strtoul() has an odd interface */
00497        if ( s[ 0 ] == '-' ) {
00498               return -1;
00499        }
00500 
00501        u = strtoul( s, &next, x );
00502        if ( next == s || next[ 0 ] != '\0' ) {
00503               return -1;
00504        }
00505 
00506        if ( (unsigned long)(unsigned)u != u ) {
00507               return 1;
00508        }
00509 
00510        *v = u;
00511 
00512        return 0;
00513 }
00514 
00515 int
00516 lutil_atolx( long *v, const char *s, int x )
00517 {
00518        char *next;
00519        long l;
00520        int save_errno;
00521 
00522        assert( s != NULL );
00523        assert( v != NULL );
00524 
00525        if ( isspace( s[ 0 ] ) ) {
00526               return -1;
00527        }
00528 
00529        errno = 0;
00530        l = strtol( s, &next, x );
00531        save_errno = errno;
00532        if ( next == s || next[ 0 ] != '\0' ) {
00533               return -1;
00534        }
00535 
00536        if ( ( l == LONG_MIN || l == LONG_MAX ) && save_errno != 0 ) {
00537               return -1;
00538        }
00539 
00540        *v = l;
00541 
00542        return 0;
00543 }
00544 
00545 int
00546 lutil_atoulx( unsigned long *v, const char *s, int x )
00547 {
00548        char *next;
00549        unsigned long ul;
00550        int save_errno;
00551 
00552        assert( s != NULL );
00553        assert( v != NULL );
00554 
00555        /* strtoul() has an odd interface */
00556        if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) {
00557               return -1;
00558        }
00559 
00560        errno = 0;
00561        ul = strtoul( s, &next, x );
00562        save_errno = errno;
00563        if ( next == s || next[ 0 ] != '\0' ) {
00564               return -1;
00565        }
00566 
00567        if ( ( ul == 0 || ul == ULONG_MAX ) && save_errno != 0 ) {
00568               return -1;
00569        }
00570 
00571        *v = ul;
00572 
00573        return 0;
00574 }
00575 
00576 #ifdef HAVE_LONG_LONG
00577 #if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ)
00578 int
00579 lutil_atollx( long long *v, const char *s, int x )
00580 {
00581        char *next;
00582        long long ll;
00583        int save_errno;
00584 
00585        assert( s != NULL );
00586        assert( v != NULL );
00587 
00588        if ( isspace( s[ 0 ] ) ) {
00589               return -1;
00590        }
00591 
00592        errno = 0;
00593 #ifdef HAVE_STRTOLL
00594        ll = strtoll( s, &next, x );
00595 #else /* HAVE_STRTOQ */
00596        ll = (unsigned long long)strtoq( s, &next, x );
00597 #endif /* HAVE_STRTOQ */
00598        save_errno = errno;
00599        if ( next == s || next[ 0 ] != '\0' ) {
00600               return -1;
00601        }
00602 
00603        /* LLONG_MIN, LLONG_MAX are C99 only */
00604 #if defined (LLONG_MIN) && defined(LLONG_MAX)
00605        if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) {
00606               return -1;
00607        }
00608 #endif /* LLONG_MIN && LLONG_MAX */
00609 
00610        *v = ll;
00611 
00612        return 0;
00613 }
00614 #endif /* HAVE_STRTOLL || HAVE_STRTOQ */
00615 
00616 #if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ)
00617 int
00618 lutil_atoullx( unsigned long long *v, const char *s, int x )
00619 {
00620        char *next;
00621        unsigned long long ull;
00622        int save_errno;
00623 
00624        assert( s != NULL );
00625        assert( v != NULL );
00626 
00627        /* strtoull() has an odd interface */
00628        if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) {
00629               return -1;
00630        }
00631 
00632        errno = 0;
00633 #ifdef HAVE_STRTOULL
00634        ull = strtoull( s, &next, x );
00635 #else /* HAVE_STRTOUQ */
00636        ull = (unsigned long long)strtouq( s, &next, x );
00637 #endif /* HAVE_STRTOUQ */
00638        save_errno = errno;
00639        if ( next == s || next[ 0 ] != '\0' ) {
00640               return -1;
00641        }
00642 
00643        /* ULLONG_MAX is C99 only */
00644 #if defined(ULLONG_MAX)
00645        if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) {
00646               return -1;
00647        }
00648 #endif /* ULLONG_MAX */
00649 
00650        *v = ull;
00651 
00652        return 0;
00653 }
00654 #endif /* HAVE_STRTOULL || HAVE_STRTOUQ */
00655 #endif /* HAVE_LONG_LONG */
00656 
00657 /* Multiply an integer by 100000000 and add new */
00658 typedef struct lutil_int_decnum {
00659        unsigned char *buf;
00660        int bufsiz;
00661        int beg;
00662        int len;
00663 } lutil_int_decnum;
00664 
00665 #define       FACTOR1       (100000000&0xffff)
00666 #define FACTOR2 (100000000>>16)
00667 
00668 static void
00669 scale( int new, lutil_int_decnum *prev, unsigned char *tmp )
00670 {
00671        int i, j;
00672        unsigned char *in = prev->buf+prev->beg;
00673        unsigned int part;
00674        unsigned char *out = tmp + prev->bufsiz - prev->len;
00675 
00676        memset( tmp, 0, prev->bufsiz );
00677        if ( prev->len ) {
00678               for ( i = prev->len-1; i>=0; i-- ) {
00679                      part = in[i] * FACTOR1;
00680                      for ( j = i; part; j-- ) {
00681                             part += out[j];
00682                             out[j] = part & 0xff;
00683                             part >>= 8;
00684                      }
00685                      part = in[i] * FACTOR2;
00686                      for ( j = i-2; part; j-- ) {
00687                             part += out[j];
00688                             out[j] = part & 0xff;
00689                             part >>= 8;
00690                      }
00691               }
00692               j++;
00693               prev->beg += j;
00694               prev->len -= j;
00695        }
00696 
00697        out = tmp + prev->bufsiz;
00698        i = 0;
00699        do {
00700               i--;
00701               new += out[i];
00702               out[i] = new & 0xff;
00703               new >>= 8;
00704        } while ( new );
00705        i = -i;
00706        if ( prev->len < i ) {
00707               prev->beg = prev->bufsiz - i;
00708               prev->len = i;
00709        }
00710        AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len );
00711 }
00712 
00713 /* Convert unlimited length decimal or hex string to binary.
00714  * Output buffer must be provided, bv_len must indicate buffer size
00715  * Hex input can be "0x1234" or "'1234'H"
00716  *
00717  * Note: High bit of binary form is always the sign bit. If the number
00718  * is supposed to be positive but has the high bit set, a zero byte
00719  * is prepended. It is assumed that this has already been handled on
00720  * any hex input.
00721  */
00722 int
00723 lutil_str2bin( struct berval *in, struct berval *out, void *ctx )
00724 {
00725        char *pin, *pout;
00726        char *end;
00727        int i, chunk, len, rc = 0, hex = 0;
00728        if ( !out || !out->bv_val || out->bv_len < in->bv_len )
00729               return -1;
00730 
00731        pout = out->bv_val;
00732        /* Leading "0x" for hex input */
00733        if ( in->bv_len > 2 && in->bv_val[0] == '0' &&
00734               ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) )
00735        {
00736               len = in->bv_len - 2;
00737               pin = in->bv_val + 2;
00738               hex = 1;
00739        } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' &&
00740               in->bv_val[in->bv_len-2] == '\'' &&
00741               in->bv_val[in->bv_len-1] == 'H' )
00742        {
00743               len = in->bv_len - 3;
00744               pin = in->bv_val + 1;
00745               hex = 1;
00746        }
00747        if ( hex ) {
00748 #define HEXMAX       (2 * sizeof(long))
00749               unsigned long l;
00750               char tbuf[HEXMAX+1];
00751 
00752               /* Convert a longword at a time, but handle leading
00753                * odd bytes first
00754                */
00755               chunk = len % HEXMAX;
00756               if ( !chunk )
00757                      chunk = HEXMAX;
00758 
00759               while ( len ) {
00760                      int ochunk;
00761                      memcpy( tbuf, pin, chunk );
00762                      tbuf[chunk] = '\0';
00763                      errno = 0;
00764                      l = strtoul( tbuf, &end, 16 );
00765                      if ( errno )
00766                             return -1;
00767                      ochunk = (chunk + 1)/2;
00768                      for ( i = ochunk - 1; i >= 0; i-- ) {
00769                             pout[i] = l & 0xff;
00770                             l >>= 8;
00771                      }
00772                      pin += chunk;
00773                      pout += ochunk;
00774                      len -= chunk;
00775                      chunk = HEXMAX;
00776               }
00777               out->bv_len = pout - out->bv_val;
00778        } else {
00779        /* Decimal */
00780 #define       DECMAX 8      /* 8 digits at a time */
00781               char tmpbuf[64], *tmp;
00782               lutil_int_decnum num;
00783               int neg = 0;
00784               long l;
00785               char tbuf[DECMAX+1];
00786 
00787               len = in->bv_len;
00788               pin = in->bv_val;
00789               num.buf = (unsigned char *)out->bv_val;
00790               num.bufsiz = out->bv_len;
00791               num.beg = num.bufsiz-1;
00792               num.len = 0;
00793               if ( pin[0] == '-' ) {
00794                      neg = 0xff;
00795                      len--;
00796                      pin++;
00797               }
00798 
00799               /* tmp must be at least as large as outbuf */
00800               if ( out->bv_len > sizeof(tmpbuf)) {
00801                      tmp = ber_memalloc_x( out->bv_len, ctx );
00802               } else {
00803                      tmp = tmpbuf;
00804               }
00805               chunk = len & (DECMAX-1);
00806               if ( !chunk )
00807                      chunk = DECMAX;
00808 
00809               while ( len ) {
00810                      memcpy( tbuf, pin, chunk );
00811                      tbuf[chunk] = '\0';
00812                      errno = 0;
00813                      l = strtol( tbuf, &end, 10 );
00814                      if ( errno ) {
00815                             rc = -1;
00816                             goto decfail;
00817                      }
00818                      scale( l, &num, (unsigned char *)tmp );
00819                      pin += chunk;
00820                      len -= chunk;
00821                      chunk = DECMAX;
00822               }
00823               /* Negate the result */
00824               if ( neg ) {
00825                      unsigned char *ptr;
00826 
00827                      ptr = num.buf+num.beg;
00828 
00829                      /* flip all bits */
00830                      for ( i=0; i<num.len; i++ )
00831                             ptr[i] ^= 0xff;
00832 
00833                      /* add 1, with carry - overflow handled below */
00834                      while ( i-- && ! (ptr[i] = (ptr[i] + 1) & 0xff )) ;
00835               }
00836               /* Prepend sign byte if wrong sign bit */
00837               if (( num.buf[num.beg] ^ neg ) & 0x80 ) {
00838                      num.beg--;
00839                      num.len++;
00840                      num.buf[num.beg] = neg;
00841               }
00842               if ( num.beg )
00843                      AC_MEMCPY( num.buf, num.buf+num.beg, num.len );
00844               out->bv_len = num.len;
00845 decfail:
00846               if ( tmp != tmpbuf ) {
00847                      ber_memfree_x( tmp, ctx );
00848               }
00849        }
00850        return rc;
00851 }
00852 
00853 static char          time_unit[] = "dhms";
00854 
00855 /* Used to parse and unparse time intervals, not timestamps */
00856 int
00857 lutil_parse_time(
00858        const char    *in,
00859        unsigned long *tp )
00860 {
00861        unsigned long t = 0;
00862        char          *s,
00863                      *next;
00864        int           sofar = -1,
00865                      scale[] = { 86400, 3600, 60, 1 };
00866 
00867        *tp = 0;
00868 
00869        for ( s = (char *)in; s[ 0 ] != '\0'; ) {
00870               unsigned long u;
00871               char          *what;
00872 
00873               /* strtoul() has an odd interface */
00874               if ( s[ 0 ] == '-' ) {
00875                      return -1;
00876               }
00877 
00878               u = strtoul( s, &next, 10 );
00879               if ( next == s ) {
00880                      return -1;
00881               }
00882 
00883               if ( next[ 0 ] == '\0' ) {
00884                      /* assume seconds */
00885                      t += u;
00886                      break;
00887               }
00888 
00889               what = strchr( time_unit, next[ 0 ] );
00890               if ( what == NULL ) {
00891                      return -1;
00892               }
00893 
00894               if ( what - time_unit <= sofar ) {
00895                      return -1;
00896               }
00897 
00898               sofar = what - time_unit;
00899               t += u * scale[ sofar ];
00900 
00901               s = &next[ 1 ];
00902        }
00903 
00904        *tp = t;
00905        return 0;
00906 }
00907 
00908 int
00909 lutil_unparse_time(
00910        char                 *buf,
00911        size_t               buflen,
00912        unsigned long        t )
00913 {
00914        int           len, i;
00915        unsigned long v[ 4 ];
00916        char          *ptr = buf;
00917 
00918        v[ 0 ] = t/86400;
00919        v[ 1 ] = (t%86400)/3600;
00920        v[ 2 ] = (t%3600)/60;
00921        v[ 3 ] = t%60;
00922 
00923        for ( i = 0; i < 4; i++ ) {
00924               if ( v[i] > 0 || ( i == 3 && ptr == buf ) ) {
00925                      len = snprintf( ptr, buflen, "%lu%c", v[ i ], time_unit[ i ] );
00926                      if ( len < 0 || (unsigned)len >= buflen ) {
00927                             return -1;
00928                      }
00929                      buflen -= len;
00930                      ptr += len;
00931               }
00932        }
00933 
00934        return 0;
00935 }
00936 
00937 /*
00938  * formatted print to string
00939  *
00940  * - if return code < 0, the error code returned by vsnprintf(3) is returned
00941  *
00942  * - if return code > 0, the buffer was not long enough;
00943  *     - if next is not NULL, *next will be set to buf + bufsize - 1
00944  *     - if len is not NULL, *len will contain the required buffer length
00945  *
00946  * - if return code == 0, the buffer was long enough;
00947  *     - if next is not NULL, *next will point to the end of the string printed so far
00948  *     - if len is not NULL, *len will contain the length of the string printed so far 
00949  */
00950 int
00951 lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... )
00952 {
00953        va_list              ap;
00954        int           ret;
00955 
00956        assert( buf != NULL );
00957        assert( bufsize > 0 );
00958        assert( fmt != NULL );
00959 
00960        va_start( ap, fmt );
00961        ret = vsnprintf( buf, bufsize, fmt, ap );
00962        va_end( ap );
00963 
00964        if ( ret < 0 ) {
00965               return ret;
00966        }
00967 
00968        if ( len ) {
00969               *len = ret;
00970        }
00971 
00972        if ( (unsigned) ret >= bufsize ) {
00973               if ( next ) {
00974                      *next = &buf[ bufsize - 1 ];
00975               }
00976 
00977               return 1;
00978        }
00979 
00980        if ( next ) {
00981               *next = &buf[ ret ];
00982        }
00983 
00984        return 0;
00985 }
00986