/* $Id$ */ /* * FedStage DRMAA utilities library * Copyright (C) 2006-2008 FedStage Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef lint static char rcsid[] # ifdef __GNUC__ __attribute__ ((unused)) # endif = "$Id$"; #endif static char * fsd_expand_printf_ph( const char *fmt ); void fsd_free_vector( char **vector ) { char **i; if( vector == NULL ) return; for( i = vector; *i != NULL; i++ ) fsd_free( *i ); fsd_free( vector ); } char ** fsd_copy_vector( const char *const * vector ) { unsigned n_items, i; char** volatile buf = NULL; char** volatile result = NULL; TRY { if( vector ) for( n_items = 0; vector[ n_items ] != NULL; n_items++ ) {} else n_items = 0; fsd_calloc( buf, n_items+1, char* ); for( i = 0; i < n_items; i++ ) buf[i] = fsd_strdup( vector[i] ); } ELSE { result = buf; buf = NULL; } FINALLY { fsd_free_vector( buf ); } END_TRY return result; } char * fsd_replace( char *str, const char *placeholder, const char *value ) { size_t ph_len, v_len; char *found = NULL; char* volatile s = str; if( str == NULL ) fsd_exc_raise_code( FSD_ERRNO_INTERNAL_ERROR ); ph_len = strlen( placeholder ); v_len = strlen( value ); do { size_t s_len; s_len = strlen( s ); found = strstr( s, placeholder ); if( found ) { char* volatile result; size_t pos = found - s; TRY { fsd_calloc( result, s_len - ph_len + v_len + 1, char ); memcpy( result, s, pos ); memcpy( result+pos, value, v_len ); memcpy( result+pos+v_len, s+pos+ph_len, s_len-pos-ph_len ); result[ s_len-ph_len+v_len ] = 0; } FINALLY { fsd_free( s ); s = result; } END_TRY } } while( found ); return s; } char * fsd_explode( const char *const *vector, char glue, int n ) { char* volatile result = NULL; char* volatile buf = NULL; char *s; const char *const *i; unsigned idx, max=(unsigned)n; size_t size =0; TRY { for( i = vector, idx = 0; idx < max && *i != NULL; i++, idx++ ) { if( i != vector ) size++; size += strlen(*i); } fsd_calloc( buf, size+1, char ); s = buf; for( i = vector, idx = 0; idx < max && *i != NULL; i++, idx++ ) { if( i != vector ) *s++ = glue; strcpy( s, *i ); s += strlen( *i ); } } ELSE { result = buf; buf = NULL; } FINALLY { fsd_free( buf ); } END_TRY return result; } char * fsd_strdup( const char *s ) { char *result; if( s == NULL ) return NULL; result = strdup( s ); if( result == NULL ) fsd_exc_raise_sys( ENOMEM ); return result; } char * fsd_strndup( const char *s, size_t n ) { char *result; if( s == NULL ) return NULL; result = strndup( s, n ); if( result == NULL ) fsd_exc_raise_sys( ENOMEM ); return result; } int fsd_atoi( const char *string ) { const char *s = string; int sign = +1; int v = 0; while( isspace(*(const unsigned char*)s) ) s++; switch( *s ) { case '+': sign = +1; s++; break; case '-': sign = -1; s++; break; default: break; } while( isspace(*(const unsigned char*)s) ) s++; if( '0' <= *s && *s <= '9' ) { while( '0' <= *s && *s <= '9' ) { if( v > INT_MAX/10 ) goto range_error; v *= 10; v += *s++ - '0'; if( v < 0 ) goto range_error; } } else goto nan_error; while( isspace(*(const unsigned char*)s) ) s++; if( *s != '\0' ) goto nan_error; return sign * v; range_error: fsd_exc_raise_fmt( FSD_ERRNO_INVALID_ARGUMENT, "value out of range: %s", string ); return 0; nan_error: fsd_exc_raise_fmt( FSD_ERRNO_INVALID_ARGUMENT, "not an number: %s", string ); return 0; } void fsd_str_append( bool *truncated, char **p, char *end, const char *fmt, ... ) { va_list args; va_start( args, fmt ); *p += fsd_vsnprintf( truncated, *p, end-*p, fmt, args ); va_end( args ); } size_t fsd_snprintf( bool *truncated, char *str, size_t size, const char *fmt, ... ) { va_list args; size_t result; va_start( args, fmt ); result = fsd_vsnprintf( truncated, str, size, fmt, args ); va_end( args ); return result; } size_t fsd_vsnprintf( bool *truncated, char *str, size_t size, const char *fmt, va_list args ) { int n; char *fmt_buf = NULL; fmt_buf = fsd_expand_printf_ph( fmt ); if( fmt_buf ) fmt = fmt_buf; n = vsnprintf( str, size, fmt, args ); if( fmt_buf ) fsd_free( fmt_buf ); if( 0 <= n && (size_t)n < size ) {} else { str[size-1] = '\0'; *truncated = true; } return n; } char * fsd_asprintf( const char *fmt, ... ) { va_list args; char *result = NULL; va_start( args, fmt ); result = fsd_vasprintf( fmt, args ); va_end( args ); return result; } char * fsd_vasprintf( const char *fmt, va_list args ) { char *result = NULL; char *fmt_buf = NULL; int rc; fmt_buf = fsd_expand_printf_ph( fmt ); if( fmt_buf ) fmt = fmt_buf; rc = vasprintf( &result, fmt, args ); if( fmt_buf ) fsd_free( fmt_buf ); if( rc == -1 ) fsd_exc_raise_sys( ENOMEM ); return result; } /** * ``%m`` placeholder which is a glibc extension * can be safely used in fsd_*printf functions. */ char * fsd_expand_printf_ph( const char *fmt ) { char* volatile result = NULL; if( strstr(fmt, "%m") == NULL ) return result; TRY { const char *pos; while( (pos = strstr(fmt, "%m")) != NULL && (pos == fmt || pos[-1] != '%') ) { char* volatile errno_msg = NULL; volatile bool own_errno_msg = false; TRY { char *buf = NULL; size_t fmt_len = strlen(fmt); size_t ph_pos = pos - fmt; size_t errno_msg_len; errno_msg = fsd_astrerror( errno, (bool*)&own_errno_msg ); errno_msg_len = strlen(errno_msg); fsd_calloc( buf, fmt_len-2+errno_msg_len+1, char ); /* replace ``%m`` with strerror(errno) */ strncat( buf, fmt, ph_pos ); strcat( buf+ph_pos, errno_msg ); strcat( buf+ph_pos+errno_msg_len, fmt+ph_pos+2 ); fsd_free( result ); fmt = result = buf; } FINALLY { if( errno_msg && own_errno_msg ) fsd_free( errno_msg ); } END_TRY } } EXCEPT_DEFAULT { fsd_free( result ); fsd_exc_reraise(); } END_TRY return result; } const char * fsd_strerror_r( int errnum, char *buffer, size_t buffer_size ) { # ifdef HAVE_DECL_STRERROR_R # ifdef _GNU_SOURCE return strerror_r( errnum, buffer, buffer_size ); # else strerror_r( errnum, buffer, buffer_size ); return buffer; # endif /* !_GNU_SOURCE */ # else /* assume strerror is thread safe -- returned string is constant */ return strerror(errnum); # endif /* ! HAVE_STRERROR_R */ } char * fsd_astrerror( int errnum, bool *malloced ) { #ifdef HAVE_DECL_STRERROR_R char *buffer = NULL; size_t buffer_size = 0; char *result = NULL; do { if( buffer_size == 0 ) buffer_size = 1024; else buffer_size *= 2; fsd_realloc( buffer, buffer_size, char ); # ifdef _GNU_SOURCE result = strerror_r( errnum, buffer, buffer_size ); if( result == buffer && strlen(result)+1 == buffer_size ) continue; # else if( strerror_r( errnum, buffer, buffer_size ) && errno == ERANGE ) { result = buffer; continue; } # endif /* !_GNU_SOURCE */ } while( false ); *malloced = (buffer == result); if( buffer != result ) fsd_free( buffer ); return result; #else /* ! HAVE_DECL_STRERROR_R */ /* assume strerror is thread safe -- returned string is constant */ *malloced = false; return strerror(errnum); #endif /* ! HAVE_DECL_STRERROR_R */ } void fsd_get_time( struct timespec *ts ) { struct timeval tv; int rc; rc = gettimeofday( &tv, NULL ); if( rc ) fsd_exc_raise_sys( 0 ); else { ts->tv_sec = tv.tv_sec; ts->tv_nsec = 1000 * tv.tv_usec; } } void fsd_ts_add( struct timespec *a, const struct timespec *b ) { const int nano = 1000000000; a->tv_sec += b->tv_sec; a->tv_nsec += b->tv_nsec; if( a->tv_nsec >= nano ) { a->tv_nsec -= nano; a->tv_sec ++; } } int fsd_ts_cmp( const struct timespec *a, const struct timespec *b ) { if( a->tv_sec != b->tv_sec ) return a->tv_sec - b->tv_sec; else return a->tv_nsec - b->tv_nsec; } void fsd_read_file( const char *filename, bool must_exist, char **content, size_t *length ) { volatile int fd = -1; char* volatile buffer = NULL; size_t size = 0; size_t capacity = 0; ssize_t n_read; TRY { *content = NULL; *length = 0; fd = open( filename, O_RDONLY ); if( fd == -1 ) { if( errno==ENOENT && !must_exist ) { *content = NULL; *length = 0; } else fsd_exc_raise_sys( 0 ); } else { do { capacity = size + 1024; fsd_realloc( buffer, capacity, char ); n_read = read( fd, buffer, capacity-size ); if( n_read == (ssize_t)-1 ) fsd_exc_raise_sys( 0 ); else size += n_read; } while( n_read != 0 ); fsd_realloc( buffer, size+1, char ); buffer[ size ] = '\0'; } } ELSE { *content = buffer; buffer = NULL; *length = size; } FINALLY { fsd_free( buffer ); if( fd >= 0 ) close( fd ); } END_TRY } char * fsd_getcwd(void) { char* volatile buffer = NULL; char* volatile result = NULL; size_t size = 64; TRY { fsd_calloc( buffer, size, char ); while( true ) { char *result = getcwd( buffer, size ); if( result != NULL ) break; else if( errno == ERANGE ) { size *= 2; fsd_realloc( buffer, size, char ); } else fsd_exc_raise_sys( 0 ); } fsd_realloc( buffer, strlen(buffer)+1, char ); } ELSE { result = buffer; buffer = NULL; } FINALLY { fsd_free( buffer ); } END_TRY return result; } char * fsd_readline(FILE *f) { char* volatile buffer = NULL; char* volatile result = NULL; size_t size = 1024; int ch = '\0'; int index = 0; TRY { fsd_calloc( buffer, size + 1, char ); errno = 0; /* reset errno as getc seems not to do this and it would be inpossible to distinc between EOF and an error*/ while( (ch = getc(f)) != EOF) /* getc is buffered internally */ { if (ch == '\n') break; if( index >= (int)size ) { size *= 2; fsd_realloc( buffer, size + 1, char ); } buffer[index++] = (char)ch; } if ( (ch == '\n') /* end of line */ || (ch == EOF && !errno) /* true EOF */) { if (index == 0) { result = NULL; /*nothing read = return NULL */ } else { buffer[index]= '\0'; /* just in case - calloc memset to 0 */ result = fsd_strdup(buffer); } } else if (ch == EOF && errno) { fsd_exc_raise_sys( 0 ); } else { fsd_assert(0); /*not reached */ } } FINALLY { fsd_free( buffer ); } END_TRY return result; } const char * fsd_strsignal( int signum ) { #define DETECT_SIG( signame ) \ case signame: return #signame; switch( signum ) { /* signals described by POSIX.1 */ DETECT_SIG( SIGHUP ) DETECT_SIG( SIGINT ) DETECT_SIG( SIGQUIT ) DETECT_SIG( SIGILL ) DETECT_SIG( SIGABRT ) DETECT_SIG( SIGFPE ) DETECT_SIG( SIGKILL ) DETECT_SIG( SIGSEGV ) DETECT_SIG( SIGPIPE ) DETECT_SIG( SIGALRM ) DETECT_SIG( SIGTERM ) DETECT_SIG( SIGUSR1 ) DETECT_SIG( SIGUSR2 ) DETECT_SIG( SIGCHLD ) DETECT_SIG( SIGCONT ) DETECT_SIG( SIGSTOP ) DETECT_SIG( SIGTSTP ) DETECT_SIG( SIGTTIN ) DETECT_SIG( SIGTTOU ) /* signals described in SUSv2 and SUSv3 / POSIX 1003.1-2001 */ #ifdef SIGBUS DETECT_SIG( SIGBUS ) #endif #ifdef SIGPOLL DETECT_SIG( SIGPOLL ) #endif #ifdef SIGPROF DETECT_SIG( SIGPROF ) #endif #ifdef SIGSYS DETECT_SIG( SIGSYS ) #endif #ifdef SIGTRAP DETECT_SIG( SIGTRAP ) #endif #ifdef SIGURG DETECT_SIG( SIGURG ) #endif #ifdef SIGVTALRM DETECT_SIG( SIGVTALRM ) #endif #ifdef SIGXCPU DETECT_SIG( SIGXCPU ) #endif #ifdef SIGXFSZ DETECT_SIG( SIGXFSZ ) #endif default: # ifdef HAVE_SYS_SIGLIST return sys_siglist[signum]; # else return "unknown signal?!"; # endif break; } }