-
Notifications
You must be signed in to change notification settings - Fork 0
/
glopConfig.cpp
191 lines (172 loc) · 6.02 KB
/
glopConfig.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "glopConfig.h"
/*
The Magic Sauce
The method is recursive
find the key of the new parameter
match the ending char to the tokens that we have reserved
if we know what to do with it, then do the right action
if not, try to do the best action we can think of, print a message, and carry on
key tokens - what we do when reaching certain tokens for the label
len>0 { make a new group and recurse the parse function
len>0 = parse for the value and assign the pair
len>0 # error - read rest of the line
len>0 } error - ignore just this character
len>0 \n error - ignore just this character
len=0 } closing group - simply unwind stack
len=0 \n blank line - ignore just thist char
len=0 # comment line - ignore line
len=0 = error - read rest of the line
len=0 { error - irnore just this character
value tokens
\n normal specification, just save the value pair
} normal specification and also closing the group it is in
# normal specification with a comment after it
= error - can't specify a value for a value
{ error - cant open an unnamed group
*/
namespace GlopConfig{
char getKey(FILE* fd, std::string& key){
key = "";
int c = fgetc(fd);
while(c!=EOF){
if(c=='\t') // lets not deal with tabs
c=' ';
if(c=='=' || c=='{' || c=='}' || c=='\n' || c=='#')
return c;
else{
if(c!=' ' || key.length()>0) // remove the preceding blank spaces, for indentation purposes
key+=c; // nothing of note yet, keep going
c = fgetc(fd);
}
}
return c;
}
char getBody(FILE* fd,std::string& value){
value = "";
int c = fgetc(fd);
while(c!=EOF){
if(c=='\t') // lets not deal with tabs
c=' ';
if(c=='=' || c=='{' || c=='}' || c=='\n' || c=='#')
return c;
else{
if(c!=' ' || value.length()>0) // remove the preceding blank spaces, for indentation purposes
value+=c; // nothing of note yet, keep going
c = fgetc(fd);
}
}
return c;
}
void readRestOfLine(FILE* fd){
int c=fgetc(fd);
while(c!=EOF && c!='\n') c=fgetc(fd);
}
void removeTrailingSpaces(std::string& sss){
int length = sss.length() - 1;
if(length == 0) return;
while(sss[length] == ' '){
sss.erase(length,1); // erase the last char
length --;
}
}
void ParseFile_Recurse(FILE* fd, Settings& settings,int& lineCount){
std::string key,value;
char lastCharParsed;
do{
lastCharParsed = getKey(fd,key);
removeTrailingSpaces(key);
if(lastCharParsed == '=' && key.size()>0){
lastCharParsed = getBody(fd,value);
removeTrailingSpaces(value);
settings.values[key] = value;
//Now lets add a new nested tree of if statements
//sorry future me about this mess
if(lastCharParsed=='#'){
readRestOfLine(fd);
lineCount++;
}else if(lastCharParsed=='}'){
return; //unwind the stack to be done with this group
}else if(lastCharParsed=='\n'){
//nothing special
lineCount++;
}else if(lastCharParsed=='{'){
printf("ERROR: CONFIG:%d: Opening new group ( { ) while specifing value\n",lineCount);
}else if(lastCharParsed=='='){
printf("ERROR: CONFIG:%d: Value specifing ( = ) while specifing value\n",lineCount);
}else if( !feof(fd) ){
printf("ERROR: CONFIG:%d: Reached EOF Unexpectedly (value parsing)\n",lineCount);
}
}else if(lastCharParsed == '{' && key.size()>0){
//found a named group, so recurse down to get everything inside of it
ParseFile_Recurse(fd,settings.groups[key],lineCount);
}else if(lastCharParsed == '}' && key.size()==0){
//found that we are closing the group we are currently in
return; // unwind the stack
}else if(lastCharParsed == '\n' && key.size()==0){
//just ignore blank lines
lineCount++;
}else if(lastCharParsed == '#' && key.size()==0){
//ignore lines that only have comments
readRestOfLine(fd);
lineCount++;
}
// end of good states, following are bad states
else if( lastCharParsed=='#' && key.size()>0 ){
readRestOfLine(fd);
lineCount++;
printf("ERROR: CONFIG:%d: found a comment token ( # ) while parsing label\n",lineCount);
}else if( lastCharParsed=='=' && key.size()==0 ){
readRestOfLine(fd);
lineCount++;
printf("ERROR: CONFIG:%d: found a ( = ) token with an empty label\n",lineCount);
}else if( lastCharParsed=='}' && key.size()>0 ){
printf("ERROR: CONFIG:%d: found a ( } ) token with a non-empty label\n",lineCount);
}else if( lastCharParsed=='\n' && key.size()>0 ){
printf("ERROR: CONFIG:%d: reached end of line with a non-empty label\n",lineCount);
lineCount++;
}else if( lastCharParsed=='{' && key.size()>0 ){
printf("ERROR: CONFIG:%d: found a ( { ) token with an empty label\n",lineCount);
}else if( feof(fd) ){
if(key.size()>0)
printf("ERROR: CONFIG:%d: Reached EOF Unexpectedly (key parsing)\n",lineCount);
//else no-one cares as we are not losing any information
}
}while(!feof(fd));
}
Settings ParseFile(std::string filename){
Settings settings;
FILE* fd = fopen(filename.c_str(),"r");
if(fd == NULL)
return settings;
int lineCount=1; // for getting accurate reporting of errors in the file
ParseFile_Recurse(fd,settings,lineCount);
fclose(fd);
return settings;
}
void SaveToFile_Recurse(FILE* fd, Settings& s,std::string prefix){
{ // write the current level key-value pairs first
std::map<std::string,std::string>::iterator itt = s.values.begin();
while(itt!=s.values.end()){
fprintf(fd,"%s%s = %s\n",prefix.c_str(),itt->first.c_str(),itt->second.c_str());
++itt;
}
}
{ // recurse down into the groups
std::map<std::string,Settings>::iterator itt = s.groups.begin();
while(itt!=s.groups.end()){
fprintf(fd,"%s%s {\n",prefix.c_str(),itt->first.c_str()); // header of the group
SaveToFile_Recurse(fd,itt->second,prefix+" "); // all the data the group itself contains
fprintf(fd, "%s}\n", prefix.c_str()); // the closing bracket of the group
++itt;
}
}
}
void SaveToFile(std::string filename,Settings& settings){
FILE* fd = fopen(filename.c_str(),"w");
if(fd == NULL)
return; // couldn't open file
//now recurse down the groups
SaveToFile_Recurse(fd,settings,"");
fclose(fd);
}
}; // namespace ConfigParser