428ff8422cb296fdc72f8d85a7bb8bf8a4f32ad0
[OpenSRF.git] / src / libopensrf / string_array.c
1 #include <opensrf/string_array.h>
2
3 osrfStringArray* osrfNewStringArray(int size) {
4         if(size > STRING_ARRAY_MAX_SIZE)
5                 osrfLogError( OSRF_LOG_MARK, "osrfNewStringArray size is too large");
6
7         osrfStringArray* arr;
8         OSRF_MALLOC(arr, sizeof(osrfStringArray));
9         arr->size = 0;
10
11         // Initialize list
12         arr->list.size = 0;
13         arr->list.freeItem = NULL;
14         if( size <= 0 )
15                 arr->list.arrsize = 16;
16         else
17                 arr->list.arrsize = size;
18         OSRF_MALLOC( arr->list.arrlist, arr->list.arrsize * sizeof(void*) );
19
20         // Nullify all pointers in the array
21
22         int i;
23         for( i = 0; i < arr->list.arrsize; ++i )
24                 arr->list.arrlist[ i ] = NULL;
25
26         osrfListSetDefaultFree(&arr->list);
27         return arr;
28 }
29
30 void osrfStringArrayAdd( osrfStringArray* arr, const char* string ) {
31         if(arr == NULL || string == NULL ) return;
32         if( arr->list.size > STRING_ARRAY_MAX_SIZE )
33                 osrfLogError( OSRF_LOG_MARK, "osrfStringArrayAdd size is too large" );
34     osrfListPush(&arr->list, strdup(string));
35     arr->size = arr->list.size;
36 }
37
38 char* osrfStringArrayGetString( osrfStringArray* arr, int index ) {
39     if(!arr) return NULL;
40         return OSRF_LIST_GET_INDEX(&arr->list, index);
41 }
42
43 void osrfStringArrayFree(osrfStringArray* arr) {
44
45         // This function is a sleazy hack designed to avoid the
46         // need to duplicate the code in osrfListFree().  It
47         // works because:
48         //
49         // 1. The osrfList is the first member of an
50         //    osrfStringArray.  C guarantees that a pointer
51         //    to the one is also a pointer to the other.
52         //
53         // 2. The rest of the osrfStringArray owns no memory
54         //    and requires no special attention when freeing.
55         //
56         // If these facts ever cease to be true, we'll have to
57         // revisit this function.
58         
59         osrfListFree( (osrfList*) arr );
60 }
61
62 int osrfStringArrayContains(
63         const osrfStringArray* arr, const char* string ) {
64         if(!(arr && string)) return 0;
65         int i;
66         for( i = 0; i < arr->size; i++ ) {
67         char* str = OSRF_LIST_GET_INDEX(&arr->list, i);
68                 if(str && !strcmp(str, string)) 
69             return 1;
70         }
71
72         return 0;
73 }
74
75 void osrfStringArrayRemove( osrfStringArray* arr, const char* tstr ) {
76         if(!(arr && tstr)) return;
77         int i;
78     char* str;
79
80         for( i = 0; i < arr->size; i++ ) {
81         /* find and remove the string */
82         str = OSRF_LIST_GET_INDEX(&arr->list, i);
83                 if(str && !strcmp(str, tstr)) {
84             osrfListRemove(&arr->list, i);
85                         break;
86                 }
87         }
88
89     /* disable automatic item freeing on delete and shift
90      * items up in the array to fill in the gap
91      */
92     arr->list.freeItem = NULL;
93         for( ; i < arr->size - 1; i++ ) 
94         osrfListSet(&arr->list, OSRF_LIST_GET_INDEX(&arr->list, i+1), i);
95
96     /* remove the last item since it was shifted up */
97     osrfListRemove(&arr->list, i);
98
99     /* re-enable automatic item freeing in delete */
100     osrfListSetDefaultFree(&arr->list);
101         arr->size--;
102 }
103
104 osrfStringArray* osrfStringArrayTokenize( const char* src, char delim )
105 {
106         // Take the length so that we know how big a buffer we need,
107         // in the worst case.  Esitimate the number of tokens, assuming
108         // 5 characters per token, and add a few for a pad.
109
110         if( NULL == src || '\0' == *src )               // Got nothing?
111                 return osrfNewStringArray( 1 );         // Retrun empty array
112
113         size_t src_len = strlen( src );
114         size_t est_count = src_len / 6 + 5;
115         int in_token = 0;     // boolean
116         char buf[ src_len + 1 ];
117         char* out = buf;
118         osrfStringArray* arr = osrfNewStringArray( est_count );
119
120         for( ;; ++src ) {
121                 if( in_token ) {        // We're building a token
122                         if( *src == delim ) {
123                                 *out = '\0';
124                                 osrfStringArrayAdd( arr, buf );
125                                 in_token = 0;
126                         }
127                         else if( '\0' == *src ) {
128                                 *out = '\0';
129                                 osrfStringArrayAdd( arr, buf );
130                                 break;
131                         }
132                         else {
133                                 *out++ = *src;
134                         }
135                 }
136                 else {                          // We're between tokens
137                         if( *src == delim ) {
138                                 ;                       // skip it
139                         }
140                         else if( '\0' == *src ) {
141                                 break;
142                         }
143                         else {
144                                 out = buf;              // Start the next one
145                                 *out++ = *src;
146                                 in_token = 1;
147                         }
148                 }
149         }
150         
151         return arr;
152 }