]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/utils.c
1. Add comments to be recognized by doxygen or other such
[OpenSRF.git] / src / libopensrf / utils.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3
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.
8
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.
13 */
14
15 /**
16         @file utils.c
17         
18         @brief A collection of various low-level utility functions.
19         
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
22         itself as needed.
23 */
24 #include <opensrf/utils.h>
25 #include <opensrf/log.h>
26 #include <errno.h>
27
28 /**
29         @brief A thin wrapper for malloc().
30         
31         @param size How many bytes to allocate.
32         @return a pointer to the allocated memory.
33
34         If the allocation fails, safe_malloc calls exit().  Consequently the
35         calling code doesn't have to check for NULL.
36
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().
41 */
42 inline void* safe_malloc( int size ) {
43         void* ptr = (void*) malloc( size );
44         if( ptr == NULL ) {
45                 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
46                 exit(99);
47         }
48         memset( ptr, 0, size ); // remove this after safe_calloc transition
49         return ptr;
50 }
51
52 /**
53         @brief A thin wrapper for calloc().
54         
55         @param size How many bytes to allocate.
56         @return a pointer to the allocated memory.
57
58         If the allocation fails, safe_calloc calls exit().  Consequently the
59         calling code doesn't have to check for NULL.
60  */
61 inline void* safe_calloc( int size ) {
62         void* ptr = (void*) calloc( 1, size );
63         if( ptr == NULL ) {
64                 osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
65                 exit(99);
66         }
67         return ptr;
68 }
69
70 /**
71         @brief Saves a pointer to the beginning of the argv[] array from main().  See init_proc_title().
72 */
73 static char** global_argv = NULL;
74 /**
75         @brief Saves the length of the argv[] array from main().  See init_proc_title().
76  */
77 static int global_argv_size = 0;
78
79 /**
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().
83         @return zero.
84
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
88         global_argv_size.
89
90         The return value, being invariant, is useless.
91
92         This function prepares for a subsequent call to set_proc_title().
93 */
94 int init_proc_title( int argc, char* argv[] ) {
95
96         global_argv = argv;
97
98         int i = 0;
99         while( i < argc ) {
100                 int len = strlen( global_argv[i]);
101                 osrf_clearbuf( global_argv[i], len );
102                 global_argv_size += len;
103                 i++;
104         }
105
106         global_argv_size -= 2;
107         return 0;
108 }
109
110 /**
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.
118
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.
122
123         The replacement string goes into a location identified by a previous call
124         to init_proc_title().
125
126         WARNING: this function makes assumptions about the memory layout of
127         the argv[] array.  ANSI C does not guarantee that these assumptions
128         are correct.
129 */
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 );
134 }
135
136 /**
137         @brief Determine current date and time to high precision.
138         @return Current date and time as seconds since the Epoch.
139
140         Used for profiling.  The time resolution is system-dependent but is no finer
141         than microseconds.
142 */
143 double get_timestamp_millis( void ) {
144         struct timeval tv;
145         gettimeofday(&tv, NULL);
146         double time     = (int)tv.tv_sec        + ( ((double)tv.tv_usec / 1000000) );
147         return time;
148 }
149
150
151 /**
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.
156
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.
160
161         See also clr_fl().
162 */
163 int set_fl( int fd, int flags ) {
164         
165         int val;
166
167         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
168                 return -1;
169
170         val |= flags;
171
172         if( fcntl( fd, F_SETFL, val ) < 0 ) 
173                 return -1;
174
175         return 0;
176 }
177         
178 /**
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.
183
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.
187
188         See also set_fl().
189  */
190 int clr_fl( int fd, int flags ) {
191         
192         int val;
193
194         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
195                 return -1;
196
197         val &= ~flags;
198
199         if( fcntl( fd, F_SETFL, val ) < 0 ) 
200                 return -1;
201
202         return 0;
203 }
204
205 /**
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.
212
213         WARNINGS: the first parameter is not checked for NULL.  The return value in case of an
214         error is not obviously sensible.
215 */
216 long va_list_size(const char* format, va_list args) {
217         int len = 0;
218         len = vsnprintf(NULL, 0, format, args);
219         va_end(args);
220         return len + 2;
221 }
222
223
224 /**
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.
229
230         The calling code is responsible for freeing the string.
231 */
232 char* va_list_to_string(const char* format, ...) {
233
234         long len = 0;
235         va_list args;
236         va_list a_copy;
237
238         va_copy(a_copy, args);
239
240         va_start(args, format);
241         len = va_list_size(format, args);
242
243         char buf[len];
244         osrf_clearbuf(buf, sizeof(buf));
245
246         va_start(a_copy, format);
247         vsnprintf(buf, len - 1, format, a_copy);
248         va_end(a_copy);
249         return strdup(buf);
250 }
251
252 // ---------------------------------------------------------------------------------
253 // Flesh out a ubiqitous growing string buffer
254 // ---------------------------------------------------------------------------------
255
256 /**
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
259                 terminal nul.
260         @return A pointer to the newly created growing_buffer.
261
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.
265
266         The calling code is responsible for freeing the growing_buffer by calling buffer_free()
267         or buffer_release().
268 */
269 growing_buffer* buffer_init(int num_initial_bytes) {
270
271         if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
272
273         size_t len = sizeof(growing_buffer);
274
275         growing_buffer* gb;
276         OSRF_MALLOC(gb, len);
277
278         gb->n_used = 0;/* nothing stored so far */
279         gb->size = num_initial_bytes;
280         OSRF_MALLOC(gb->buf, gb->size + 1);
281
282         return gb;
283 }
284
285
286 /**
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.
290
291         This function fails if it is asked to allocate BUFFER_MAX_SIZE
292         or more bytes.
293 */
294 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
295
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.
298
299         // Make sure the request is not excessive
300         
301         if( total_len >= BUFFER_MAX_SIZE ) {
302                 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
303                                 (unsigned long) BUFFER_MAX_SIZE );
304                 buffer_free( gb );
305                 return 1;
306         }
307
308         // Pick a big enough buffer size, but don't exceed a maximum
309         
310         while( total_len >= gb->size ) {
311                 gb->size *= 2;
312         }
313
314         if( gb->size > BUFFER_MAX_SIZE )
315                 gb->size = BUFFER_MAX_SIZE;
316
317         // Allocate and populate the new buffer
318         
319         char* new_data;
320         OSRF_MALLOC( new_data, gb->size );
321         memcpy( new_data, gb->buf, gb->n_used );
322         new_data[ gb->n_used ] = '\0';
323
324         // Replace the old buffer
325         
326         free( gb->buf );
327         gb->buf = new_data;
328         return 0;
329 }
330
331
332 /**
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.
338
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.
341 */
342 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
343
344         if(!gb || !format) return -1; 
345
346         long len = 0;
347         va_list args;
348         va_list a_copy;
349
350         va_copy(a_copy, args);
351
352         va_start(args, format);
353         len = va_list_size(format, args);
354
355         char buf[len];
356         osrf_clearbuf(buf, sizeof(buf));
357
358         va_start(a_copy, format);
359         vsnprintf(buf, len - 1, format, a_copy);
360         va_end(a_copy);
361
362         return buffer_add(gb, buf);
363 }
364
365
366 /**
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.
371 */
372 int buffer_add(growing_buffer* gb, const char* data) {
373         if(!(gb && data)) return -1;
374
375         int data_len = strlen( data );
376
377         if(data_len == 0) return gb->n_used;
378
379         int total_len = data_len + gb->n_used;
380
381         if( total_len >= gb->size ) {
382                 if( buffer_expand( gb, total_len ) )
383                         return -1;
384         }
385
386         strcpy( gb->buf + gb->n_used, data );
387         gb->n_used = total_len;
388         return total_len;
389 }
390
391 /**
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.
397
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.
400 */
401 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
402         if(!(gb && data)) return -1;
403
404         if(n == 0) return 0;
405
406         int total_len = n + gb->n_used;
407
408         if( total_len >= gb->size ) {
409                 if( buffer_expand( gb, total_len ) )
410                         return -1;
411         }
412
413         memcpy( gb->buf + gb->n_used, data, n );
414         gb->buf[total_len] = '\0';
415         gb->n_used = total_len;
416         return total_len;
417 }
418
419
420 /**
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.
424 */
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 );
429         gb->n_used = 0;
430         gb->buf[ 0 ] = '\0';
431         return gb->n_used;
432 }
433
434 /**
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.
438
439         The calling code is responsible for freeing the string.
440
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().
443 */
444 char* buffer_release( growing_buffer* gb) {
445         char* s = gb->buf;
446         s[gb->n_used] = '\0';
447         free( gb );
448         return s;
449 }
450
451 /**
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).
455 */
456 int buffer_free( growing_buffer* gb ) {
457         if( gb == NULL )
458                 return 0;
459         free( gb->buf );
460         free( gb );
461         return 1;
462 }
463
464 /**
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.
468
469         The growing_buffer itself is not affected.
470
471         The calling code is responsible for freeing the string.
472 */
473 char* buffer_data( const growing_buffer *gb) {
474         return strdup( gb->buf );
475 }
476
477 /**
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).
481 */
482 char buffer_chomp(growing_buffer* gb) {
483         char c = '\0';
484     if(gb && gb->n_used > 0) {
485             gb->n_used--;
486                 c = gb->buf[gb->n_used];
487             gb->buf[gb->n_used] = '\0';
488     }
489     return c;
490 }
491
492
493 /**
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.
498
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.
501 */
502 int buffer_add_char(growing_buffer* gb, char c ) {
503         if(gb && gb->buf) {
504
505                 int total_len = gb->n_used + 1;
506
507                 if( total_len >= gb->size ) {
508                         if( buffer_expand( gb, total_len ) )
509                                 return -1;
510                 }
511         
512                 gb->buf[ gb->n_used ]   = c;
513                 gb->buf[ ++gb->n_used ] = '\0';
514                 return gb->n_used;
515         } else
516                 return 0;
517 }
518
519
520 /**
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
525                 special characters.
526         @return A pointer to the translated version of the string.
527
528         Deprecated.  Use buffer_append_utf8() instead.
529
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.
537
538         If full_escape is zero, the translation will (incorrectly) leave
539         these characters unescaped and unchanged.
540
541         The calling code is responsible for freeing the returned string.
542 */
543 char* uescape( const char* string, int size, int full_escape ) {
544
545         if( NULL == string )
546                 return NULL;
547         
548         growing_buffer* buf = buffer_init(size + 64);
549         int clen = 0;
550         int idx = 0;
551         unsigned long int c = 0x0;
552
553         while (string[idx]) {
554
555                 c = 0x0;
556
557                 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
558
559                         if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
560
561                                 clen = 1;
562                                 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
563                                         clen = 3;
564                                         c = (unsigned char)string[idx] ^ 0xF0;
565
566                                 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
567                                         clen = 2;
568                                         c = (unsigned char)string[idx] ^ 0xE0;
569
570                                 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
571                                         clen = 1;
572                                         c = (unsigned char)string[idx] ^ 0xC0;
573                                 }
574
575                                 for (;clen;clen--) {
576
577                                         idx++; // look at the next byte
578                                         c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
579
580                                 }
581
582                                 buffer_fadd(buf, "\\u%04x", c);
583
584                         } else {
585                                 buffer_free(buf);
586                                 return NULL;
587                         }
588
589                 } else {
590                         c = string[idx];
591
592                         /* escape the usual suspects */
593                         if(full_escape) {
594                                 switch(c) {
595                                         case '"':
596                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
597                                                 OSRF_BUFFER_ADD_CHAR(buf, '"');
598                                                 break;
599         
600                                         case '\b':
601                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
602                                                 OSRF_BUFFER_ADD_CHAR(buf, 'b');
603                                                 break;
604         
605                                         case '\f':
606                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
607                                                 OSRF_BUFFER_ADD_CHAR(buf, 'f');
608                                                 break;
609         
610                                         case '\t':
611                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
612                                                 OSRF_BUFFER_ADD_CHAR(buf, 't');
613                                                 break;
614         
615                                         case '\n':
616                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
617                                                 OSRF_BUFFER_ADD_CHAR(buf, 'n');
618                                                 break;
619         
620                                         case '\r':
621                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
622                                                 OSRF_BUFFER_ADD_CHAR(buf, 'r');
623                                                 break;
624
625                                         case '\\':
626                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
627                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
628                                                 break;
629
630                                         default:
631                                                 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
632                                                 else OSRF_BUFFER_ADD_CHAR(buf, c);
633                                 }
634
635                         } else {
636                                 OSRF_BUFFER_ADD_CHAR(buf, c);
637                         }
638                 }
639
640                 idx++;
641         }
642
643         return buffer_release(buf);
644 }
645
646
647 /**
648         @brief Become a proper daemon.
649         @return 0 if successful, or -1 if not.
650
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.
654 */
655 int daemonize( void ) {
656         pid_t f = fork();
657
658         if (f == -1) {
659                 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
660                 return -1;
661
662         } else if (f == 0) { // We're in the child now...
663                 
664                 // Change directories.  Otherwise whatever directory
665                 // we're in couldn't be deleted until the program
666                 // terminated -- possibly causing some inconvenience.
667                 chdir( "/" );
668
669                 /* create new session */
670                 setsid();
671
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 );
677                 
678                 return 0;
679
680         } else { // We're in the parent...
681                 _exit(0);
682         }
683 }
684
685
686 /**
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
690         doesn't.
691
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.
696 */
697 int stringisnum(const char* s) {
698         char* w;
699         strtol(s, &w, 10);
700         return *w ? 0 : 1;
701 }
702         
703
704
705 /**
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.
710
711         The calling code is responsible for freeing the returned string.
712
713         This function is a wrapper for some public domain routines written by David Madore,
714         Ron Rivest, and Colin Plumb.
715 */
716 char* md5sum( const char* text, ... ) {
717
718         struct md5_ctx ctx;
719         unsigned char digest[16];
720
721         MD5_start (&ctx);
722
723         VA_LIST_TO_STRING(text);
724
725         int i;
726         for ( i=0 ; i != strlen(VA_BUF) ; i++ )
727                 MD5_feed (&ctx, VA_BUF[i]);
728
729         MD5_stop (&ctx, digest);
730
731         char buf[16];
732         char final[256];
733         osrf_clearbuf(final, sizeof(final));
734
735         for ( i=0 ; i<16 ; i++ ) {
736                 snprintf(buf, sizeof(buf), "%02x", digest[i]);
737                 strcat( final, buf );
738         }
739
740         return strdup(final);
741
742 }
743
744 /**
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.
748
749         The most likely reason a file descriptor would be invalid is if it isn't open.
750 */
751 int osrfUtilsCheckFileDescriptor( int fd ) {
752
753         fd_set tmpset;
754         FD_ZERO(&tmpset);
755         FD_SET(fd, &tmpset);
756
757         struct timeval tv;
758         tv.tv_sec = 0;
759         tv.tv_usec = 0;
760
761         if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
762                 if( errno == EBADF ) return -1;
763         }
764
765         return 0;
766 }
767