Broadcast forwarder for ip-bound gameservers
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.

configfile.c 7.4KB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /***************************************************************************
  2. * Copyright (C) 03/2010 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <ctype.h>
  24. #include "configfile.h"
  25. #include "list.h"
  26. #include "logging.h"
  27. #define BUFSIZE 1024
  28. struct conf_section {
  29. struct list_head list;
  30. struct list_head tupel_list;
  31. const char *name;
  32. };
  33. struct conf_tupel {
  34. struct list_head list;
  35. const char *option;
  36. const char *parameter;
  37. };
  38. static LIST_HEAD(config_list);
  39. static struct conf_section * config_add_section(const char *name)
  40. {
  41. struct conf_section *section;
  42. section = malloc(sizeof(struct conf_section) + strlen(name));
  43. if (section == NULL)
  44. return NULL;
  45. INIT_LIST_HEAD(&section->list);
  46. INIT_LIST_HEAD(&section->tupel_list);
  47. section->name = strdup(name);
  48. if (section->name == NULL) {
  49. free(section);
  50. return NULL;
  51. }
  52. list_add_tail(&section->list, &config_list);
  53. return section;
  54. }
  55. static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter)
  56. {
  57. struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel));
  58. if (tupel == NULL)
  59. return -1;
  60. INIT_LIST_HEAD(&tupel->list);
  61. tupel->option = strdup(option);
  62. tupel->parameter = strdup(parameter);
  63. if (tupel->option == NULL || tupel->parameter == NULL) {
  64. free(tupel);
  65. return -1;
  66. }
  67. list_add_tail(&tupel->list, &section->tupel_list);
  68. return 0;
  69. }
  70. int config_parse(const char *config)
  71. {
  72. FILE *fz = fopen(config, "r");
  73. if (fz == NULL) {
  74. log_print(LOG_ERROR, "config_parse(): %s", config);
  75. return -1;
  76. }
  77. char *line = malloc(BUFSIZE);
  78. if (line == NULL) {
  79. log_print(LOG_ERROR, "config_parse(): out of memory");
  80. fclose(fz);
  81. return -1;
  82. }
  83. int linenum = 0;
  84. struct conf_section *section = NULL;
  85. while (fgets(line, BUFSIZE, fz) != NULL) {
  86. linenum++;
  87. if (line[0] == '#' || line[0] <= ' ') {
  88. continue;
  89. } else if (line[0] == '[') {
  90. char *tok = strtok(line +1, " ]\n");
  91. if (tok == NULL || (section = config_add_section(tok)) == NULL) {
  92. log_print(LOG_WARN, "config_parse(): invalid section in row %d", linenum);
  93. free(line);
  94. fclose(fz);
  95. return -1;
  96. }
  97. continue;
  98. } else if (section == NULL) {
  99. log_print(LOG_WARN, "config_parse(): missing section in row %d", linenum);
  100. free(line);
  101. fclose(fz);
  102. return -1;
  103. }
  104. char *tmp, *tok = strtok_r(line, " \t\n", &tmp);
  105. if (tok != NULL) {
  106. char *tok2;
  107. while ((tok2 = strtok_r(NULL, " \n", &tmp))) {
  108. if (config_add_tupel(section, tok, tok2) != 0)
  109. log_print(LOG_WARN, "config_parse(): invalid row %d", linenum);
  110. }
  111. }
  112. }
  113. fclose(fz);
  114. free(line);
  115. return 0;
  116. }
  117. void config_free(void)
  118. {
  119. struct conf_section *section, *section_tmp;
  120. struct conf_tupel *tupel, *tupel_tmp;
  121. list_for_each_entry_safe(section, section_tmp, &config_list, list) {
  122. list_for_each_entry_safe(tupel, tupel_tmp, &section->tupel_list, list) {
  123. list_del(&tupel->list);
  124. free((char *)tupel->option);
  125. free((char *)tupel->parameter);
  126. free(tupel);
  127. }
  128. list_del(&section->list);
  129. free(section);
  130. }
  131. }
  132. static struct conf_section * config_get_section(const char *name)
  133. {
  134. struct conf_section *section;
  135. list_for_each_entry(section, &config_list, list) {
  136. if (!strcmp(section->name, name))
  137. return section;
  138. }
  139. return NULL;
  140. }
  141. const char * config_get_string(const char *section_str, const char *option, const char *def)
  142. {
  143. struct conf_section *section = config_get_section(section_str);
  144. if (section != NULL) {
  145. struct conf_tupel *tupel;
  146. list_for_each_entry(tupel, &section->tupel_list, list) {
  147. if (!strcmp(tupel->option, option))
  148. return tupel->parameter;
  149. }
  150. }
  151. if (def != NULL)
  152. log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'",
  153. section_str, option, def);
  154. return def;
  155. }
  156. int config_get_int(const char *section, const char *option, int *value, int def)
  157. {
  158. const char *ret = config_get_string(section, option, NULL);
  159. if (ret == NULL) {
  160. log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'",
  161. section, option, def);
  162. *value = def;
  163. return -1;
  164. }
  165. char *tmp;
  166. *value = strtol(ret, &tmp, 0);
  167. if (*tmp != '\0' && !isspace(*tmp)) {
  168. log_print(LOG_WARN, "config [%s:%s] not an integer: '%s', using default '%d'",
  169. section, option, ret, def);
  170. *value = def;
  171. return -1;
  172. }
  173. return 0;
  174. }
  175. int config_get_strings(const char *section_str, const char *option,
  176. int (*callback)(const char *value, void *privdata),
  177. void *privdata)
  178. {
  179. struct conf_section *section = config_get_section(section_str);
  180. if (section == NULL)
  181. return -1;
  182. int cnt = 0;
  183. struct conf_tupel *tupel;
  184. list_for_each_entry(tupel, &section->tupel_list, list) {
  185. if (!strcmp(tupel->option, option))
  186. if (callback(tupel->parameter, privdata) == 0)
  187. cnt++;
  188. }
  189. return cnt;
  190. }
  191. struct strtoken * strtokenize(const char *input, const char *delim, int maxfields)
  192. {
  193. struct strtoken *tokens = malloc(sizeof(struct strtoken) +
  194. (maxfields +1) * sizeof(char *) +
  195. strlen(input));
  196. if (tokens == NULL)
  197. return NULL;
  198. char *ptr = (char *)&tokens->field[maxfields];
  199. strcpy(ptr, input);
  200. int i;
  201. char *tmp;
  202. tokens->count = 0;
  203. for (i = 0; i < maxfields; i++) {
  204. tokens->field[i] = strtok_r(ptr, delim, &tmp);
  205. ptr = NULL;
  206. if (tokens->field[i] != NULL)
  207. tokens->count++;
  208. }
  209. return tokens;
  210. }
  211. struct strtoken * config_get_strtoken(const char *section, const char *option, const char *delim, int maxfields)
  212. {
  213. const char *ret = config_get_string(section, option, NULL);
  214. if (ret == NULL) {
  215. log_print(LOG_WARN, "config [%s:%s] not found", section, option);
  216. return NULL;
  217. }
  218. return strtokenize(ret, delim, maxfields);
  219. }
  220. int config_get_strtokens(const char *section_str, const char *option, const char *delim, int maxfields,
  221. int (*callback)(struct strtoken *data, void *privdata),
  222. void *privdata)
  223. {
  224. struct conf_section *section = config_get_section(section_str);
  225. if (section == NULL)
  226. return -1;
  227. int cnt = 0;
  228. struct conf_tupel *tupel;
  229. list_for_each_entry(tupel, &section->tupel_list, list) {
  230. if (!strcmp(tupel->option, option)) {
  231. struct strtoken *tokens = strtokenize(tupel->parameter, delim, maxfields);
  232. if (tokens != NULL) {
  233. if (callback(tokens, privdata) == 0)
  234. cnt++;
  235. free(tokens);
  236. }
  237. }
  238. }
  239. return cnt;
  240. }