]> git.vomp.tv Git - vompserver.git/blob - config.c
FTA options patch by davep
[vompserver.git] / config.c
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Copyright 2004-2005 University Of Bradford
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "config.h"
23
24 Config::Config()
25 {
26   initted = 0;
27   lastLineLength = 0;
28   log = Log::getInstance();
29 }
30
31 int Config::init(char* takeFileName)
32 {
33   if (initted) return 1;
34
35   pthread_mutex_init(&fileLock, NULL);
36
37   if (strlen(takeFileName) > (MAX_FILENAME_LENGTH - 1))
38   {
39     log->log("Config", Log::DEBUG, "Config error: Config filename too long");
40     return 0;
41   }
42
43   strcpy(fileName, takeFileName);
44   strcpy(fileNameTemp, takeFileName);
45   strcat(fileNameTemp, ".tmp");
46
47   file = fopen(fileName, "r");
48   if (!file)
49   {
50     file = fopen(fileName, "w");
51     if (!file)
52     {
53       log->log("Config", Log::DEBUG, "Config error: Could not access config file");
54       return 0;
55     }
56   }
57   fclose(file);
58
59   initted = 1;
60
61   return 1;
62 }
63
64 int Config::shutdown()
65 {
66   if (!initted) return 1;
67
68   pthread_mutex_lock(&fileLock);
69   initted = 0;
70   pthread_mutex_unlock(&fileLock);
71   pthread_mutex_destroy(&fileLock);
72
73   return 1;
74 }
75
76 int Config::openFile()
77 {
78   if (!initted) return 0;
79   if (pthread_mutex_lock(&fileLock))
80   {
81     log->log("Config", Log::DEBUG, "Config error: Could not get lock");
82     return 0;
83   }
84   if (!initted)
85   {
86     log->log("Config", Log::DEBUG, "Config error: Initted 0 after lock");
87     pthread_mutex_unlock(&fileLock);
88     return 0;
89   }
90
91   file = fopen(fileName, "r");
92   if (!file)
93   {
94     log->log("Config", Log::DEBUG, "Config error: Could not open config file");
95     pthread_mutex_unlock(&fileLock);
96     return 0;
97   }
98   return 1;
99 }
100
101 void Config::closeFile()
102 {
103   if (!initted) return;
104
105   fclose(file);
106   file = NULL;
107   pthread_mutex_unlock(&fileLock);
108 }
109
110 int Config::readLine()
111 {
112   if (!initted || !file) { log->log("Config", Log::DEBUG, "1"); return 0; }
113   if (!fgets(buffer, BUFFER_LENGTH-1, file)) { log->log("Config", Log::DEBUG, "2"); return 0; }
114   lastLineLength = strlen(buffer);
115   log->log("Config", Log::DEBUG, "buffer before trim: '%s'", buffer);
116   trim(buffer);
117   log->log("Config", Log::DEBUG, "buffer after trim: '%s'", buffer);
118   return 1;
119 }
120
121 // START HERE
122
123 FILE* Config::copyToHere(long position)
124 {
125   FILE* newFile = fopen(fileNameTemp, "w");
126
127   if (!newFile) return NULL;
128
129   long newPos = 0;
130   rewind(file);
131
132   while (newPos < position)
133   {
134     fgets(buffer, BUFFER_LENGTH-1, file);
135     fputs(buffer, newFile);
136     newPos += strlen(buffer);
137   }
138   return newFile;
139 }
140
141 int Config::copyRest(FILE* newFile)
142 {
143   if (newFile)
144   {
145     while(fgets(buffer, BUFFER_LENGTH-1, file))
146     {
147       fputs(buffer, newFile);
148     }
149
150     fclose(newFile);
151   }
152   fclose(file);
153   file = NULL;
154
155   if (newFile) rename(fileNameTemp, fileName);
156
157   pthread_mutex_unlock(&fileLock);
158   return 1;
159 }
160
161 int Config::deleteValue(char* section, char* key)
162 {
163   if (!initted) return 0;
164   if (!openFile()) return 0;
165
166   if (!findSection(section))
167   {
168     closeFile();
169     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
170     return 0;
171   }
172   if (!findKey(key))
173   {
174     closeFile();
175     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
176     return 0;
177   }
178
179   FILE* newFile = copyToHere(ftell(file) - lastLineLength);
180   fgets(buffer, BUFFER_LENGTH-1, file);
181
182   return copyRest(newFile);
183 }
184
185 int Config::setValueLong(char* section, char* key, long newValue)
186 {
187   char longBuffer[50];
188   sprintf(longBuffer, "%li", newValue);
189   return setValueString(section, key, longBuffer);
190 }
191
192 int Config::setValueLongLong(char* section, char* key, long long newValue)
193 {
194   char longBuffer[50];
195   sprintf(longBuffer, "%lli", newValue);
196   return setValueString(section, key, longBuffer);
197 }
198
199 int Config::setValueDouble(char* section, char* key, double newValue)
200 {
201   char doubleBuffer[50];
202   sprintf(doubleBuffer, "%f", newValue);
203   return setValueString(section, key, doubleBuffer);
204 }
205
206 int Config::setValueString(char* section, char* key, char* newValue)
207 {
208   if (!initted) return 0;
209   if (!openFile()) return 0;
210
211   if (findSection(section))
212   {
213     if (findKey(key))
214     {
215       FILE* newFile = copyToHere(ftell(file) - lastLineLength);
216       if (!newFile)
217       {
218         closeFile();
219         log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
220         return 0;
221       }
222
223       fgets(buffer, BUFFER_LENGTH-1, file);
224       fprintf(newFile, "%s = %s\n", key, newValue);
225       return copyRest(newFile);
226     }
227     else
228     {
229       rewind(file);
230       findSection(section);
231       FILE* newFile = copyToHere(ftell(file));
232       if (!newFile)
233       {
234         closeFile();
235         log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
236         return 0;
237       }
238
239       fprintf(newFile, "%s = %s\n", key, newValue);
240       return copyRest(newFile);
241     }
242   }
243   else
244   {
245     // section not found
246     fseek(file, 0, SEEK_END);
247     FILE* newFile = copyToHere(ftell(file));
248     if (!newFile)
249     {
250       closeFile();
251       log->log("Config", Log::DEBUG, "Config error: Could not write temp config file");
252       return 0;
253     }
254
255     fprintf(newFile, "[%s]\n%s = %s\n", section, key, newValue);
256     return copyRest(newFile);
257   }
258 }
259
260 char* Config::getSectionKeyNames(char* section, int& numberOfReturns, int& allKeysSize)
261 {
262   numberOfReturns = 0;
263   allKeysSize = 0;
264   char* allKeys = NULL;
265   int allKeysIndex = 0;
266   int keyLength;
267   char* equalspos;
268
269   if (!initted) return NULL;
270   if (!openFile()) return NULL;
271   if (!findSection(section)) return NULL;
272
273   char foundKey[BUFFER_LENGTH];
274
275   while(readLine())
276   {
277     // Is this line a section header? if so, exit
278     if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) break;
279
280     equalspos = strstr(buffer, "=");
281     if (!equalspos) continue;  // if there is no = then it's not a key
282     memcpy(foundKey, buffer, equalspos-buffer);
283     foundKey[equalspos-buffer] = '\0';
284     trim(foundKey);
285     keyLength = strlen(foundKey);
286     allKeysSize += keyLength + 1;
287     allKeys = (char*)realloc(allKeys, allKeysSize);
288     memcpy(&allKeys[allKeysIndex], foundKey, keyLength);
289     allKeysIndex += keyLength;
290     allKeys[allKeysIndex] = '\0';
291     allKeysIndex++;
292     numberOfReturns++;
293   }
294
295   closeFile();
296   return allKeys;
297 }
298
299
300 // END HERE
301
302 int Config::findSection(char* section)
303 {
304   if (!initted || !file) return 0;
305   if (strlen(section) > (BUFFER_LENGTH-2))
306   {
307     log->log("Config", Log::DEBUG, "Config error: Section given exceeds max length");
308     return 0;
309   }
310
311   char toFind[BUFFER_LENGTH];
312   toFind[0] = '[';
313   toFind[1] = '\0';
314   strcat(toFind, section);
315   strcat(toFind, "]");
316
317   while(readLine())
318   {
319     log->log("Config", Log::DEBUG, "to find '%s' this line '%s'", toFind, buffer);
320     if (!strcmp(toFind, buffer)) return 1;
321   }
322   return 0;
323 }
324
325 int Config::findKey(char* key)
326 {
327   if (!initted || !file) return 0;
328
329   if (strlen(key) > (BUFFER_LENGTH-1))
330   {
331     log->log("Config", Log::DEBUG, "Config error: Key given exceeds max length");
332     return 0;
333   }
334
335   char prepForTest[BUFFER_LENGTH];
336
337   // do a rough search first, this could match substrings that we don't want
338   while(readLine())
339   {
340     // Is this line a section header? if so, exit
341     if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) return 0;
342     if (strstr(buffer, key))
343     {
344       // rough search found match
345       char* equalspos = strstr(buffer, "=");
346       if (!equalspos) continue;
347       memcpy(prepForTest, buffer, equalspos-buffer);
348       prepForTest[equalspos-buffer] = '\0';
349       trim(prepForTest);
350
351       if (!strcmp(key, prepForTest))
352       {
353         // in buffer, set all up to equals to space, then trim!
354         for(char* curPos = buffer; curPos <= equalspos; curPos++)
355         {
356           *curPos = ' ';
357         }
358         trim(buffer);
359         return 1;
360       }
361     }
362   }
363   return 0;
364 }
365
366 char* Config::getValueString(char* section, char* key)
367 {
368   if (!initted) return NULL;
369   if (!openFile()) return NULL;
370
371   if (!findSection(section))
372   {
373     closeFile();
374     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
375     return 0;
376   }
377   if (!findKey(key))
378   {
379     closeFile();
380     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
381     return 0;
382   }
383
384   char* returnString = new char[strlen(buffer)+1];
385   strcpy(returnString, buffer);
386
387   closeFile();
388
389   return returnString;
390 }
391
392 long Config::getValueLong(char* section, char* key, int* failure)
393 {
394   *failure = 1;
395   if (!initted) return 0;
396   if (!openFile()) return 0;
397
398   if (!findSection(section))
399   {
400     closeFile();
401     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
402     return 0;
403   }
404   if (!findKey(key))
405   {
406     closeFile();
407     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
408     return 0;
409   }
410   *failure = 0;
411
412   char* check;
413   long retVal = strtol(buffer, &check, 10);
414   if ((retVal == 0) && (check == buffer)) *failure = 1;
415   closeFile();
416
417   return retVal;
418 }
419
420 long long Config::getValueLongLong(char* section, char* key, int* failure)
421 {
422   *failure = 1;
423   if (!initted) return 0;
424   if (!openFile()) return 0;
425
426   if (!findSection(section))
427   {
428     closeFile();
429     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
430     return 0;
431   }
432   if (!findKey(key))
433   {
434     closeFile();
435     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
436     return 0;
437   }
438   *failure = 0;
439
440   char* check;
441   long long retVal = strtoll(buffer, &check, 10);
442   if ((retVal == 0) && (check == buffer)) *failure = 1;
443   closeFile();
444
445   return retVal;
446 }
447
448 double Config::getValueDouble(char* section, char* key, int* failure)
449 {
450   *failure = 1;
451   if (!initted) return 0;
452   if (!openFile()) return 0;
453
454   if (!findSection(section))
455   {
456     closeFile();
457     log->log("Config", Log::DEBUG, "Config error: Section %s not found", section);
458     return 0;
459   }
460   if (!findKey(key))
461   {
462     closeFile();
463     log->log("Config", Log::DEBUG, "Config error: Key %s not found", key);
464     return 0;
465   }
466
467   *failure = 0;
468
469   char* check;
470   double retVal = strtod(buffer, &check);
471   if ((retVal == 0) && (check == buffer)) *failure = 1;
472
473   closeFile();
474
475   return retVal;
476 }
477
478
479
480 void Config::trim(char* str)
481 {
482   int pos, len, start, end;
483
484   // Kill comments
485   len = strlen(str);
486   for(pos = 0; pos < len; pos++)
487   {
488     if ((str[pos] == '#') || (str[pos] == ';'))
489     {
490       // Mod. If #/; is at start of line ok. Else, if it is after a space, ok.
491
492       if ((pos == 0) || (isspace(str[pos - 1])))
493       {
494         str[pos] = '\0';
495         break;
496       }
497
498     }
499   }
500
501   len = strlen(str);
502   end = len;
503   if (!len) return;
504
505   start = 0;
506   while(isspace(str[start])) start++;
507   while(isspace(str[end-1]))
508   {
509     end--;
510     if (end == 0)
511     {
512       str[0] = '\0';
513       return;
514     }
515   }
516   for(pos = start; pos < end; pos++) str[pos - start] = str[pos];
517   str[end - start] = '\0';
518 }