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