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
118 Formats a string as directed, and uses it to replace the name of the
119 currently running executable. This replacement string is what will
120 be seen and reported by utilities such as ps and top.
122 The replacement string goes into a location identified by a previous call
123 to init_proc_title().
125 WARNING: this function makes assumptions about the memory layout of
126 the argv[] array. ANSI C does not guarantee that these assumptions
129 int set_proc_title( const char* format, ... ) {
130 VA_LIST_TO_STRING(format);
131 osrf_clearbuf( *(global_argv), global_argv_size);
132 (void) strncpy( *(global_argv), VA_BUF, global_argv_size - 1 );
133 if (strlen(VA_BUF) >= global_argv_size) {
134 *(global_argv)[global_argv_size - 1] = '\0';
136 return (strlen(VA_BUF) > strlen(*(global_argv))) ? strlen(VA_BUF) : strlen(*(global_argv));
140 @brief Determine current date and time to high precision.
141 @return Current date and time as seconds since the Epoch.
143 Used for profiling. The time resolution is system-dependent but is no finer
146 double get_timestamp_millis( void ) {
148 gettimeofday(&tv, NULL);
149 double time = (int)tv.tv_sec + ( ((double)tv.tv_usec / 1000000) );
155 @brief Set designated file status flags for an open file descriptor.
156 @param fd The file descriptor to be tweaked.
157 @param flags A set of bitflags.
158 @return 0 if successful, -1 or if not.
160 Whatever bits are set in the flags parameter become set in the file status flags of
161 the file descriptor -- subject to the limitation that the only bits affected (at
162 least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
166 int set_fl( int fd, int flags ) {
170 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
175 if( fcntl( fd, F_SETFL, val ) < 0 )
182 @brief Clear designated file status flags for an open file descriptor.
183 @param fd The file descriptor to be tweaked.
184 @param flags A set of bitflags.
185 @return 0 if successful, or -1 if not.
187 Whatever bits are set in the flags parameter become cleared in the file status flags
188 of the file descriptor -- subject to the limitation that the only bits affected (at
189 least on Linux) are O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
193 int clr_fl( int fd, int flags ) {
197 if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
202 if( fcntl( fd, F_SETFL, val ) < 0 )
209 @brief Determine how lohg a string will be after printf-style formatting.
210 @param format The format string.
211 @param args The variable-length list of arguments
212 @return If successful: the length of the string that would be created, plus 1 for
213 a terminal nul, plus another 1, presumably to be on the safe side. If unsuccessful
214 due to a formatting error: 1.
216 WARNINGS: the first parameter is not checked for NULL. The return value in case of an
217 error is not obviously sensible.
219 long va_list_size(const char* format, va_list args) {
221 len = vsnprintf(NULL, 0, format, args);
228 @brief Format a printf-style string into a newly allocated buffer.
229 @param format The format string. Subsequent parameters, if any, will be
230 formatted and inserted into the resulting string.
231 @return A pointer to the string so created.
233 The calling code is responsible for freeing the string.
235 char* va_list_to_string(const char* format, ...) {
241 va_copy(a_copy, args);
242 va_start(args, format);
244 char* buf = safe_malloc( va_list_size(format, args) );
247 va_start(a_copy, format);
248 vsnprintf(buf, len - 1, format, a_copy);
253 // ---------------------------------------------------------------------------------
254 // Flesh out a ubiqitous growing string buffer
255 // ---------------------------------------------------------------------------------
258 @brief Create a growing_buffer containing an empty string.
259 @param num_initial_bytes The initial size of the internal buffer, not counting the
261 @return A pointer to the newly created growing_buffer.
263 The value of num_initial_bytes should typically be a plausible guess of how big
264 the string will ever be. However the guess doesn't have to accurate, because more
265 memory will be allocated as needed.
267 The calling code is responsible for freeing the growing_buffer by calling osrf_buffer_free()
268 or osrf_buffer_release().
270 growing_buffer* osrf_buffer_init(int num_initial_bytes) {
272 if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
274 size_t len = sizeof(growing_buffer);
277 OSRF_MALLOC(gb, len);
279 gb->n_used = 0;/* nothing stored so far */
280 gb->size = num_initial_bytes;
281 OSRF_MALLOC(gb->buf, gb->size + 1);
286 growing_buffer* buffer_init( int initial_num_bytes) {
287 return osrf_buffer_init(initial_num_bytes);
292 @brief Allocate more memory for a growing_buffer.
293 @param gb A pointer to the growing_buffer.
294 @param total_len How much total memory we need for the buffer.
295 @return 0 if successful, or 1 if not.
297 This function fails if it is asked to allocate BUFFER_MAX_SIZE
300 static int osrf_buffer_expand( growing_buffer* gb, size_t total_len ) {
302 // We do not check to see if the buffer is already big enough. It is the
303 //responsibility of the calling function to call this only when necessary.
305 // Make sure the request is not excessive
307 if( total_len >= BUFFER_MAX_SIZE ) {
308 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
309 (unsigned long) BUFFER_MAX_SIZE );
310 osrf_buffer_free( gb );
314 // Pick a big enough buffer size, but don't exceed a maximum
316 while( total_len >= gb->size ) {
320 if( gb->size > BUFFER_MAX_SIZE )
321 gb->size = BUFFER_MAX_SIZE;
323 // Allocate and populate the new buffer
326 OSRF_MALLOC( new_data, gb->size );
327 memcpy( new_data, gb->buf, gb->n_used );
328 new_data[ gb->n_used ] = '\0';
330 // Replace the old buffer
337 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
338 return osrf_buffer_expand(gb, total_len);
342 @brief Append a formatted string to a growing_buffer.
343 @param gb A pointer to the growing_buffer.
344 @param format A printf-style format string. Subsequent parameters, if any, will be
345 formatted and inserted into the resulting string.
346 @return If successful,the length of the resulting string; otherwise -1.
348 This function fails if either of the first two parameters is NULL,
349 or if the resulting string requires BUFFER_MAX_SIZE or more bytes.
351 int osrf_buffer_fadd(growing_buffer* gb, const char* format, ... ) {
353 if(!gb || !format) return -1;
359 va_copy(a_copy, args);
361 va_start(args, format);
362 len = va_list_size(format, args);
365 osrf_clearbuf(buf, sizeof(buf));
367 va_start(a_copy, format);
368 vsnprintf(buf, len - 1, format, a_copy);
371 return osrf_buffer_add(gb, buf);
374 /* Just repeating this wholesale because varargs is *handwave* unhappy *handwave* about something. */
375 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
377 if(!gb || !format) return -1;
383 va_copy(a_copy, args);
385 va_start(args, format);
386 len = va_list_size(format, args);
389 osrf_clearbuf(buf, sizeof(buf));
391 va_start(a_copy, format);
392 vsnprintf(buf, len - 1, format, a_copy);
395 return osrf_buffer_add(gb, buf);
400 @brief Appends a string to a growing_buffer.
401 @param gb A pointer to the growing_buffer.
402 @param data A pointer to the string to be appended.
403 @return If successful, the length of the resulting string; or if not, -1.
405 int osrf_buffer_add(growing_buffer* gb, const char* data) {
406 if(!(gb && data)) return -1;
408 int data_len = strlen( data );
410 if(data_len == 0) return gb->n_used;
412 int total_len = data_len + gb->n_used;
414 if( total_len >= gb->size ) {
415 if( osrf_buffer_expand( gb, total_len ) )
419 strcpy( gb->buf + gb->n_used, data );
420 gb->n_used = total_len;
424 int buffer_add(growing_buffer* gb, const char* c) {
425 return osrf_buffer_add(gb, c);
429 @brief Append a specified number of characters to a growing_buffer.
430 @param gb A pointer to the growing_buffer.
431 @param data A pointer to the characters to be appended.
432 @param n How many characters to be append.
433 @return If sccessful, the length of the resulting string; or if not, -1.
435 If the characters to be appended include an embedded nul byte, it will be appended
436 along with the others. The results are likely to be unpleasant.
438 int osrf_buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
439 if(!(gb && data)) return -1;
443 int total_len = n + gb->n_used;
445 if( total_len >= gb->size ) {
446 if( osrf_buffer_expand( gb, total_len ) )
450 memcpy( gb->buf + gb->n_used, data, n );
451 gb->buf[total_len] = '\0';
452 gb->n_used = total_len;
456 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
457 return osrf_buffer_add_n(gb, data, n);
461 @brief Reset a growing_buffer so that it contains an empty string.
462 @param gb A pointer to the growing_buffer.
463 @return 0 if successful, -1 if not.
465 int osrf_buffer_reset( growing_buffer *gb){
466 if( gb == NULL ) { return -1; }
467 if( gb->buf == NULL ) { return -1; }
468 osrf_clearbuf( gb->buf, gb->size );
474 int buffer_reset( growing_buffer* gb) {
475 return osrf_buffer_reset(gb);
479 @brief Free a growing_buffer and return a pointer to the string inside.
480 @param gb A pointer to the growing_buffer.
481 @return A pointer to the string previously contained by the growing buffer.
483 The calling code is responsible for freeing the string.
485 This function is equivalent to osrf_buffer_data() followed by osrf_buffer_free(). However
486 it is more efficient, because it avoids calls to strudup and free().
488 char* osrf_buffer_release( growing_buffer* gb) {
490 s[gb->n_used] = '\0';
495 char* buffer_release( growing_buffer* gb ) {
496 return osrf_buffer_release(gb);
500 @brief Free a growing_buffer and its contents.
501 @param gb A pointer to the growing_buffer.
502 @return 1 if successful, or 0 if not (because the input parameter is NULL).
504 int osrf_buffer_free( growing_buffer* gb ) {
512 int buffer_free( growing_buffer* gb ) {
513 return osrf_buffer_free(gb);
517 @brief Create a copy of the string inside a growing_buffer.
518 @param gb A pointer to the growing_buffer.
519 @return A pointer to the newly created copy.
521 The growing_buffer itself is not affected.
523 The calling code is responsible for freeing the string.
525 char* osrf_buffer_data( const growing_buffer *gb) {
526 return strdup( gb->buf );
529 char* buffer_data( const growing_buffer* gb) {
530 return osrf_buffer_data(gb);
534 @brief Remove the last character from a growing_buffer.
535 @param gb A pointer to the growing_buffer.
536 @return The character removed (or a nul byte if the string is already empty).
538 char osrf_buffer_chomp(growing_buffer* gb) {
540 if(gb && gb->n_used > 0) {
542 c = gb->buf[gb->n_used];
543 gb->buf[gb->n_used] = '\0';
548 char buffer_chomp(growing_buffer* gb) {
549 return osrf_buffer_chomp(gb);
553 @brief Append a single character to a growing_buffer.
554 @param gb A pointer to the growing_buffer.
555 @param c The character to be appended.
556 @return The length of the resulting string.
558 If the character appended is a nul byte it will still be appended as if
559 it were a normal character. The results are likely to be unpleasant.
561 int osrf_buffer_add_char(growing_buffer* gb, char c ) {
564 int total_len = gb->n_used + 1;
566 if( total_len >= gb->size ) {
567 if( osrf_buffer_expand( gb, total_len ) )
571 gb->buf[ gb->n_used ] = c;
572 gb->buf[ ++gb->n_used ] = '\0';
578 int buffer_add_char(growing_buffer* gb, char c) {
579 return osrf_buffer_add_char(gb, c);
583 @brief Translate a UTF8 string into escaped ASCII, suitable for JSON.
584 @param string The input string to be translated.
585 @param size The length of the input string (need not be accurate).
586 @param full_escape Boolean; true turns on the escaping of certain
588 @return A pointer to the translated version of the string.
590 Deprecated. Use osrf_buffer_append_utf8() instead.
592 If full_escape is non-zero, the translation will escape certain
593 certain characters with a backslash, according to the conventions
594 used in C and other languages: quotation marks, bell characters,
595 form feeds, horizontal tabs, carriage returns, line feeds, and
596 backslashes. A character with a numerical value less than 32, and
597 not one of the special characters mentioned above, will be
598 translated to a backslash followed by four hexadecimal characters.
600 If full_escape is zero, the translation will (incorrectly) leave
601 these characters unescaped and unchanged.
603 The calling code is responsible for freeing the returned string.
605 char* uescape( const char* string, int size, int full_escape ) {
610 growing_buffer* buf = osrf_buffer_init(size + 64);
613 unsigned long int c = 0x0;
615 while (string[idx]) {
619 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
621 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
624 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
626 c = (unsigned char)string[idx] ^ 0xF0;
628 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
630 c = (unsigned char)string[idx] ^ 0xE0;
632 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
634 c = (unsigned char)string[idx] ^ 0xC0;
639 idx++; // look at the next byte
640 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
644 osrf_buffer_fadd(buf, "\\u%04x", c);
647 osrf_buffer_free(buf);
654 /* escape the usual suspects */
658 OSRF_BUFFER_ADD_CHAR(buf, '\\');
659 OSRF_BUFFER_ADD_CHAR(buf, '"');
663 OSRF_BUFFER_ADD_CHAR(buf, '\\');
664 OSRF_BUFFER_ADD_CHAR(buf, 'b');
668 OSRF_BUFFER_ADD_CHAR(buf, '\\');
669 OSRF_BUFFER_ADD_CHAR(buf, 'f');
673 OSRF_BUFFER_ADD_CHAR(buf, '\\');
674 OSRF_BUFFER_ADD_CHAR(buf, 't');
678 OSRF_BUFFER_ADD_CHAR(buf, '\\');
679 OSRF_BUFFER_ADD_CHAR(buf, 'n');
683 OSRF_BUFFER_ADD_CHAR(buf, '\\');
684 OSRF_BUFFER_ADD_CHAR(buf, 'r');
688 OSRF_BUFFER_ADD_CHAR(buf, '\\');
689 OSRF_BUFFER_ADD_CHAR(buf, '\\');
693 if( c < 32 ) osrf_buffer_fadd(buf, "\\u%04x", c);
694 else OSRF_BUFFER_ADD_CHAR(buf, c);
698 OSRF_BUFFER_ADD_CHAR(buf, c);
705 return osrf_buffer_release(buf);
710 @brief Become a proper daemon.
711 @param callback Ptr to a function. From parent, called with child PID as first argument, and the next argument to *this* function as the second argument. From child, called with -1, -1 (yes pid_t is signed)
712 @param callback_arg An integer argument passed as the second argument to the callback function from the parent process post-fork()
713 @return 0 if successful, or -1 if not.
715 Call fork(). The parent exits. The child moves to the root directory, detaches from
716 the terminal, and redirects the standard streams (stdin, stdout, stderr) to /dev/null.
718 int daemonizeWithCallback( void (*callback)(pid_t, int), int callback_arg ) {
722 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
725 } else if (f == 0) { // We're in the child now...
730 // Change directories. Otherwise whatever directory
731 // we're in couldn't be deleted until the program
732 // terminated -- possibly causing some inconvenience.
733 (void) (chdir( "/" )+1);
735 /* create new session */
738 // Now that we're no longer attached to a terminal,
739 // we don't want any traffic on the standard streams
740 (void) (freopen( "/dev/null", "r", stdin )+1);
741 (void) (freopen( "/dev/null", "w", stdout )+1);
742 (void) (freopen( "/dev/null", "w", stderr )+1);
746 } else { // We're in the parent...
748 callback( f, callback_arg );
755 @brief Become a proper daemon.
756 @return 0 if successful, or -1 if not.
758 See daemonizeWithCallback() for details.
760 int daemonize( void ) {
761 return daemonizeWithCallback( NULL, 0 );
766 @brief Determine whether a string represents a decimal integer.
767 @param s A pointer to the string.
768 @return 1 if the string represents a decimal integer, or 0 if it
771 To qualify as a decimal integer, the string must consist entirely
772 of optional leading white space, an optional leading sign, and
773 one or more decimal digits. In addition, the number must be
774 representable as a long.
776 int stringisnum(const char* s) {
785 @brief Translate a printf-style formatted string into an MD5 message digest.
786 @param text The format string. Subsequent parameters, if any, provide values to be
787 formatted and inserted into the format string.
788 @return A pointer to a string of 32 hexadecimal characters.
790 The calling code is responsible for freeing the returned string.
792 This function is a wrapper for some public domain routines written by David Madore,
793 Ron Rivest, and Colin Plumb.
795 char* md5sum( const char* text ) {
798 unsigned char digest[16];
803 for ( i=0 ; i != strlen(text) ; i++ )
804 MD5_feed (&ctx, text[i]);
806 MD5_stop (&ctx, digest);
809 char final[ 1 + 2 * sizeof( digest ) ];
812 for ( i=0 ; i<16 ; i++ ) {
813 snprintf(buf, sizeof(buf), "%02x", digest[i]);
814 strcat( final, buf );
817 return strdup(final);
822 @brief Determine whether a given file descriptor is valid.
823 @param fd The file descriptor to be checked.
824 @return 0 if the file descriptor is valid, or -1 if it isn't.
826 The most likely reason a file descriptor would be invalid is if it isn't open.
828 int osrfUtilsCheckFileDescriptor( int fd ) {
838 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
839 if( errno == EBADF ) return -1;
845 size_t osrfXmlEscapingLength ( const char* str ) {
848 for (s = str; *s; ++s) {