LP1830642 Remove variable args from md5sum()
[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.
117
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.
121
122         The replacement string goes into a location identified by a previous call
123         to init_proc_title().
124
125         WARNING: this function makes assumptions about the memory layout of
126         the argv[] array.  ANSI C does not guarantee that these assumptions
127         are correct.
128 */
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';
135         }
136         return (strlen(VA_BUF) > strlen(*(global_argv))) ? strlen(VA_BUF) : strlen(*(global_argv));
137 }
138
139 /**
140         @brief Determine current date and time to high precision.
141         @return Current date and time as seconds since the Epoch.
142
143         Used for profiling.  The time resolution is system-dependent but is no finer
144         than microseconds.
145 */
146 double get_timestamp_millis( void ) {
147         struct timeval tv;
148         gettimeofday(&tv, NULL);
149         double time     = (int)tv.tv_sec        + ( ((double)tv.tv_usec / 1000000) );
150         return time;
151 }
152
153
154 /**
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.
159
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.
163
164         See also clr_fl().
165 */
166 int set_fl( int fd, int flags ) {
167         
168         int val;
169
170         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
171                 return -1;
172
173         val |= flags;
174
175         if( fcntl( fd, F_SETFL, val ) < 0 ) 
176                 return -1;
177
178         return 0;
179 }
180         
181 /**
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.
186
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.
190
191         See also set_fl().
192  */
193 int clr_fl( int fd, int flags ) {
194         
195         int val;
196
197         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
198                 return -1;
199
200         val &= ~flags;
201
202         if( fcntl( fd, F_SETFL, val ) < 0 ) 
203                 return -1;
204
205         return 0;
206 }
207
208 /**
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.
215
216         WARNINGS: the first parameter is not checked for NULL.  The return value in case of an
217         error is not obviously sensible.
218 */
219 long va_list_size(const char* format, va_list args) {
220         int len = 0;
221         len = vsnprintf(NULL, 0, format, args);
222         va_end(args);
223         return len + 2;
224 }
225
226
227 /**
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.
232
233         The calling code is responsible for freeing the string.
234 */
235 char* va_list_to_string(const char* format, ...) {
236
237         long len = 0;
238         va_list args;
239         va_list a_copy;
240
241         va_copy(a_copy, args);
242         va_start(args, format);
243
244         char* buf = safe_malloc( va_list_size(format, args) );
245         *buf = '\0';
246
247         va_start(a_copy, format);
248         vsnprintf(buf, len - 1, format, a_copy);
249         va_end(a_copy);
250         return buf;
251 }
252
253 // ---------------------------------------------------------------------------------
254 // Flesh out a ubiqitous growing string buffer
255 // ---------------------------------------------------------------------------------
256
257 /**
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
260                 terminal nul.
261         @return A pointer to the newly created growing_buffer.
262
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.
266
267         The calling code is responsible for freeing the growing_buffer by calling buffer_free()
268         or buffer_release().
269 */
270 growing_buffer* buffer_init(int num_initial_bytes) {
271
272         if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
273
274         size_t len = sizeof(growing_buffer);
275
276         growing_buffer* gb;
277         OSRF_MALLOC(gb, len);
278
279         gb->n_used = 0;/* nothing stored so far */
280         gb->size = num_initial_bytes;
281         OSRF_MALLOC(gb->buf, gb->size + 1);
282
283         return gb;
284 }
285
286
287 /**
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.
292
293         This function fails if it is asked to allocate BUFFER_MAX_SIZE
294         or more bytes.
295 */
296 static int buffer_expand( growing_buffer* gb, size_t total_len ) {
297
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.
300
301         // Make sure the request is not excessive
302         
303         if( total_len >= BUFFER_MAX_SIZE ) {
304                 fprintf(stderr, "Buffer reached MAX_SIZE of %lu",
305                                 (unsigned long) BUFFER_MAX_SIZE );
306                 buffer_free( gb );
307                 return 1;
308         }
309
310         // Pick a big enough buffer size, but don't exceed a maximum
311         
312         while( total_len >= gb->size ) {
313                 gb->size *= 2;
314         }
315
316         if( gb->size > BUFFER_MAX_SIZE )
317                 gb->size = BUFFER_MAX_SIZE;
318
319         // Allocate and populate the new buffer
320         
321         char* new_data;
322         OSRF_MALLOC( new_data, gb->size );
323         memcpy( new_data, gb->buf, gb->n_used );
324         new_data[ gb->n_used ] = '\0';
325
326         // Replace the old buffer
327         
328         free( gb->buf );
329         gb->buf = new_data;
330         return 0;
331 }
332
333
334 /**
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.
340
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.
343 */
344 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
345
346         if(!gb || !format) return -1; 
347
348         long len = 0;
349         va_list args;
350         va_list a_copy;
351
352         va_copy(a_copy, args);
353
354         va_start(args, format);
355         len = va_list_size(format, args);
356
357         char buf[len];
358         osrf_clearbuf(buf, sizeof(buf));
359
360         va_start(a_copy, format);
361         vsnprintf(buf, len - 1, format, a_copy);
362         va_end(a_copy);
363
364         return buffer_add(gb, buf);
365 }
366
367
368 /**
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.
373 */
374 int buffer_add(growing_buffer* gb, const char* data) {
375         if(!(gb && data)) return -1;
376
377         int data_len = strlen( data );
378
379         if(data_len == 0) return gb->n_used;
380
381         int total_len = data_len + gb->n_used;
382
383         if( total_len >= gb->size ) {
384                 if( buffer_expand( gb, total_len ) )
385                         return -1;
386         }
387
388         strcpy( gb->buf + gb->n_used, data );
389         gb->n_used = total_len;
390         return total_len;
391 }
392
393 /**
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.
399
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.
402 */
403 int buffer_add_n(growing_buffer* gb, const char* data, size_t n) {
404         if(!(gb && data)) return -1;
405
406         if(n == 0) return 0;
407
408         int total_len = n + gb->n_used;
409
410         if( total_len >= gb->size ) {
411                 if( buffer_expand( gb, total_len ) )
412                         return -1;
413         }
414
415         memcpy( gb->buf + gb->n_used, data, n );
416         gb->buf[total_len] = '\0';
417         gb->n_used = total_len;
418         return total_len;
419 }
420
421
422 /**
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.
426 */
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 );
431         gb->n_used = 0;
432         gb->buf[ 0 ] = '\0';
433         return gb->n_used;
434 }
435
436 /**
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.
440
441         The calling code is responsible for freeing the string.
442
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().
445 */
446 char* buffer_release( growing_buffer* gb) {
447         char* s = gb->buf;
448         s[gb->n_used] = '\0';
449         free( gb );
450         return s;
451 }
452
453 /**
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).
457 */
458 int buffer_free( growing_buffer* gb ) {
459         if( gb == NULL )
460                 return 0;
461         free( gb->buf );
462         free( gb );
463         return 1;
464 }
465
466 /**
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.
470
471         The growing_buffer itself is not affected.
472
473         The calling code is responsible for freeing the string.
474 */
475 char* buffer_data( const growing_buffer *gb) {
476         return strdup( gb->buf );
477 }
478
479 /**
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).
483 */
484 char buffer_chomp(growing_buffer* gb) {
485         char c = '\0';
486     if(gb && gb->n_used > 0) {
487             gb->n_used--;
488                 c = gb->buf[gb->n_used];
489             gb->buf[gb->n_used] = '\0';
490     }
491     return c;
492 }
493
494
495 /**
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.
500
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.
503 */
504 int buffer_add_char(growing_buffer* gb, char c ) {
505         if(gb && gb->buf) {
506
507                 int total_len = gb->n_used + 1;
508
509                 if( total_len >= gb->size ) {
510                         if( buffer_expand( gb, total_len ) )
511                                 return -1;
512                 }
513         
514                 gb->buf[ gb->n_used ]   = c;
515                 gb->buf[ ++gb->n_used ] = '\0';
516                 return gb->n_used;
517         } else
518                 return 0;
519 }
520
521
522 /**
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
527                 special characters.
528         @return A pointer to the translated version of the string.
529
530         Deprecated.  Use buffer_append_utf8() instead.
531
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.
539
540         If full_escape is zero, the translation will (incorrectly) leave
541         these characters unescaped and unchanged.
542
543         The calling code is responsible for freeing the returned string.
544 */
545 char* uescape( const char* string, int size, int full_escape ) {
546
547         if( NULL == string )
548                 return NULL;
549         
550         growing_buffer* buf = buffer_init(size + 64);
551         int clen = 0;
552         int idx = 0;
553         unsigned long int c = 0x0;
554
555         while (string[idx]) {
556
557                 c = 0x0;
558
559                 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
560
561                         if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
562
563                                 clen = 1;
564                                 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
565                                         clen = 3;
566                                         c = (unsigned char)string[idx] ^ 0xF0;
567
568                                 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
569                                         clen = 2;
570                                         c = (unsigned char)string[idx] ^ 0xE0;
571
572                                 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
573                                         clen = 1;
574                                         c = (unsigned char)string[idx] ^ 0xC0;
575                                 }
576
577                                 for (;clen;clen--) {
578
579                                         idx++; // look at the next byte
580                                         c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
581
582                                 }
583
584                                 buffer_fadd(buf, "\\u%04x", c);
585
586                         } else {
587                                 buffer_free(buf);
588                                 return NULL;
589                         }
590
591                 } else {
592                         c = string[idx];
593
594                         /* escape the usual suspects */
595                         if(full_escape) {
596                                 switch(c) {
597                                         case '"':
598                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
599                                                 OSRF_BUFFER_ADD_CHAR(buf, '"');
600                                                 break;
601         
602                                         case '\b':
603                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
604                                                 OSRF_BUFFER_ADD_CHAR(buf, 'b');
605                                                 break;
606         
607                                         case '\f':
608                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
609                                                 OSRF_BUFFER_ADD_CHAR(buf, 'f');
610                                                 break;
611         
612                                         case '\t':
613                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
614                                                 OSRF_BUFFER_ADD_CHAR(buf, 't');
615                                                 break;
616         
617                                         case '\n':
618                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
619                                                 OSRF_BUFFER_ADD_CHAR(buf, 'n');
620                                                 break;
621         
622                                         case '\r':
623                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
624                                                 OSRF_BUFFER_ADD_CHAR(buf, 'r');
625                                                 break;
626
627                                         case '\\':
628                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
629                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
630                                                 break;
631
632                                         default:
633                                                 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
634                                                 else OSRF_BUFFER_ADD_CHAR(buf, c);
635                                 }
636
637                         } else {
638                                 OSRF_BUFFER_ADD_CHAR(buf, c);
639                         }
640                 }
641
642                 idx++;
643         }
644
645         return buffer_release(buf);
646 }
647
648
649 /**
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.
654
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.
657 */
658 int daemonizeWithCallback( void (*callback)(pid_t, int), int callback_arg ) {
659         pid_t f = fork();
660
661         if (f == -1) {
662                 osrfLogError( OSRF_LOG_MARK, "Failed to fork!" );
663                 return -1;
664
665         } else if (f == 0) { // We're in the child now...
666                 
667                 if( callback )
668                         callback( -1, -1 );
669
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);
674
675                 /* create new session */
676                 setsid();
677
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);
683                 
684                 return 0;
685
686         } else { // We're in the parent...
687                 if( callback )
688                         callback( f, callback_arg );
689
690                 _exit(0);
691         }
692 }
693
694 /**
695         @brief Become a proper daemon.
696         @return 0 if successful, or -1 if not.
697
698         See daemonizeWithCallback() for details.
699 */
700 int daemonize( void ) {
701         return daemonizeWithCallback( NULL, 0 );
702 }
703
704
705 /**
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
709         doesn't.
710
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.
715 */
716 int stringisnum(const char* s) {
717         char* w;
718         strtol(s, &w, 10);
719         return *w ? 0 : 1;
720 }
721         
722
723
724 /**
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.
729
730         The calling code is responsible for freeing the returned string.
731
732         This function is a wrapper for some public domain routines written by David Madore,
733         Ron Rivest, and Colin Plumb.
734 */
735 char* md5sum( const char* text ) {
736
737         struct md5_ctx ctx;
738         unsigned char digest[16];
739
740         MD5_start (&ctx);
741
742         int i;
743         for ( i=0 ; i != strlen(text) ; i++ )
744                 MD5_feed (&ctx, text[i]);
745
746         MD5_stop (&ctx, digest);
747
748         char buf[16];
749         char final[ 1 + 2 * sizeof( digest ) ];
750         final[0] = '\0';
751
752         for ( i=0 ; i<16 ; i++ ) {
753                 snprintf(buf, sizeof(buf), "%02x", digest[i]);
754                 strcat( final, buf );
755         }
756
757         return strdup(final);
758
759 }
760
761 /**
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.
765
766         The most likely reason a file descriptor would be invalid is if it isn't open.
767 */
768 int osrfUtilsCheckFileDescriptor( int fd ) {
769
770         fd_set tmpset;
771         FD_ZERO(&tmpset);
772         FD_SET(fd, &tmpset);
773
774         struct timeval tv;
775         tv.tv_sec = 0;
776         tv.tv_usec = 0;
777
778         if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
779                 if( errno == EBADF ) return -1;
780         }
781
782         return 0;
783 }
784
785 size_t osrfXmlEscapingLength ( const char* str ) {
786         int extra = 0;
787         const char* s;
788         for (s = str; *s; ++s) {
789                 switch (*s) {
790                         case '>':
791                         case '<':
792                                 extra += 3;
793                                 break;
794                         case '&':
795                                 extra += 4;
796                                 break;
797                         case '"':
798                                 extra += 11;
799                                 break;
800                         default:
801                                 break;
802                 }
803         }
804
805         return extra;
806 }
807