Split config parsing out of parse.h.
[cubemap] / config.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 #include <assert.h>
6 #include <vector>
7 #include <string>
8
9 #include "config.h"
10 #include "parse.h"
11
12 using namespace std;
13
14 vector<ConfigLine> parse_config(const string &filename)
15 {
16         vector<ConfigLine> ret;
17
18         FILE *fp = fopen(filename.c_str(), "r");
19         if (fp == NULL) {
20                 perror(filename.c_str());
21                 exit(1);
22         }
23
24         char buf[4096];
25         while (!feof(fp)) {
26                 if (fgets(buf, sizeof(buf), fp) == NULL) {
27                         break;
28                 }
29
30                 // Chop off the string at the first #, \r or \n.
31                 buf[strcspn(buf, "#\r\n")] = 0;
32
33                 // Remove all whitespace from the end of the string.
34                 size_t len = strlen(buf);
35                 while (len > 0 && isspace(buf[len - 1])) {
36                         buf[--len] = 0;
37                 }
38
39                 // If the line is now all blank, ignore it.
40                 if (len == 0) {
41                         continue;
42                 }
43
44                 vector<string> tokens = split_tokens(buf);
45                 assert(!tokens.empty());
46                 
47                 ConfigLine line;
48                 line.keyword = tokens[0];
49
50                 for (size_t i = 1; i < tokens.size(); ++i) {
51                         // foo=bar is a parameter; anything else is an argument.
52                         size_t equals_pos = tokens[i].find_first_of('=');
53                         if (equals_pos == string::npos) {
54                                 line.arguments.push_back(tokens[i]);
55                         } else {
56                                 string key = tokens[i].substr(0, equals_pos);
57                                 string value = tokens[i].substr(equals_pos + 1, string::npos);
58                                 line.parameters.insert(make_pair(key, value));
59                         }
60                 }
61
62                 ret.push_back(line);
63         }
64
65         fclose(fp);
66         return ret;
67 }
68
69 string fetch_config_string(const vector<ConfigLine> &config, const string &keyword,
70                            ParameterType parameter_type, const string &default_value)
71 {
72         assert(parameter_type == PARAMATER_MANDATORY || parameter_type == PARAMETER_OPTIONAL);
73         for (unsigned i = 0; i < config.size(); ++i) {
74                 if (config[i].keyword != keyword) {
75                         continue;
76                 }
77                 if (config[i].parameters.size() > 0 ||
78                     config[i].arguments.size() != 1) {
79                         fprintf(stderr, "ERROR: '%s' takes one argument and no parameters\n", keyword.c_str());
80                         exit(1);
81                 }
82                 return config[i].arguments[0];
83         }
84         if (parameter_type == PARAMATER_MANDATORY) {
85                 fprintf(stderr, "ERROR: Missing '%s' statement in config file.\n",
86                         keyword.c_str());
87                 exit(1);
88         } else {
89                 return default_value;
90         }
91 }
92
93 int fetch_config_int(const std::vector<ConfigLine> &config, const std::string &keyword,
94                      int min_limit, int max_limit,
95                      ParameterType parameter_type, int default_value)
96 {
97         assert(parameter_type == PARAMATER_MANDATORY || parameter_type == PARAMETER_OPTIONAL);
98         bool value_found = false;
99         int value = -1;
100         for (unsigned i = 0; i < config.size(); ++i) {
101                 if (config[i].keyword != keyword) {
102                         continue;
103                 }
104                 if (config[i].parameters.size() > 0 ||
105                     config[i].arguments.size() != 1) {
106                         fprintf(stderr, "ERROR: '%s' takes one argument and no parameters\n", keyword.c_str());
107                         exit(1);
108                 }
109                 value_found = true;
110                 value = atoi(config[i].arguments[0].c_str());  // TODO: verify int validity.
111         }
112         if (!value_found) {
113                 if (parameter_type == PARAMETER_OPTIONAL) {
114                         return default_value;
115                 }
116                 fprintf(stderr, "ERROR: Missing '%s' statement in config file.\n",
117                         keyword.c_str());
118                 exit(1);
119         }
120         if (value < min_limit || value > max_limit) {
121                 fprintf(stderr, "ERROR: '%s' is set to %d, must be in [%d,%d]\n",
122                         keyword.c_str(), value, min_limit, max_limit);
123                 exit(1);
124         }
125         return value;
126 }