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);
239 va_start(args, format);
241 char* buf = safe_malloc( va_list_size(format, args) );
244 va_start(a_copy, format);
245 vsnprintf(buf, len - 1, format, a_copy);
250 // ---------------------------------------------------------------------------------
251 // Flesh out a ubiqitous growing string buffer
252 // ---------------------------------------------------------------------------------
255 @brief Create a growing_buffer containing an empty string.
256 @param num_initial_bytes The initial size of the internal buffer, not counting the
258 @return A pointer to the newly created growing_buffer.
260 The value of num_initial_bytes should typically be a plausible guess of how big
261 the string will ever be. However the guess doesn't have to accurate, because more
262 memory will be allocated as needed.
264 The calling code is responsible for freeing the growing_buffer by calling buffer_free()
267 growing_buffer* buffer_init(int num_initial_bytes) {
269 if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
271 size_t len = sizeof(growing_buffer);
274 OSRF_MALLOC(gb, len);
276 gb->n_used = 0;/* nothing stored so far */
277 gb->size = num_initial_bytes;
278 OSRF_MALLOC(gb->buf, gb->size + 1);
285 @brief Allocate more memory for a growing_buffer.
286 @param gb A pointer to the growing_buffer.
287 @param total_len How much total memory we need for the buffer.
288 @return 0 if successful, or 1 if not.
290 This function fails if it is asked to allocate BUFFER_MAX_SIZE
293 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
295 // We do not check to see if the buffer is already big enough. It is the
296 //responsibility of the calling function to call this only when necessary.
298 // Make sure the request is not excessive
300 if( total_len >= BUFFER_MAX_SIZE ) {
301 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
302 (unsigned long) BUFFER_MAX_SIZE );
307 // Pick a big enough buffer size, but don't exceed a maximum
309 while( total_len >= gb->size ) {
313 if( gb->size > BUFFER_MAX_SIZE )
314 gb->size = BUFFER_MAX_SIZE;
316 // Allocate and populate the new buffer
319 OSRF_MALLOC( new_data, gb->size );
320 memcpy( new_data, gb->buf, gb->n_used );
321 new_data[ gb->n_used ] = '\0';
323 // Replace the old buffer
332 @brief Append a formatted string to a growing_buffer.
333 @param gb A pointer to the growing_buffer.
334 @param format A printf-style format string. Subsequent parameters, if any, will be
335 formatted and inserted into the resulting string.
336 @return If successful,the length of the resulting string; otherwise -1.
338 This function fails if either of the first two parameters is NULL,
339 or if the resulting string requires BUFFER_MAX_SIZE or more bytes.
341 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
343 if(!gb || !format) return -1;
349 va_copy(a_copy, args);
351 va_start(args, format);
352 len = va_list_size(format, args);
355 osrf_clearbuf(buf, sizeof(buf));
357 va_start(a_copy, format);
358 vsnprintf(buf, len - 1, format, a_copy);
361 return buffer_add(gb, buf);
366 @brief Appends a string to a growing_buffer.
367 @param gb A pointer to the growing_buffer.
368 @param data A pointer to the string to be appended.
369 @return If successful, the length of the resulting string; or if not, -1.
371 int buffer_add(growing_buffer* gb, const char* data) {
372 if(!(gb && data)) return -1;
374 int data_len = strlen( data );
376 if(data_len == 0) return gb->n_used;
378 int total_len = data_len + gb->n_used;
380 if( total_len >= gb->size ) {
381 if( buffer_expand( gb, total_len ) )
385 strcpy( gb->buf + gb->n_used, data );
386 gb->n_used = total_len;
391 @brief Append a specified number of characters to a growing_buffer.
392 @param gb A pointer to the growing_buffer.
393 @param data A pointer to the characters to be appended.
394 @param n How many characters to be append.
395 @return If sccessful, the length of the resulting string; or if not, -1.
397 If the characters to be appended include an embedded nul byte, it will be appended
398 along with the others. The results are likely to be unpleasant.
400 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
401 if(!(gb && data)) return -1;
405 int total_len = n + gb->n_used;
407 if( total_len >= gb->size ) {
408 if( buffer_expand( gb, total_len ) )
412 memcpy( gb->buf + gb->n_used, data, n );
413 gb->buf[total_len] = '\0';
414 gb->n_used = total_len;
420 @brief Reset a growing_buffer so that it contains an empty string.
421 @param gb A pointer to the growing_buffer.
422 @return 0 if successful, -1 if not.
424 int buffer_reset( growing_buffer *gb){
425 if( gb == NULL ) { return -1; }
426 if( gb->buf == NULL ) { return -1; }
427 osrf_clearbuf( gb->buf, gb->size );
434 @brief Free a growing_buffer and return a pointer to the string inside.
435 @param gb A pointer to the growing_buffer.
436 @return A pointer to the string previously contained by the growing buffer.
438 The calling code is responsible for freeing the string.
440 This function is equivalent to buffer_data() followed by buffer_free(). However
441 it is more efficient, because it avoids calls to strudup and free().
443 char* buffer_release( growing_buffer* gb) {
445 s[gb->n_used] = '\0';
451 @brief Free a growing_buffer and its contents.
452 @param gb A pointer to the growing_buffer.
453 @return 1 if successful, or 0 if not (because the input parameter is NULL).
455 int buffer_free( growing_buffer* gb ) {
464 @brief Create a copy of the string inside a growing_buffer.
465 @param gb A pointer to the growing_buffer.
466 @return A pointer to the newly created copy.
468 The growing_buffer itself is not affected.
470 The calling code is responsible for freeing the string.
472 char* buffer_data( const growing_buffer *gb) {
473 return strdup( gb->buf );
477 @brief Remove the last character from a growing_buffer.
478 @param gb A pointer to the growing_buffer.
479 @return The character removed (or a nul byte if the string is already empty).
481 char buffer_chomp(growing_buffer* gb) {
483 if(gb && gb->n_used > 0) {
485 c = gb->buf[gb->n_used];
486 gb->buf[gb->n_used] = '\0';
493 @brief Append a single character to a growing_buffer.
494 @param gb A pointer to the growing_buffer.
495 @param c The character to be appended.
496 @return The length of the resulting string.
498 If the character appended is a nul byte it will still be appended as if
499 it were a normal character. The results are likely to be unpleasant.
501 int buffer_add_char(growing_buffer* gb, char c ) {
504 int total_len = gb->n_used + 1;
506 if( total_len >= gb->size ) {
507 if( buffer_expand( gb, total_len ) )
511 gb->buf[ gb->n_used ] = c;
512 gb->buf[ ++gb->n_used ] = '\0';
520 @brief Translate a UTF8 string into escaped ASCII, suitable for JSON.
521 @param string The input string to be translated.
522 @param size The length of the input string (need not be accurate).
523 @param full_escape Boolean; true turns on the escaping of certain
525 @return A pointer to the translated version of the string.
527 Deprecated. Use buffer_append_utf8() instead.
529 If full_escape is non-zero, the translation will escape certain
530 certain characters with a backslash, according to the conventions
531 used in C and other languages: quotation marks, bell characters,
532 form feeds, horizontal tabs, carriage returns, line feeds, and
533 backslashes. A character with a numerical value less than 32, and
534 not one of the special characters mentioned above, will be
535 translated to a backslash followed by four hexadecimal characters.
537 If full_escape is zero, the translation will (incorrectly) leave
538 these characters unescaped and unchanged.
540 The calling code is responsible for freeing the returned string.
542 char* uescape( const char* string, int size, int full_escape ) {
547 growing_buffer* buf = buffer_init(size + 64);
550 unsigned long int c = 0x0;
552 while (string[idx]) {
556 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
558 if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
561 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
563 c = (unsigned char)string[idx] ^ 0xF0;
565 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
567 c = (unsigned char)string[idx] ^ 0xE0;
569 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
571 c = (unsigned char)string[idx] ^ 0xC0;
576 idx++; // look at the next byte
577 c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
581 buffer_fadd(buf, "\\u%04x", c);
591 /* escape the usual suspects */
595 OSRF_BUFFER_ADD_CHAR(buf, '\\');
596 OSRF_BUFFER_ADD_CHAR(buf, '"');
600 OSRF_BUFFER_ADD_CHAR(buf, '\\');
601 OSRF_BUFFER_ADD_CHAR(buf, 'b');
605 OSRF_BUFFER_ADD_CHAR(buf, '\\');
606 OSRF_BUFFER_ADD_CHAR(buf, 'f');
610 OSRF_BUFFER_ADD_CHAR(buf, '\\');
611 OSRF_BUFFER_ADD_CHAR(buf, 't');
615 OSRF_BUFFER_ADD_CHAR(buf, '\\');
616 OSRF_BUFFER_ADD_CHAR(buf, 'n');
620 OSRF_BUFFER_ADD_CHAR(buf, '\\');
621 OSRF_BUFFER_ADD_CHAR(buf, 'r');
625 OSRF_BUFFER_ADD_CHAR(buf, '\\');
626 OSRF_BUFFER_ADD_CHAR(buf, '\\');
630 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
631 else OSRF_BUFFER_ADD_CHAR(buf, c);
635 OSRF_BUFFER_ADD_CHAR(buf, c);
642 return buffer_release(buf);
647 @brief Become a proper daemon.
648 @return 0 if successful, or -1 if not.
650 Call fork(). The parent exits. The child moves to the root directory, detaches from
651 the terminal, and redirects the standard streams (stdin, stdout, stderr) to /dev/null.
653 int daemonize( void ) {
657 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
660 } else if (f == 0) { // We're in the child now...
662 // Change directories. Otherwise whatever directory
663 // we're in couldn't be deleted until the program
664 // terminated -- possibly causing some inconvenience.
667 /* create new session */
670 // Now that we're no longer attached to a terminal,
671 // we don't want any traffic on the standard streams
672 freopen( "/dev/null", "r", stdin );
673 freopen( "/dev/null", "w", stdout );
674 freopen( "/dev/null", "w", stderr );
678 } else { // We're in the parent...
685 @brief Determine whether a string represents a decimal integer.
686 @param s A pointer to the string.
687 @return 1 if the string represents a decimal integer, or 0 if it
690 To qualify as a decimal integer, the string must consist entirely
691 of optional leading white space, an optional leading sign, and
692 one or more decimal digits. In addition, the number must be
693 representable as a long.
695 int stringisnum(const char* s) {
704 @brief Translate a printf-style formatted string into an MD5 message digest.
705 @param text The format string. Subsequent parameters, if any, provide values to be
706 formatted and inserted into the format string.
707 @return A pointer to a string of 32 hexadecimal characters.
709 The calling code is responsible for freeing the returned string.
711 This function is a wrapper for some public domain routines written by David Madore,
712 Ron Rivest, and Colin Plumb.
714 char* md5sum( const char* text, ... ) {
717 unsigned char digest[16];
721 VA_LIST_TO_STRING(text);
724 for ( i=0 ; i != strlen(VA_BUF) ; i++ )
725 MD5_feed (&ctx, VA_BUF[i]);
727 MD5_stop (&ctx, digest);
730 char final[ 1 + 2 * sizeof( digest ) ];
733 for ( i=0 ; i<16 ; i++ ) {
734 snprintf(buf, sizeof(buf), "%02x", digest[i]);
735 strcat( final, buf );
738 return strdup(final);
743 @brief Determine whether a given file descriptor is valid.
744 @param fd The file descriptor to be checked.
745 @return 0 if the file descriptor is valid, or -1 if it isn't.
747 The most likely reason a file descriptor would be invalid is if it isn't open.
749 int osrfUtilsCheckFileDescriptor( int fd ) {
759 if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
760 if( errno == EBADF ) return -1;