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;
250 /** Append a specified number of characters to a growing_buffer.
251 If the characters so appended include an embedded nul, the results
252 are likely to be unhappy.
254 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
255 if(!(gb && data)) return 0;
259 int total_len = n + gb->n_used;
261 if( total_len >= gb->size ) {
262 if( buffer_expand( gb, total_len ) )
266 memcpy( gb->buf + gb->n_used, data, n );
267 gb->buf[total_len] = '\0';
268 gb->n_used = total_len;
273 int buffer_reset( growing_buffer *gb){
274 if( gb == NULL ) { return -1; }
275 if( gb->buf == NULL ) { return -1; }
276 osrf_clearbuf( gb->buf, gb->size );
282 /* Return a pointer to the text within a growing_buffer, */
283 /* while destroying the growing_buffer itself. */
285 char* buffer_release( growing_buffer* gb) {
287 s[gb->n_used] = '\0';
292 /* Destroy a growing_buffer and the text it contains */
294 int buffer_free( growing_buffer* gb ) {
302 char* buffer_data( const growing_buffer *gb) {
303 return strdup( gb->buf );
306 char buffer_chomp(growing_buffer* gb) {
308 if(gb && gb->n_used > 0) {
310 c = gb->buf[gb->n_used];
311 gb->buf[gb->n_used] = '\0';
317 int buffer_add_char(growing_buffer* gb, char c ) {
320 int total_len = gb->n_used + 1;
322 if( total_len >= gb->size ) {
323 if( buffer_expand( gb, total_len ) )
327 gb->buf[ gb->n_used ] = c;
328 gb->buf[ ++gb->n_used ] = '\0';
335 char* uescape( const char* string, int size, int full_escape ) {
340 growing_buffer* buf = buffer_init(size + 64);
343 unsigned long int c = 0x0;
345 while (string[idx]) {
349 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
351 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
354 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
356 c = (unsigned char)string[idx] ^ 0xF0;
358 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
360 c = (unsigned char)string[idx] ^ 0xE0;
362 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
364 c = (unsigned char)string[idx] ^ 0xC0;
369 idx++; // look at the next byte
370 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
374 buffer_fadd(buf, "\\u%04x", c);
384 /* escape the usual suspects */
388 OSRF_BUFFER_ADD_CHAR(buf, '\\');
389 OSRF_BUFFER_ADD_CHAR(buf, '"');
393 OSRF_BUFFER_ADD_CHAR(buf, '\\');
394 OSRF_BUFFER_ADD_CHAR(buf, 'b');
398 OSRF_BUFFER_ADD_CHAR(buf, '\\');
399 OSRF_BUFFER_ADD_CHAR(buf, 'f');
403 OSRF_BUFFER_ADD_CHAR(buf, '\\');
404 OSRF_BUFFER_ADD_CHAR(buf, 't');
408 OSRF_BUFFER_ADD_CHAR(buf, '\\');
409 OSRF_BUFFER_ADD_CHAR(buf, 'n');
413 OSRF_BUFFER_ADD_CHAR(buf, '\\');
414 OSRF_BUFFER_ADD_CHAR(buf, 'r');
418 OSRF_BUFFER_ADD_CHAR(buf, '\\');
419 OSRF_BUFFER_ADD_CHAR(buf, '\\');
423 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
424 else OSRF_BUFFER_ADD_CHAR(buf, c);
428 OSRF_BUFFER_ADD_CHAR(buf, c);
435 return buffer_release(buf);
439 // A function to turn a process into a daemon
440 int daemonize( void ) {
444 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
447 } else if (f == 0) { // We're in the child now...
449 // Change directories. Otherwise whatever directory
450 // we're in couldn't be deleted until the program
451 // terminated -- possibly causing some inconvenience.
454 /* create new session */
457 // Now that we're no longer attached to a terminal,
458 // we don't want any traffic on the standard streams
459 freopen( "/dev/null", "r", stdin );
460 freopen( "/dev/null", "w", stdout );
461 freopen( "/dev/null", "w", stderr );
465 } else { // We're in the parent...
471 /* Return 1 if the string represents an integer, */
472 /* as recognized by strtol(); Otherwise return 0. */
474 int stringisnum(const char* s) {
482 char* file_to_string(const char* filename) {
484 if(!filename) return NULL;
486 FILE * file = fopen( filename, "r" );
488 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
493 char buf[ BUFSIZ + 1 ];
494 growing_buffer* gb = buffer_init(sizeof(buf));
496 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
497 buf[ num_read ] = '\0';
503 return buffer_release(gb);
507 char* md5sum( const char* text, ... ) {
510 unsigned char digest[16];
514 VA_LIST_TO_STRING(text);
517 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
518 MD5_feed (&ctx, VA_BUF[i]);
520 MD5_stop (&ctx, digest);
524 osrf_clearbuf(final, sizeof(final));
526 for ( i=0 ; i<16 ; i++ ) {
527 snprintf(buf, sizeof(buf), "%02x", digest[i]);
528 strcat( final, buf );
531 return strdup(final);
535 int osrfUtilsCheckFileDescriptor( int fd ) {
545 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
546 if( errno == EBADF ) return -1;