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 buffer_free()
270 growing_buffer* 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);
288 @brief Allocate more memory for a growing_buffer.
289 @param gb A pointer to the growing_buffer.
290 @param total_len How much total memory we need for the buffer.
291 @return 0 if successful, or 1 if not.
293 This function fails if it is asked to allocate BUFFER_MAX_SIZE
296 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
298 // We do not check to see if the buffer is already big enough. It is the
299 //responsibility of the calling function to call this only when necessary.
301 // Make sure the request is not excessive
303 if( total_len >= BUFFER_MAX_SIZE ) {
304 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
305 (unsigned long) BUFFER_MAX_SIZE );
310 // Pick a big enough buffer size, but don't exceed a maximum
312 while( total_len >= gb->size ) {
316 if( gb->size > BUFFER_MAX_SIZE )
317 gb->size = BUFFER_MAX_SIZE;
319 // Allocate and populate the new buffer
322 OSRF_MALLOC( new_data, gb->size );
323 memcpy( new_data, gb->buf, gb->n_used );
324 new_data[ gb->n_used ] = '\0';
326 // Replace the old buffer
335 @brief Append a formatted string to a growing_buffer.
336 @param gb A pointer to the growing_buffer.
337 @param format A printf-style format string. Subsequent parameters, if any, will be
338 formatted and inserted into the resulting string.
339 @return If successful,the length of the resulting string; otherwise -1.
341 This function fails if either of the first two parameters is NULL,
342 or if the resulting string requires BUFFER_MAX_SIZE or more bytes.
344 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
346 if(!gb || !format) return -1;
352 va_copy(a_copy, args);
354 va_start(args, format);
355 len = va_list_size(format, args);
358 osrf_clearbuf(buf, sizeof(buf));
360 va_start(a_copy, format);
361 vsnprintf(buf, len - 1, format, a_copy);
364 return buffer_add(gb, buf);
369 @brief Appends a string to a growing_buffer.
370 @param gb A pointer to the growing_buffer.
371 @param data A pointer to the string to be appended.
372 @return If successful, the length of the resulting string; or if not, -1.
374 int buffer_add(growing_buffer* gb, const char* data) {
375 if(!(gb && data)) return -1;
377 int data_len = strlen( data );
379 if(data_len == 0) return gb->n_used;
381 int total_len = data_len + gb->n_used;
383 if( total_len >= gb->size ) {
384 if( buffer_expand( gb, total_len ) )
388 strcpy( gb->buf + gb->n_used, data );
389 gb->n_used = total_len;
394 @brief Append a specified number of characters to a growing_buffer.
395 @param gb A pointer to the growing_buffer.
396 @param data A pointer to the characters to be appended.
397 @param n How many characters to be append.
398 @return If sccessful, the length of the resulting string; or if not, -1.
400 If the characters to be appended include an embedded nul byte, it will be appended
401 along with the others. The results are likely to be unpleasant.
403 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
404 if(!(gb && data)) return -1;
408 int total_len = n + gb->n_used;
410 if( total_len >= gb->size ) {
411 if( buffer_expand( gb, total_len ) )
415 memcpy( gb->buf + gb->n_used, data, n );
416 gb->buf[total_len] = '\0';
417 gb->n_used = total_len;
423 @brief Reset a growing_buffer so that it contains an empty string.
424 @param gb A pointer to the growing_buffer.
425 @return 0 if successful, -1 if not.
427 int buffer_reset( growing_buffer *gb){
428 if( gb == NULL ) { return -1; }
429 if( gb->buf == NULL ) { return -1; }
430 osrf_clearbuf( gb->buf, gb->size );
437 @brief Free a growing_buffer and return a pointer to the string inside.
438 @param gb A pointer to the growing_buffer.
439 @return A pointer to the string previously contained by the growing buffer.
441 The calling code is responsible for freeing the string.
443 This function is equivalent to buffer_data() followed by buffer_free(). However
444 it is more efficient, because it avoids calls to strudup and free().
446 char* buffer_release( growing_buffer* gb) {
448 s[gb->n_used] = '\0';
454 @brief Free a growing_buffer and its contents.
455 @param gb A pointer to the growing_buffer.
456 @return 1 if successful, or 0 if not (because the input parameter is NULL).
458 int buffer_free( growing_buffer* gb ) {
467 @brief Create a copy of the string inside a growing_buffer.
468 @param gb A pointer to the growing_buffer.
469 @return A pointer to the newly created copy.
471 The growing_buffer itself is not affected.
473 The calling code is responsible for freeing the string.
475 char* buffer_data( const growing_buffer *gb) {
476 return strdup( gb->buf );
480 @brief Remove the last character from a growing_buffer.
481 @param gb A pointer to the growing_buffer.
482 @return The character removed (or a nul byte if the string is already empty).
484 char buffer_chomp(growing_buffer* gb) {
486 if(gb && gb->n_used > 0) {
488 c = gb->buf[gb->n_used];
489 gb->buf[gb->n_used] = '\0';
496 @brief Append a single character to a growing_buffer.
497 @param gb A pointer to the growing_buffer.
498 @param c The character to be appended.
499 @return The length of the resulting string.
501 If the character appended is a nul byte it will still be appended as if
502 it were a normal character. The results are likely to be unpleasant.
504 int buffer_add_char(growing_buffer* gb, char c ) {
507 int total_len = gb->n_used + 1;
509 if( total_len >= gb->size ) {
510 if( buffer_expand( gb, total_len ) )
514 gb->buf[ gb->n_used ] = c;
515 gb->buf[ ++gb->n_used ] = '\0';
523 @brief Translate a UTF8 string into escaped ASCII, suitable for JSON.
524 @param string The input string to be translated.
525 @param size The length of the input string (need not be accurate).
526 @param full_escape Boolean; true turns on the escaping of certain
528 @return A pointer to the translated version of the string.
530 Deprecated. Use buffer_append_utf8() instead.
532 If full_escape is non-zero, the translation will escape certain
533 certain characters with a backslash, according to the conventions
534 used in C and other languages: quotation marks, bell characters,
535 form feeds, horizontal tabs, carriage returns, line feeds, and
536 backslashes. A character with a numerical value less than 32, and
537 not one of the special characters mentioned above, will be
538 translated to a backslash followed by four hexadecimal characters.
540 If full_escape is zero, the translation will (incorrectly) leave
541 these characters unescaped and unchanged.
543 The calling code is responsible for freeing the returned string.
545 char* uescape( const char* string, int size, int full_escape ) {
550 growing_buffer* buf = buffer_init(size + 64);
553 unsigned long int c = 0x0;
555 while (string[idx]) {
559 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
561 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
564 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
566 c = (unsigned char)string[idx] ^ 0xF0;
568 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
570 c = (unsigned char)string[idx] ^ 0xE0;
572 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
574 c = (unsigned char)string[idx] ^ 0xC0;
579 idx++; // look at the next byte
580 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
584 buffer_fadd(buf, "\\u%04x", c);
594 /* escape the usual suspects */
598 OSRF_BUFFER_ADD_CHAR(buf, '\\');
599 OSRF_BUFFER_ADD_CHAR(buf, '"');
603 OSRF_BUFFER_ADD_CHAR(buf, '\\');
604 OSRF_BUFFER_ADD_CHAR(buf, 'b');
608 OSRF_BUFFER_ADD_CHAR(buf, '\\');
609 OSRF_BUFFER_ADD_CHAR(buf, 'f');
613 OSRF_BUFFER_ADD_CHAR(buf, '\\');
614 OSRF_BUFFER_ADD_CHAR(buf, 't');
618 OSRF_BUFFER_ADD_CHAR(buf, '\\');
619 OSRF_BUFFER_ADD_CHAR(buf, 'n');
623 OSRF_BUFFER_ADD_CHAR(buf, '\\');
624 OSRF_BUFFER_ADD_CHAR(buf, 'r');
628 OSRF_BUFFER_ADD_CHAR(buf, '\\');
629 OSRF_BUFFER_ADD_CHAR(buf, '\\');
633 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
634 else OSRF_BUFFER_ADD_CHAR(buf, c);
638 OSRF_BUFFER_ADD_CHAR(buf, c);
645 return buffer_release(buf);
650 @brief Become a proper daemon.
651 @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)
652 @param callback_arg An integer argument passed as the second argument to the callback function from the parent process post-fork()
653 @return 0 if successful, or -1 if not.
655 Call fork(). The parent exits. The child moves to the root directory, detaches from
656 the terminal, and redirects the standard streams (stdin, stdout, stderr) to /dev/null.
658 int daemonizeWithCallback( void (*callback)(pid_t, int), int callback_arg ) {
662 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
665 } else if (f == 0) { // We're in the child now...
670 // Change directories. Otherwise whatever directory
671 // we're in couldn't be deleted until the program
672 // terminated -- possibly causing some inconvenience.
673 (void) (chdir( "/" )+1);
675 /* create new session */
678 // Now that we're no longer attached to a terminal,
679 // we don't want any traffic on the standard streams
680 (void) (freopen( "/dev/null", "r", stdin )+1);
681 (void) (freopen( "/dev/null", "w", stdout )+1);
682 (void) (freopen( "/dev/null", "w", stderr )+1);
686 } else { // We're in the parent...
688 callback( f, callback_arg );
695 @brief Become a proper daemon.
696 @return 0 if successful, or -1 if not.
698 See daemonizeWithCallback() for details.
700 int daemonize( void ) {
701 return daemonizeWithCallback( NULL, 0 );
706 @brief Determine whether a string represents a decimal integer.
707 @param s A pointer to the string.
708 @return 1 if the string represents a decimal integer, or 0 if it
711 To qualify as a decimal integer, the string must consist entirely
712 of optional leading white space, an optional leading sign, and
713 one or more decimal digits. In addition, the number must be
714 representable as a long.
716 int stringisnum(const char* s) {
725 @brief Translate a printf-style formatted string into an MD5 message digest.
726 @param text The format string. Subsequent parameters, if any, provide values to be
727 formatted and inserted into the format string.
728 @return A pointer to a string of 32 hexadecimal characters.
730 The calling code is responsible for freeing the returned string.
732 This function is a wrapper for some public domain routines written by David Madore,
733 Ron Rivest, and Colin Plumb.
735 char* md5sum( const char* text ) {
738 unsigned char digest[16];
743 for ( i=0 ; i != strlen(text) ; i++ )
744 MD5_feed (&ctx, text[i]);
746 MD5_stop (&ctx, digest);
749 char final[ 1 + 2 * sizeof( digest ) ];
752 for ( i=0 ; i<16 ; i++ ) {
753 snprintf(buf, sizeof(buf), "%02x", digest[i]);
754 strcat( final, buf );
757 return strdup(final);
762 @brief Determine whether a given file descriptor is valid.
763 @param fd The file descriptor to be checked.
764 @return 0 if the file descriptor is valid, or -1 if it isn't.
766 The most likely reason a file descriptor would be invalid is if it isn't open.
768 int osrfUtilsCheckFileDescriptor( int fd ) {
778 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
779 if( errno == EBADF ) return -1;
785 size_t osrfXmlEscapingLength ( const char* str ) {
788 for (s = str; *s; ++s) {