You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

inifile.cc 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*
  2. Library for inifile like data files.
  3. Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "inifile.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #define MYNAME "inifile"
  21. typedef struct inifile_entry_s {
  22. queue Q;
  23. char* key;
  24. char* val;
  25. } inifile_entry_t;
  26. typedef struct inifile_section_s {
  27. queue Q;
  28. char* name;
  29. int ientries;
  30. queue entries;
  31. } inifile_section_t;
  32. /* internal procedures */
  33. #define START_BUFSIZE 257
  34. #define DELTA_BUFSIZE 128
  35. #define GPSBABEL_INIFILE "gpsbabel.ini"
  36. /* Remember the filename we used so we can include it in errors. */
  37. char* gbinipathname;
  38. static char*
  39. find_gpsbabel_inifile(const char* path) /* can be empty or NULL */
  40. {
  41. FILE* test;
  42. char* buff;
  43. int len;
  44. if (path == NULL) {
  45. return NULL;
  46. }
  47. len = strlen(path);
  48. buff = (char*) xmalloc(len + 1 + strlen(GPSBABEL_INIFILE) + 1);
  49. strcpy(buff, path);
  50. if (len > 0) {
  51. char test = buff[len - 1];
  52. #ifdef __WIN32__
  53. if ((test != '\\') && (test != ':')) {
  54. strcat(buff, "\\");
  55. }
  56. #else
  57. if (test != '/') {
  58. strcat(buff, "/");
  59. }
  60. #endif
  61. }
  62. strcat(buff, GPSBABEL_INIFILE);
  63. test = fopen(buff, "rb");
  64. if (test) {
  65. fclose(test);
  66. return buff;
  67. }
  68. xfree(buff);
  69. return NULL;
  70. }
  71. static gbfile*
  72. open_gpsbabel_inifile(void)
  73. {
  74. char* name;
  75. char* envstr;
  76. gbfile* res = NULL;
  77. envstr = getenv("GPSBABELINI");
  78. if (envstr != NULL) {
  79. FILE* test;
  80. test = fopen(envstr, "r");
  81. if (test != NULL) {
  82. fclose(test);
  83. return gbfopen(envstr, "r", "GPSBabel");
  84. }
  85. warning("WARNING: GPSBabel-inifile, defined in environment, NOT found!\n");
  86. return NULL;
  87. }
  88. name = find_gpsbabel_inifile(""); /* PWD */
  89. if (name == NULL) {
  90. #ifdef __WIN32__
  91. name = find_gpsbabel_inifile(getenv("APPDATA"));
  92. if (name == NULL) {
  93. name = find_gpsbabel_inifile(getenv("WINDIR"));
  94. }
  95. if (name == NULL) {
  96. name = find_gpsbabel_inifile(getenv("SYSTEMROOT"));
  97. }
  98. #else
  99. if ((envstr = getenv("HOME")) != NULL) {
  100. char* path;
  101. path = (char*) xmalloc(strlen(envstr) + 11);
  102. strcpy(path, envstr);
  103. strcat(path, "/.gpsbabel");
  104. name = find_gpsbabel_inifile(path);
  105. xfree(path);
  106. }
  107. if (name == NULL) {
  108. name = find_gpsbabel_inifile("/usr/local/etc");
  109. }
  110. if (name == NULL) {
  111. name = find_gpsbabel_inifile("/etc");
  112. }
  113. #endif
  114. }
  115. if (name != NULL) {
  116. res = gbfopen(name, "r", "GPSBabel");
  117. if (gbinipathname) {
  118. xfree(gbinipathname);
  119. }
  120. gbinipathname = name;
  121. }
  122. return res;
  123. }
  124. static void
  125. inifile_load_file(gbfile* fin, inifile_t* inifile, const char* myname)
  126. {
  127. char* buf;
  128. inifile_section_t* sec = NULL;
  129. int line = 0;
  130. while ((buf = gbfgetstr(fin))) {
  131. char* cin = lrtrim(buf);
  132. if ((line++ == 0) && fin->unicode) {
  133. inifile->unicode = 1;
  134. }
  135. if (*cin == '\0') {
  136. continue; /* skip empty lines */
  137. }
  138. if ((*cin == '#') || (*cin == ';')) {
  139. continue; /* skip comments */
  140. }
  141. if (*cin == '[') {
  142. char* cend = strchr(++cin, ']');
  143. if (cend != NULL) {
  144. *cend = '\0';
  145. cin = lrtrim(cin);
  146. }
  147. if ((*cin == '\0') || (cend == NULL)) {
  148. fatal("%s: invalid section header '%s' in '%s'.\n", myname, cin, gbinipathname);
  149. }
  150. sec = (inifile_section_t*) xcalloc(1, sizeof(*sec));
  151. sec->name = xstrdup(cin);
  152. QUEUE_INIT(&sec->entries);
  153. ENQUEUE_TAIL(&inifile->secs, &sec->Q);
  154. inifile->isecs++;
  155. } else {
  156. char* cx;
  157. inifile_entry_t* entry;
  158. if (sec == NULL) {
  159. fatal("%s: missing section header in '%s'.\n", myname,gbinipathname);
  160. }
  161. entry = (inifile_entry_t*) xcalloc(1, sizeof(*entry));
  162. ENQUEUE_TAIL(&sec->entries, &entry->Q);
  163. sec->ientries++;
  164. cx = strchr(cin, '=');
  165. if (cx != NULL) {
  166. *cx = '\0';
  167. cin = lrtrim(cin);
  168. }
  169. entry->key = xstrdup(cin);
  170. if (cx != NULL) {
  171. cx = lrtrim(++cx);
  172. entry->val = xstrdup(cx);
  173. } else {
  174. entry->val = xstrdup("");
  175. }
  176. }
  177. }
  178. }
  179. static char*
  180. inifile_find_value(const inifile_t* inifile, const char* sec_name, const char* key)
  181. {
  182. queue* elem, *tmp;
  183. if (inifile == NULL) {
  184. return NULL;
  185. }
  186. QUEUE_FOR_EACH(&inifile->secs, elem, tmp) {
  187. inifile_section_t* sec = (inifile_section_t*) elem;
  188. if (case_ignore_strcmp(sec->name, sec_name) == 0) {
  189. queue* elem, *tmp;
  190. QUEUE_FOR_EACH(&sec->entries, elem, tmp) {
  191. inifile_entry_t* entry = (inifile_entry_t*) elem;
  192. if (case_ignore_strcmp(entry->key, key) == 0) {
  193. return entry->val;
  194. }
  195. }
  196. }
  197. }
  198. return NULL;
  199. }
  200. /* public procedures */
  201. /*
  202. inifile_init:
  203. reads inifile filename into memory
  204. myname represents the calling module
  205. filename == NULL: try to open global gpsbabel.ini
  206. */
  207. inifile_t*
  208. inifile_init(const char* filename, const char* myname)
  209. {
  210. inifile_t* result;
  211. gbfile* fin = NULL;
  212. if (filename == NULL) {
  213. fin = open_gpsbabel_inifile();
  214. if (fin == NULL) {
  215. return NULL;
  216. }
  217. } else {
  218. fin = gbfopen(filename, "rb", myname);
  219. }
  220. result = (inifile_t*) xcalloc(1, sizeof(*result));
  221. QUEUE_INIT(&result->secs);
  222. inifile_load_file(fin, result, myname);
  223. gbfclose(fin);
  224. return result;
  225. }
  226. void
  227. inifile_done(inifile_t* inifile)
  228. {
  229. if (inifile == NULL) {
  230. return;
  231. }
  232. if (inifile->isecs > 0) {
  233. queue* elem, *tmp;
  234. QUEUE_FOR_EACH(&inifile->secs, elem, tmp) {
  235. inifile_section_t* sec = (inifile_section_t*) elem;
  236. if (sec->ientries > 0) {
  237. queue* elem, *tmp;
  238. QUEUE_FOR_EACH(&sec->entries, elem, tmp) {
  239. inifile_entry_t* entry = (inifile_entry_t*) elem;
  240. if (entry->key) {
  241. xfree(entry->key);
  242. }
  243. if (entry->val) {
  244. xfree(entry->val);
  245. }
  246. dequeue(elem);
  247. xfree(entry);
  248. }
  249. }
  250. dequeue(elem);
  251. if (sec->name) {
  252. xfree(sec->name);
  253. }
  254. xfree(sec);
  255. }
  256. xfree(inifile);
  257. }
  258. if (gbinipathname) {
  259. xfree(gbinipathname);
  260. gbinipathname = NULL;
  261. }
  262. }
  263. int
  264. inifile_has_section(const inifile_t* inifile, const char* section)
  265. {
  266. queue* elem, *tmp;
  267. QUEUE_FOR_EACH(&inifile->secs, elem, tmp) {
  268. inifile_section_t* sec = (inifile_section_t*) elem;
  269. if (case_ignore_strcmp(sec->name, section) == 0) {
  270. return 1;
  271. }
  272. }
  273. return 0;
  274. }
  275. /*
  276. inifile_readstr:
  277. returns NULL if not found, otherwise a pointer to the value of key ...
  278. all key values are valid entities until "inifile_done"
  279. */
  280. char*
  281. inifile_readstr(const inifile_t* inifile, const char* section, const char* key)
  282. {
  283. return inifile_find_value(inifile, section, key);
  284. }
  285. /*
  286. inifile_readint:
  287. on success the value is stored into "*value" and "inifile_readint" returns 1,
  288. otherwise inifile_readint returns 0
  289. */
  290. int
  291. inifile_readint(const inifile_t* inifile, const char* section, const char* key, int* value)
  292. {
  293. char* str;
  294. str = inifile_find_value(inifile, section, key);
  295. if (str == NULL) {
  296. return 0;
  297. }
  298. if (value != NULL) {
  299. *value = atoi(str);
  300. }
  301. return 1;
  302. }
  303. /*
  304. inifile_readint_def:
  305. if found inifile_readint_def returns value of key, otherwise a default value "def"
  306. */
  307. int
  308. inifile_readint_def(const inifile_t* inifile, const char* section, const char* key, const int def)
  309. {
  310. int result;
  311. if (inifile_readint(inifile, section, key, &result) == 0) {
  312. return def;
  313. } else {
  314. return result;
  315. }
  316. }