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 );
285 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
288 if(gb->n_used < gb->size - 1)\
289 gb->buf[gb->n_used++] = c;\
291 buffer_add_char(gb, c);\
296 int buffer_add_char(growing_buffer* gb, char c ) {
299 int total_len = gb->n_used + 1;
301 if( total_len >= gb->size ) {
302 if( buffer_expand( gb, total_len ) )
306 gb->buf[ gb->n_used ] = c;
307 gb->buf[ ++gb->n_used ] = '\0';
314 char* uescape( const char* string, int size, int full_escape ) {
316 growing_buffer* buf = buffer_init(size + 64);
319 unsigned long int c = 0x0;
321 while (string[idx]) {
325 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
327 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
330 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
332 c = (unsigned char)string[idx] ^ 0xF0;
334 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
336 c = (unsigned char)string[idx] ^ 0xE0;
338 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
340 c = (unsigned char)string[idx] ^ 0xC0;
345 idx++; // look at the next byte
346 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
350 buffer_fadd(buf, "\\u%04x", c);
360 /* escape the usual suspects */
364 OSRF_BUFFER_ADD_CHAR(buf, '\\');
365 OSRF_BUFFER_ADD_CHAR(buf, '"');
369 OSRF_BUFFER_ADD_CHAR(buf, '\\');
370 OSRF_BUFFER_ADD_CHAR(buf, 'b');
374 OSRF_BUFFER_ADD_CHAR(buf, '\\');
375 OSRF_BUFFER_ADD_CHAR(buf, 'f');
379 OSRF_BUFFER_ADD_CHAR(buf, '\\');
380 OSRF_BUFFER_ADD_CHAR(buf, 't');
384 OSRF_BUFFER_ADD_CHAR(buf, '\\');
385 OSRF_BUFFER_ADD_CHAR(buf, 'n');
389 OSRF_BUFFER_ADD_CHAR(buf, '\\');
390 OSRF_BUFFER_ADD_CHAR(buf, 'r');
394 OSRF_BUFFER_ADD_CHAR(buf, '\\');
395 OSRF_BUFFER_ADD_CHAR(buf, '\\');
399 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
400 else OSRF_BUFFER_ADD_CHAR(buf, c);
404 OSRF_BUFFER_ADD_CHAR(buf, c);
411 return buffer_release(buf);
415 // A function to turn a process into a daemon
416 int daemonize( void ) {
420 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
423 } else if (f == 0) { // We're in the child now...
425 // Change directories. Otherwise whatever directory
426 // we're in couldn't be deleted until the program
427 // terminated -- possibly causing some inconvenience.
430 /* create new session */
433 // Now that we're no longer attached to a terminal,
434 // we don't want any traffic on the standard streams
435 freopen( "/dev/null", "r", stdin );
436 freopen( "/dev/null", "w", stdout );
437 freopen( "/dev/null", "w", stderr );
441 } else { // We're in the parent...
447 /* Return 1 if the string represents an integer, */
448 /* as recognized by strtol(); Otherwise return 0. */
450 int stringisnum(const char* s) {
458 char* file_to_string(const char* filename) {
460 if(!filename) return NULL;
462 FILE * file = fopen( filename, "r" );
464 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
469 char buf[ BUFSIZ + 1 ];
470 growing_buffer* gb = buffer_init(sizeof(buf));
472 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
473 buf[ num_read ] = '\0';
479 return buffer_release(gb);
483 char* md5sum( const char* text, ... ) {
486 unsigned char digest[16];
490 VA_LIST_TO_STRING(text);
493 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
494 MD5_feed (&ctx, VA_BUF[i]);
496 MD5_stop (&ctx, digest);
500 osrf_clearbuf(final, sizeof(final));
502 for ( i=0 ; i<16 ; i++ ) {
503 snprintf(buf, sizeof(buf), "%02x", digest[i]);
504 strcat( final, buf );
507 return strdup(final);
511 int osrfUtilsCheckFileDescriptor( int fd ) {
521 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
522 if( errno == EBADF ) return -1;