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 char buffer_chomp(growing_buffer* gb) {
286 if(gb && gb->n_used > 0) {
288 c = gb->buf[gb->n_used];
289 gb->buf[gb->n_used] = '\0';
295 int buffer_add_char(growing_buffer* gb, char c ) {
298 int total_len = gb->n_used + 1;
300 if( total_len >= gb->size ) {
301 if( buffer_expand( gb, total_len ) )
305 gb->buf[ gb->n_used ] = c;
306 gb->buf[ ++gb->n_used ] = '\0';
313 char* uescape( const char* string, int size, int full_escape ) {
318 growing_buffer* buf = buffer_init(size + 64);
321 unsigned long int c = 0x0;
323 while (string[idx]) {
327 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
329 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
332 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
334 c = (unsigned char)string[idx] ^ 0xF0;
336 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
338 c = (unsigned char)string[idx] ^ 0xE0;
340 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
342 c = (unsigned char)string[idx] ^ 0xC0;
347 idx++; // look at the next byte
348 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
352 buffer_fadd(buf, "\\u%04x", c);
362 /* escape the usual suspects */
366 OSRF_BUFFER_ADD_CHAR(buf, '\\');
367 OSRF_BUFFER_ADD_CHAR(buf, '"');
371 OSRF_BUFFER_ADD_CHAR(buf, '\\');
372 OSRF_BUFFER_ADD_CHAR(buf, 'b');
376 OSRF_BUFFER_ADD_CHAR(buf, '\\');
377 OSRF_BUFFER_ADD_CHAR(buf, 'f');
381 OSRF_BUFFER_ADD_CHAR(buf, '\\');
382 OSRF_BUFFER_ADD_CHAR(buf, 't');
386 OSRF_BUFFER_ADD_CHAR(buf, '\\');
387 OSRF_BUFFER_ADD_CHAR(buf, 'n');
391 OSRF_BUFFER_ADD_CHAR(buf, '\\');
392 OSRF_BUFFER_ADD_CHAR(buf, 'r');
396 OSRF_BUFFER_ADD_CHAR(buf, '\\');
397 OSRF_BUFFER_ADD_CHAR(buf, '\\');
401 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
402 else OSRF_BUFFER_ADD_CHAR(buf, c);
406 OSRF_BUFFER_ADD_CHAR(buf, c);
413 return buffer_release(buf);
417 // A function to turn a process into a daemon
418 int daemonize( void ) {
422 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
425 } else if (f == 0) { // We're in the child now...
427 // Change directories. Otherwise whatever directory
428 // we're in couldn't be deleted until the program
429 // terminated -- possibly causing some inconvenience.
432 /* create new session */
435 // Now that we're no longer attached to a terminal,
436 // we don't want any traffic on the standard streams
437 freopen( "/dev/null", "r", stdin );
438 freopen( "/dev/null", "w", stdout );
439 freopen( "/dev/null", "w", stderr );
443 } else { // We're in the parent...
449 /* Return 1 if the string represents an integer, */
450 /* as recognized by strtol(); Otherwise return 0. */
452 int stringisnum(const char* s) {
460 char* file_to_string(const char* filename) {
462 if(!filename) return NULL;
464 FILE * file = fopen( filename, "r" );
466 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
471 char buf[ BUFSIZ + 1 ];
472 growing_buffer* gb = buffer_init(sizeof(buf));
474 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
475 buf[ num_read ] = '\0';
481 return buffer_release(gb);
485 char* md5sum( const char* text, ... ) {
488 unsigned char digest[16];
492 VA_LIST_TO_STRING(text);
495 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
496 MD5_feed (&ctx, VA_BUF[i]);
498 MD5_stop (&ctx, digest);
502 osrf_clearbuf(final, sizeof(final));
504 for ( i=0 ; i<16 ; i++ ) {
505 snprintf(buf, sizeof(buf), "%02x", digest[i]);
506 strcat( final, buf );
509 return strdup(final);
513 int osrfUtilsCheckFileDescriptor( int fd ) {
523 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
524 if( errno == EBADF ) return -1;