"Fossies" - the Fresh Open Source Software Archive

Member "xearth-1.1/xearth.c" (7 Nov 1999, 31823 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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 
  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  */
  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  */
  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 
  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 
  223 void test_mode()
  224 {
  225 }
  226 
  227 
  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 
  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 
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
  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  */
 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  */
 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  */
 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  */
 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 
 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 
 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 
 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 
 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 
 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 }