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