1 #include <cstdio>
2 #include <cstring>
3 #include <sstream>
4 #include <string>
5 using namespace std;
6 
7 #include "keywords.h"
8 #include "parseColor.h"
9 #include "xpUtil.h"
10 
11 // sloppy, but it's an easy way to set the comment marker as a line
12 // terminator
13 static bool commentEndsLine = true;
14 
15 bool
isDelimiter(char c)16 isDelimiter(char c)
17 {
18     return(c == ' ' || c == '\t');
19 }
20 
21 bool
isEndOfLine(char c)22 isEndOfLine(char c)
23 {
24     // 13 is DOS end-of-line, 28 is the file separator
25     bool returnValue = (c == '\0' || c == 13 || c == 28);
26 
27     if (commentEndsLine) returnValue = (c == '#' || returnValue);
28 
29     return(returnValue);
30 }
31 
32 static void
skipPastToken(int & i,const char * line,const char endChar)33 skipPastToken(int &i, const char *line, const char endChar)
34 {
35     while (line[i] != endChar)
36     {
37         if (isEndOfLine(line[i]))
38         {
39             ostringstream errStr;
40             errStr << "Malformed line:\n\t" << line << "\n";
41             xpWarn(errStr.str(), __FILE__, __LINE__);
42 
43             return;
44         }
45         i++;
46     }
47 }
48 
49 static void
skipPastToken(int & i,const char * line)50 skipPastToken(int &i, const char *line)
51 {
52     while (!isDelimiter(line[i]))
53     {
54         if (isEndOfLine(line[i])) return;
55         i++;
56     }
57 }
58 
59 // If the line contains 'key', return everything between 'key' and 'endChar'
60 static bool
getValue(const char * line,int & i,const char * key,const char endChar,char * & returnstring)61 getValue(const char *line, int &i, const char *key, const char endChar,
62          char *&returnstring)
63 {
64     const unsigned int length = strlen(key);
65     if (strncmp(line + i, key, length) == 0)
66     {
67         i += length;
68         int istart = i;
69         skipPastToken(i, line, endChar);
70         returnstring = new char[i - istart + 1];
71         strncpy(returnstring, (line + istart), i - istart);
72         returnstring[i-istart] = '\0';
73         i++;
74         return(true);
75     }
76     return(false);
77 }
78 
79 // If the line contains 'key', return everything between 'key' and
80 // 'endChar' comment markers are allowed in the string.  Use this for
81 // reading marker labels.
82 static bool
getValueIncludingComment(const char * line,int & i,const char * key,const char endChar,char * & returnstring)83 getValueIncludingComment(const char *line, int &i, const char *key,
84                        const char endChar, char *&returnstring)
85 {
86     commentEndsLine = false;
87     bool returnValue = getValue(line, i, key, endChar, returnstring);
88     commentEndsLine = true;
89     return(returnValue);
90 }
91 
92 static bool
getValueAfter(const char * line,int & i,const char * key,const char endChar,char * & returnstring)93 getValueAfter(const char *line, int &i, const char *key, const char endChar,
94          char *&returnstring)
95 // If the line contains the 'key', skip past 'endChar' and return
96 // everything to the end of the line in 'returnString'
97 {
98     const unsigned int length = strlen(key);
99     if (strncmp(line + i, key, length) == 0)
100     {
101         i += length;
102         skipPastToken(i, line, endChar);        // Skips 'to' endChar
103         int istart = i + 1;     // Add another to not include endChar
104         skipPastToken(i, line);
105         returnstring = new char[i - istart + 1];
106         strncpy(returnstring, (line + istart), i - istart);
107         returnstring[i-istart] = '\0';
108         i++;
109         return(true);
110     }
111     return(false);
112 }
113 
114 static bool
getValue(const char * line,int & i,const char * key,char * & returnstring)115 getValue(const char *line, int &i, const char *key, char *&returnstring)
116 {
117     const unsigned int length = strlen(key);
118     if (strncmp(line + i, key, length) == 0)
119     {
120         i += length;
121         int istart = i;
122         skipPastToken(i, line);
123         returnstring = new char[i - istart + 1];
124         strncpy(returnstring, (line + istart), i - istart);
125         returnstring[i-istart] = '\0';
126         i++;
127         return(true);
128     }
129     return(false);
130 }
131 
132 // This routine returns the next token in the line and its type.
133 int
parse(int & i,const char * line,char * & returnString)134 parse(int &i, const char *line, char *&returnString)
135 {
136     if (i >= (int) strlen(line)) return(ENDOFLINE);
137 
138     if (returnString != NULL)
139         xpWarn("returnString is not NULL!\n", __FILE__, __LINE__);
140 
141     int returnVal = UNKNOWN;
142 
143     if (isDelimiter(line[i]))
144     {
145         i++;
146         returnVal = DELIMITER;
147     }
148     else if (isEndOfLine(line[i]))
149         returnVal = ENDOFLINE;
150     else if (getValue(line, i, "align=", returnString))
151         returnVal = ALIGN;
152     else if (getValue(line, i, "arc_color={", '}', returnString))
153         returnVal = ARC_COLOR;
154     else if (getValue(line, i, "arc_color=", returnString))
155     {
156         unsigned char RGB[3];
157         parseColor(returnString, RGB);
158         delete [] returnString;
159         returnString = new char[32];
160         snprintf(returnString, 32, "%d,%d,%d", RGB[0], RGB[1], RGB[2]);
161         returnVal = ARC_COLOR;
162     }
163     else if (getValue(line, i, "arc_thickness=", returnString))
164         returnVal = THICKNESS;
165     // This line must be after all other "arc_" keywords, because it
166     // gobbles all forms
167     else if (getValueAfter(line, i, "arc_", '=', returnString))
168         returnVal = ARC_FILE;
169     else if (getValue(line, i, "[", ']', returnString))
170         returnVal = BODY;
171     else if (getValue(line, i, "altcirc=", returnString))
172         returnVal = CIRCLE;
173     else if (getValue(line, i, "circle=", returnString))
174         returnVal = CIRCLE;
175     else if (getValue(line, i, "bump_map=", returnString))
176         returnVal = BUMP_MAP;
177     else if (getValue(line, i, "bump_scale=", returnString))
178         returnVal = BUMP_SCALE;
179     else if (getValue(line, i, "bump_shade=", returnString))
180         returnVal = BUMP_SHADE;
181     else if (getValue(line, i, "cloud_gamma=", returnString))
182         returnVal = CLOUD_GAMMA;
183     else if (getValue(line, i, "cloud_map=", returnString))
184         returnVal = CLOUD_MAP;
185     else if (getValue(line, i, "cloud_ssec=", returnString))
186         returnVal = CLOUD_SSEC;
187     else if (getValue(line, i, "cloud_threshold=", returnString))
188         returnVal = CLOUD_THRESHOLD;
189     else if (getValue(line, i, "color={", '}', returnString))
190         returnVal = COLOR;
191     else if (getValue(line, i, "color=", returnString))
192     {
193         unsigned char RGB[3];
194         parseColor(returnString, RGB);
195         delete [] returnString;
196         returnString = new char[32];
197         snprintf(returnString, 32, "%d,%d,%d", RGB[0], RGB[1], RGB[2]);
198         returnVal = COLOR;
199     }
200     else if (getValue(line, i, "draw_orbit=", returnString))
201         returnVal = DRAW_ORBIT;
202     else if (getValue(line, i, "font=", returnString))
203         returnVal = FONT;
204     else if (getValue(line, i, "fontsize=", returnString))
205         returnVal = FONTSIZE;
206     else if (getValue(line, i, "grid=", returnString))
207         returnVal = GRID;
208     else if (getValue(line, i, "grid1=", returnString))
209         returnVal = GRID1;
210     else if (getValue(line, i, "grid2=", returnString))
211         returnVal = GRID2;
212     else if (getValue(line, i, "grid_color=", returnString))
213         returnVal = GRID_COLOR;
214     else if (getValue(line, i, "image=", returnString))
215         returnVal = IMAGE;
216     else if (getValue(line, i, "lang=", returnString))
217         returnVal = LANGUAGE;
218     else if (getValue(line, i, "magnify=", returnString))
219         returnVal = MAGNIFY;
220     else if (getValue(line, i, "mapbounds={", '}', returnString))
221         returnVal = MAP_BOUNDS;
222     else if (getValue(line, i, "marker_color={", '}', returnString))
223         returnVal = MARKER_COLOR;
224     else if (getValue(line, i, "marker_color=", returnString))
225     {
226         unsigned char RGB[3];
227         parseColor(returnString, RGB);
228         delete [] returnString;
229         returnString = new char[32];
230         snprintf(returnString, 32, "%d,%d,%d", RGB[0], RGB[1], RGB[2]);
231         returnVal = MARKER_COLOR;
232     }
233     else if (getValue(line, i, "marker_font=", returnString))
234         returnVal = MARKER_FONT;
235     else if (getValue(line, i, "marker_fontsize=", returnString))
236         returnVal = MARKER_FONTSIZE;
237     // This line must be after all other "marker_" keywords, because
238     // it gobbles all forms
239     else if (getValueAfter(line, i, "marker_", '=', returnString))
240         returnVal = MARKER_FILE;
241     else if (getValue(line, i, "map=", returnString))
242         returnVal = DAY_MAP;
243     else if (getValue(line, i, "max_radius_for_label=", returnString))
244         returnVal = MAX_RAD_FOR_LABEL;
245     else if (getValue(line, i, "min_radius_for_label=", returnString))
246         returnVal = MIN_RAD_FOR_LABEL;
247     else if (getValue(line, i, "min_radius_for_markers=", returnString))
248         returnVal = MIN_RAD_FOR_MARKERS;
249     else if (getValue(line, i, "max_radius=", returnString))
250         returnVal = MAX_RAD_FOR_MARKERS;
251     else if (getValue(line, i, "min_radius=", returnString))
252         returnVal = MIN_RAD_FOR_MARKERS;
253     else if (getValueIncludingComment(line, i, "\"", '"', returnString))
254         returnVal = NAME;
255     else if (getValueIncludingComment(line, i, "{", '}', returnString))
256         returnVal = NAME;
257     else if (getValue(line, i, "night_map=", returnString))
258         returnVal = NIGHT_MAP;
259     else if (getValue(line, i, "orbit={", '}', returnString))
260         returnVal = ORBIT;
261     else if (getValue(line, i, "orbit_color={", '}', returnString))
262         returnVal = ORBIT_COLOR;
263     else if (getValue(line, i, "orbit_color=", returnString))
264     {
265         unsigned char RGB[3];
266         parseColor(returnString, RGB);
267         delete [] returnString;
268         returnString = new char[32];
269         snprintf(returnString, 32, "%d,%d,%d", RGB[0], RGB[1], RGB[2]);
270         returnVal = ORBIT_COLOR;
271     }
272     else if (getValue(line, i, "relative_to=", returnString))
273         returnVal = ORIGIN;
274     else if (getValue(line, i, "opacity=", returnString))
275         returnVal = OPACITY;
276     else if (getValue(line, i, "outlined=", returnString))
277         returnVal = OUTLINED;
278     else if (getValue(line, i, "position=", returnString))
279         returnVal = POSITION;
280     else if (getValue(line, i, "radius=", returnString))
281         returnVal = RADIUS;
282     else if (getValue(line, i, "random_origin=", returnString))
283         returnVal = RANDOM_ORIGIN;
284     else if (getValue(line, i, "random_target=", returnString))
285         returnVal = RANDOM_TARGET;
286     else if (getValue(line, i, "rayleigh_emission_weight=", returnString))
287         returnVal = RAYLEIGH_EMISSION_WEIGHT;
288     else if (getValue(line, i, "rayleigh_file=", returnString))
289         returnVal = RAYLEIGH_FILE;
290     else if (getValue(line, i, "rayleigh_limb_scale=", returnString))
291         returnVal = RAYLEIGH_LIMB_SCALE;
292     else if (getValue(line, i, "rayleigh_scale=", returnString))
293         returnVal = RAYLEIGH_SCALE;
294     // Any 'new' satellite_* tokens must be before this, because it
295     // gobbles all forms
296     else if (getValueAfter(line, i, "satellite_", '=', returnString))
297         returnVal = SATELLITE_FILE;
298     else if (getValue(line, i, "shade=", returnString))
299         returnVal = SHADE;
300     else if (getValue(line, i, "spacing=", returnString))
301         returnVal = SPACING;
302     else if (getValue(line, i, "specular_map=", returnString))
303         returnVal = SPECULAR_MAP;
304     else if (getValue(line, i, "symbolsize=", returnString))
305         returnVal = SYMBOLSIZE;
306     else if (getValue(line, i, "text_color={", '}', returnString))
307         returnVal = TEXT_COLOR;
308     else if (getValue(line, i, "thickness=", returnString))
309         returnVal = THICKNESS;
310     else if (strncmp(line+i, "timezone=", 9) == 0)
311     {
312         i += 9;
313         int istart = i;
314         while (line[i] == '/' || line[i] == ',' || !isDelimiter(line[i]))
315         {
316             if (isEndOfLine(line[i])) break;
317             i++;
318         }
319         returnString = new char[i - istart + 1];
320         strncpy(returnString, (line + istart), i - istart);
321         returnString[i-istart] = '\0';
322         returnVal = TIMEZONE;
323     }
324     else if (getValue(line, i, "trail={", '}', returnString))
325         returnVal = TRAIL;
326     else if (getValue(line, i, "trail_output=", returnString))
327         returnVal = OUTPUT;
328     else if (getValue(line, i, "transparent={", '}', returnString))
329         returnVal = TRANSPARENT;
330     else if (getValue(line, i, "twilight=", returnString))
331         returnVal = TWILIGHT;
332     else // assume it's a latitude/longitude value
333     {
334         int istart = i;
335         skipPastToken(i, line);
336         returnString = new char[i - istart + 1];
337         strncpy(returnString, (line + istart), i - istart);
338         returnString[i-istart] = '\0';
339 
340         returnVal = LATLON;
341     }
342 
343     return(returnVal);
344 }
345