07ed9a2696a3ccafffd6b7cf134e451886f974aa
[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 #include <opensrf/utils.h>
16 #include <errno.h>
17
18 inline void* safe_malloc( int size ) {
19         void* ptr = (void*) malloc( size );
20         if( ptr == NULL ) {
21                 perror("safe_malloc(): Out of Memory" );
22                 exit(99);
23         }
24         memset( ptr, 0, size );
25         return ptr;
26 }
27
28 /****************
29  The following static variables, and the following two functions,
30  overwrite the argv array passed to main().  The purpose is to
31  change the program name as reported by ps and similar utilities.
32
33  Warning: this code makes the non-portable assumption that the
34  strings to which argv[] points are contiguous in memory.  The
35  C Standard makes no such guarantee.
36  ****************/
37 static char** global_argv = NULL;
38 static int global_argv_size = 0;
39
40 int init_proc_title( int argc, char* argv[] ) {
41
42         global_argv = argv;
43
44         int i = 0;
45         while( i < argc ) {
46                 int len = strlen( global_argv[i]);
47                 bzero( global_argv[i++], len );
48                 global_argv_size += len;
49         }
50
51         global_argv_size -= 2;
52         return 0;
53 }
54
55 int set_proc_title( char* format, ... ) {
56         VA_LIST_TO_STRING(format);
57         bzero( *(global_argv), global_argv_size );
58         return snprintf( *(global_argv), global_argv_size, VA_BUF );
59 }
60
61
62 /* utility method for profiling */
63 double get_timestamp_millis() {
64         struct timeval tv;
65         gettimeofday(&tv, NULL);
66         double time     = (int)tv.tv_sec        + ( ((double)tv.tv_usec / 1000000) );
67         return time;
68 }
69
70
71 /* setting/clearing file flags */
72 int set_fl( int fd, int flags ) {
73         
74         int val;
75
76         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
77                 return -1;
78
79         val |= flags;
80
81         if( fcntl( fd, F_SETFL, val ) < 0 ) 
82                 return -1;
83
84         return 0;
85 }
86         
87 int clr_fl( int fd, int flags ) {
88         
89         int val;
90
91         if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) 
92                 return -1;
93
94         val &= ~flags;
95
96         if( fcntl( fd, F_SETFL, val ) < 0 ) 
97                 return -1;
98
99         return 0;
100 }
101
102 long va_list_size(const char* format, va_list args) {
103         int len = 0;
104         len = vsnprintf(NULL, 0, format, args);
105         va_end(args);
106         len += 2;
107         return len;
108 }
109
110
111 char* va_list_to_string(const char* format, ...) {
112
113         long len = 0;
114         va_list args;
115         va_list a_copy;
116
117         va_copy(a_copy, args);
118
119         va_start(args, format);
120         len = va_list_size(format, args);
121
122         char buf[len];
123         memset(buf, 0, len);
124
125         va_start(a_copy, format);
126         vsnprintf(buf, len - 1, format, a_copy);
127         va_end(a_copy);
128         return strdup(buf);
129 }
130
131 // ---------------------------------------------------------------------------------
132 // Flesh out a ubiqitous growing string buffer
133 // ---------------------------------------------------------------------------------
134
135 growing_buffer* buffer_init(int num_initial_bytes) {
136
137         if( num_initial_bytes > BUFFER_MAX_SIZE ) return NULL;
138
139         size_t len = sizeof(growing_buffer);
140
141         growing_buffer* gb;
142         OSRF_MALLOC(gb, len);
143
144         gb->n_used = 0;/* nothing stored so far */
145         gb->size = num_initial_bytes;
146         OSRF_MALLOC(gb->buf, gb->size + 1);
147
148         return gb;
149 }
150
151
152 int buffer_fadd(growing_buffer* gb, const char* format, ... ) {
153
154         if(!gb || !format) return 0; 
155
156         long len = 0;
157         va_list args;
158         va_list a_copy;
159
160         va_copy(a_copy, args);
161
162         va_start(args, format);
163         len = va_list_size(format, args);
164
165         char buf[len];
166         memset(buf, 0, len);
167
168         va_start(a_copy, format);
169         vsnprintf(buf, len - 1, format, a_copy);
170         va_end(a_copy);
171
172         return buffer_add(gb, buf);
173
174 }
175
176
177 int buffer_add(growing_buffer* gb, char* data) {
178         if(!(gb && data)) return 0;
179
180         int data_len = strlen( data );
181
182         if(data_len == 0) return 0;
183
184         int total_len = data_len + gb->n_used;
185
186         if( total_len >= gb->size ) {
187                 while( total_len >= gb->size ) {
188                         gb->size *= 2;
189                 }
190         
191                 if( gb->size > BUFFER_MAX_SIZE ) {
192                         fprintf(stderr, "Buffer reached MAX_SIZE of %d", BUFFER_MAX_SIZE );
193                         buffer_free( gb );
194                         return 0;
195                 }
196         
197                 char* new_data;
198                 OSRF_MALLOC(new_data, gb->size );
199         
200                 strcpy( new_data, gb->buf );
201                 free( gb->buf );
202                 gb->buf = new_data;
203         }
204
205         strcat( gb->buf, data );
206         gb->n_used = total_len;
207         return total_len;
208 }
209
210
211 int buffer_reset( growing_buffer *gb){
212         if( gb == NULL ) { return 0; }
213         if( gb->buf == NULL ) { return 0; }
214         memset( gb->buf, 0, gb->size );
215         gb->n_used = 0;
216         return 1;
217 }
218
219 /* Return a pointer to the text within a growing_buffer, */
220 /* while destroying the growing_buffer itself.           */
221
222 char* buffer_release( growing_buffer* gb) {
223         char* s = gb->buf;
224         s[gb->n_used] = '\0';
225         free( gb );
226         return s;
227 }
228
229 /* Destroy a growing_buffer and the text it contains */
230
231 int buffer_free( growing_buffer* gb ) {
232         if( gb == NULL ) 
233                 return 0;
234         free( gb->buf );
235         free( gb );
236         return 1;
237 }
238
239 char* buffer_data( growing_buffer *gb) {
240         return strdup( gb->buf );
241 }
242
243
244 /*
245 #define OSRF_BUFFER_ADD_CHAR(gb, c)\
246         do {\
247                 if(gb) {\
248                         if(gb->n_used < gb->size - 1)\
249                                 gb->buf[gb->n_used++] = c;\
250                         else\
251                                 buffer_add_char(gb, c);\
252                 }\
253         }while(0)
254         */
255
256 int buffer_add_char(growing_buffer* gb, char c) {
257         char buf[2];
258         buf[0] = c;
259         buf[1] = '\0';
260         buffer_add(gb, buf);
261         return 1;
262 }
263
264
265
266 char* uescape( const char* string, int size, int full_escape ) {
267
268         growing_buffer* buf = buffer_init(size + 64);
269         int clen = 0;
270         int idx = 0;
271         unsigned long int c = 0x0;
272
273         while (string[idx]) {
274
275                 c = 0x0;
276
277                 if ((unsigned char)string[idx] >= 0x80) { // not ASCII
278
279                         if ((unsigned char)string[idx] >= 0xC0 && (unsigned char)string[idx] <= 0xF4) { // starts a UTF8 string
280
281                                 clen = 1;
282                                 if (((unsigned char)string[idx] & 0xF0) == 0xF0) {
283                                         clen = 3;
284                                         c = (unsigned char)string[idx] ^ 0xF0;
285
286                                 } else if (((unsigned char)string[idx] & 0xE0) == 0xE0) {
287                                         clen = 2;
288                                         c = (unsigned char)string[idx] ^ 0xE0;
289
290                                 } else if (((unsigned char)string[idx] & 0xC0) == 0xC0) {
291                                         clen = 1;
292                                         c = (unsigned char)string[idx] ^ 0xC0;
293                                 }
294
295                                 for (;clen;clen--) {
296
297                                         idx++; // look at the next byte
298                                         c = (c << 6) | ((unsigned char)string[idx] & 0x3F); // add this byte worth
299
300                                 }
301
302                                 buffer_fadd(buf, "\\u%04x", c);
303
304                         } else {
305                                 buffer_free(buf);
306                                 return NULL;
307                         }
308
309                 } else {
310                         c = string[idx];
311
312                         /* escape the usual suspects */
313                         if(full_escape) {
314                                 switch(c) {
315                                         case '"':
316                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
317                                                 OSRF_BUFFER_ADD_CHAR(buf, '"');
318                                                 break;
319         
320                                         case '\b':
321                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
322                                                 OSRF_BUFFER_ADD_CHAR(buf, 'b');
323                                                 break;
324         
325                                         case '\f':
326                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
327                                                 OSRF_BUFFER_ADD_CHAR(buf, 'f');
328                                                 break;
329         
330                                         case '\t':
331                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
332                                                 OSRF_BUFFER_ADD_CHAR(buf, 't');
333                                                 break;
334         
335                                         case '\n':
336                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
337                                                 OSRF_BUFFER_ADD_CHAR(buf, 'n');
338                                                 break;
339         
340                                         case '\r':
341                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
342                                                 OSRF_BUFFER_ADD_CHAR(buf, 'r');
343                                                 break;
344
345                                         case '\\':
346                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
347                                                 OSRF_BUFFER_ADD_CHAR(buf, '\\');
348                                                 break;
349
350                                         default:
351                                                 if( c < 32 ) buffer_fadd(buf, "\\u%04x", c);
352                                                 else OSRF_BUFFER_ADD_CHAR(buf, c);
353                                 }
354
355                         } else {
356                                 OSRF_BUFFER_ADD_CHAR(buf, c);
357                         }
358                 }
359
360                 idx++;
361         }
362
363         char* d = buffer_data(buf);
364         buffer_free(buf);
365         return d;
366 }
367
368
369 // A function to turn a process into a daemon and set it's process name in ps/top
370 int daemonize() {
371         int f = fork();
372
373         if (f == -1) {
374                 perror("Failed to fork!");
375                 return -1;
376
377         } else if (f == 0) { // We're in the child now...
378                 setsid();
379                 return 0;
380
381         } else { // We're in the parent...
382                 exit(0);
383         }
384 }
385
386
387 /* Return 1 if the string represents an integer,  */
388 /* as recognized by strtol(); Otherwise return 0. */
389
390 int stringisnum(char* s) {
391         char* w;
392         strtol(s, &w, 10);
393         return *w ? 0 : 1;
394 }
395         
396
397
398 char* file_to_string(const char* filename) {
399
400         if(!filename) return NULL;
401
402         int len = 1024;
403         char buf[len];
404         bzero(buf, len);
405         growing_buffer* gb = buffer_init(len);
406
407         FILE* file = fopen(filename, "r");
408         if(!file) {
409                 int l = strlen(filename) + 64;
410                 char b[l];
411                 snprintf(b,l,"Unable to open file [%s] in file_to_string()", filename);
412                 perror(b);
413                 return NULL;
414         }
415
416         while(fgets(buf, len - 1, file)) {
417                 buffer_add(gb, buf);
418                 bzero(buf, len);
419         }
420
421         fclose(file);
422
423         char* data = buffer_data(gb);
424         buffer_free(gb);
425         return data;
426 }
427
428
429 char* md5sum( char* text, ... ) {
430
431         struct md5_ctx ctx;
432         unsigned char digest[16];
433
434         MD5_start (&ctx);
435
436         VA_LIST_TO_STRING(text);
437
438         int i;
439         for ( i=0 ; i != strlen(VA_BUF) ; i++ )
440                 MD5_feed (&ctx, VA_BUF[i]);
441
442         MD5_stop (&ctx, digest);
443
444         char buf[16];
445         memset(buf,0,16);
446
447         char final[256];
448         memset(final,0,256);
449
450         for ( i=0 ; i<16 ; i++ ) {
451                 sprintf(buf, "%02x", digest[i]);
452                 strcat( final, buf );
453         }
454
455         return strdup(final);
456
457 }
458
459 int osrfUtilsCheckFileDescriptor( int fd ) {
460
461         fd_set tmpset;
462         FD_ZERO(&tmpset);
463         FD_SET(fd, &tmpset);
464
465         struct timeval tv;
466         tv.tv_sec = 0;
467         tv.tv_usec = 0;
468
469         if( select(fd + 1, &tmpset, NULL, NULL, &tv) == -1 ) {
470                 if( errno == EBADF ) return -1;
471         }
472
473         return 0;
474 }
475