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