X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Fliblutil%2Futils.c;h=51f35701e0466bbc9e37479ce80e78e26cad9a29;hb=6adee8cd44f016b90183685d9db84a67c47992bc;hp=0da7df479071f1cd4cfe7d6de3d2ba977aba10c6;hpb=716d1770a2b3c1220af255fc36aecd2f8389e898;p=openldap diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c index 0da7df4790..51f35701e0 100644 --- a/libraries/liblutil/utils.c +++ b/libraries/liblutil/utils.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2006 The OpenLDAP Foundation. + * Copyright 1998-2011 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,21 +15,29 @@ #include "portable.h" +#include #include #include +#include #include #include #include #include +#include #ifdef HAVE_IO_H #include #endif #ifdef HAVE_FCNTL_H #include #endif +#ifdef _WIN32 +#include +#endif -#include -#include +#include "lutil.h" +#include "ldap_defaults.h" +#include "ldap_pvt.h" +#include "lber_pvt.h" #ifdef HAVE_EBCDIC int _trans_argv = 1; @@ -70,6 +78,13 @@ char* lutil_progname( const char* name, int argc, char *argv[] ) LUTIL_SLASHPATH( argv[0] ); progname = strrchr ( argv[0], *LDAP_DIRSEP ); progname = progname ? &progname[1] : argv[0]; +#ifdef _WIN32 + { + size_t len = strlen( progname ); + if ( len > 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 ) + progname[len - 4] = '\0'; + } +#endif return progname; } @@ -133,7 +148,7 @@ size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta ) snprintf( p, smax - 15, "%02ld%02ld", delta / 3600, ( delta % 3600 ) / 60 ); - return ret + 5; + return ret + 4; } int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt ) @@ -247,14 +262,17 @@ int lutil_parsetime( char *atm, struct lutil_tm *tm ) if (tm->tm_sec < 0 || tm->tm_sec > 61) break; /* Fractions of seconds */ - for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) { - i*=10; i+= *ptr++ - '0'; - fracs++; - } - tm->tm_usec = i; - if (i) { - for (i = fracs; i<6; i++) - tm->tm_usec *= 10; + if ( *ptr == '.' ) { + ptr++; + for (i = 0, fracs = 0; isdigit((unsigned char) *ptr); ) { + i*=10; i+= *ptr++ - '0'; + fracs++; + } + tm->tm_usec = i; + if (i) { + for (i = fracs; i<6; i++) + tm->tm_usec *= 10; + } } /* Must be UTC */ @@ -300,6 +318,21 @@ lutil_strncopy( return a-1; } +/* memcopy is like memcpy except it returns a pointer to the byte past + * the end of the result buffer, set to NULL. This allows fast construction + * of catenated buffers. Provided for API consistency with lutil_str*copy(). + */ +char * +lutil_memcopy( + char *a, + const char *b, + size_t n +) +{ + AC_MEMCPY(a, b, n); + return a + n; +} + #ifndef HAVE_MKSTEMP int mkstemp( char * template ) { @@ -311,11 +344,109 @@ int mkstemp( char * template ) } #endif +#ifdef _MSC_VER +/* Equivalent of MS CRT's _dosmaperr(). + * @param lastError[in] Result of GetLastError(). + */ +static errno_t win2errno(DWORD lastError) +{ + const struct { + DWORD windows_code; + errno_t errno_code; + } WIN2ERRNO_TABLE[] = { + { ERROR_SUCCESS, 0 }, + { ERROR_FILE_NOT_FOUND, ENOENT }, + { ERROR_PATH_NOT_FOUND, ENOENT }, + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, + { ERROR_ACCESS_DENIED, EACCES }, + { ERROR_INVALID_HANDLE, EBADF }, + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, + { ERROR_LOCK_VIOLATION, EACCES }, + { ERROR_FILE_EXISTS, EEXIST }, + { ERROR_INVALID_PARAMETER, EINVAL }, + { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG }, + }; + const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) / +sizeof(WIN2ERRNO_TABLE[0]); + const errno_t DEFAULT_ERRNO_ERROR = -1; + unsigned int i; + + for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) { + if (WIN2ERRNO_TABLE[i].windows_code == lastError) { + return WIN2ERRNO_TABLE[i].errno_code; + } + } + return DEFAULT_ERRNO_ERROR; +} + +struct dirent { + char *d_name; +}; +typedef struct DIR { + HANDLE dir; + struct dirent data; + int first; + char buf[MAX_PATH+1]; +} DIR; +DIR *opendir( char *path ) +{ + char tmp[32768]; + int len = strlen(path); + DIR *d; + HANDLE h; + WIN32_FIND_DATA data; + + if (len+3 >= sizeof(tmp)) { + errno = ENAMETOOLONG; + return NULL; + } + + strcpy(tmp, path); + tmp[len++] = '\\'; + tmp[len++] = '*'; + tmp[len] = '\0'; + + h = FindFirstFile( tmp, &data ); + + if ( h == INVALID_HANDLE_VALUE ) { + errno = win2errno( GetLastError()); + return NULL; + } + + d = ber_memalloc( sizeof(DIR) ); + if ( !d ) + return NULL; + d->dir = h; + d->data.d_name = d->buf; + d->first = 1; + strcpy(d->data.d_name, data.cFileName); + return d; +} +struct dirent *readdir(DIR *dir) +{ + WIN32_FIND_DATA data; + + if (dir->first) { + dir->first = 0; + } else { + if (!FindNextFile(dir->dir, &data)) + return NULL; + strcpy(dir->data.d_name, data.cFileName); + } + return &dir->data; +} +int closedir(DIR *dir) +{ + FindClose(dir->dir); + ber_memfree(dir); +} +#endif + /* * Memory Reverse Search */ void * -lutil_memrchr(const void *b, int c, size_t n) +(lutil_memrchr)(const void *b, int c, size_t n) { if (n != 0) { const unsigned char *s, *bb = b, cc = c; @@ -384,17 +515,28 @@ lutil_atoux( unsigned *v, const char *s, int x ) int lutil_atolx( long *v, const char *s, int x ) { - char *next; - long l; + char *next; + long l; + int save_errno; assert( s != NULL ); assert( v != NULL ); + if ( isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; l = strtol( s, &next, x ); + save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } + if ( ( l == LONG_MIN || l == LONG_MAX ) && save_errno != 0 ) { + return -1; + } + *v = l; return 0; @@ -403,29 +545,316 @@ lutil_atolx( long *v, const char *s, int x ) int lutil_atoulx( unsigned long *v, const char *s, int x ) { - char *next; - unsigned long ul; + char *next; + unsigned long ul; + int save_errno; assert( s != NULL ); assert( v != NULL ); /* strtoul() has an odd interface */ - if ( s[ 0 ] == '-' ) { + if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { return -1; } + errno = 0; ul = strtoul( s, &next, x ); + save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } + if ( ( ul == 0 || ul == ULONG_MAX ) && save_errno != 0 ) { + return -1; + } + *v = ul; return 0; } +#ifdef HAVE_LONG_LONG +#if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ) +int +lutil_atollx( long long *v, const char *s, int x ) +{ + char *next; + long long ll; + int save_errno; + + assert( s != NULL ); + assert( v != NULL ); + + if ( isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; +#ifdef HAVE_STRTOLL + ll = strtoll( s, &next, x ); +#else /* HAVE_STRTOQ */ + ll = (unsigned long long)strtoq( s, &next, x ); +#endif /* HAVE_STRTOQ */ + save_errno = errno; + if ( next == s || next[ 0 ] != '\0' ) { + return -1; + } + + /* LLONG_MIN, LLONG_MAX are C99 only */ +#if defined (LLONG_MIN) && defined(LLONG_MAX) + if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) { + return -1; + } +#endif /* LLONG_MIN && LLONG_MAX */ + + *v = ll; + + return 0; +} +#endif /* HAVE_STRTOLL || HAVE_STRTOQ */ + +#if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ) +int +lutil_atoullx( unsigned long long *v, const char *s, int x ) +{ + char *next; + unsigned long long ull; + int save_errno; + + assert( s != NULL ); + assert( v != NULL ); + + /* strtoull() has an odd interface */ + if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; +#ifdef HAVE_STRTOULL + ull = strtoull( s, &next, x ); +#else /* HAVE_STRTOUQ */ + ull = (unsigned long long)strtouq( s, &next, x ); +#endif /* HAVE_STRTOUQ */ + save_errno = errno; + if ( next == s || next[ 0 ] != '\0' ) { + return -1; + } + + /* ULLONG_MAX is C99 only */ +#if defined(ULLONG_MAX) + if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) { + return -1; + } +#endif /* ULLONG_MAX */ + + *v = ull; + + return 0; +} +#endif /* HAVE_STRTOULL || HAVE_STRTOUQ */ +#endif /* HAVE_LONG_LONG */ + +/* Multiply an integer by 100000000 and add new */ +typedef struct lutil_int_decnum { + unsigned char *buf; + int bufsiz; + int beg; + int len; +} lutil_int_decnum; + +#define FACTOR1 (100000000&0xffff) +#define FACTOR2 (100000000>>16) + +static void +scale( int new, lutil_int_decnum *prev, unsigned char *tmp ) +{ + int i, j; + unsigned char *in = prev->buf+prev->beg; + unsigned int part; + unsigned char *out = tmp + prev->bufsiz - prev->len; + + memset( tmp, 0, prev->bufsiz ); + if ( prev->len ) { + for ( i = prev->len-1; i>=0; i-- ) { + part = in[i] * FACTOR1; + for ( j = i; part; j-- ) { + part += out[j]; + out[j] = part & 0xff; + part >>= 8; + } + part = in[i] * FACTOR2; + for ( j = i-2; part; j-- ) { + part += out[j]; + out[j] = part & 0xff; + part >>= 8; + } + } + j++; + prev->beg += j; + prev->len -= j; + } + + out = tmp + prev->bufsiz; + i = 0; + do { + i--; + new += out[i]; + out[i] = new & 0xff; + new >>= 8; + } while ( new ); + i = -i; + if ( prev->len < i ) { + prev->beg = prev->bufsiz - i; + prev->len = i; + } + AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len ); +} + +/* Convert unlimited length decimal or hex string to binary. + * Output buffer must be provided, bv_len must indicate buffer size + * Hex input can be "0x1234" or "'1234'H" + * + * Temporarily modifies the input string. + * + * Note: High bit of binary form is always the sign bit. If the number + * is supposed to be positive but has the high bit set, a zero byte + * is prepended. It is assumed that this has already been handled on + * any hex input. + */ +int +lutil_str2bin( struct berval *in, struct berval *out, void *ctx ) +{ + char *pin, *pout, ctmp; + char *end; + int i, chunk, len, rc = 0, hex = 0; + if ( !out || !out->bv_val || out->bv_len < in->bv_len ) + return -1; + + pout = out->bv_val; + /* Leading "0x" for hex input */ + if ( in->bv_len > 2 && in->bv_val[0] == '0' && + ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) ) + { + len = in->bv_len - 2; + pin = in->bv_val + 2; + hex = 1; + } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' && + in->bv_val[in->bv_len-2] == '\'' && + in->bv_val[in->bv_len-1] == 'H' ) + { + len = in->bv_len - 3; + pin = in->bv_val + 1; + hex = 1; + } + if ( hex ) { +#define HEXMAX (2 * sizeof(long)) + unsigned long l; + /* Convert a longword at a time, but handle leading + * odd bytes first + */ + chunk = len % HEXMAX; + if ( !chunk ) + chunk = HEXMAX; + + while ( len ) { + int ochunk; + ctmp = pin[chunk]; + pin[chunk] = '\0'; + errno = 0; + l = strtoul( pin, &end, 16 ); + pin[chunk] = ctmp; + if ( errno ) + return -1; + ochunk = (chunk + 1)/2; + for ( i = ochunk - 1; i >= 0; i-- ) { + pout[i] = l & 0xff; + l >>= 8; + } + pin += chunk; + pout += ochunk; + len -= chunk; + chunk = HEXMAX; + } + out->bv_len = pout - out->bv_val; + } else { + /* Decimal */ + char tmpbuf[64], *tmp; + lutil_int_decnum num; + int neg = 0; + long l; + + len = in->bv_len; + pin = in->bv_val; + num.buf = (unsigned char *)out->bv_val; + num.bufsiz = out->bv_len; + num.beg = num.bufsiz-1; + num.len = 0; + if ( pin[0] == '-' ) { + neg = 0xff; + len--; + pin++; + } + +#define DECMAX 8 /* 8 digits at a time */ + + /* tmp must be at least as large as outbuf */ + if ( out->bv_len > sizeof(tmpbuf)) { + tmp = ber_memalloc_x( out->bv_len, ctx ); + } else { + tmp = tmpbuf; + } + chunk = len & (DECMAX-1); + if ( !chunk ) + chunk = DECMAX; + + while ( len ) { + ctmp = pin[chunk]; + pin[chunk] = '\0'; + errno = 0; + l = strtol( pin, &end, 10 ); + pin[chunk] = ctmp; + if ( errno ) { + rc = -1; + goto decfail; + } + scale( l, &num, (unsigned char *)tmp ); + pin += chunk; + len -= chunk; + chunk = DECMAX; + } + /* Negate the result */ + if ( neg ) { + unsigned char *ptr; + + ptr = num.buf+num.beg; + + /* flip all bits */ + for ( i=0; ibv_len = num.len; +decfail: + if ( tmp != tmpbuf ) { + ber_memfree_x( tmp, ctx ); + } + } + return rc; +} + static char time_unit[] = "dhms"; +/* Used to parse and unparse time intervals, not timestamps */ int lutil_parse_time( const char *in, @@ -507,3 +936,53 @@ lutil_unparse_time( return 0; } +/* + * formatted print to string + * + * - if return code < 0, the error code returned by vsnprintf(3) is returned + * + * - if return code > 0, the buffer was not long enough; + * - if next is not NULL, *next will be set to buf + bufsize - 1 + * - if len is not NULL, *len will contain the required buffer length + * + * - if return code == 0, the buffer was long enough; + * - if next is not NULL, *next will point to the end of the string printed so far + * - if len is not NULL, *len will contain the length of the string printed so far + */ +int +lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... ) +{ + va_list ap; + int ret; + + assert( buf != NULL ); + assert( bufsize > 0 ); + assert( fmt != NULL ); + + va_start( ap, fmt ); + ret = vsnprintf( buf, bufsize, fmt, ap ); + va_end( ap ); + + if ( ret < 0 ) { + return ret; + } + + if ( len ) { + *len = ret; + } + + if ( (unsigned) ret >= bufsize ) { + if ( next ) { + *next = &buf[ bufsize - 1 ]; + } + + return 1; + } + + if ( next ) { + *next = &buf[ ret ]; + } + + return 0; +} +