Although yet untested (but it compiles and is still unused) add UAT to the repo.
[obnox/wireshark/wip.git] / epan / uat.c
1 /*
2  *  uat.c
3  *
4  *  User Accessible Tables
5  *  Mantain an array of user accessible data strucures
6  *
7  */
8 #ifdef HAVE_CONFIG_H
9 # include "config.h"
10 #endif
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <ctype.h>
17 #include <stdarg.h>
18
19 #include <glib.h>
20 #include <epan/emem.h>
21 #include <epan/filesystem.h>
22
23 #include "uat-int.h"
24
25 static GPtrArray* all_uats = NULL;
26
27 void uat_init(void) {
28         all_uats = g_ptr_array_new();
29 }
30
31 uat_t* uat_start(const char* name,
32                                  size_t size,
33                                  char* filename,
34                                  void** data_ptr,
35                                  guint* num_items_ptr,
36                                  uat_copy_cb_t copy_cb,
37                                  uat_update_cb_t update_cb,
38                                  uat_free_cb_t free_cb) {
39         
40         uat_t* uat = g_malloc(sizeof(uat_t));
41         g_ptr_array_add(all_uats,uat);
42         
43         g_assert(name && size && filename && data_ptr && num_items_ptr);
44         
45         uat->name = g_strdup(name);
46         uat->record_size = size;
47         uat->filename = g_strdup(filename);
48         uat->user_ptr = data_ptr;
49         uat->nrows_p = num_items_ptr;
50         uat->copy_cb = copy_cb;
51         uat->update_cb = update_cb;
52         uat->free_cb = free_cb;
53         
54         uat->fields = NULL;
55         uat->ncols = 0;
56         uat->user_data = g_array_new(FALSE,FALSE,uat->record_size);
57         uat->finalized = FALSE;
58         uat->rep = NULL;
59         uat->free_rep = NULL;
60         
61         return uat;
62 }
63
64 void uat_add_field(uat_t* uat,
65                                    const char* name,
66                                    uat_text_mode_t mode,
67                                    uat_fld_chk_cb_t chk_cb,
68                                    uat_fld_set_cb_t set_cb,
69                                    uat_fld_tostr_cb_t tostr_cb) {
70         
71         uat_fld_t* f = g_malloc(sizeof(uat_fld_t));
72
73         g_assert( name && set_cb && tostr_cb && (! uat->finalized ) 
74                           && (mode == PT_TXTMOD_STRING || mode == PT_TXTMOD_HEXBYTES) );
75         
76         f->name = g_strdup(name);
77         f->mode = mode;
78         f->chk_cb = chk_cb;
79         f->set_cb = set_cb;
80         f->tostr_cb = tostr_cb;
81
82         f->rep = NULL;
83         f->free_rep = NULL;     
84         f->colnum = uat->ncols;
85         f->next = NULL;
86
87         uat->ncols++;
88         
89         if (uat->fields) {
90                 uat_fld_t* c;
91                 for (c = uat->fields; c->next; c = c->next) ;
92                 c->next = f;
93         } else {
94                 uat->fields = f;        
95         }
96 }
97
98 void uat_finalize(uat_t* uat) {
99         UAT_UPDATE(uat);
100         uat->finalized = TRUE;
101 }
102
103 uat_t* uat_new(const char* uat_name,
104                            size_t size,
105                            char* filename,
106                            void** data_ptr,
107                            guint* numitems_ptr,
108                            uat_copy_cb_t copy_cb,
109                            uat_update_cb_t update_cb,
110                            uat_free_cb_t free_cb,
111                            ...) {
112         uat_t* uat = uat_start(uat_name, size, filename, data_ptr, numitems_ptr, copy_cb, update_cb, free_cb);
113         va_list ap;
114         char* name;
115         uat_text_mode_t mode;
116         uat_fld_chk_cb_t chk_cb;
117         uat_fld_set_cb_t set_cb;
118         uat_fld_tostr_cb_t tostr_cb;
119         va_start(ap,free_cb);
120         
121         name = va_arg(ap,char*);
122         
123         do {
124                 mode = va_arg(ap,uat_text_mode_t);
125                 chk_cb = va_arg(ap,uat_fld_chk_cb_t);
126                 set_cb = va_arg(ap,uat_fld_set_cb_t);
127                 tostr_cb = va_arg(ap,uat_fld_tostr_cb_t);
128
129                 uat_add_field(uat, name, mode, chk_cb, set_cb, tostr_cb);
130                 
131                 name = va_arg(ap,char*);
132         } while (name);
133         
134         va_end(ap);
135         
136         uat_finalize(uat);
137         
138         return uat;
139 }
140
141 void* uat_add_record(uat_t* uat, const void* data) {
142         void* rec;
143         
144         g_assert( uat->finalized );
145         
146         g_array_append_vals (uat->user_data, data, 1);
147         
148         rec = uat->user_data->data + (uat->record_size * (uat->user_data->len-1));
149         
150         if (uat->copy_cb) {
151                 uat->copy_cb(rec, data, uat->record_size);
152         }
153         
154         
155         UAT_UPDATE(uat);
156         
157         return rec;
158 }
159
160 void uat_remove_record_idx(uat_t* uat, guint idx) {
161         
162         g_assert( uat->finalized && idx < uat->user_data->len);
163
164         g_array_remove_index(uat->user_data, idx);
165         
166         UAT_UPDATE(uat);
167
168 }
169
170
171 gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing) {
172         gchar* pers_fname =  get_persconffile_path(uat->filename,for_writing);
173         
174         if (! file_exists(pers_fname)) {
175                 gchar* data_fname = get_datafile_path(uat->filename);
176                 
177                 if (file_exists(data_fname)) {
178                         return data_fname;
179                 }
180         }
181         
182         return pers_fname;
183 }
184
185 static void putfld(FILE* fp, void* rec, uat_fld_t* f) {
186         guint fld_len;
187         char* fld_ptr;
188         
189         f->tostr_cb(rec,&fld_ptr,&fld_len);
190         
191         switch(f->mode){
192                 case  PT_TXTMOD_STRING: {
193                         guint i;
194                         
195                         putc('"',fp);
196                         
197                         for(i=0;i<fld_len;i++) {
198                                 char c = fld_ptr[i];
199                                 
200                                 if (c == '"') {
201                                         fputs("\134\042",fp);
202                                 } else if (isprint(c)) {
203                                         putc(c,fp);
204                                 } else {
205                                         fprintf(fp,"\\x%.2x",c);
206                                 }
207                         }
208                         
209                         putc('"',fp);
210                         return;
211                 }
212                 case PT_TXTMOD_HEXBYTES: {
213                         guint i;
214                         
215                         for(i=0;i<fld_len;i++) {
216                                 fprintf(fp,"%.2x",fld_ptr[i]);
217                         }
218                         
219                         return;
220                 }
221                 default:
222                         g_assert_not_reached();
223         }
224 }
225
226 gboolean uat_save(uat_t* uat, char** error) {
227         guint i;
228         gchar* fname = uat_get_actual_filename(uat,TRUE);
229         FILE* fp = fopen(fname,"w");
230         
231
232         if (!fp) {
233                 *error = ep_strdup_printf("uat_save: error opening '%s': %s",fname,strerror(errno));
234                 return FALSE;
235         }
236
237         *error = NULL;
238
239         for ( i = 0 ; i < uat->user_data->len - 1 ; i++ ) {
240                 void* rec = uat->user_data->data + (uat->record_size * (uat->user_data->len-1));
241                 uat_fld_t* f;
242                 
243                 f = uat->fields;
244                 
245                 putfld(fp, rec, f);
246                         
247                 while (( f = f->next )) {
248                         fputs(",",fp);
249                         putfld(fp, rec, f);                             
250                 }
251
252                 fputs("\n",fp);
253         }
254
255         fclose(fp);
256         
257         return TRUE;
258 }
259
260 void uat_destroy(uat_t* uat) {
261         g_ptr_array_remove(all_uats,uat);
262         
263 }
264
265 void* uat_dup(uat_t* uat, guint* len_p) {
266         guint size = (uat->record_size * uat->user_data->len);
267         *len_p = size;
268         return size ? g_memdup(uat->user_data->data,size) : NULL ;
269 }
270
271 void* uat_se_dup(uat_t* uat, guint* len_p) {
272         guint size = (uat->record_size * uat->user_data->len);
273         *len_p = size;
274         return size ? se_memdup(uat->user_data->data,size) : NULL ;
275 }
276
277 void uat_cleanup(void) {
278
279         while( all_uats->len ) {
280                 uat_destroy((uat_t*)all_uats->pdata);
281         }
282
283         g_ptr_array_free(all_uats,TRUE);
284 }
285