2 Copyright (C) 2005 Georgia Public Library Service
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
15 #include <opensrf/utils.h>
16 #include <opensrf/log.h>
19 inline void* safe_malloc( int size ) {
20 void* ptr = (void*) malloc( size );
22 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
25 memset( ptr, 0, size ); // remove this after safe_calloc transition
29 inline void* safe_calloc( int size ) {
30 void* ptr = (void*) calloc( 1, size );
32 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
39 The following static variables, and the following two functions,
40 overwrite the argv array passed to main(). The purpose is to
41 change the program name as reported by ps and similar utilities.
43 Warning: this code makes the non-portable assumption that the
44 strings to which argv[] points are contiguous in memory. The
45 C Standard makes no such guarantee.
47 static char** global_argv = NULL;
48 static int global_argv_size = 0;
50 int init_proc_title( int argc, char* argv[] ) {
56 int len = strlen( global_argv[i]);
57 osrf_clearbuf( global_argv[i], len );
58 global_argv_size += len;
62 global_argv_size -= 2;
66 int set_proc_title( const char* format, ... ) {
67 VA_LIST_TO_STRING(format);
68 osrf_clearbuf( *(global_argv), global_argv_size);
69 return snprintf( *(global_argv), global_argv_size, VA_BUF );
73 /* utility method for profiling */
74 double get_timestamp_millis( void ) {
76 gettimeofday(&tv, NULL);
77 double time = (int)tv.tv_sec + ( ((double)tv.tv_usec / 1000000) );
82 /* setting/clearing file flags */
83 int set_fl( int fd, int flags ) {
87 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
92 if( fcntl( fd, F_SETFL, val ) < 0 )
98 int clr_fl( int fd, int flags ) {
102 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
107 if( fcntl( fd, F_SETFL, val ) < 0 )
113 long va_list_size(const char* format, va_list args) {
115 len = vsnprintf(NULL, 0, format, args);
122 char* va_list_to_string(const char* format, ...) {
128 va_copy(a_copy, args);
130 va_start(args, format);
131 len = va_list_size(format, args);
134 osrf_clearbuf(buf, sizeof(buf));
136 va_start(a_copy, format);
137 vsnprintf(buf, len - 1, format, a_copy);
142 // ---------------------------------------------------------------------------------
143 // Flesh out a ubiqitous growing string buffer
144 // ---------------------------------------------------------------------------------
146 growing_buffer* buffer_init(int num_initial_bytes) {
148 if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
150 size_t len = sizeof(growing_buffer);
153 OSRF_MALLOC(gb, len);
155 gb->n_used = 0;/* nothing stored so far */
156 gb->size = num_initial_bytes;
157 OSRF_MALLOC(gb->buf, gb->size + 1);
163 /* Expand the internal buffer of a growing_buffer so that it */
164 /* will accommodate a specified string length. Return 0 if */
165 /* successful, or 1 otherwise. */
167 /* Note that we do not check to see if the buffer is already */
168 /* big enough. It is the responsibility of the calling */
169 /* function to call this only when necessary. */
171 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
173 // Make sure the request is not excessive
175 if( total_len >= BUFFER_MAX_SIZE ) {
176 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
177 (unsigned long) BUFFER_MAX_SIZE );
182 // Pick a big enough buffer size, but don't exceed a maximum
184 while( total_len >= gb->size ) {
188 if( gb->size > BUFFER_MAX_SIZE )
189 gb->size = BUFFER_MAX_SIZE;
191 // Allocate and populate the new buffer
194 OSRF_MALLOC( new_data, gb->size );
195 memcpy( new_data, gb->buf, gb->n_used );
196 new_data[ gb->n_used ] = '\0';
198 // Replace the old buffer
206 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
208 if(!gb || !format) return 0;
214 va_copy(a_copy, args);
216 va_start(args, format);
217 len = va_list_size(format, args);
220 osrf_clearbuf(buf, sizeof(buf));
222 va_start(a_copy, format);
223 vsnprintf(buf, len - 1, format, a_copy);
226 return buffer_add(gb, buf);
231 int buffer_add(growing_buffer* gb, const char* data) {
232 if(!(gb && data)) return 0;
234 int data_len = strlen( data );
236 if(data_len == 0) return 0;
238 int total_len = data_len + gb->n_used;
240 if( total_len >= gb->size ) {
241 if( buffer_expand( gb, total_len ) )
245 strcpy( gb->buf + gb->n_used, data );
246 gb->n_used = total_len;
251 int buffer_reset( growing_buffer *gb){
252 if( gb == NULL ) { return -1; }
253 if( gb->buf == NULL ) { return -1; }
254 osrf_clearbuf( gb->buf, gb->size );
260 /* Return a pointer to the text within a growing_buffer, */
261 /* while destroying the growing_buffer itself. */
263 char* buffer_release( growing_buffer* gb) {
265 s[gb->n_used] = '\0';
270 /* Destroy a growing_buffer and the text it contains */
272 int buffer_free( growing_buffer* gb ) {
280 char* buffer_data( const growing_buffer *gb) {
281 return strdup( gb->buf );
284 int buffer_chomp(growing_buffer* gb) {
285 if( gb == NULL ) { return -1; }
288 gb->buf[gb->n_used] = '\0';
295 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
298 if(gb->n_used < gb->size - 1)\
299 gb->buf[gb->n_used++] = c;\
301 buffer_add_char(gb, c);\
306 int buffer_add_char(growing_buffer* gb, char c ) {
309 int total_len = gb->n_used + 1;
311 if( total_len >= gb->size ) {
312 if( buffer_expand( gb, total_len ) )
316 gb->buf[ gb->n_used ] = c;
317 gb->buf[ ++gb->n_used ] = '\0';
324 char* uescape( const char* string, int size, int full_escape ) {
329 growing_buffer* buf = buffer_init(size + 64);
332 unsigned long int c = 0x0;
334 while (string[idx]) {
338 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
340 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
343 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
345 c = (unsigned char)string[idx] ^ 0xF0;
347 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
349 c = (unsigned char)string[idx] ^ 0xE0;
351 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
353 c = (unsigned char)string[idx] ^ 0xC0;
358 idx++; // look at the next byte
359 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
363 buffer_fadd(buf, "\\u%04x", c);
373 /* escape the usual suspects */
377 OSRF_BUFFER_ADD_CHAR(buf, '\\');
378 OSRF_BUFFER_ADD_CHAR(buf, '"');
382 OSRF_BUFFER_ADD_CHAR(buf, '\\');
383 OSRF_BUFFER_ADD_CHAR(buf, 'b');
387 OSRF_BUFFER_ADD_CHAR(buf, '\\');
388 OSRF_BUFFER_ADD_CHAR(buf, 'f');
392 OSRF_BUFFER_ADD_CHAR(buf, '\\');
393 OSRF_BUFFER_ADD_CHAR(buf, 't');
397 OSRF_BUFFER_ADD_CHAR(buf, '\\');
398 OSRF_BUFFER_ADD_CHAR(buf, 'n');
402 OSRF_BUFFER_ADD_CHAR(buf, '\\');
403 OSRF_BUFFER_ADD_CHAR(buf, 'r');
407 OSRF_BUFFER_ADD_CHAR(buf, '\\');
408 OSRF_BUFFER_ADD_CHAR(buf, '\\');
412 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
413 else OSRF_BUFFER_ADD_CHAR(buf, c);
417 OSRF_BUFFER_ADD_CHAR(buf, c);
424 return buffer_release(buf);
428 // A function to turn a process into a daemon
429 int daemonize( void ) {
433 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
436 } else if (f == 0) { // We're in the child now...
438 // Change directories. Otherwise whatever directory
439 // we're in couldn't be deleted until the program
440 // terminated -- possibly causing some inconvenience.
443 /* create new session */
446 // Now that we're no longer attached to a terminal,
447 // we don't want any traffic on the standard streams
448 freopen( "/dev/null", "r", stdin );
449 freopen( "/dev/null", "w", stdout );
450 freopen( "/dev/null", "w", stderr );
454 } else { // We're in the parent...
460 /* Return 1 if the string represents an integer, */
461 /* as recognized by strtol(); Otherwise return 0. */
463 int stringisnum(const char* s) {
471 char* file_to_string(const char* filename) {
473 if(!filename) return NULL;
475 FILE * file = fopen( filename, "r" );
477 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
482 char buf[ BUFSIZ + 1 ];
483 growing_buffer* gb = buffer_init(sizeof(buf));
485 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
486 buf[ num_read ] = '\0';
492 return buffer_release(gb);
496 char* md5sum( const char* text, ... ) {
499 unsigned char digest[16];
503 VA_LIST_TO_STRING(text);
506 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
507 MD5_feed (&ctx, VA_BUF[i]);
509 MD5_stop (&ctx, digest);
513 osrf_clearbuf(final, sizeof(final));
515 for ( i=0 ; i<16 ; i++ ) {
516 snprintf(buf, sizeof(buf), "%02x", digest[i]);
517 strcat( final, buf );
520 return strdup(final);
524 int osrfUtilsCheckFileDescriptor( int fd ) {
534 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
535 if( errno == EBADF ) return -1;