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