1 #include <clocale>
2 #include <cstdio>
3 #include <cstring>
4 #include <fstream>
5 #include <sstream>
6 #include <string>
7 #include <clocale>
8 using namespace std;
9
10 #include "body.h"
11 #include "findFile.h"
12 #include "keywords.h"
13 #include "Options.h"
14 #include "parse.h"
15 #include "PlanetProperties.h"
16 #include "xpDefines.h"
17 #include "xpUtil.h"
18
19 #include "libplanet/Planet.h"
20
21 static PlanetProperties *defaultProperties;
22 static PlanetProperties *currentProperties;
23
i2b(int x)24 static inline unsigned char i2b( int x ) { return static_cast<unsigned int>(x) & 0xffU; }
25
26 static void
readConfig(const char * line,PlanetProperties * planetProperties[])27 readConfig(const char *line, PlanetProperties *planetProperties[])
28 {
29 int i = 0;
30 while (isDelimiter(line[i]))
31 {
32 i++;
33 if (static_cast<unsigned int> (i) > strlen(line)) return;
34 }
35 if (isEndOfLine(line[i])) return;
36
37 Options *options = Options::getInstance();
38
39 while (static_cast<unsigned int> (i) < strlen(line))
40 {
41 char *returnString = NULL;
42 int val = parse(i, line, returnString);
43
44 if (val != BODY && currentProperties == NULL)
45 xpExit("No Planet defined in config file!\n",
46 __FILE__, __LINE__);
47
48 switch (val)
49 {
50 case ARC_COLOR:
51 {
52 int r, g, b;
53 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
54 {
55 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
56 currentProperties->ArcColor(color);
57 }
58 else
59 {
60 xpWarn("Need three values for arc_color\n",
61 __FILE__, __LINE__);
62 }
63 }
64 break;
65 case ARC_FILE:
66 currentProperties->AddArcFile(returnString);
67 break;
68 case BODY:
69 {
70 body index = Planet::parseBodyName(returnString);
71 if (index < RANDOM_BODY)
72 {
73 // [default] should come first in the config file.
74 // The first time we get to a body after [default],
75 // set all of the planet properties to the default
76 // value. If [default] isn't first, all of the bodies
77 // specified before it get wiped out.
78 if (currentProperties == defaultProperties)
79 {
80 for (int ibody = SUN; ibody < RANDOM_BODY; ibody++)
81 {
82 *planetProperties[ibody] = *defaultProperties;
83 }
84 }
85
86 currentProperties = planetProperties[index];
87 }
88 else if (index == DEFAULT)
89 {
90 // We really shouldn't have to do this, since
91 // currentProperties is set to defaultProperties
92 // before the file is read in, and [default] should
93 // come at the top.
94 currentProperties = defaultProperties;
95 }
96 else
97 {
98 xpExit("Unknown body in config file\n", __FILE__, __LINE__);
99 }
100 }
101 break;
102 case BUMP_MAP:
103 {
104 // This is one that doesn't belong in [default]
105 if (currentProperties == defaultProperties)
106 {
107 ostringstream errStr;
108 errStr << "bump_map specified in [default] section. "
109 << "You probably want to put it in a specific "
110 << "planet's section (like [earth]).\n";
111 xpWarn(errStr.str(), __FILE__, __LINE__);
112 }
113 string bumpMap(returnString);
114 if (bumpMap.find('.') == string::npos)
115 bumpMap += defaultMapExt;
116 currentProperties->BumpMap(bumpMap);
117 }
118 break;
119 case BUMP_SCALE:
120 {
121 checkLocale(LC_NUMERIC, "C");
122 double bumpScale;
123 sscanf(returnString, "%lf", &bumpScale);
124 currentProperties->BumpScale(bumpScale);
125 checkLocale(LC_NUMERIC, "");
126 }
127 break;
128 case BUMP_SHADE:
129 {
130 int s;
131 sscanf(returnString, "%d", &s);
132 if (s < 0)
133 s = 0;
134 else if (s > 100)
135 s = 100;
136 currentProperties->BumpShade(s/100.);
137 }
138 break;
139 case CLOUD_GAMMA:
140 {
141 checkLocale(LC_NUMERIC, "C");
142 double cloudGamma;
143 sscanf(returnString, "%lf", &cloudGamma);
144 currentProperties->CloudGamma(cloudGamma);
145 checkLocale(LC_NUMERIC, "");
146 }
147 break;
148 case CLOUD_MAP:
149 {
150 // This is one that doesn't belong in [default]
151 if (currentProperties == defaultProperties)
152 {
153 ostringstream errStr;
154 errStr << "cloud_map specified in [default] section. "
155 << "You probably want to put it in a specific "
156 << "planet's section (like [earth]).\n";
157 xpWarn(errStr.str(), __FILE__, __LINE__);
158 }
159 string cloudMap(returnString);
160 if (cloudMap.find('.') == string::npos)
161 cloudMap += defaultMapExt;
162 currentProperties->CloudMap(cloudMap);
163 }
164 break;
165 case CLOUD_SSEC:
166 currentProperties->SSECMap(returnString[0] == 't'
167 || returnString[0] == 'T');
168 break;
169 case CLOUD_THRESHOLD:
170 {
171 int t;
172 sscanf(returnString, "%d", &t);
173 if (t < 0)
174 t = 0;
175 else if (t > 255)
176 t = 255;
177 currentProperties->CloudThreshold(t);
178 }
179 break;
180 case COLOR:
181 {
182 int r, g, b;
183 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
184 {
185 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
186 currentProperties->Color(color);
187 }
188 else
189 {
190 xpWarn("Need three values for color\n",
191 __FILE__, __LINE__);
192 }
193 }
194 break;
195 case DAY_MAP:
196 case IMAGE:
197 // This is one that doesn't belong in [default]
198 if (currentProperties == defaultProperties)
199 {
200 ostringstream errStr;
201 errStr << "image or map specified in [default] section. "
202 << "You probably want to put it in a specific "
203 << "planet's section (like [earth]).\n";
204 xpWarn(errStr.str(), __FILE__, __LINE__);
205 }
206 currentProperties->DayMap(returnString);
207 break;
208 case DELIMITER:
209 break;
210 case DRAW_ORBIT:
211 {
212 bool drawOrbit = (returnString[0] == 't'
213 || returnString[0] == 'T');
214 currentProperties->DrawOrbit(drawOrbit);
215 }
216 break;
217 case ENDOFLINE:
218 break;
219 case GRID:
220 {
221 bool grid = (returnString[0] == 't'
222 || returnString[0] == 'T');
223 currentProperties->Grid(grid);
224 }
225 break;
226 case GRID1:
227 {
228 int grid1;
229 sscanf(returnString, "%d", &grid1);
230 if (grid1 < 0 || grid1 > 90)
231 xpExit("grid1 must be between 0 and 90\n",
232 __FILE__, __LINE__);
233 currentProperties->Grid1(grid1);
234 }
235 break;
236 case GRID2:
237 {
238 int grid2;
239 sscanf(returnString, "%d", &grid2);
240 if (grid2 < 0)
241 xpExit("grid2 must be positive\n", __FILE__, __LINE__);
242 currentProperties->Grid2(grid2);
243 }
244 break;
245 case GRID_COLOR:
246 {
247 int r, g, b;
248 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
249 {
250 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
251 currentProperties->GridColor(color);
252 }
253 else
254 {
255 xpWarn("Need three values for grid_color\n",
256 __FILE__, __LINE__);
257 }
258 }
259 break;
260 case MAGNIFY:
261 {
262 checkLocale(LC_NUMERIC, "C");
263 double value;
264 sscanf(returnString, "%lf", &value);
265 if (value < 0) value = 1;
266 currentProperties->Magnify(value);
267 checkLocale(LC_NUMERIC, "");
268 }
269 break;
270 case MAP_BOUNDS:
271 {
272 // This is one that doesn't belong in [default]
273 if (currentProperties == defaultProperties)
274 {
275 ostringstream errStr;
276 errStr << "map_bounds specified in [default] section. "
277 << "You probably want to put it in a specific "
278 << "planet's section (like [earth]).\n";
279 xpWarn(errStr.str(), __FILE__, __LINE__);
280 }
281 checkLocale(LC_NUMERIC, "C");
282 double uly, ulx, lry, lrx;
283 int numRead = sscanf(returnString, "%lf,%lf,%lf,%lf",
284 &uly, &ulx, &lry, &lrx);
285 if (numRead == 4)
286 {
287 currentProperties->MapBounds(true, uly, ulx, lry, lrx);
288 }
289 else
290 {
291 xpWarn("Need four values for mapbounds\n",
292 __FILE__, __LINE__);
293 }
294 checkLocale(LC_NUMERIC, "");
295 }
296 break;
297 case MARKER_COLOR:
298 {
299 int r, g, b;
300 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
301 {
302 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
303 currentProperties->MarkerColor(color);
304 }
305 else
306 {
307 xpWarn("Need three values for marker_color\n",
308 __FILE__, __LINE__);
309 }
310 }
311 break;
312 case MARKER_FILE:
313 currentProperties->AddMarkerFile(returnString);
314 break;
315 case MARKER_FONT:
316 currentProperties->MarkerFont(returnString);
317 break;
318 case MARKER_FONTSIZE:
319 {
320 int fontSize;
321 sscanf(returnString, "%d", &fontSize);
322 if (fontSize > 0)
323 {
324 currentProperties->MarkerFontSize(fontSize);
325 }
326 else
327 {
328 xpWarn("fontSize must be positive.\n",
329 __FILE__, __LINE__);
330 }
331 }
332 break;
333 case MAX_RAD_FOR_LABEL:
334 {
335 checkLocale(LC_NUMERIC, "C");
336 double value;
337 sscanf(returnString, "%lf", &value);
338 currentProperties->MaxRadiusForLabel(value);
339 checkLocale(LC_NUMERIC, "");
340 }
341 break;
342 case MIN_RAD_FOR_LABEL:
343 {
344 checkLocale(LC_NUMERIC, "C");
345 double value;
346 sscanf(returnString, "%lf", &value);
347 currentProperties->MinRadiusForLabel(value);
348 checkLocale(LC_NUMERIC, "");
349 }
350 break;
351 case MIN_RAD_FOR_MARKERS:
352 {
353 checkLocale(LC_NUMERIC, "C");
354 double value;
355 sscanf(returnString, "%lf", &value);
356 currentProperties->MinRadiusForMarkers(value);
357 checkLocale(LC_NUMERIC, "");
358 }
359 break;
360 case NAME:
361 // This is one that doesn't belong in [default]
362 if (currentProperties == defaultProperties)
363 {
364 ostringstream errStr;
365 errStr << "name specified in [default] section. "
366 << "You probably want to put it in a specific "
367 << "planet's section (like [earth]).\n";
368 xpWarn(errStr.str(), __FILE__, __LINE__);
369 }
370 currentProperties->Name(returnString);
371 break;
372 case NIGHT_MAP:
373 // This is one that doesn't belong in [default]
374 if (currentProperties == defaultProperties)
375 {
376 ostringstream errStr;
377 errStr << "night_map specified in [default] section. "
378 << "You probably want to put it in a specific "
379 << "planet's section (like [earth]).\n";
380 xpWarn(errStr.str(), __FILE__, __LINE__);
381 }
382 currentProperties->NightMap(returnString);
383 break;
384 case ORBIT:
385 {
386 checkLocale(LC_NUMERIC, "C");
387 double start, stop, delta;
388 int numRead = sscanf(returnString, "%lf,%lf,%lf",
389 &start, &stop, &delta);
390 if (numRead == 3)
391 {
392 currentProperties->StartOrbit(start);
393 currentProperties->StopOrbit(stop);
394 currentProperties->DelOrbit(delta);
395 }
396 else
397 {
398 xpWarn("Need three values for orbit\n",
399 __FILE__, __LINE__);
400 }
401 checkLocale(LC_NUMERIC, "");
402 }
403 break;
404 case ORBIT_COLOR:
405 {
406 int r, g, b;
407 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
408 {
409 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
410 currentProperties->OrbitColor(color);
411 }
412 else
413 {
414 xpWarn("Need three values for orbit_color\n",
415 __FILE__, __LINE__);
416 }
417 }
418 break;
419 case RANDOM_ORIGIN:
420 currentProperties->RandomOrigin(returnString[0] == 't'
421 || returnString[0] == 'T');
422 break;
423 case RANDOM_TARGET:
424 currentProperties->RandomTarget(returnString[0] == 't'
425 || returnString[0] == 'T');
426 break;
427 case RAYLEIGH_EMISSION_WEIGHT:
428 {
429 checkLocale(LC_NUMERIC, "C");
430 double scale;
431 sscanf(returnString, "%lf", &scale);
432 currentProperties->RayleighEmissionWeight(scale);
433 checkLocale(LC_NUMERIC, "");
434 }
435 break;
436 case RAYLEIGH_FILE:
437 currentProperties->RayleighFile(returnString);
438 break;
439 case RAYLEIGH_LIMB_SCALE:
440 {
441 checkLocale(LC_NUMERIC, "C");
442 double scale;
443 sscanf(returnString, "%lf", &scale);
444 currentProperties->RayleighLimbScale(scale);
445 checkLocale(LC_NUMERIC, "");
446 }
447 break;
448 case RAYLEIGH_SCALE:
449 {
450 checkLocale(LC_NUMERIC, "C");
451 double scale;
452 sscanf(returnString, "%lf", &scale);
453 currentProperties->RayleighScale(scale);
454 checkLocale(LC_NUMERIC, "");
455 }
456 break;
457 case SATELLITE_FILE:
458 currentProperties->AddSatelliteFile(returnString);
459 break;
460 case SHADE:
461 {
462 int s;
463 sscanf(returnString, "%d", &s);
464 if (s < 0)
465 s = 0;
466 else if (s > 100)
467 s = 100;
468 currentProperties->Shade(s/100.);
469 }
470 break;
471 case SPECULAR_MAP:
472 currentProperties->SpecularMap(returnString);
473 break;
474 case TEXT_COLOR:
475 {
476 int r, g, b;
477 if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3)
478 {
479 unsigned char color[3] = { i2b(r), i2b(g), i2b(b) };
480 currentProperties->TextColor(color);
481 }
482 else
483 {
484 xpWarn("Need three values for text_color\n",
485 __FILE__, __LINE__);
486 }
487 }
488 break;
489 case THICKNESS:
490 {
491 int thickness;
492 sscanf(returnString, "%d", &thickness);
493 if (thickness > 0)
494 {
495 currentProperties->ArcThickness(thickness);
496 }
497 else
498 {
499 xpWarn("thickness must be positive.\n",
500 __FILE__, __LINE__);
501 }
502 }
503 break;
504 case TWILIGHT:
505 {
506 int value;
507 sscanf(returnString, "%d", &value);
508 if (value >= 0 && value <= 90)
509 {
510 currentProperties->Twilight(value);
511 }
512 else
513 {
514 xpWarn("Twilight value should be between 0 and 90 degrees\n",
515 __FILE__, __LINE__);
516 }
517 }
518 break;
519 default:
520 {
521 ostringstream errStr;
522 errStr << "Unknown keyword in configuration file:\n\t"
523 << line << endl;
524 xpWarn(errStr.str(), __FILE__, __LINE__);
525 }
526 break;
527 }
528
529 if (val != DELIMITER && options->Verbosity() > 3)
530 {
531 ostringstream msg;
532 msg << "value is " << keyWordString[val - '?'];
533 if (returnString != NULL)
534 msg << ", returnString is " << returnString;
535 msg << endl;
536 xpMsg(msg.str(), __FILE__, __LINE__);
537 }
538
539 delete [] returnString;
540
541 if (val == ENDOFLINE) break;
542 }
543 }
544
545 void
readConfigFile(string configFile,PlanetProperties * planetProperties[])546 readConfigFile(string configFile, PlanetProperties *planetProperties[])
547 {
548 bool foundFile = findFile(configFile, "config");
549 if (foundFile)
550 {
551 defaultProperties = new PlanetProperties(UNKNOWN_BODY);
552 currentProperties = defaultProperties;
553
554 ifstream inFile(configFile.c_str());
555 char *line = new char[256];
556 while (inFile.getline(line, 256, '\n'))
557 readConfig(line, planetProperties);
558
559 // This condition will only be true if [default] is the only
560 // section in the config file. In this case, set all planet
561 // properties to the default values.
562 if (currentProperties == defaultProperties)
563 {
564 for (int ibody = SUN; ibody < RANDOM_BODY; ibody++)
565 {
566 *planetProperties[ibody] = *defaultProperties;
567 }
568 }
569
570 inFile.close();
571 delete [] line;
572
573 delete defaultProperties;
574 }
575 else
576 {
577 ostringstream errStr;
578 errStr << "Can't load configuration file " << configFile << endl;
579 xpExit(errStr.str(), __FILE__, __LINE__);
580 }
581 }
582