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 strcat( gb->buf, 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, sizeof(gb->buf) );
259 /* Return a pointer to the text within a growing_buffer, */
260 /* while destroying the growing_buffer itself. */
262 char* buffer_release( growing_buffer* gb) {
264 s[gb->n_used] = '\0';
269 /* Destroy a growing_buffer and the text it contains */
271 int buffer_free( growing_buffer* gb ) {
279 char* buffer_data( const growing_buffer *gb) {
280 return strdup( gb->buf );
283 int buffer_chomp(growing_buffer* gb) {
284 if( gb == NULL ) { return -1; }
287 gb->buf[gb->n_used] = '\0';
294 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
297 if(gb->n_used < gb->size - 1)\
298 gb->buf[gb->n_used++] = c;\
300 buffer_add_char(gb, c);\
305 int buffer_add_char(growing_buffer* gb, char c ) {
308 int total_len = gb->n_used + 1;
310 if( total_len >= gb->size ) {
311 if( buffer_expand( gb, total_len ) )
315 gb->buf[ gb->n_used ] = c;
316 gb->buf[ ++gb->n_used ] = '\0';
323 char* uescape( const char* string, int size, int full_escape ) {
325 growing_buffer* buf = buffer_init(size + 64);
328 unsigned long int c = 0x0;
330 while (string[idx]) {
334 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
336 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
339 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
341 c = (unsigned char)string[idx] ^ 0xF0;
343 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
345 c = (unsigned char)string[idx] ^ 0xE0;
347 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
349 c = (unsigned char)string[idx] ^ 0xC0;
354 idx++; // look at the next byte
355 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
359 buffer_fadd(buf, "\\u%04x", c);
369 /* escape the usual suspects */
373 OSRF_BUFFER_ADD_CHAR(buf, '\\');
374 OSRF_BUFFER_ADD_CHAR(buf, '"');
378 OSRF_BUFFER_ADD_CHAR(buf, '\\');
379 OSRF_BUFFER_ADD_CHAR(buf, 'b');
383 OSRF_BUFFER_ADD_CHAR(buf, '\\');
384 OSRF_BUFFER_ADD_CHAR(buf, 'f');
388 OSRF_BUFFER_ADD_CHAR(buf, '\\');
389 OSRF_BUFFER_ADD_CHAR(buf, 't');
393 OSRF_BUFFER_ADD_CHAR(buf, '\\');
394 OSRF_BUFFER_ADD_CHAR(buf, 'n');
398 OSRF_BUFFER_ADD_CHAR(buf, '\\');
399 OSRF_BUFFER_ADD_CHAR(buf, 'r');
403 OSRF_BUFFER_ADD_CHAR(buf, '\\');
404 OSRF_BUFFER_ADD_CHAR(buf, '\\');
408 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
409 else OSRF_BUFFER_ADD_CHAR(buf, c);
413 OSRF_BUFFER_ADD_CHAR(buf, c);
420 return buffer_release(buf);
424 // A function to turn a process into a daemon
425 int daemonize( void ) {
429 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
432 } else if (f == 0) { // We're in the child now...
434 // Change directories. Otherwise whatever directory
435 // we're in couldn't be deleted until the program
436 // terminated -- possibly causing some inconvenience.
439 /* create new session */
442 // Now that we're no longer attached to a terminal,
443 // we don't want any traffic on the standard streams
444 freopen( "/dev/null", "r", stdin );
445 freopen( "/dev/null", "w", stdout );
446 freopen( "/dev/null", "w", stderr );
450 } else { // We're in the parent...
456 /* Return 1 if the string represents an integer, */
457 /* as recognized by strtol(); Otherwise return 0. */
459 int stringisnum(const char* s) {
467 char* file_to_string(const char* filename) {
469 if(!filename) return NULL;
471 FILE * file = fopen( filename, "r" );
473 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
478 char buf[ BUFSIZ + 1 ];
479 growing_buffer* gb = buffer_init(sizeof(buf));
481 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
482 buf[ num_read ] = '\0';
488 return buffer_release(gb);
492 char* md5sum( const char* text, ... ) {
495 unsigned char digest[16];
499 VA_LIST_TO_STRING(text);
502 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
503 MD5_feed (&ctx, VA_BUF[i]);
505 MD5_stop (&ctx, digest);
509 osrf_clearbuf(final, sizeof(final));
511 for ( i=0 ; i<16 ; i++ ) {
512 snprintf(buf, sizeof(buf), "%02x", digest[i]);
513 strcat( final, buf );
516 return strdup(final);
520 int osrfUtilsCheckFileDescriptor( int fd ) {
530 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
531 if( errno == EBADF ) return -1;