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