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 static const char hex_chars[] = "0123456789abcdef";
20 static unsigned char hex_code[7] = "\\u00";
22 inline void* safe_malloc( int size ) {
23 void* ptr = (void*) malloc( size );
25 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
28 memset( ptr, 0, size ); // remove this after safe_calloc transition
32 inline void* safe_calloc( int size ) {
33 void* ptr = (void*) calloc( 1, size );
35 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
42 The following static variables, and the following two functions,
43 overwrite the argv array passed to main(). The purpose is to
44 change the program name as reported by ps and similar utilities.
46 Warning: this code makes the non-portable assumption that the
47 strings to which argv[] points are contiguous in memory. The
48 C Standard makes no such guarantee.
50 static char** global_argv = NULL;
51 static int global_argv_size = 0;
53 int init_proc_title( int argc, char* argv[] ) {
59 int len = strlen( global_argv[i]);
60 osrf_clearbuf( global_argv[i], len );
61 global_argv_size += len;
65 global_argv_size -= 2;
69 int set_proc_title( const char* format, ... ) {
70 VA_LIST_TO_STRING(format);
71 osrf_clearbuf( *(global_argv), global_argv_size);
72 return snprintf( *(global_argv), global_argv_size, VA_BUF );
76 /* utility method for profiling */
77 double get_timestamp_millis( void ) {
79 gettimeofday(&tv, NULL);
80 double time = (int)tv.tv_sec + ( ((double)tv.tv_usec / 1000000) );
85 /* setting/clearing file flags */
86 int set_fl( int fd, int flags ) {
90 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
95 if( fcntl( fd, F_SETFL, val ) < 0 )
101 int clr_fl( int fd, int flags ) {
105 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
110 if( fcntl( fd, F_SETFL, val ) < 0 )
116 long va_list_size(const char* format, va_list args) {
118 len = vsnprintf(NULL, 0, format, args);
125 char* va_list_to_string(const char* format, ...) {
131 va_copy(a_copy, args);
133 va_start(args, format);
134 len = va_list_size(format, args);
137 osrf_clearbuf(buf, sizeof(buf));
139 va_start(a_copy, format);
140 vsnprintf(buf, len - 1, format, a_copy);
145 // ---------------------------------------------------------------------------------
146 // Flesh out a ubiqitous growing string buffer
147 // ---------------------------------------------------------------------------------
149 growing_buffer* buffer_init(int num_initial_bytes) {
151 if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
153 size_t len = sizeof(growing_buffer);
156 OSRF_MALLOC(gb, len);
158 gb->n_used = 0;/* nothing stored so far */
159 gb->size = num_initial_bytes;
160 OSRF_MALLOC(gb->buf, gb->size + 1);
166 /* Expand the internal buffer of a growing_buffer so that it */
167 /* will accommodate a specified string length. Return 0 if */
168 /* successful, or 1 otherwise. */
170 /* Note that we do not check to see if the buffer is already */
171 /* big enough. It is the responsibility of the calling */
172 /* function to call this only when necessary. */
174 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
176 // Make sure the request is not excessive
178 if( total_len >= BUFFER_MAX_SIZE ) {
179 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
180 (unsigned long) BUFFER_MAX_SIZE );
185 // Pick a big enough buffer size, but don't exceed a maximum
187 while( total_len >= gb->size ) {
191 if( gb->size > BUFFER_MAX_SIZE )
192 gb->size = BUFFER_MAX_SIZE;
194 // Allocate and populate the new buffer
197 OSRF_MALLOC( new_data, gb->size );
198 memcpy( new_data, gb->buf, gb->n_used );
199 new_data[ gb->n_used ] = '\0';
201 // Replace the old buffer
209 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
211 if(!gb || !format) return 0;
217 va_copy(a_copy, args);
219 va_start(args, format);
220 len = va_list_size(format, args);
223 osrf_clearbuf(buf, sizeof(buf));
225 va_start(a_copy, format);
226 vsnprintf(buf, len - 1, format, a_copy);
229 return buffer_add(gb, buf);
234 int buffer_add(growing_buffer* gb, const char* data) {
235 if(!(gb && data)) return 0;
237 int data_len = strlen( data );
239 if(data_len == 0) return 0;
241 int total_len = data_len + gb->n_used;
243 if( total_len >= gb->size ) {
244 if( buffer_expand( gb, total_len ) )
248 strcpy( gb->buf + gb->n_used, data );
249 gb->n_used = total_len;
254 int buffer_reset( growing_buffer *gb){
255 if( gb == NULL ) { return -1; }
256 if( gb->buf == NULL ) { return -1; }
257 osrf_clearbuf( gb->buf, gb->size );
263 /* Return a pointer to the text within a growing_buffer, */
264 /* while destroying the growing_buffer itself. */
266 char* buffer_release( growing_buffer* gb) {
268 s[gb->n_used] = '\0';
273 /* Destroy a growing_buffer and the text it contains */
275 int buffer_free( growing_buffer* gb ) {
283 char* buffer_data( const growing_buffer *gb) {
284 return strdup( gb->buf );
287 int buffer_chomp(growing_buffer* gb) {
288 if( gb == NULL ) { return -1; }
291 gb->buf[gb->n_used] = '\0';
298 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
301 if(gb->n_used < gb->size - 1)\
302 gb->buf[gb->n_used++] = c;\
304 buffer_add_char(gb, c);\
309 int buffer_add_char(growing_buffer* gb, char c ) {
312 int total_len = gb->n_used + 1;
314 if( total_len >= gb->size ) {
315 if( buffer_expand( gb, total_len ) )
319 gb->buf[ gb->n_used ] = c;
320 gb->buf[ ++gb->n_used ] = '\0';
327 char* uescape( const char* string, int size, int full_escape ) {
332 growing_buffer* buf = buffer_init(size + 64);
335 unsigned long int c = 0x0;
337 while (string[idx]) {
341 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
343 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
346 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
348 c = (unsigned char)string[idx] ^ 0xF0;
350 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
352 c = (unsigned char)string[idx] ^ 0xE0;
354 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
356 c = (unsigned char)string[idx] ^ 0xC0;
361 idx++; // look at the next byte
362 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
366 buffer_fadd(buf, "\\u%04x", c);
376 /* escape the usual suspects */
380 OSRF_BUFFER_ADD_CHAR(buf, '\\');
381 OSRF_BUFFER_ADD_CHAR(buf, '"');
385 OSRF_BUFFER_ADD_CHAR(buf, '\\');
386 OSRF_BUFFER_ADD_CHAR(buf, 'b');
390 OSRF_BUFFER_ADD_CHAR(buf, '\\');
391 OSRF_BUFFER_ADD_CHAR(buf, 'f');
395 OSRF_BUFFER_ADD_CHAR(buf, '\\');
396 OSRF_BUFFER_ADD_CHAR(buf, 't');
400 OSRF_BUFFER_ADD_CHAR(buf, '\\');
401 OSRF_BUFFER_ADD_CHAR(buf, 'n');
405 OSRF_BUFFER_ADD_CHAR(buf, '\\');
406 OSRF_BUFFER_ADD_CHAR(buf, 'r');
410 OSRF_BUFFER_ADD_CHAR(buf, '\\');
411 OSRF_BUFFER_ADD_CHAR(buf, '\\');
415 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
416 else OSRF_BUFFER_ADD_CHAR(buf, c);
420 OSRF_BUFFER_ADD_CHAR(buf, c);
427 return buffer_release(buf);
430 int buffer_append_uescape( growing_buffer* buf, const char* string ) {
433 return 0; // Nothing to add? Nothing to do
436 return -1; // Nothing to add to
441 while (string[idx]) {
445 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
447 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
450 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
452 c = (unsigned char)string[idx] ^ 0xF0;
454 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
456 c = (unsigned char)string[idx] ^ 0xE0;
458 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
460 c = (unsigned char)string[idx] ^ 0xC0;
465 idx++; // look at the next byte
466 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
469 buffer_fadd(buf, "\\u%04x", c);
475 } else if(string[idx] >= ' ' ) { // printable ASCII character
481 OSRF_BUFFER_ADD_CHAR(buf, '\\');
482 OSRF_BUFFER_ADD_CHAR(buf, c);
486 OSRF_BUFFER_ADD_CHAR(buf, c);
492 /* escape the usual suspects */
495 OSRF_BUFFER_ADD_CHAR(buf, '\\');
496 OSRF_BUFFER_ADD_CHAR(buf, 'b');
500 OSRF_BUFFER_ADD_CHAR(buf, '\\');
501 OSRF_BUFFER_ADD_CHAR(buf, 'f');
505 OSRF_BUFFER_ADD_CHAR(buf, '\\');
506 OSRF_BUFFER_ADD_CHAR(buf, 't');
510 OSRF_BUFFER_ADD_CHAR(buf, '\\');
511 OSRF_BUFFER_ADD_CHAR(buf, 'n');
515 OSRF_BUFFER_ADD_CHAR(buf, '\\');
516 OSRF_BUFFER_ADD_CHAR(buf, 'r');
521 // Represent as \u followed by four hex characters
522 hex_code[ 4 ] = hex_chars[ c >> 4 ]; // high nybble
523 hex_code[ 5 ] = hex_chars[ c & 0x0F ]; // low nybble
524 hex_code[ 6 ] = '\0';
525 OSRF_BUFFER_ADD(buf, (char *) hex_code);
537 // A function to turn a process into a daemon
538 int daemonize( void ) {
542 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
545 } else if (f == 0) { // We're in the child now...
547 // Change directories. Otherwise whatever directory
548 // we're in couldn't be deleted until the program
549 // terminated -- possibly causing some inconvenience.
552 /* create new session */
555 // Now that we're no longer attached to a terminal,
556 // we don't want any traffic on the standard streams
557 freopen( "/dev/null", "r", stdin );
558 freopen( "/dev/null", "w", stdout );
559 freopen( "/dev/null", "w", stderr );
563 } else { // We're in the parent...
569 /* Return 1 if the string represents an integer, */
570 /* as recognized by strtol(); Otherwise return 0. */
572 int stringisnum(const char* s) {
580 char* file_to_string(const char* filename) {
582 if(!filename) return NULL;
584 FILE * file = fopen( filename, "r" );
586 osrfLogError( OSRF_LOG_MARK, "Unable to open file [%s]", filename );
591 char buf[ BUFSIZ + 1 ];
592 growing_buffer* gb = buffer_init(sizeof(buf));
594 while( ( num_read = fread( buf, 1, sizeof(buf) - 1, file) ) ) {
595 buf[ num_read ] = '\0';
601 return buffer_release(gb);
605 char* md5sum( const char* text, ... ) {
608 unsigned char digest[16];
612 VA_LIST_TO_STRING(text);
615 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
616 MD5_feed (&ctx, VA_BUF[i]);
618 MD5_stop (&ctx, digest);
622 osrf_clearbuf(final, sizeof(final));
624 for ( i=0 ; i<16 ; i++ ) {
625 snprintf(buf, sizeof(buf), "%02x", digest[i]);
626 strcat( final, buf );
629 return strdup(final);
633 int osrfUtilsCheckFileDescriptor( int fd ) {
643 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
644 if( errno == EBADF ) return -1;