version update
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bchash.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include "bchash.h"
27 #include "bcsignals.h"
28 #include "filesystem.h"
29
30 BC_Hash::BC_Hash()
31 {
32         this->filename[0] = 0;
33         total = 0;
34         allocated = 0;
35         names = 0;
36         values = 0;
37 }
38
39 BC_Hash::BC_Hash(const char *filename)
40 {
41         strcpy(this->filename, filename);
42         total = 0;
43         allocated = 0;
44         names = 0;
45         values = 0;
46
47         FileSystem directory;
48
49         directory.parse_tildas(this->filename);
50 }
51
52 void BC_Hash::clear()
53 {
54         for(int i = 0; i < total; i++)
55         {
56                 delete [] names[i];
57                 delete [] values[i];
58         }
59         total = 0;
60 }
61
62 BC_Hash::~BC_Hash()
63 {
64         clear();
65         delete [] names;
66         delete [] values;
67 }
68
69 void BC_Hash::reallocate_table(int new_total)
70 {
71         if(allocated < new_total)
72         {
73                 int new_allocated = new_total * 2;
74                 char **new_names = new char*[new_allocated];
75                 char **new_values = new char*[new_allocated];
76
77                 for(int i = 0; i < total; i++)
78                 {
79                         new_names[i] = names[i];
80                         new_values[i] = values[i];
81                 }
82
83                 delete [] names;
84                 delete [] values;
85
86                 names = new_names;
87                 values = new_values;
88                 allocated = new_allocated;
89         }
90 }
91
92 int BC_Hash::load_file(FILE *fp)
93 {
94         char line[4096];
95         int done = 0, ch = -1;
96         total = 0;
97
98         while( !done ) {
99                 char *bp = line, *ep = bp + sizeof(line);
100                 if( !fgets(bp, ep-bp, fp) ) break;
101                 // skip ws (indent)
102                 while( bp < ep && *bp == ' ' ) ++bp;
103                 if( bp >= ep || !*bp || *bp == '\n' ) continue;
104                 char *title = bp;
105                 // span to ws
106                 while( bp < ep && *bp && *bp != ' ' && *bp != '\n' ) ++bp;
107                 if( bp >= ep || title == bp ) continue;
108                 int title_len = bp - title;
109                 // skip blank seperator
110                 if( *bp++ != ' ' ) continue;
111                 reallocate_table(total + 1);
112                 char *tp = new char[title_len + 1];
113                 names[total] = tp;
114                 while( --title_len >= 0 ) *tp++ = *title++;
115                 *tp = 0;
116                 // accumulate value (+ continued lines)
117                 char *value = bp;
118                 while( bp < ep && !done ) {
119                         while( bp < ep && *bp && *bp != '\n' ) ++bp;
120                         if( bp >= ep || !*bp ) break;
121                         if( (ch=fgetc(fp)) < 0 ) break;
122                         if( ch != '+' ) { ungetc(ch, fp); break; }
123                         *bp++ = '\n';
124                         done = !fgets(bp, ep-bp, fp);
125                 }
126                 int value_len = bp - value;
127                 char *vp = new char[value_len + 1];
128                 values[total] = vp;
129                 while( --value_len >= 0 ) *vp++ = *value++;
130                 *vp = 0;
131                 total++;
132         }
133         return 0;
134 }
135
136 int BC_Hash::load()
137 {
138         FILE *fp = fopen(filename, "r");
139         if( !fp ) return 1;
140         int ret = load_file(fp);
141         fclose(fp);
142         return ret;
143 }
144
145 int BC_Hash::save_file(FILE *fp)
146 {
147         for(int i = 0; i < total; i++) {
148                 fputs(names[i], fp);
149                 char *vp = values[i];
150                 char *bp = vp;
151                 fputc(' ',fp);
152                 while( (vp=strchr(vp, '\n')) ) {
153                         while( bp < vp ) fputc(*bp++,fp);
154                         fputc('\n',fp);  fputc('+',fp);
155                         ++bp;  ++vp;
156                 }
157                 while( *bp ) fputc(*bp++,fp);
158                 fputc('\n', fp);
159         }
160         return 0;
161 }
162
163 int BC_Hash::save()
164 {
165         FILE *fp = fopen(filename,"w");
166         if( !fp ) return 1;
167         int ret = save_file(fp);
168         fclose(fp);
169         return ret;
170 }
171
172 int BC_Hash::load_string(const char *bfr)
173 {
174         FILE *fp = fmemopen((void*)bfr, strlen(bfr), "r");
175         if( !fp ) return 1;
176         int ret = load_file(fp);
177         fclose(fp);
178         return ret;
179 }
180
181 int BC_Hash::save_string(char *&bfr)
182 {
183         size_t bsz = 0;
184         FILE *fp = open_memstream(&bfr, &bsz);
185         if( !fp ) return 1;
186         int ret = save_file(fp);
187         fclose(fp);
188         return ret;
189 }
190
191
192
193 int32_t BC_Hash::get(const char *name, int32_t default_)
194 {
195         for(int i = 0; i < total; i++)
196         {
197                 if(!strcmp(names[i], name))
198                 {
199                         return (int32_t)atol(values[i]);
200                 }
201         }
202         return default_;  // failed
203 }
204
205 int64_t BC_Hash::get(const char *name, int64_t default_)
206 {
207         int64_t result = default_;
208         for(int i = 0; i < total; i++)
209         {
210                 if(!strcmp(names[i], name))
211                 {
212                         sscanf(values[i], "%jd", &result);
213                         return result;
214                 }
215         }
216         return result;
217 }
218
219 double BC_Hash::get(const char *name, double default_)
220 {
221         for(int i = 0; i < total; i++)
222         {
223                 if(!strcmp(names[i], name))
224                 {
225                         return atof(values[i]);
226                 }
227         }
228         return default_;  // failed
229 }
230
231 float BC_Hash::get(const char *name, float default_)
232 {
233         for(int i = 0; i < total; i++)
234         {
235                 if(!strcmp(names[i], name))
236                 {
237                         return atof(values[i]);
238                 }
239         }
240         return default_;  // failed
241 }
242
243 char* BC_Hash::get(const char *name, char *default_)
244 {
245         for(int i = 0; i < total; i++)
246         {
247                 if(!strcmp(names[i], name))
248                 {
249                         strcpy(default_, values[i]);
250                         return values[i];
251                 }
252         }
253         return default_;  // failed
254 }
255
256 int BC_Hash::update(const char *name, double value) // update a value if it exists
257 {
258         char string[BCSTRLEN];
259         sprintf(string, "%.16e", value);
260         return update(name, string);
261 }
262
263 int BC_Hash::update(const char *name, float value) // update a value if it exists
264 {
265         char string[BCSTRLEN];
266         sprintf(string, "%.6e", value);
267         return update(name, string);
268 }
269
270 int BC_Hash::update(const char *name, int32_t value) // update a value if it exists
271 {
272         char string[BCSTRLEN];
273         sprintf(string, "%d", value);
274         return update(name, string);
275 }
276
277 int BC_Hash::update(const char *name, int64_t value) // update a value if it exists
278 {
279         char string[BCSTRLEN];
280         sprintf(string, "%jd", value);
281         return update(name, string);
282 }
283
284 int BC_Hash::update(const char *name, const char *value)
285 {
286         for(int i = 0; i < total; i++)
287         {
288                 if(!strcmp(names[i], name))
289                 {
290                         delete [] values[i];
291                         values[i] = new char[strlen(value) + 1];
292                         strcpy(values[i], value);
293                         return 0;
294                 }
295         }
296
297 // didn't find so create new entry
298         reallocate_table(total + 1);
299         names[total] = new char[strlen(name) + 1];
300         strcpy(names[total], name);
301         values[total] = new char[strlen(value) + 1];
302         strcpy(values[total], value);
303         total++;
304         return 1;
305 }
306
307 #define varFn(rtyp, fn, typ) \
308 rtyp BC_Hash::fn##f(typ value, const char *fmt, ...) { \
309   char string[BCTEXTLEN];  va_list ap; va_start(ap, fmt); \
310   vsnprintf(string, BCTEXTLEN, fmt, ap); \
311   va_end(ap);  return fn(string, value); \
312 }
313
314 varFn(int,update,double)        varFn(double,get,double)
315 varFn(int,update,float)         varFn(float,get,float)
316 varFn(int,update,int32_t)       varFn(int32_t,get,int32_t)
317 varFn(int,update,int64_t)       varFn(int64_t,get,int64_t)
318 varFn(int,update,const char *)  varFn(char *,get,char *)
319
320
321 void BC_Hash::copy_from(BC_Hash *src)
322 {
323 // Can't delete because this is used by file decoders after plugins
324 // request data.  use explicit destructor to clear/clean
325 //      this->~BC_Hash();
326
327 SET_TRACE
328         reallocate_table(src->total);
329 //      total = src->total;
330 SET_TRACE
331         for(int i = 0; i < src->total; i++)
332         {
333                 update(src->names[i], src->values[i]);
334 //              names[i] = new char[strlen(src->names[i]) + 1];
335 //              values[i] = new char[strlen(src->values[i]) + 1];
336 //              strcpy(names[i], src->names[i]);
337 //              strcpy(values[i], src->values[i]);
338         }
339 SET_TRACE
340 }
341
342 int BC_Hash::equivalent(BC_Hash *src)
343 {
344         for(int i = 0; i < total && i < src->total; i++)
345         {
346                 if(strcmp(names[i], src->names[i]) ||
347                         strcmp(values[i], src->values[i])) return 0;
348         }
349         return 1;
350 }
351
352 int BC_Hash::size()
353 {
354         return total;
355 }
356
357 char* BC_Hash::get_key(int number)
358 {
359         return names[number];
360 }
361
362 char* BC_Hash::get_value(int number)
363 {
364         return values[number];
365 }
366
367
368 void BC_Hash::dump()
369 {
370         printf("BC_Hash::dump\n");
371         for(int i = 0; i < total; i++)
372                 printf("        key=%s value=%s\n", names[i], values[i]);
373 }