1 /*
2  * xearth.c
3  * kirk johnson
4  * july 1993
5  *
6  * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
7  *
8  * Parts of the source code (as marked) are:
9  *   Copyright (C) 1989, 1990, 1991 by Jim Frost
10  *   Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
11  *
12  * Permission to use, copy, modify and freely distribute xearth for
13  * non-commercial and not-for-profit purposes is hereby granted
14  * without fee, provided that both the above copyright notice and this
15  * permission notice appear in all copies and in supporting
16  * documentation.
17  *
18  * Unisys Corporation holds worldwide patent rights on the Lempel Zev
19  * Welch (LZW) compression technique employed in the CompuServe GIF
20  * image file format as well as in other formats. Unisys has made it
21  * clear, however, that it does not require licensing or fees to be
22  * paid for freely distributed, non-commercial applications (such as
23  * xearth) that employ LZW/GIF technology. Those wishing further
24  * information about licensing the LZW patent should contact Unisys
25  * directly at (lzw_info@unisys.com) or by writing to
26  *
27  *   Unisys Corporation
28  *   Welch Licensing Department
29  *   M/S-C1SW19
30  *   P.O. Box 500
31  *   Blue Bell, PA 19424
32  *
33  * The author makes no representations about the suitability of this
34  * software for any purpose. It is provided "as is" without express or
35  * implied warranty.
36  *
37  * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
39  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
40  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
43  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44  */
45 
46 #include "xearth.h"
47 #include "kljcpyrt.h"
48 extern int errno;
49 
50 #ifndef NO_SETPRIORITY
51 /* apparently some systems (possibly mt.xinu 4.3bsd?) may need
52  * <sys/time.h> to be included here before <sys/resource.h>.
53  */
54 #include <sys/resource.h>       /* for setpriority() */
55 #endif
56 
57 #define ModeX    (0)            /* possible output_mode values */
58 #define ModePPM  (1)
59 #define ModeGIF  (2)
60 #define ModeTest (3)
61 
62 /* tokens in specifiers are delimited by spaces, tabs, commas, and
63  * forward slashes
64  */
65 #define IsTokenDelim(x)  (((x)==' ')||((x)=='\t')||((x)==',')||((x)=='/'))
66 #define NotTokenDelim(x) (!IsTokenDelim(x))
67 
68 int  main _P((int, char *[]));
69 void set_priority _P((int));
70 void output _P((void));
71 void test_mode _P((void));
72 void sun_relative_position _P((double *, double *));
73 void simple_orbit _P((time_t, double *, double *));
74 void pick_random_position _P((double *, double *));
75 void set_defaults _P((void));
76 int  using_x _P((int, char *[]));
77 void command_line _P((int, char *[]));
78 
79 char    *progname;              /* program name                */
80 int      proj_type;             /* projection type             */
81 int      output_mode;           /* output mode (X, PPM, ...)   */
82 double   view_lon;              /* viewing position longitude  */
83 double   view_lat;              /* viewing position latitude   */
84 double   view_rot;              /* viewing rotation (degrees)  */
85 int      rotate_type;           /* type of rotation            */
86 int      view_pos_type;         /* type of viewing position    */
87 double   sun_rel_lon;           /* view lon, relative to sun   */
88 double   sun_rel_lat;           /* view lat, relative to sun   */
89 double   orbit_period;          /* orbit period (seconds)      */
90 double   orbit_inclin;          /* orbit inclination (degrees) */
91 double   view_mag;              /* viewing magnification       */
92 int      do_shade;              /* render with shading?        */
93 double   sun_lon;               /* sun position longitude      */
94 double   sun_lat;               /* sun position latitude       */
95 int      compute_sun_pos;       /* compute sun's position?     */
96 int      wdth;                  /* image width (pixels)        */
97 int      hght;                  /* image height (pixels)       */
98 int      shift_x;               /* image shift (x, pixels)     */
99 int      shift_y;               /* image shift (y, pixels)     */
100 int      do_stars;              /* show stars in background?   */
101 double   star_freq;             /* frequency of stars          */
102 int      big_stars;             /* percent of doublewide stars */
103 int      do_grid;               /* show lon/lat grid?          */
104 int      grid_big;              /* lon/lat grid line spacing   */
105 int      grid_small;            /* dot spacing along grids     */
106 int      do_label;              /* label image                 */
107 int      do_markers;            /* display markers (X only)    */
108 char    *markerfile;            /* for user-spec. marker info  */
109 int      wait_time;             /* wait time between redraw    */
110 double   time_warp;             /* passage of time multiplier  */
111 int      fixed_time;            /* fixed viewing time (ssue)   */
112 int      day;                   /* day side brightness (%)     */
113 int      night;                 /* night side brightness (%)   */
114 int      terminator;            /* terminator discontinuity, % */
115 double   xgamma;                /* gamma correction (X only)   */
116 int      use_two_pixmaps;       /* use two pixmaps? (X only)   */
117 int      num_colors;            /* number of colors to use     */
118 int      do_fork;               /* fork child process?         */
119 int      priority;              /* desired process priority    */
120 
121 time_t start_time = 0;
122 time_t current_time;
123 char   errmsgbuf[1024];         /* for formatting warning/error msgs */
124 
125 
main(argc,argv)126 int main(argc, argv)
127      int   argc;
128      char *argv[];
129 {
130   set_defaults();
131 
132   if (using_x(argc, argv))
133     command_line_x(argc, argv);
134   else
135     command_line(argc, argv);
136 
137   if (priority != 0)
138     set_priority(priority);
139 
140   srandom(((int) time(NULL)) + ((int) getpid()));
141 
142   output();
143 
144   return 0;
145 }
146 
147 
148 #ifdef NO_SETPRIORITY
149 
150 /* setpriority()-like functionality for System V
151  * derivates that only provide nice()
152  */
set_priority(new)153 void set_priority(new)
154      int new;
155 {
156   int old;
157 
158   /* determine current priority of the process
159    */
160   errno = 0;
161   old   = nice(0);
162   if ((old == -1) && (errno != 0))
163   {
164     perror("nice");
165     exit(-1);
166   }
167 
168   /* try to change priority to new
169    */
170   new = nice(new - old);
171   if ((new == -1) && (errno != 0))
172   {
173     perror("nice");
174     exit(-1);
175   }
176 }
177 
178 #else /* NO_SETPRIORITY */
179 
180 /* for systems that provide setpriority(),
181  * set_priority() is just a wrapper
182  */
set_priority(new)183 void set_priority(new)
184      int new;
185 {
186   if ((setpriority(PRIO_PROCESS, getpid(), new) == -1))
187   {
188     perror("setpriority");
189     exit(-1);
190   }
191 }
192 
193 #endif /* NO_SETPRIORITY */
194 
195 
output()196 void output()
197 {
198   switch (output_mode)
199   {
200   case ModePPM:
201     ppm_output();
202     break;
203 
204   case ModeGIF:
205     gif_output();
206     break;
207 
208   case ModeX:
209     if ((!do_fork) || (fork() == 0))
210       x11_output();
211     break;
212 
213   case ModeTest:
214     test_mode();
215     break;
216 
217   default:
218     assert(0);
219   }
220 }
221 
222 
test_mode()223 void test_mode()
224 {
225 }
226 
227 
compute_positions()228 void compute_positions()
229 {
230   /* determine "current" time
231    */
232   if (fixed_time == 0)
233   {
234     current_time = time(NULL);
235     if (start_time == 0)
236       start_time = current_time;
237     else
238       current_time = start_time + (current_time - start_time) * time_warp;
239   }
240   else
241   {
242     current_time = fixed_time;
243   }
244 
245   /* determine position on earth's surface where sun is directly
246    * overhead
247    */
248   if (compute_sun_pos)
249     sun_position(current_time, &sun_lat, &sun_lon);
250 
251   /* determine viewing position
252    */
253   if (view_pos_type == ViewPosTypeSun)
254   {
255     sun_relative_position(&view_lat, &view_lon);
256   }
257   else if (view_pos_type == ViewPosTypeOrbit)
258   {
259     simple_orbit(current_time, &view_lat, &view_lon);
260   }
261   else if (view_pos_type == ViewPosTypeRandom)
262   {
263     pick_random_position(&view_lat, &view_lon);
264   }
265   else if (view_pos_type == ViewPosTypeMoon)
266   {
267     moon_position(current_time, &view_lat, &view_lon);
268   }
269 
270   /* for ViewRotGalactic, compute appropriate viewing rotation
271    */
272   if (rotate_type == ViewRotGalactic)
273   {
274     view_rot = sun_lat * sin((view_lon - sun_lon) * (M_PI / 180));
275   }
276 }
277 
278 
sun_relative_position(lat_ret,lon_ret)279 void sun_relative_position(lat_ret, lon_ret)
280      double *lat_ret;           /* (return) latitude  */
281      double *lon_ret;           /* (return) longitude */
282 {
283   double lat, lon;
284 
285   lat = sun_lat + sun_rel_lat;
286   lon = sun_lon + sun_rel_lon;
287 
288   /* sanity check */
289   assert((lat >= -180) && (lat <= 180));
290   assert((lon >= -360) && (lon <= 360));
291 
292   if (lat > 90)
293   {
294     lat  = 180 - lat;
295     lon += 180;
296   }
297   else if (lat < -90)
298   {
299     lat  = -180 - lat;
300     lon += 180;
301   }
302 
303   if (lon > 180)
304   {
305     do
306       lon -= 360;
307     while (lon > 180);
308   }
309   else if (lon < -180)
310   {
311     do
312       lon += 360;
313     while (lon < -180);
314   }
315 
316   *lat_ret = lat;
317   *lon_ret = lon;
318 }
319 
320 
simple_orbit(ssue,lat,lon)321 void simple_orbit(ssue, lat, lon)
322      time_t  ssue;              /* seconds since unix epoch */
323      double *lat;               /* (return) latitude        */
324      double *lon;               /* (return) longitude       */
325 {
326   double x, y, z;
327   double a, c, s;
328   double t1, t2;
329 
330   /* start at 0 N 0 E */
331   x = 0;
332   y = 0;
333   z = 1;
334 
335   /* rotate in about y axis (from z towards x) according to the number
336    * of orbits we've completed
337    */
338   a  = ((double) ssue / orbit_period) * (2*M_PI);
339   c  = cos(a);
340   s  = sin(a);
341   t1 = c*z - s*x;
342   t2 = s*z + c*x;
343   z  = t1;
344   x  = t2;
345 
346   /* rotate about z axis (from x towards y) according to the
347    * inclination of the orbit
348    */
349   a  = orbit_inclin * (M_PI/180);
350   c  = cos(a);
351   s  = sin(a);
352   t1 = c*x - s*y;
353   t2 = s*x + c*y;
354   x  = t1;
355   y  = t2;
356 
357   /* rotate about y axis (from x towards z) according to the number of
358    * rotations the earth has made
359    */
360   a  = ((double) ssue / EarthPeriod) * (2*M_PI);
361   c  = cos(a);
362   s  = sin(a);
363   t1 = c*x - s*z;
364   t2 = s*x + c*z;
365   x  = t1;
366   z  = t2;
367 
368   *lat = asin(y) * (180/M_PI);
369   *lon = atan2(x, z) * (180/M_PI);
370 }
371 
372 
373 /* pick a position (lat, lon) at random
374  */
pick_random_position(lat_ret,lon_ret)375 void pick_random_position(lat_ret, lon_ret)
376      double *lat_ret;           /* (return) latitude  */
377      double *lon_ret;           /* (return) longitude */
378 {
379   int    i;
380   double pos[3];
381   double mag;
382   double s_lat, c_lat;
383   double s_lon, c_lon;
384 
385   /* select a vector at random */
386   do
387   {
388     mag = 0;
389     for (i=0; i<3; i++)
390     {
391       pos[i] = ((random() % 20001) * 1e-4) - 1;
392       mag   += pos[i] * pos[i];
393     }
394   } while ((mag > 1.0) || (mag < 0.01));
395 
396   /* normalize the vector */
397   mag = sqrt(mag);
398   for (i=0; i<3; i++)
399     pos[i] /= mag;
400 
401   /* convert to (lat, lon) */
402   s_lat = pos[1];
403   c_lat = sqrt(1 - s_lat*s_lat);
404   s_lon = pos[0] / c_lat;
405   c_lon = pos[2] / c_lat;
406 
407   *lat_ret = atan2(s_lat, c_lat) * (180/M_PI);
408   *lon_ret = atan2(s_lon, c_lon) * (180/M_PI);
409 }
410 
411 
412 /* look through the command line arguments to figure out if we're
413  * using X or not (if "-ppm", "-gif", or "-test" is found, we're not
414  * using X, otherwise we are).
415  */
using_x(argc,argv)416 int using_x(argc, argv)
417      int   argc;
418      char *argv[];
419 {
420   int i;
421 
422   /* loop through the args, break if we find "-ppm", "-gif", or
423    * "-test"
424    */
425   for (i=1; i<argc; i++)
426     if ((strcmp(argv[i], "-ppm") == 0) ||
427         (strcmp(argv[i], "-gif") == 0) ||
428         (strcmp(argv[i], "-test") == 0))
429       break;
430 
431   /* if we made it through the loop without finding "-ppm", "-gif", or
432    * "-test" (and breaking out), assume we're using X.
433    */
434   return (i == argc);
435 }
436 
437 
438 /* set_defaults() gets called at xearth startup (before command line
439  * arguments are handled), regardless of what output mode (x, ppm,
440  * gif) is being used.
441  */
set_defaults()442 void set_defaults()
443 {
444   output_mode      = ModeX;
445   proj_type        = ProjTypeOrthographic;
446   view_pos_type    = ViewPosTypeSun;
447   sun_rel_lat      = 0;
448   sun_rel_lon      = 0;
449   compute_sun_pos  = 1;
450   view_rot         = 0;
451   rotate_type      = ViewRotNorth;
452   wdth             = DefaultWdthHght;
453   hght             = DefaultWdthHght;
454   shift_x          = 0;
455   shift_y          = 0;
456   view_mag         = 1.0;
457   do_shade         = 1;
458   do_label         = 0;
459   do_markers       = 1;
460   wait_time        = 300;
461   time_warp        = 1;
462   day              = 100;
463   night            = 5;
464   terminator       = 1;
465   use_two_pixmaps  = 1;
466   num_colors       = 64;
467   do_fork          = 0;
468   priority         = 0;
469   do_stars         = 1;
470   star_freq        = 0.002;
471   big_stars        = 0;
472   do_grid          = 0;
473   grid_big         = 6;
474   grid_small       = 15;
475   fixed_time       = 0;
476   xgamma           = 1.0;
477 }
478 
479 
480 /* procedure for interpreting command line arguments when we're not
481  * using X; command_line_x() is used when we are.
482  */
command_line(argc,argv)483 void command_line(argc, argv)
484      int   argc;
485      char *argv[];
486 {
487   int i;
488 
489   progname = argv[0];
490 
491   for (i=1; i<argc; i++)
492   {
493     if (strcmp(argv[i], "-proj") == 0)
494     {
495       i += 1;
496       if (i >= argc) usage("missing arg to -proj");
497       decode_proj_type(argv[i]);
498     }
499     else if (strcmp(argv[i], "-pos") == 0)
500     {
501       i += 1;
502       if (i >= argc) usage("missing arg to -pos");
503       decode_viewing_pos(argv[i]);
504     }
505     else if (strcmp(argv[i], "-rot") == 0)
506     {
507       i += 1;
508       if (i >= argc) usage("missing arg to -rot");
509       decode_rotation(argv[i]);
510     }
511     else if (strcmp(argv[i], "-sunpos") == 0)
512     {
513       i += 1;
514       if (i >= argc) usage("missing arg to -sunpos");
515       decode_sun_pos(argv[i]);
516     }
517     else if (strcmp(argv[i], "-mag") == 0)
518     {
519       i += 1;
520       if (i >= argc) usage("missing arg to -mag");
521       sscanf(argv[i], "%lf", &view_mag);
522       if (view_mag <= 0)
523         fatal("viewing magnification must be positive");
524     }
525     else if (strcmp(argv[i], "-size") == 0)
526     {
527       i += 1;
528       if (i >= argc) usage("missing arg to -size");
529       decode_size(argv[i]);
530     }
531     else if (strcmp(argv[i], "-shift") == 0)
532     {
533       i += 1;
534       if (i >= argc) usage("missing arg to -shift");
535       decode_shift(argv[i]);
536     }
537     else if (strcmp(argv[i], "-shade") == 0)
538     {
539       do_shade = 1;
540     }
541     else if (strcmp(argv[i], "-noshade") == 0)
542     {
543       do_shade = 0;
544     }
545     else if (strcmp(argv[i], "-label") == 0)
546     {
547       do_label = 1;
548       warning("labeling not supported with GIF and PPM output");
549     }
550     else if (strcmp(argv[i], "-nolabel") == 0)
551     {
552       do_label = 0;
553     }
554     else if (strcmp(argv[i], "-labelpos") == 0)
555     {
556       i += 1;
557       if (i >= argc) usage("missing arg to -labelpos");
558       warning("-labelpos not relevant for GIF or PPM output");
559     }
560     else if (strcmp(argv[i], "-markers") == 0)
561     {
562       do_markers = 1;
563       warning("markers not supported with GIF and PPM output");
564     }
565     else if (strcmp(argv[i], "-nomarkers") == 0)
566     {
567       do_markers = 0;
568     }
569     else if (strcmp(argv[i], "-markerfile") == 0)
570     {
571       i += 1;
572       if (i >= argc) usage("missing arg to -markerfile");
573       warning("-markerfile not relevant for GIF or PPM output");
574     }
575     else if (strcmp(argv[i], "-showmarkers") == 0)
576     {
577       warning("-showmarkers not relevant for GIF or PPM output");
578     }
579     else if (strcmp(argv[i], "-stars") == 0)
580     {
581       do_stars = 1;
582     }
583     else if (strcmp(argv[i], "-nostars") == 0)
584     {
585       do_stars = 0;
586     }
587     else if (strcmp(argv[i], "-starfreq") == 0)
588     {
589       i += 1;
590       if (i >= argc) usage("missing arg to -starfreq");
591       sscanf(argv[i], "%lf", &star_freq);
592       if ((star_freq < 0) || (star_freq > 1))
593         fatal("arg to -starfreq must be between 0 and 1");
594     }
595     else if (strcmp(argv[i], "-bigstars") == 0)
596     {
597       i += 1;
598       if (i >= argc) usage("missing arg to -bigstars");
599       sscanf(argv[i], "%d", &big_stars);
600       if ((big_stars < 0) || (big_stars > 100))
601         fatal("arg to -bigstars must be between 0 and 100");
602     }
603     else if (strcmp(argv[i], "-grid") == 0)
604     {
605       do_grid = 1;
606     }
607     else if (strcmp(argv[i], "-nogrid") == 0)
608     {
609       do_grid = 0;
610     }
611     else if (strcmp(argv[i], "-grid1") == 0)
612     {
613       i += 1;
614       if (i >= argc) usage("missing arg to -grid1");
615       sscanf(argv[i], "%d", &grid_big);
616       if (grid_big <= 0)
617         fatal("arg to -grid1 must be positive");
618     }
619     else if (strcmp(argv[i], "-grid2") == 0)
620     {
621       i += 1;
622       if (i >= argc) usage("missing arg to -grid2");
623       sscanf(argv[i], "%d", &grid_small);
624       if (grid_small <= 0)
625         fatal("arg to -grid2 must be positive");
626     }
627     else if (strcmp(argv[i], "-day") == 0)
628     {
629       i += 1;
630       if (i >= argc) usage("missing arg to -day");
631       sscanf(argv[i], "%d", &day);
632       if ((day > 100) || (day < 0))
633         fatal("arg to -day must be between 0 and 100");
634     }
635     else if (strcmp(argv[i], "-night") == 0)
636     {
637       i += 1;
638       if (i >= argc) usage("missing arg to -night");
639       sscanf(argv[i], "%d", &night);
640       if ((night > 100) || (night < 0))
641         fatal("arg to -night must be between 0 and 100");
642     }
643     else if (strcmp(argv[i], "-term") == 0)
644     {
645       i += 1;
646       if (i >= argc) usage("missing arg to -term");
647       sscanf(argv[i], "%d", &terminator);
648       if ((terminator > 100) || (terminator < 0))
649         fatal("arg to -term must be between 0 and 100");
650     }
651     else if (strcmp(argv[i], "-gamma") == 0)
652     {
653       i += 1;
654       if (i >= argc) usage("missing arg to -gamma");
655       sscanf(argv[i], "%lf", &xgamma);
656       if (xgamma <= 0)
657         fatal("arg to -gamma must be positive");
658       warning("gamma correction not supported with GIF and PPM output");
659     }
660     else if (strcmp(argv[i], "-wait") == 0)
661     {
662       i += 1;
663       if (i >= argc) usage("missing arg to -wait");
664       sscanf(argv[i], "%d", &wait_time);
665       if (wait_time < 0)
666         fatal("arg to -wait must be non-negative");
667     }
668     else if (strcmp(argv[i], "-timewarp") == 0)
669     {
670       i += 1;
671       if (i >= argc) usage("missing arg to -timewarp");
672       sscanf(argv[i], "%lf", &time_warp);
673       if (time_warp <= 0)
674         fatal("arg to -timewarp must be positive");
675     }
676     else if (strcmp(argv[i], "-time") == 0)
677     {
678       i += 1;
679       if (i >= argc) usage("missing arg to -time");
680       sscanf(argv[i], "%d", &fixed_time);
681     }
682     else if (strcmp(argv[i], "-onepix") == 0)
683     {
684       use_two_pixmaps = 0;
685       warning("-onepix not relevant for GIF or PPM output");
686     }
687     else if (strcmp(argv[i], "-twopix") == 0)
688     {
689       use_two_pixmaps = 1;
690       warning("-twopix not relevant for GIF or PPM output");
691     }
692     else if (strcmp(argv[i], "-mono") == 0)
693     {
694       warning("monochrome mode not supported with GIF and PPM output");
695     }
696     else if (strcmp(argv[i], "-nomono") == 0)
697     {
698       warning("monochrome mode not supported with GIF and PPM output");
699     }
700     else if (strcmp(argv[i], "-ncolors") == 0)
701     {
702       i += 1;
703       if (i >= argc) usage("missing arg to -ncolors");
704       sscanf(argv[i], "%d", &num_colors);
705       if ((num_colors < 3) || (num_colors > 1024))
706         fatal("arg to -ncolors must be between 3 and 1024");
707     }
708     else if (strcmp(argv[i], "-font") == 0)
709     {
710       i += 1;
711       if (i >= argc) usage("missing arg to -font");
712       warning("-font not relevant for GIF or PPM output");
713     }
714     else if (strcmp(argv[i], "-root") == 0)
715     {
716       warning("-root not relevant for GIF or PPM output");
717     }
718     else if (strcmp(argv[i], "-noroot") == 0)
719     {
720       warning("-noroot not relevant for GIF or PPM output");
721     }
722     else if (strcmp(argv[i], "-geometry") == 0)
723     {
724       warning("-geometry not relevant for GIF or PPM output");
725     }
726     else if (strcmp(argv[i], "-title") == 0)
727     {
728       warning("-title not relevant for GIF or PPM output");
729     }
730     else if (strcmp(argv[i], "-iconname") == 0)
731     {
732       warning("-iconname not relevant for GIF or PPM output");
733     }
734     else if (strcmp(argv[i], "-name") == 0)
735     {
736       warning("-name not relevant for GIF or PPM output");
737     }
738     else if (strcmp(argv[i], "-fork") == 0)
739     {
740       do_fork = 1;
741     }
742     else if (strcmp(argv[i], "-nofork") == 0)
743     {
744       do_fork = 0;
745     }
746     else if (strcmp(argv[i], "-once") == 0)
747     {
748       warning("-once not relevant for GIF or PPM output");
749     }
750     else if (strcmp(argv[i], "-noonce") == 0)
751     {
752       warning("-once not relevant for GIF or PPM output");
753     }
754     else if (strcmp(argv[i], "-nice") == 0)
755     {
756       i += 1;
757       if (i >= argc) usage("missing arg to -nice");
758       sscanf(argv[i], "%d", &priority);
759     }
760     else if (strcmp(argv[i], "-version") == 0)
761     {
762       version_info(1);
763     }
764     else if (strcmp(argv[i], "-ppm") == 0)
765     {
766       output_mode = ModePPM;
767     }
768     else if (strcmp(argv[i], "-gif") == 0)
769     {
770       output_mode = ModeGIF;
771     }
772     else if (strcmp(argv[i], "-test") == 0)
773     {
774       output_mode = ModeTest;
775     }
776     else if (strcmp(argv[i], "-display") == 0)
777     {
778       warning("-display not relevant for GIF or PPM output");
779     }
780     else
781     {
782       usage(NULL);
783     }
784   }
785 }
786 
787 
788 /* if efficiency really mattered here (which it doesn't), this code
789  * could definitely be made quite a bit more efficient.
790  */
tokenize(s,argc_ret,msg)791 char **tokenize(s, argc_ret, msg)
792      char        *s;
793      int         *argc_ret;
794      const char **msg;
795 {
796   int    lim;
797   int    argc;
798   char **argv;
799 
800   *msg = NULL;
801   lim  = 4;
802   argc = 0;
803   argv = (char **) malloc((unsigned) sizeof(char *) * lim);
804   assert(argv != NULL);
805 
806   while (1)
807   {
808     /* skip delimiters (space, tab, comma, forward slash)
809      */
810     while (1)
811     {
812       if (NotTokenDelim(*s)) break;
813       *s = '\0';
814       s += 1;
815     }
816 
817     if ((*s) == '\0')
818     {
819       /* if we're at the end of s, no more tokens
820        */
821       break;
822     }
823     else if ((*s) == '#')
824     {
825       /* if we find a comment character (#), replace it
826        * with a NUL and act like we found the end s
827        */
828       *s = '\0';
829       break;
830     }
831 
832     /* make sure there's room for another token
833      */
834     if (argc == lim)
835     {
836       lim *= 2;
837       argv = (char **) realloc(argv, (unsigned) sizeof(char *) * lim);
838       assert(argv != NULL);
839     }
840 
841     /* get the next token
842      */
843     if ((*s) == '"')
844     {
845       /* string token
846        */
847       *s = '\0';
848       s += 1;
849       argv[argc++] = s;
850 
851       while (((*s) != '"') && ((*s) != '\0'))
852         s += 1;
853 
854       if ((*s) == '\0')
855       {
856         /* oops, never found closing double quote
857          */
858         *msg = "unterminated string (missing \")";
859       }
860       else
861       {
862         /* string token terminated normally
863          */
864         *s = '\0';
865         s += 1;
866       }
867     }
868     else
869     {
870       /* normal token
871        */
872       argv[argc++] = s;
873 
874       while (NotTokenDelim(*s) &&
875              ((*s) != '#') && ((*s) != '"') && ((*s) != '\0'))
876         s += 1;
877     }
878   }
879 
880   *argc_ret = argc;
881   return argv;
882 }
883 
884 
885 /* decode projection type; three possibilities:
886  *  orthographic - orthographic projection (short form: orth)
887  *  mercator     - mercator projection (short form: merc)
888  *  cylindrical  - cylindrical projection (short form: cyl)
889  */
decode_proj_type(s)890 void decode_proj_type(s)
891      char *s;
892 {
893   if ((strcmp(s, "orthographic") == 0) || (strcmp(s, "orth") == 0))
894   {
895     proj_type = ProjTypeOrthographic;
896   }
897   else if ((strcmp(s, "mercator") == 0) || (strcmp(s, "merc") == 0))
898   {
899     proj_type = ProjTypeMercator;
900   }
901   else if ((strcmp(s, "cylindrical") == 0) || (strcmp(s, "cyl") == 0))
902   {
903     proj_type = ProjTypeCylindrical;
904   }
905   else
906   {
907     sprintf(errmsgbuf, "unknown projection type (%s)", s);
908     fatal(errmsgbuf);
909   }
910 }
911 
912 
913 /* decode viewing position specifier; five possibilities:
914  *
915  *  fixed lat lon  - viewing position fixed wrt earth at (lat, lon)
916  *
917  *  sunrel lat lon - viewing position fixed wrt sun at (lat, lon)
918  *                   [position interpreted as if sun was at (0, 0)]
919  *
920  *  orbit per inc  - moving viewing position following simple orbit
921  *                   with period per and inclination inc
922  *
923  *  random         - random viewing position
924  *
925  *  moon           - current location of the moon
926  *
927  * fields can be separated with either spaces, commas, or slashes.
928  */
decode_viewing_pos(s)929 void decode_viewing_pos(s)
930      char *s;
931 {
932   int         argc;
933   char      **argv;
934   const char *msg;
935   double      arg1;
936   double      arg2;
937 
938   argv = tokenize(s, &argc, &msg);
939   if (msg != NULL)
940   {
941     sprintf(errmsgbuf, "viewing position specifier: %s", msg);
942     warning(errmsgbuf);
943   }
944 
945   if (argc == 3)
946   {
947     arg1 = 0;
948     arg2 = 0;
949     sscanf(argv[1], "%lf", &arg1);
950     sscanf(argv[2], "%lf", &arg2);
951   }
952 
953   if (strcmp(argv[0], "fixed") == 0)
954   {
955     if (argc != 3)
956       fatal("wrong number of args in viewing position specifier");
957 
958     view_lat      = arg1;
959     view_lon      = arg2;
960     view_pos_type = ViewPosTypeFixed;
961 
962     if ((view_lat > 90) || (view_lat < -90))
963       fatal("viewing latitude must be between -90 and 90");
964     if ((view_lon > 180) || (view_lon < -180))
965       fatal("viewing longitude must be between -180 and 180");
966   }
967   else if (strcmp(argv[0], "sunrel") == 0)
968   {
969     if (argc != 3)
970       fatal("wrong number of args in viewing position specifier");
971 
972     sun_rel_lat   = arg1;
973     sun_rel_lon   = arg2;
974     view_pos_type = ViewPosTypeSun;
975 
976     if ((sun_rel_lat > 90) || (sun_rel_lat < -90))
977       fatal("latitude relative to sun must be between -90 and 90");
978     if ((sun_rel_lon > 180) || (sun_rel_lon < -180))
979       fatal("longitude relative to sun must be between -180 and 180");
980   }
981   else if (strcmp(argv[0], "orbit") == 0)
982   {
983     if (argc != 3)
984       fatal("wrong number of args in viewing position specifier");
985 
986     orbit_period  = arg1 * 3600;
987     orbit_inclin  = arg2;
988     view_pos_type = ViewPosTypeOrbit;
989 
990     if (orbit_period <= 0)
991       fatal("orbital period must be positive");
992     if ((orbit_inclin > 90) || (orbit_inclin < -90))
993       fatal("orbital inclination must be between -90 and 90");
994   }
995   else if (strcmp(argv[0], "random") == 0)
996   {
997     if (argc != 1)
998       fatal("wrong number of args in viewing position specifier");
999 
1000     view_pos_type = ViewPosTypeRandom;
1001   }
1002   else if (strcmp(argv[0], "moon") == 0)
1003   {
1004     if (argc != 1)
1005       fatal("wrong number of args in viewing position specifier");
1006 
1007     view_pos_type = ViewPosTypeMoon;
1008   }
1009   else
1010   {
1011     fprintf(stderr, "`%s'\n", argv[0]);
1012     fatal("unrecognized keyword in viewing position specifier");
1013   }
1014 
1015   free(argv);
1016 }
1017 
1018 
1019 /* decode rotation; two possibilities:
1020  *
1021  *  <angle>  - in degrees
1022  *  galactic - galactic north
1023  */
decode_rotation(s)1024 void decode_rotation(s)
1025      char *s;
1026 {
1027   int  argc;
1028   char **argv;
1029   const char *msg;
1030 
1031   argv = tokenize (s, &argc, &msg);
1032   if (msg != NULL)
1033   {
1034     sprintf(errmsgbuf, "rotation specifier: %s", msg);
1035     warning(errmsgbuf);
1036   }
1037   if (argc != 1)
1038      fatal("wrong number of args in rotation specifier");
1039 
1040   if (strcmp (argv[0], "galactic") == 0)
1041   {
1042     rotate_type = ViewRotGalactic;
1043   }
1044   else
1045   {
1046     sscanf (argv[0], "%lf", &view_rot);
1047     if ((view_rot < -180) || (view_rot > 360))
1048       fatal("viewing rotation must be between -180 and 360");
1049   }
1050 
1051   free (argv);
1052 }
1053 
1054 
1055 /* decode sun position specifier:
1056  *
1057  *  lat lon - sun position fixed wrt earth at (lat, lon)
1058  *
1059  * fields can be separated with either spaces, commas, or slashes.
1060  */
decode_sun_pos(s)1061 void decode_sun_pos(s)
1062      char *s;
1063 {
1064   int         argc;
1065   char      **argv;
1066   const char *msg;
1067 
1068   argv = tokenize(s, &argc, &msg);
1069   if (msg != NULL)
1070   {
1071     sprintf(errmsgbuf, "sun position specifier: %s", msg);
1072     warning(errmsgbuf);
1073   }
1074 
1075   if (argc != 2)
1076     fatal("wrong number of args in sun position specifier");
1077 
1078   sscanf(argv[0], "%lf", &sun_lat);
1079   sscanf(argv[1], "%lf", &sun_lon);
1080 
1081   if ((sun_lat > 90) || (sun_lat < -90))
1082     fatal("sun latitude must be between -90 and 90");
1083   if ((sun_lon > 180) || (sun_lon < -180))
1084     fatal("sun longitude must be between -180 and 180");
1085 
1086   compute_sun_pos = 0;
1087 
1088   free(argv);
1089 }
1090 
1091 
1092 /* decode size specifier:
1093  *
1094  *  width height - width and height of image (in pixels)
1095  *
1096  * fields can be separated with either spaces, commas, or slashes.
1097  */
decode_size(s)1098 void decode_size(s)
1099      char *s;
1100 {
1101   int         argc;
1102   char      **argv;
1103   const char *msg;
1104 
1105   argv = tokenize(s, &argc, &msg);
1106   if (msg != NULL)
1107   {
1108     sprintf(errmsgbuf, "size specifier: %s", msg);
1109     warning(errmsgbuf);
1110   }
1111 
1112   if (argc != 2)
1113     fatal("wrong number of args in size specifier");
1114 
1115   sscanf(argv[0], "%d", &wdth);
1116   sscanf(argv[1], "%d", &hght);
1117 
1118   if (wdth <= 0)
1119     fatal("wdth arg must be positive");
1120   if (hght <= 0)
1121     fatal("hght arg must be positive");
1122 
1123   free(argv);
1124 }
1125 
1126 
1127 /* decode shift specifier:
1128  *
1129  *  xofs yofs - offset in x and y dimensions
1130  *
1131  * fields can be separated with either spaces, commas, or slashes.
1132  */
decode_shift(s)1133 void decode_shift(s)
1134      char *s;
1135 {
1136   int         argc;
1137   char      **argv;
1138   const char *msg;
1139 
1140   argv = tokenize(s, &argc, &msg);
1141   if (msg != NULL)
1142   {
1143     sprintf(errmsgbuf, "shift specifier: %s", msg);
1144     warning(errmsgbuf);
1145   }
1146 
1147   if (argc != 2)
1148     fatal("wrong number of args in shift specifier");
1149 
1150   sscanf(argv[0], "%d", &shift_x);
1151   sscanf(argv[1], "%d", &shift_y);
1152 
1153   free(argv);
1154 }
1155 
1156 
xearth_bzero(buf,len)1157 void xearth_bzero(buf, len)
1158      char    *buf;
1159      unsigned len;
1160 {
1161   int *tmp;
1162 
1163   /* assume sizeof(int) is a power of two
1164    */
1165   assert((sizeof(int) == 4) || (sizeof(int) == 8));
1166 
1167   if (len < sizeof(int))
1168   {
1169     /* special case small regions
1170      */
1171     while (len > 0)
1172     {
1173       *buf = 0;
1174       buf += 1;
1175       len -= 1;
1176     }
1177   }
1178   else
1179   {
1180     /* zero leading non-word-aligned bytes
1181      */
1182     while (((long) buf) & (sizeof(int)-1))
1183     {
1184       *buf = 0;
1185       buf += 1;
1186       len -= 1;
1187     }
1188 
1189     /* zero trailing non-word-aligned bytes
1190      */
1191     while (len & (sizeof(int)-1))
1192     {
1193       len     -= 1;
1194       buf[len] = 0;
1195     }
1196 
1197     /* convert remaining len to words
1198      */
1199     tmp = (int *) buf;
1200     if (sizeof(int) == 4)
1201       len >>= 2;
1202     else if (sizeof(int) == 8)
1203       len >>= 3;
1204     else
1205       assert(0);
1206 
1207     /* zero trailing non-quadword-aligned words
1208      */
1209     while (len & 0x03)
1210     {
1211       len     -= 1;
1212       tmp[len] = 0;
1213     }
1214 
1215     /* zero remaining data four words at a time
1216      */
1217     while (len)
1218     {
1219       tmp[0] = 0;
1220       tmp[1] = 0;
1221       tmp[2] = 0;
1222       tmp[3] = 0;
1223       tmp += 4;
1224       len -= 4;
1225     }
1226   }
1227 }
1228 
1229 
version_info(flag)1230 void version_info(flag)
1231      int flag;
1232 {
1233   fflush(stdout);
1234   fprintf(stderr, "\n");
1235   fprintf(stderr, "This is xearth version %s.\n", VersionString);
1236   fprintf(stderr, "(Home page URL: %s)\n", HomePageURL);
1237   fprintf(stderr, "\n");
1238 
1239   if (flag) exit(0);
1240 }
1241 
1242 
usage(msg)1243 void usage(msg)
1244      const char *msg;
1245 {
1246   version_info(0);
1247   if (msg != NULL)
1248     fprintf(stderr, "%s\n", msg);
1249   fprintf(stderr, "usage: %s\n", progname);
1250   fprintf(stderr, " [-proj proj_type] [-pos pos_spec] [-rot angle]\n");
1251   fprintf(stderr, " [-sunpos sun_pos_spec] [-mag factor] [-size size_spec]\n");
1252   fprintf(stderr, " [-shift shift_spec] [-shade|-noshade] [-label|-nolabel]\n");
1253   fprintf(stderr, " [-labelpos geom] [-markers|-nomarkers] [-markerfile file]\n");
1254   fprintf(stderr, " [-showmarkers] [-stars|-nostars] [-starfreq frequency]\n");
1255   fprintf(stderr, " [-bigstars percent] [-grid|-nogrid] [-grid1 grid1] [-grid2 grid2]\n");
1256   fprintf(stderr, " [-day pct] [-night pct] [-term pct] [-gamma gamma_value]\n");
1257   fprintf(stderr, " [-wait secs] [-timewarp factor] [-time fixed_time]\n");
1258   fprintf(stderr, " [-onepix|-twopix] [-mono|-nomono] [-ncolors num_colors]\n");
1259   fprintf(stderr, " [-font font_name] [-root|-noroot] [-geometry geom] [-title title]\n");
1260   fprintf(stderr, " [-iconname iconname] [-name name] [-fork|-nofork] [-once|-noonce]\n");
1261   fprintf(stderr, " [-nice priority] [-gif] [-ppm] [-display dpyname] [-version]\n");
1262   fprintf(stderr, "\n");
1263   exit(1);
1264 }
1265 
1266 
warning(msg)1267 void warning(msg)
1268      const char *msg;
1269 {
1270   fflush(stdout);
1271   fprintf(stderr, "xearth %s: warning - %s\n", VersionString, msg);
1272   fflush(stderr);
1273 }
1274 
1275 
fatal(msg)1276 void fatal(msg)
1277      const char *msg;
1278 {
1279   fflush(stdout);
1280   fprintf(stderr, "xearth %s: fatal - %s\n", VersionString, msg);
1281   fprintf(stderr, "\n");
1282   exit(1);
1283 }
1284