Commit | Line | Data |
---|---|---|
7b49793d | 1 | /* |
c295905f AW |
2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). |
3 | Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | |
4 | Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
7b49793d | 5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. |
c295905f AW |
6 | */ |
7 | ||
8 | #include "libs/Kernel.h" | |
9 | #include "ConfigValue.h" | |
10 | #include "FileConfigSource.h" | |
11 | #include "ConfigCache.h" | |
f45e6161 | 12 | #include "checksumm.h" |
61134a65 | 13 | #include "utils.h" |
a39e1557 AW |
14 | #include <malloc.h> |
15 | ||
c295905f AW |
16 | using namespace std; |
17 | #include <string> | |
bcb96295 | 18 | #include <string.h> |
c295905f | 19 | |
f45e6161 L |
20 | #define include_checksum CHECKSUM("include") |
21 | ||
577414f6 JM |
22 | FileConfigSource::FileConfigSource(string config_file, const char *name) |
23 | { | |
24 | this->name_checksum = get_checksum(name); | |
8d857d2e | 25 | this->config_file = config_file; |
c295905f AW |
26 | this->config_file_found = false; |
27 | } | |
28 | ||
2ee2ad19 | 29 | bool FileConfigSource::readLine(string& line, int lineno, FILE *fp) |
bcb96295 JM |
30 | { |
31 | char buf[132]; | |
32 | char *l= fgets(buf, sizeof(buf)-1, fp); | |
33 | if(l != NULL) { | |
34 | if(buf[strlen(l)-1] != '\n') { | |
35 | // truncate long lines | |
2ee2ad19 JM |
36 | if(lineno != 0) { |
37 | // report if it is not truncating a comment | |
38 | if(strchr(buf, '#') == NULL) | |
39 | printf("Truncated long line %d in: %s\n", lineno, config_file.c_str()); | |
40 | } | |
bcb96295 JM |
41 | // read until the next \n or eof |
42 | int c; | |
43 | while((c=fgetc(fp)) != '\n' && c != EOF) /* discard */; | |
44 | } | |
45 | line.assign(buf); | |
46 | return true; | |
47 | } | |
48 | ||
49 | return false; | |
50 | } | |
51 | ||
c295905f | 52 | // Transfer all values found in the file to the passed cache |
577414f6 JM |
53 | void FileConfigSource::transfer_values_to_cache( ConfigCache *cache ) |
54 | { | |
577414f6 JM |
55 | if( !this->has_config_file() ) { |
56 | return; | |
57 | } | |
f45e6161 L |
58 | transfer_values_to_cache( cache, this->get_config_file().c_str()); |
59 | } | |
60 | ||
61 | void FileConfigSource::transfer_values_to_cache( ConfigCache *cache, const char * file_name ) | |
62 | { | |
63 | if( !file_exists(file_name) ) { | |
64 | return; | |
65 | } | |
66 | ||
7b49793d | 67 | // Open the config file ( find it if we haven't already found it ) |
f45e6161 | 68 | FILE *lp = fopen(file_name, "r"); |
bcb96295 | 69 | |
2ee2ad19 | 70 | int ln= 1; |
7b49793d | 71 | // For each line |
bcb96295 JM |
72 | while(!feof(lp)) { |
73 | string line; | |
2ee2ad19 | 74 | if(readLine(line, ln++, lp)) { |
f45e6161 L |
75 | // process the config line and store the value in cache |
76 | ConfigValue* cv = process_line_from_ascii_config(line, cache); | |
77 | ||
78 | // if this line is an include directive then attempt to read the included file | |
79 | if(cv->check_sums[0] == include_checksum) { | |
80 | string inc_file_name = cv->value.c_str(); | |
81 | if(!file_exists(inc_file_name)) { | |
82 | // if the file is not found at the location entered then look around for it a bit | |
83 | if(inc_file_name[0] != '/') inc_file_name = "/" + inc_file_name; | |
84 | string path(file_name); | |
85 | path = path.substr(0,path.find_last_of('/')); | |
86 | ||
87 | // first check the path of the current config file | |
88 | if(file_exists(path + inc_file_name)) inc_file_name = path + inc_file_name; | |
89 | // then check root locations | |
90 | else if(file_exists("/sd" + inc_file_name)) inc_file_name = "/sd" + inc_file_name; | |
91 | else if(file_exists("/local" + inc_file_name)) inc_file_name = "/local" + inc_file_name; | |
92 | } | |
93 | if(file_exists(inc_file_name)) { | |
c77d6dae JM |
94 | printf("Including config file: %s\n", inc_file_name.c_str()); |
95 | ||
f45e6161 L |
96 | // save position in current config file |
97 | fpos_t pos; | |
98 | fgetpos(lp, &pos); | |
99 | ||
100 | // open and read the included file | |
101 | freopen(inc_file_name.c_str(), "r", lp); | |
102 | this->transfer_values_to_cache(cache, inc_file_name.c_str()); | |
103 | ||
104 | // reopen the current config file and restore position | |
105 | freopen(file_name, "r", lp); | |
106 | fsetpos(lp, &pos); | |
c77d6dae JM |
107 | }else{ |
108 | printf("Unable to find included config file: %s\n", inc_file_name.c_str()); | |
f45e6161 L |
109 | } |
110 | } | |
bcb96295 | 111 | }else break; |
577414f6 | 112 | } |
bcb96295 | 113 | fclose(lp); |
c295905f AW |
114 | } |
115 | ||
5913c006 | 116 | // Return true if the check_sums match |
577414f6 JM |
117 | bool FileConfigSource::is_named( uint16_t check_sum ) |
118 | { | |
5efaa1b1 L |
119 | return check_sum == this->name_checksum; |
120 | } | |
121 | ||
d8cff5af JM |
122 | // OverWrite or append a config setting to the file |
123 | bool FileConfigSource::write( string setting, string value ) | |
577414f6 | 124 | { |
d8cff5af JM |
125 | if( !this->has_config_file() ) { |
126 | return false; | |
127 | } | |
128 | ||
129 | uint16_t setting_checksums[3]; | |
130 | get_checksums(setting_checksums, setting ); | |
131 | ||
5913c006 L |
132 | // Open the config file ( find it if we haven't already found it ) |
133 | FILE *lp = fopen(this->get_config_file().c_str(), "r+"); | |
d8cff5af JM |
134 | |
135 | // search each line for a match | |
136 | while(!feof(lp)) { | |
137 | string line; | |
138 | fpos_t bol, eol; | |
139 | fgetpos( lp, &bol ); // get start of line | |
2ee2ad19 | 140 | if(readLine(line, 0, lp)) { |
d8cff5af JM |
141 | fgetpos( lp, &eol ); // get end of line |
142 | if(!process_line_from_ascii_config(line, setting_checksums).empty()) { | |
143 | // found it | |
144 | unsigned int free_space = eol - bol - 4; // length of line | |
145 | // check we have enough space for this insertion | |
146 | if( (setting.length() + value.length() + 3) > free_space ) { | |
147 | //THEKERNEL->streams->printf("ERROR: Not enough room for value\r\n"); | |
148 | fclose(lp); | |
149 | return false; | |
150 | } | |
151 | ||
152 | // Update line, leaves whatever was at end of line there just overwrites the key and value | |
153 | fseek(lp, bol, SEEK_SET); | |
154 | fputs(setting.c_str(), lp); | |
155 | fputs(" ", lp); | |
156 | fputs(value.c_str(), lp); | |
157 | fputs(" #", lp); | |
5913c006 | 158 | fclose(lp); |
d8cff5af | 159 | return true; |
5913c006 | 160 | } |
d8cff5af JM |
161 | }else break; |
162 | } | |
163 | ||
164 | // not found so append the new value | |
5913c006 | 165 | fclose(lp); |
d8cff5af JM |
166 | lp = fopen(this->get_config_file().c_str(), "a"); |
167 | fputs("\n", lp); | |
168 | fputs(setting.c_str(), lp); | |
169 | fputs(" ", lp); | |
170 | fputs(value.c_str(), lp); | |
171 | fputs(" # added\n", lp); | |
172 | fclose(lp); | |
173 | ||
174 | return true; | |
5913c006 | 175 | } |
5efaa1b1 | 176 | |
5761c645 | 177 | // Return the value for a specific checksum |
577414f6 JM |
178 | string FileConfigSource::read( uint16_t check_sums[3] ) |
179 | { | |
5761c645 L |
180 | string value = ""; |
181 | ||
577414f6 JM |
182 | if( this->has_config_file() == false ) { |
183 | return value; | |
184 | } | |
185 | ||
7b49793d | 186 | // Open the config file ( find it if we haven't already found it ) |
bcb96295 | 187 | FILE *lp = fopen(this->get_config_file().c_str(), "r"); |
7b49793d | 188 | // For each line |
bcb96295 JM |
189 | while(!feof(lp)) { |
190 | string line; | |
2ee2ad19 | 191 | if(readLine(line, 0, lp)) { |
bcb96295 JM |
192 | value = process_line_from_ascii_config(line, check_sums); |
193 | if(!value.empty()) break; // found it | |
194 | }else break; | |
577414f6 | 195 | } |
bcb96295 | 196 | fclose(lp); |
5761c645 L |
197 | |
198 | return value; | |
199 | } | |
5efaa1b1 | 200 | |
c295905f | 201 | // Return wether or not we have a readable config file |
577414f6 JM |
202 | bool FileConfigSource::has_config_file() |
203 | { | |
204 | if( this->config_file_found ) { | |
205 | return true; | |
206 | } | |
8d857d2e | 207 | this->try_config_file(this->config_file); |
577414f6 | 208 | if( this->config_file_found ) { |
c295905f | 209 | return true; |
577414f6 | 210 | } else { |
c295905f AW |
211 | return false; |
212 | } | |
213 | ||
214 | } | |
215 | ||
216 | // Tool function for get_config_file | |
577414f6 JM |
217 | inline void FileConfigSource::try_config_file(string candidate) |
218 | { | |
219 | if(file_exists(candidate)) { | |
220 | this->config_file_found = true; | |
221 | } | |
c295905f AW |
222 | } |
223 | ||
224 | // Get the filename for the config file | |
577414f6 JM |
225 | string FileConfigSource::get_config_file() |
226 | { | |
227 | if( this->config_file_found ) { | |
228 | return this->config_file; | |
229 | } | |
230 | if( this->has_config_file() ) { | |
c295905f | 231 | return this->config_file; |
577414f6 | 232 | } else { |
c295905f | 233 | printf("ERROR: no config file found\r\n"); |
577414f6 | 234 | return ""; |
c295905f AW |
235 | } |
236 | } | |
237 | ||
238 | ||
239 | ||
240 | ||
241 | ||
242 |