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.
18 @brief A collection of various low-level utility functions.
20 About half of these functions concern the growing_buffer structure,
21 a sort of poor man's string class that allocates more space for
24 #include <opensrf/utils.h>
25 #include <opensrf/log.h>
29 @brief A thin wrapper for malloc().
31 @param size How many bytes to allocate.
32 @return a pointer to the allocated memory.
34 If the allocation fails, safe_malloc calls exit(). Consequently the
35 calling code doesn't have to check for NULL.
37 Currently safe_malloc() initializes the allocated buffer to all-bits-zero.
38 However the calling code should not rely on this behavior, because it is
39 likely to change. If you need your buffer filled with all-bits-zero, then
40 call safe_calloc() instead, or fill it yourself by calling memset().
42 inline void* safe_malloc( int size ) {
43 void* ptr = (void*) malloc( size );
45 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
48 memset( ptr, 0, size ); // remove this after safe_calloc transition
53 @brief A thin wrapper for calloc().
55 @param size How many bytes to allocate.
56 @return a pointer to the allocated memory.
58 If the allocation fails, safe_calloc calls exit(). Consequently the
59 calling code doesn't have to check for NULL.
61 inline void* safe_calloc( int size ) {
62 void* ptr = (void*) calloc( 1, size );
64 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
71 @brief Saves a pointer to the beginning of the argv[] array from main(). See init_proc_title().
73 static char** global_argv = NULL;
75 @brief Saves the length of the argv[] array from main(). See init_proc_title().
77 static int global_argv_size = 0;
80 @brief Save the size and location of the argv[] array.
81 @param argc The argc parameter to main().
82 @param argv The argv parameter to main().
85 Save a pointer to the argv[] array in the local static variable
86 global_argv. Add up the lengths of the strings in the argv[]
87 array, subtract 2, and store the result in the local variable
90 The return value, being invariant, is useless.
92 This function prepares for a subsequent call to set_proc_title().
94 int init_proc_title( int argc, char* argv[] ) {
100 int len = strlen( global_argv[i]);
101 osrf_clearbuf( global_argv[i], len );
102 global_argv_size += len;
106 global_argv_size -= 2;
111 @brief Replace the name of the running executable.
112 @param format A printf-style format string. Subsequent parameters, if any,
113 provide values to be formatted and inserted into the format string.
114 @return Length of the resulting string (or what the length would be if the
115 receiving buffer were big enough to hold it), or -1 in case of an encoding
116 error. Note: because some older versions of snprintf() don't work correctly,
117 this function may return -1 if the string is truncated for lack of space.
119 Formats a string as directed, and uses it to replace the name of the
120 currently running executable. This replacement string is what will
121 be seen and reported by utilities such as ps and top.
123 The replacement string goes into a location identified by a previous call
124 to init_proc_title().
126 WARNING: this function makes assumptions about the memory layout of
127 the argv[] array. ANSI C does not guarantee that these assumptions
130 int set_proc_title( const char* format, ... ) {
131 VA_LIST_TO_STRING(format);
132 osrf_clearbuf( *(global_argv), global_argv_size);
133 return snprintf( *(global_argv), global_argv_size, VA_BUF );
137 @brief Determine current date and time to high precision.
138 @return Current date and time as seconds since the Epoch.
140 Used for profiling. The time resolution is system-dependent but is no finer
143 double get_timestamp_millis( void ) {
145 gettimeofday(&tv, NULL);
146 double time = (int)tv.tv_sec + ( ((double)tv.tv_usec / 1000000) );
152 @brief Set designated file status flags for an open file descriptor.
153 @param fd The file descriptor to be tweaked.
154 @param flags A set of bitflags.
155 @return 0 if successful, -1 or if not.
157 Whatever bits are set in the flags parameter become set in the file status flags of
158 the file descriptor -- subject to the limitation that the only bits affected (at
159 least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
163 int set_fl( int fd, int flags ) {
167 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
172 if( fcntl( fd, F_SETFL, val ) < 0 )
179 @brief Clear designated file status flags for an open file descriptor.
180 @param fd The file descriptor to be tweaked.
181 @param flags A set of bitflags.
182 @return 0 if successful, or -1 if not.
184 Whatever bits are set in the flags parameter become cleared in the file status flags
185 of the file descriptor -- subject to the limitation that the only bits affected (at
186 least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
190 int clr_fl( int fd, int flags ) {
194 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
199 if( fcntl( fd, F_SETFL, val ) < 0 )
206 @brief Determine how lohg a string will be after printf-style formatting.
207 @param format The format string.
208 @param args The variable-length list of arguments
209 @return If successful: the length of the string that would be created, plus 1 for
210 a terminal nul, plus another 1, presumably to be on the safe side. If unsuccessful
211 due to a formatting error: 1.
213 WARNINGS: the first parameter is not checked for NULL. The return value in case of an
214 error is not obviously sensible.
216 long va_list_size(const char* format, va_list args) {
218 len = vsnprintf(NULL, 0, format, args);
225 @brief Format a printf-style string into a newly allocated buffer.
226 @param format The format string. Subsequent parameters, if any, will be
227 formatted and inserted into the resulting string.
228 @return A pointer to the string so created.
230 The calling code is responsible for freeing the string.
232 char* va_list_to_string(const char* format, ...) {
238 va_copy(a_copy, args);
240 va_start(args, format);
241 len = va_list_size(format, args);
244 osrf_clearbuf(buf, sizeof(buf));
246 va_start(a_copy, format);
247 vsnprintf(buf, len - 1, format, a_copy);
252 // ---------------------------------------------------------------------------------
253 // Flesh out a ubiqitous growing string buffer
254 // ---------------------------------------------------------------------------------
257 @brief Create a growing_buffer containing an empty string.
258 @param num_initial_bytes The initial size of the internal buffer, not counting the
260 @return A pointer to the newly created growing_buffer.
262 The value of num_initial_bytes should typically be a plausible guess of how big
263 the string will ever be. However the guess doesn't have to accurate, because more
264 memory will be allocated as needed.
266 The calling code is responsible for freeing the growing_buffer by calling buffer_free()
269 growing_buffer* buffer_init(int num_initial_bytes) {
271 if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
273 size_t len = sizeof(growing_buffer);
276 OSRF_MALLOC(gb, len);
278 gb->n_used = 0;/* nothing stored so far */
279 gb->size = num_initial_bytes;
280 OSRF_MALLOC(gb->buf, gb->size + 1);
287 @brief Allocate more memory for a growing_buffer.
288 @param gb A pointer to the growing_buffer.
289 @return 0 if successful, or 1 if not.
291 This function fails if it is asked to allocate BUFFER_MAX_SIZE
294 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
296 // We do not check to see if the buffer is already big enough. It is the
297 //responsibility of the calling function to call this only when necessary.
299 // Make sure the request is not excessive
301 if( total_len >= BUFFER_MAX_SIZE ) {
302 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
303 (unsigned long) BUFFER_MAX_SIZE );
308 // Pick a big enough buffer size, but don't exceed a maximum
310 while( total_len >= gb->size ) {
314 if( gb->size > BUFFER_MAX_SIZE )
315 gb->size = BUFFER_MAX_SIZE;
317 // Allocate and populate the new buffer
320 OSRF_MALLOC( new_data, gb->size );
321 memcpy( new_data, gb->buf, gb->n_used );
322 new_data[ gb->n_used ] = '\0';
324 // Replace the old buffer
333 @brief Append a formatted string to a growing_buffer.
334 @param gb A pointer to the growing_buffer.
335 @param format A printf-style format string. Subsequent parameters, if any, will be
336 formatted and inserted into the resulting string.
337 @return If successful,the length of the resulting string; otherwise -1.
339 This function fails if either of the first two parameters is NULL,
340 or if the resulting string requires BUFFER_MAX_SIZE or more bytes.
342 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
344 if(!gb || !format) return -1;
350 va_copy(a_copy, args);
352 va_start(args, format);
353 len = va_list_size(format, args);
356 osrf_clearbuf(buf, sizeof(buf));
358 va_start(a_copy, format);
359 vsnprintf(buf, len - 1, format, a_copy);
362 return buffer_add(gb, buf);
367 @brief Appends a string to a growing_buffer.
368 @param gb A pointer to the growing_buffer.
369 @param data A pointer to the string to be appended.
370 @return If successful, the length of the resulting string; or if not, -1.
372 int buffer_add(growing_buffer* gb, const char* data) {
373 if(!(gb && data)) return -1;
375 int data_len = strlen( data );
377 if(data_len == 0) return gb->n_used;
379 int total_len = data_len + gb->n_used;
381 if( total_len >= gb->size ) {
382 if( buffer_expand( gb, total_len ) )
386 strcpy( gb->buf + gb->n_used, data );
387 gb->n_used = total_len;
392 @brief Append a specified number of characters to a growing_buffer.
393 @param gb A pointer to the growing_buffer.
394 @param data A pointer to the characters to be appended.
395 @param n How many characters to be append.
396 @return If sccessful, the length of the resulting string; or if not, -1.
398 If the characters to be appended include an embedded nul byte, it will be appended
399 along with the others. The results are likely to be unpleasant.
401 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
402 if(!(gb && data)) return -1;
406 int total_len = n + gb->n_used;
408 if( total_len >= gb->size ) {
409 if( buffer_expand( gb, total_len ) )
413 memcpy( gb->buf + gb->n_used, data, n );
414 gb->buf[total_len] = '\0';
415 gb->n_used = total_len;
421 @brief Reset a growing_buffer so that it contains an empty string.
422 @param gb A pointer to the growing_buffer.
423 @return 0 if successful, -1 if not.
425 int buffer_reset( growing_buffer *gb){
426 if( gb == NULL ) { return -1; }
427 if( gb->buf == NULL ) { return -1; }
428 osrf_clearbuf( gb->buf, gb->size );
435 @brief Free a growing_buffer and return a pointer to the string inside.
436 @param gb A pointer to the growing_buffer.
437 @return A pointer to the string previously contained by the growing buffer.
439 The calling code is responsible for freeing the string.
441 This function is equivalent to buffer_data() followed by buffer_free(). However
442 it is more efficient, because it avoids calls to strudup and free().
444 char* buffer_release( growing_buffer* gb) {
446 s[gb->n_used] = '\0';
452 @brief Free a growing_buffer and its contents.
453 @param gb A pointer to the growing_buffer.
454 @return 1 if successful, or 0 if not (because the input parameter is NULL).
456 int buffer_free( growing_buffer* gb ) {
465 @brief Create a copy of the string inside a growing_buffer.
466 @param gb A pointer to the growing_buffer.
467 @return A pointer to the newly created copy.
469 The growing_buffer itself is not affected.
471 The calling code is responsible for freeing the string.
473 char* buffer_data( const growing_buffer *gb) {
474 return strdup( gb->buf );
478 @brief Remove the last character from a growing_buffer.
479 @param gb A pointer to the growing_buffer.
480 @return The character removed (or '\0' if the string is already empty).
482 char buffer_chomp(growing_buffer* gb) {
484 if(gb && gb->n_used > 0) {
486 c = gb->buf[gb->n_used];
487 gb->buf[gb->n_used] = '\0';
494 @brief Append a single character to a growing_buffer.
495 @param gb A pointer to the growing_buffer.
496 @param c The character to be appended.
497 @return The length of the resulting string.
499 If the character appended is a nul byte (i.e. '\0') it will still be appended as if
500 it were a normal character. The results are likely to be unpleasant.
502 int buffer_add_char(growing_buffer* gb, char c ) {
505 int total_len = gb->n_used + 1;
507 if( total_len >= gb->size ) {
508 if( buffer_expand( gb, total_len ) )
512 gb->buf[ gb->n_used ] = c;
513 gb->buf[ ++gb->n_used ] = '\0';
521 @brief Translate a UTF8 string into escaped ASCII, suitable for JSON.
522 @param string The input string to be translated.
523 @param size The length of the input string (need not be accurate).
524 @param full_escape Boolean; true turns on the escaping of certain
526 @return A pointer to the translated version of the string.
528 Deprecated. Use buffer_append_utf8() instead.
530 If full_escape is non-zero, the translation will escape certain
531 certain characters with a backslash, according to the conventions
532 used in C and other languages: quotation marks, bell characters,
533 form feeds, horizontal tabs, carriage returns, line feeds, and
534 backslashes. A character with a numerical value less than 32, and
535 not one of the special characters mentioned above, will be
536 translated to a backslash followed by four hexadecimal characters.
538 If full_escape is zero, the translation will (incorrectly) leave
539 these characters unescaped and unchanged.
541 The calling code is responsible for freeing the returned string.
543 char* uescape( const char* string, int size, int full_escape ) {
548 growing_buffer* buf = buffer_init(size + 64);
551 unsigned long int c = 0x0;
553 while (string[idx]) {
557 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
559 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
562 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
564 c = (unsigned char)string[idx] ^ 0xF0;
566 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
568 c = (unsigned char)string[idx] ^ 0xE0;
570 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
572 c = (unsigned char)string[idx] ^ 0xC0;
577 idx++; // look at the next byte
578 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
582 buffer_fadd(buf, "\\u%04x", c);
592 /* escape the usual suspects */
596 OSRF_BUFFER_ADD_CHAR(buf, '\\');
597 OSRF_BUFFER_ADD_CHAR(buf, '"');
601 OSRF_BUFFER_ADD_CHAR(buf, '\\');
602 OSRF_BUFFER_ADD_CHAR(buf, 'b');
606 OSRF_BUFFER_ADD_CHAR(buf, '\\');
607 OSRF_BUFFER_ADD_CHAR(buf, 'f');
611 OSRF_BUFFER_ADD_CHAR(buf, '\\');
612 OSRF_BUFFER_ADD_CHAR(buf, 't');
616 OSRF_BUFFER_ADD_CHAR(buf, '\\');
617 OSRF_BUFFER_ADD_CHAR(buf, 'n');
621 OSRF_BUFFER_ADD_CHAR(buf, '\\');
622 OSRF_BUFFER_ADD_CHAR(buf, 'r');
626 OSRF_BUFFER_ADD_CHAR(buf, '\\');
627 OSRF_BUFFER_ADD_CHAR(buf, '\\');
631 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
632 else OSRF_BUFFER_ADD_CHAR(buf, c);
636 OSRF_BUFFER_ADD_CHAR(buf, c);
643 return buffer_release(buf);
648 @brief Become a proper daemon.
649 @return 0 if successful, or -1 if not.
651 Call fork(). The parent exits. The child moves to the root
652 directory, detaches from the terminal, and redirects the
653 standard streams (stdin, stdout, stderr) to /dev/null.
655 int daemonize( void ) {
659 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
662 } else if (f == 0) { // We're in the child now...
664 // Change directories. Otherwise whatever directory
665 // we're in couldn't be deleted until the program
666 // terminated -- possibly causing some inconvenience.
669 /* create new session */
672 // Now that we're no longer attached to a terminal,
673 // we don't want any traffic on the standard streams
674 freopen( "/dev/null", "r", stdin );
675 freopen( "/dev/null", "w", stdout );
676 freopen( "/dev/null", "w", stderr );
680 } else { // We're in the parent...
687 @brief Determine whether a string represents a decimal integer.
688 @param s A pointer to the string.
689 @return 1 if the string represents a decimal integer, or 0 if it
692 To qualify as a decimal integer, the string must consist entirely
693 of optional leading white space, an optional leading sign, and
694 one or more decimal digits. In addition, the number must be
695 representable as a long.
697 int stringisnum(const char* s) {
706 @brief Translate a printf-style formatted string into an MD5 message digest.
707 @param text The format string. Subsequent parameters, if any, provide values to be
708 formatted and inserted into the format string.
709 @return A pointer to a string of 32 hexadecimal characters.
711 The calling code is responsible for freeing the returned string.
713 This function is a wrapper for some public domain routines written by David Madore,
714 Ron Rivest, and Colin Plumb.
716 char* md5sum( const char* text, ... ) {
719 unsigned char digest[16];
723 VA_LIST_TO_STRING(text);
726 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
727 MD5_feed (&ctx, VA_BUF[i]);
729 MD5_stop (&ctx, digest);
733 osrf_clearbuf(final, sizeof(final));
735 for ( i=0 ; i<16 ; i++ ) {
736 snprintf(buf, sizeof(buf), "%02x", digest[i]);
737 strcat( final, buf );
740 return strdup(final);
745 @brief Determine whether a given file descriptor is valid.
746 @param fd The file descriptor to be checked.
747 @return 0 if the file descriptor is valid, or -1 if it isn't.
749 The most likely reason a file descriptor would be invalid is if it isn't open.
751 int osrfUtilsCheckFileDescriptor( int fd ) {
761 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
762 if( errno == EBADF ) return -1;