home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / calculat / sun.zip / SUN.C next >
C/C++ Source or Header  |  1988-03-17  |  21KB  |  722 lines

  1. /***************************************************************************
  2. **
  3. **   SUN.C   Version 1.0  Michael Schwartz  December 25, 1984
  4. **
  5. ** This program uses the USNO algorithm to calculate sunrise and sunset 
  6. ** times from standard lattitudes and longitudes.  It has been set up as
  7. ** system independently as possible, with the exception being a function
  8. ** which gets the current (default) date and day of the year.  It is meant
  9. ** to be particularly useful for Jewish persons in out-of-the-way locations
  10. ** who might need to know the time of candle_lighting or havdalah.  With
  11. ** little difficulty, z'man k'riath shema can be calculated and added to the
  12. ** routines.
  13. **
  14. ** Inquiries can reach me at PO BOX 24536, Denver, Colorado 80224
  15. ** (a place no longer 'out of the way')
  16. **
  17. ** Ref: Almanac for Computers, pub. by US NAVAL OBSERVATORY
  18. ** Usage:
  19. ** sun [-c] [-l[lat]] [-L[long]] [-M] [-m[1-12|a]] [-d[day]]
  20. **     [-t<S|C|N|A>]  [-<12|24>]
  21. **  Latitude in deg,min'sec" N; Longitude in deg,min'sec" W
  22. **
  23. ** Accuracy:  The USNO claims accuracy withing 2 minutes except at extreme
  24. **  northern or southern lattitudes.  Comparison to local NWS charts for
  25. **  sunrise and sunset (which are cheap and easy to come by) shows that with
  26. **  the double precision calculations, the charts produced by this program 
  27. **  are no more than 1 minute removed from those charts in lattitudes lower
  28. **  than 41 degrees.  Candle lighting times agree with those on popular 
  29. **  calendars also to the 1 minute accuracy.
  30. **
  31. **  The program, unlike its fortran predecessor has a number of 
  32. ** important options and defaults.  It is capable of getting today's
  33. ** sunrise and sunset at a default location (now Denver, of course),
  34. ** producing a calendar-like table of a month or a year, and allowing the
  35. ** user to produce reams of data without reinvoking the program.
  36. **
  37. ** Permission is granted to distribute and use this program as desired.
  38. **
  39. ** Bugs:  Automatic calculation of non-default time zones will not produce
  40. **  correct local times (using the APPROXIMATE_TZ define).  Otherwise, 
  41. **  when lattitudes and longitudes are specified, the result is in Zulu (UT).
  42. **      No method of calculating DST or aligning years to Fridays/Saturdays
  43. **  or holidays has been provided in the MS-DOS version:  However,
  44. **  as more MS-DOS compilers support the ANSI time standards, the MS-DOS
  45. **  option may not be necessary for your compiler.
  46. **************************************************************************/
  47. #include <stdio.h>
  48.  
  49. #ifdef UNIX
  50. #define LONG int
  51. #ifdef MSDOS
  52. #undef MSDOS
  53. #endif
  54. #else
  55. #define LONG long
  56. #define MSDOS
  57. #define FUNC_8086 sysint21
  58. #define INT_8086  bdos
  59. /*
  60. ** The last two are currently set for the CI-86 compiler.  They are the
  61. ** machine interrupt for function calls (function 21) and the general 
  62. ** interrupt with return from AL respectively.    Change for other compilers.
  63. ** In fact, modern compilers should all be able to use the UNIX def.
  64. */
  65. #endif
  66.  
  67. #define TWELVE 1
  68. #define TWENTYFOUR 0
  69.  
  70. #define SUNSET 0
  71. #define CIVIL_TWILIGHT 1
  72. #define NAUTICAL_TWILIGHT 2
  73. #define ASTRONOMICAL_TWILIGHT 3
  74.  
  75. int myclock = TWELVE;
  76. /* Chooses a 12 hour clock */
  77. static char *location = "Denver, Colorado (East Side)";
  78. /* Defines the location for the report header */
  79. int longdeg=104, longmin=54, longsec=16, latdeg=39, latmin=41, latsec=45;
  80. /* Lattitude and longitude of east Denver,  Colorado            */
  81. int TZ = -7;
  82. /* This is the difference between MST and GMT */
  83.  
  84. #define BAD_ARG -1
  85. #define NOT_IMPLEMENTED -2
  86. #define BAD_MONTH -3
  87. #define BAD_DATE -4
  88.  
  89. #define NORMAL       0
  90. #define NO_SUNSET  1
  91. #define NO_SUNRISE 2
  92.  
  93. static char *months[] = {
  94.     "Nonesuch",
  95.     "January", "February", "March", "April", "May", "June",
  96.     "July", "August", "September", "October", "November", "December"
  97.             };
  98. static int count[] = {
  99.     1,32,60,91,121,152,182,213,244,274,305,335,366
  100.              };
  101. /*
  102. ** Note -- this is for a 365 day year.    The best possible approximation.
  103. ** However, if one asks for 2/29, the sheet will still show it.
  104. */
  105.  
  106. int cal_opt, month_opt, day_opt, multi_opt, lat_opt, long_opt, ang_opt=0;
  107. int j_opt;
  108.  
  109. int month_num, month_day, first_day, last_day;
  110.  
  111. main(argc,argv)
  112. int argc;
  113. char *argv[];
  114. {
  115.   double xsunrise, xsunset;
  116.   int j=0, day, day_adj, status;
  117. /*
  118. ** day_adj and status are used for those embarrasing places where the sun
  119. ** doesn't rise and set once a day as in the middle latitudes.
  120. ** day_adj will be -1 if today's event really happened yesterday, and
  121. **            1 if today's event won't happen until tomorrow.
  122. ** e.g, if today's sunrise occurred at 11:00PM yesterday.
  123. ** status will be 0 if NORMAL, NO_SUNRISE or NO_SUNSET if that event doesn't
  124. ** happen at all on that day (the range of an acos has been violated)
  125. */
  126.   char *sunrise, *sunset, *candle_light, *havdalah, *timeadj();
  127.   char *get_date();  /* Puts current date in a string of fixed length */
  128.  
  129. #define LIGHT -18
  130. #define HAV    42
  131. /* The offsets from sunset for candle lighting and havdalah */
  132.  
  133.   /* Default is today */
  134.   first_day = last_day = get_current_day();
  135.  
  136.   /* Handle args */
  137.   while (++j < argc)
  138.   {
  139.     if (argv[j][0] != '-')
  140.     {
  141.     prerror(BAD_ARG,argv[j]);
  142.     prusage();
  143.     }
  144.     else
  145.     {
  146.       switch (argv[j][1])
  147.       {
  148.       case 'c':
  149.     cal_opt++; break;
  150.       case 'M':
  151.     multi_opt++; 
  152.     day_opt++; first_day = last_day = get_day("\0");
  153.     break;
  154.       case 'm':
  155.     month_opt++; month_num = get_month(argv[j]+2); break;
  156.       case 'd':
  157.     day_opt++;
  158.     first_day = last_day = get_day(argv[j]+2); break;
  159.       case 'l':
  160.     lat_opt++;
  161.     get_angle("Latitude",&latdeg,&latmin,&latsec,argv[j]+2); break;
  162.       case 'L':
  163.     long_opt++;
  164.     get_angle("Longitude",&longdeg,&longmin,&longsec,argv[j]+2);
  165. #ifdef APPROXIMATE_TZ
  166.     TZ = -((longdeg*60 + longmin) + 450)/900; /* Approximation */
  167. #else
  168.     TZ = 0;      /* Use GMT */
  169. #endif
  170.     break;
  171.       case 'j':
  172.     j_opt++; break;
  173.       case '1':   /* Assume arg is -12 */
  174.     myclock = TWELVE; break;
  175.       case '2':   /* Assume arg is -24 */
  176.     myclock = TWENTYFOUR; break;
  177.       case 't':   /* Alternate sun angle for sunrise/set calculation */
  178.     if (argv[j][2] == 'S') /* Normal */
  179.       ang_opt=SUNSET;
  180.     else if (argv[j][2] == 'C') /* Civil Twilight */
  181.       ang_opt=CIVIL_TWILIGHT;
  182.     else if (argv[j][2] == 'N')
  183.       ang_opt=NAUTICAL_TWILIGHT;
  184.     else if (argv[j][2] == 'A')
  185.       ang_opt=ASTRONOMICAL_TWILIGHT;
  186.     else
  187.       prerror(BAD_ARG,argv[j]);
  188.     break;
  189.       default:
  190.     prerror(BAD_ARG,argv[j]);
  191.       }
  192.     }
  193.   }
  194.  
  195.   if (cal_opt && (lat_opt || long_opt) && !multi_opt) /* New location */
  196.     get_new_location_name();
  197.  
  198.   if (cal_opt && !multi_opt) prheader();
  199.  
  200.   for (day=first_day;day<=last_day;day++)
  201.   {
  202.     status = suntime(&xsunrise,&xsunset,day);
  203. /* Note: an "adjusted hourlength" is (xsunset - xsunrise)/12, unless this is
  204. ** less than 0; in that case, add 2.  (24/12)
  205. */
  206.  
  207.     if (status & NO_SUNRISE)
  208.        sunrise = "No sunrise today";
  209.     else
  210.        sunrise        = timeadj("Sunrise at",       xsunrise,0     ,&day_adj);
  211.     if (status & NO_SUNSET)
  212.     {
  213.       sunset = "No sunset today";
  214.       if (j_opt)
  215.       {
  216.     candle_light = "Candle lighting at **:**";
  217.     havdalah = "Havdalah at **:**";
  218.       }
  219.     }
  220.     else
  221.     {
  222.       sunset       = timeadj("Sunset at",      xsunset ,0    ,&day_adj);
  223.       if (j_opt)
  224.       {
  225.     candle_light = timeadj("Candle lighting at",xsunset ,LIGHT,&day_adj);
  226.     havdalah     = timeadj("Havdalah at",        xsunset ,HAV  ,&day_adj);
  227.       }
  228.     }
  229.     if (cal_opt)
  230.     {
  231.       if (j_opt)
  232.     printf("%-12s  %s  %s  %s  %s\n",get_date(),
  233.         sunrise, candle_light, sunset, havdalah);
  234.       else
  235.     printf("%-12s   %s  %s\n",get_date(),sunrise,sunset);
  236.     }
  237.     else
  238.     {
  239.       if (j_opt)
  240.     printf("%s %d\n\t%s              %s\n\t%s      %s\n",
  241.       months[month_num],month_day,sunrise, sunset, candle_light, havdalah);
  242.       else
  243.     printf("%s %2d\n\t%s\t\t%s\n",
  244.       months[month_num],month_day,sunrise,sunset);
  245.     }
  246.     if (day == count[month_num]-1)  /* We did last day of a month */
  247.     {
  248.       month_num++; month_day=1;
  249.       if (cal_opt && !multi_opt)
  250.       {
  251.     putchar('\f');
  252.     prheader();
  253.       }
  254.     }
  255.     else
  256.     {
  257.       if (cal_opt && !multi_opt)
  258.       {
  259.     if (!(month_day%10))
  260.     {
  261.       for (j=0;j<80;j++)
  262.         putchar('-');
  263.       putchar('\n');
  264.     }
  265.       }
  266.       month_day++;
  267.     }
  268.  
  269.     if (!(status & NO_SUNRISE))
  270.       free(sunrise);
  271.  
  272.     if (!(status & NO_SUNSET))
  273.     {
  274.       free(sunset);
  275.       if (j_opt)
  276.       {
  277.     free(candle_light); free(havdalah);
  278.       }
  279.     }
  280.   } 
  281.   if (multi_opt)
  282.     exit(main(argc,argv));
  283. }   
  284.  
  285. /******************************************************************
  286. C SUBROUTINES
  287. C *****************************************************************
  288. c     this program will calCULATE SUNSET TIMES FOR EAST DENVER.
  289. C     LAMBDA = 104,54'30" W      Longitude
  290. C     PHI = 39,42'0"N            Latitude
  291. C    FOR 1978, M=.985600t -3.251 -- M is the Sun's mean anomaly
  292. C    L=M + 1.916 SIN(M) + .020SIN(2M) + 282.565 -- L is Sun's TRUE long.
  293. C    TANa = .91746 TAN L    -- a is Sun's right ascension
  294. C    SIN DELTA = .39782 SIN L    -- Sun's declination
  295. C    COS h = (COSz - SIN DELTA*SIN PHI)/(COS DELTA*COS PHI)
  296. C    T = h + a - 0.065710t -6.620  -- h is local hour angle, a now in hours
  297. C    UT = T + LAMBDA --UT is GMT.  LAMBDA is now in hours (=deg/15)
  298. C
  299. C    WHERE Z is the zenith distance at phenomena in question. Samples:
  300. c    Z=90,50'  REGULAR SUNRISE/SET  (Atmospheric refraction + disk diameter)
  301. C    Z=96, CIVIL TWILIGHT
  302. C    Z=102 NAUTICAL TWILIGHT
  303. C    Z=106 ASTRONOMICAL TWILIGHT
  304. *************************************************************************/
  305.  
  306. #define PI  3.14159265
  307. #define TODEC(a,b,c) ((double)a + (double)b/60.0 + (double)c/3600.0)
  308. #define DEGRAD (PI/180.0)
  309. #define RADDEG (180.0/PI)
  310. #define D 0.91746
  311. #define E 0.39782
  312. #define M(x) (0.985600*x - 3.251)
  313. #define L(x) (x + 1.916*sin(DEGRAD*x) + 0.020*sin(2*DEGRAD*x) + 282.565)
  314. #define ADJ(x) (-0.065710*x - 6.620)
  315.  
  316. suntime(sunrise,sunset,day)
  317. double *sunrise, *sunset;
  318. int day;
  319. /******************************************************************
  320. **      --- This is where the REAL work is done ---
  321. ** This routine will seem FORTRANy.  An attempt has been made to
  322. ** mirror the procedure outlined in the USGS publication; very little
  323. ** optimization has been done, so that the connection between the
  324. ** publication and the software will be extremely clear.
  325. ** Thus, all angles are preserved in degrees (degrees are converted to
  326. ** hours by the observation that 360 degrees = 24 hours -- so 15.0 
  327. ** degrees are 1 hour).
  328. ******************************************************************/
  329. {
  330.   double lohr, lambda, phi, xm, xl, zm, zl, a, aa, ahr;
  331.   double sind, sindel, cosd, cosdel, h, hh, hhr, hphr, t, tprime;
  332.   double hprime, tt, ttt, ut, uut, aahr;
  333.   double cosphi, sinphi, cosz;
  334.   double sin(),cos(),acos(),tan(),atan(),sqrt();
  335.   double fabs();
  336.   int retval=NORMAL;
  337. /*********************************************************************
  338. ** lambda - longitude in degrees    phi - lattitude in degrees
  339. ** [sin|cos][d|del] - functions of pseudo-angle delta
  340. **********************************************************************/
  341.   
  342.   switch(ang_opt)
  343.   {
  344.      case SUNSET:
  345.     cosz = cos(DEGRAD*TODEC(90,50,0)); break;
  346.      case CIVIL_TWILIGHT:
  347.     cosz = cos(DEGRAD*TODEC(96,0,0)); break;
  348.      case NAUTICAL_TWILIGHT:
  349.     cosz = cos(DEGRAD*TODEC(102,0,0)); break;
  350.      case ASTRONOMICAL_TWILIGHT:
  351.     cosz = cos(DEGRAD*TODEC(106,0,0)); break;
  352.   }
  353.  
  354.   lambda = TODEC(longdeg,longmin,longsec);
  355.   lohr = lambda/15.0;
  356.   phi     = TODEC(latdeg,latmin,latsec);
  357.   cosphi = cos(DEGRAD*phi);
  358.   sinphi = sin(DEGRAD*phi);
  359.  
  360.   t = (double)day + (18.0 + lohr)/24.0;
  361.   tprime = (double)day + (6.0 + lohr)/24.0;
  362.  
  363.   xm = M(t);
  364.   zm = M(tprime);
  365.   xl = L(xm);
  366.   zl = L(zm);
  367. /*   XM,XL ARE BOTH IN DEGREES. */
  368.     
  369.   a  = RADDEG*atan( D*tan(DEGRAD*xl) ); /* Conversion to and from radians */
  370.   aa = RADDEG*atan( D*tan(DEGRAD*zl) );
  371.  
  372. /******* readjustment of angles a and aa *****************/
  373.   if ( fabs(a+360.0-xl) > 90.0 )  a += 180.0;
  374.   if (a > 360.0) a -= 360.0;
  375.  
  376.   if ( fabs(aa+360.0-zl) > 90.0 )  aa += 180.0;
  377.   if (aa > 360.0) aa -= 360.0;
  378.  
  379.   ahr = a/15.0;
  380.   sindel = E*sin(DEGRAD*xl);
  381.   cosdel = sqrt(1.0 - sindel*sindel);  /* cos delta must ALWAYS be >0 */
  382.   h = (cosz - sindel*sinphi)/( cosdel*cosphi );
  383.  
  384.   aahr= aa/15.0;
  385.   sind     = E*sin(DEGRAD*zl);
  386.   cosd     = sqrt(1.0 - sind*sind);
  387.   hh= (cosz - sind  *sinphi)/( cosd  *cosphi );
  388.  
  389.   if (fabs(h) <= 1.0)
  390.     h = RADDEG*acos(h);
  391.   else
  392.     retval |= NO_SUNSET;
  393.  
  394.   if (fabs(hh) <= 1.0)
  395.     hh= RADDEG*acos(hh);
  396.   else
  397.     retval |= NO_SUNRISE;
  398.  
  399.   hhr = h/15.0;
  400.   tt  = hhr + ahr + ADJ(t);
  401.   ut = tt + lohr;
  402.  
  403.   hprime = 360.0 - hh;    /* Puts sunrise in correct quadrant */
  404.   hphr= hprime/15.0;
  405.   ttt = hphr+ aahr + ADJ(tprime);
  406.   uut = ttt + lohr;
  407.  
  408. #ifdef DEBUG
  409.   fprintf(stderr,"DEBUG: phi %f  lambda %f\n",phi,lambda);
  410.   fprintf(stderr,"DEBUG: t   %f  tprime %f\n",t,tprime);
  411.   fprintf(stderr,"DEBUG: xl  %f  zl     %f\n",xl,zl);
  412.   fprintf(stderr,"DEBUG: a   %f  aa     %f\n",a,aa);
  413.   fprintf(stderr,"DEBUG: h   %f  hh     %f  hprime  %f\n",h, hh, hprime );
  414.   fprintf(stderr,"DEBUG: hhr %f  hphr   %f\n",hhr,hphr);
  415.   fprintf(stderr,"DEBUG: tt  %f  ttt    %f\n",tt,ttt);
  416.   fprintf(stderr,"DEBUG: ut  %f  uut    %f\n",ut,uut);
  417. #endif
  418.  
  419.   *sunset  = ut + TZ;
  420.   *sunrise = uut+ TZ;
  421.   return(retval);
  422. }
  423.  
  424. /**********************************************************************
  425.     SUBROUTINE TIMEADJ(TIME,HR,MIN,MINADJ,DAYADJ)
  426. **********************************************************************/
  427. char *timeadj(mess,time,minadj,dayadj)
  428. char *mess;
  429. double time;
  430. int minadj, *dayadj;
  431. {
  432.   char *calloc();
  433.   static char *str;
  434.   int hour, min, strlen();
  435.   int num = strlen(mess)+9;
  436.  
  437.   time += (double)minadj/60.0;
  438.   if (time < 0)
  439.   {
  440.     time += 24.0;
  441.     *dayadj -= 1;
  442.   }
  443.   hour = time; /* Type conversion causes truncation */
  444.   min  = (int)(( time - (double)hour )*60.0 + 0.5);
  445.   if (min >= 60) 
  446.   {
  447.     hour += 1;
  448.     min  -= 60;
  449.   }
  450.   if (hour > 24)
  451.   {
  452.     hour -= 24;
  453.     *dayadj += 1;
  454.   }
  455.   if (myclock==TWELVE)         /* Check for 12 hour clock */
  456.     if ( hour > 12)
  457.       hour -= 12;
  458.  
  459.   str = calloc(num,sizeof(char));
  460.   sprintf(str,"%s %2d:%02d",mess,hour,min);
  461.   return(str);
  462. }
  463.  
  464. /***************
  465. New functions
  466. ***************/
  467. get_current_day()
  468. /* This is a system dependent function which will get the current day of
  469. ** the year, and initialize the month-num and month-day
  470. */
  471. {
  472.   int day;
  473. #ifdef MSDOS
  474.   struct regval { int ax,bx,cx,dx,si,di,ds,es; } regs;
  475.   regs.ax = 0x2a00; /* MS-DOS get date function request */
  476.   FUNC_8086(®s,®s); /* Now  DH has month, DL has day */
  477.   month_num = regs.dx>>8;
  478.   month_day = regs.dx&0xff;
  479.   day = count[month_num-1] - 1 + month_day;
  480. #endif
  481. #ifdef UNIX
  482. #include <time.h>
  483.  
  484. time_t tp;
  485. struct tm    *localtime(),*t;
  486.  
  487. time(&tp);
  488. t = localtime(&tp);
  489.  
  490. month_num = t->tm_mon + 1;
  491. month_day = t->tm_mday;
  492. day = t->tm_yday;
  493. if (!lat_opt && !long_opt)
  494. {
  495.   TZ = -timezone / 3600;    /* Timezone is in seconds */
  496.   if (t->tm_isdst) TZ++;
  497. }
  498. #endif
  499.  
  500.   return(day);
  501. }
  502.  
  503. #include <ctype.h>
  504. get_day(argin)
  505. char *argin;
  506. /* Prompt if *argin NULL.  Otherwise parse for mm/dd or num */
  507. /* Gets the day of interest, possibly parsed from argin--if not, prompts */
  508. /* Also used as the final exit function if multi_opt             */
  509. {
  510.   char temp[6], *cp;
  511.   int tnum,j;
  512.   LONG atoi();
  513.  
  514.   if (*argin == NULL) /* Prompt for input */
  515.   {
  516.     argin = temp;
  517.     get_string(argin,
  518.       "Enter date in mm/dd format: (<CR> to exit): ",5);
  519.     /* This is the exit for multi_opt */
  520.     if (!*argin) exit(0);
  521.     /* If we got a NULL then exit */
  522.   }
  523.   cp = argin;
  524.   tnum = 0;
  525.   while (isdigit(*cp) && *cp)
  526.     tnum = 10*tnum + *cp++ - '0';
  527.   if (*cp)  /* We have a non-digit literal */
  528.   {
  529.     month_num = tnum;
  530.     month_day = atoi(cp+1);
  531.     if (month_num < 1 || month_num > 12)
  532.     prerror(BAD_DATE,argin);
  533.     if (month_day < 1 || month_day > 366)
  534.     prerror(BAD_DATE,argin);
  535.     return(count[tnum-1] - 1 + month_day);
  536.   }
  537.   else
  538.   {
  539.   /* The date is a single integer, and thus the number of a day of the year */
  540.     month_num = 1;
  541.     for (j=0; j<12; j++)
  542.       if (tnum >= count[j]) month_num = j+1;
  543.     month_day = tnum - count[month_num-1] + 1;
  544.     if (tnum < 1 || tnum > 366)
  545.       prerror(BAD_DATE,argin);
  546.     return (tnum);
  547.   }
  548. }
  549.  
  550. prerror(errnum,mess)
  551. int errnum;
  552. char *mess;
  553. {
  554.   static  char *messages[] =  {
  555.     "***Not used***",
  556.     "Bad argument |%s|\n",
  557.     "Option |%s| not yet implemented\n",
  558.     "Bad argument |%s| to -m[onth] flag: **Fatal**\n",
  559.     "Bad date |%s|.  Heap may be corrupted.\n"
  560.   };
  561.  
  562.   fprintf(stderr,messages[-errnum],mess);
  563.   return(errnum);
  564. }
  565.  
  566. get_angle(mess,degrees,minutes,seconds,argin)
  567. char *mess, *argin;
  568. int *degrees, *minutes, *seconds;
  569. /* Gets the angle of interest, either parsed from argin or by prompts */
  570. {
  571.   char temp[12],*cc,*degp,*minp,*secp,*strchr();
  572.   static char *zero = "0";
  573.   LONG atoi();
  574.  
  575.   if (*argin == NULL) /* Must prompt for angle */
  576.   {
  577.     fprintf(stderr,"Enter %s as deg,min'sec\": ",mess);
  578.     fflush(stderr);
  579.     /* Use stderr so as not to mess up a redirection of output */
  580.     get_string(temp," ",11);
  581.     temp[11]='\0'; /* That's right, I don't trust myself */
  582.     argin = temp;
  583.   }
  584.   if ( (cc = strchr(argin,',') ) > 0)
  585.   {
  586.     degp = argin; *cc = '\0'; minp = cc+1;
  587.   }
  588.   else
  589.   {
  590.     minp = argin;
  591.     degp = zero;
  592.   }
  593.  
  594.   if ( (cc = strchr(minp,'\'') ) > 0)
  595.   {
  596.     *cc = '\0'; secp = cc + 1;
  597.   }
  598.   else
  599.   {
  600.     secp = minp;
  601.     minp = zero;
  602.   }
  603.  
  604.   if ( (cc = strchr(secp,'"') ) > 0)
  605.   {
  606.     *cc = '\0';
  607.   }
  608.   else
  609.   {
  610.     secp = zero;
  611.   }
  612.  
  613.   *degrees = atoi(degp);
  614.   *minutes = atoi(minp);
  615.   *seconds = atoi(secp);
  616. }
  617.  
  618. static char only_date_space[16];
  619.  
  620. char *get_date()
  621. /* Converts mm/dd into a string of month day of fixed length */
  622. {
  623.   sprintf(only_date_space,"%s %2d",months[month_num],month_day);
  624.   return(only_date_space);
  625. }
  626.  
  627. prheader()
  628. /* Used to put page headers for the cal_opt */
  629. {
  630.   printf("\n               ");
  631.   printf("Sunrise and Sunset times for %s\n\n\n",location);
  632. }
  633.  
  634. get_month(argin)
  635. char *argin;
  636. {
  637.   LONG atoi();
  638.  
  639.   if (*argin == NULL)
  640.   {
  641.     first_day = count[month_num-1];
  642.     last_day  = count[month_num] -1;
  643.     month_day = 1;
  644.     return(month_num);
  645.   }
  646.   if (*argin == 'a')
  647.   {
  648.      first_day = 1;
  649.      last_day = 366;
  650.      month_num = 1;
  651.      month_day = 1;
  652.      return(month_num);
  653.   }
  654.   month_num = atoi(argin);
  655.   if ((month_num < 1) || (month_num > 12) )
  656.   {
  657.     prerror(BAD_MONTH,argin);
  658.     exit(-1);
  659.   }
  660.   first_day = count[month_num-1];
  661.   last_day  = count[month_num] - 1;
  662.   month_day = 1;
  663.   return(month_num);
  664. }
  665.  
  666. get_new_location_name()
  667. {
  668.   char *calloc();
  669.   location = calloc(51,sizeof(char));
  670. /* Don't use up this space unless we need it (For multi, use realloc?) */
  671.   get_string(location,
  672.     "Enter new location (Title for report): ",50);
  673. }
  674.  
  675. prusage()
  676. {
  677.   printf("Usage:\n");
  678.   printf("sun [-d[day]] [-c] [-M] [-l[lat]] [-L[long]]\n");
  679.   printf("    [-m[1-12|a]] [-<12|24>] [-t<S|C|N|A>] [-j]\n\n");
  680.   printf("  -m month\t-c calendar output\t-M prompt multiple days\n");
  681.   printf("  -12 - twelve hour clock.  -24 - twenty four hour clock\n");
  682.   printf("  -t: S regular S-nrise/set. C Civil. N Nautical. A Astronomical\n");
  683.   printf("  -j: Jewish - print candle lighting and havdalah times\n");
  684.   printf("If no values are specified, the d, l and L options will prompt\n");
  685.   printf("Default for date is today, default for m is this month.\n");
  686.   printf("Default is for a 12 hour clock, regular sunrise/set.\n");
  687.   exit(-1);
  688. }
  689.  
  690. get_string(buffer,mess,maxlen)
  691. char *buffer, *mess;
  692. int maxlen;
  693. {
  694. /* Returns 1 if stuff read, 0 if read had error or EOF */
  695. /* Common routine should work for both MS-DOS and UNIX */
  696.   int n_write; /* In case we wish to check status */
  697.   char *start=buffer;
  698.   char c;
  699.  
  700.   n_write = write(2,mess,strlen(mess)); /* STDERR, so not mess up output */
  701.  
  702.   while (read(0,&c,1) == 1) /* Until EOF or error */
  703.   {
  704.     if (c == '\b' || c == 127) /* BS or DEL */
  705.     {
  706.     if (buffer-start) buffer--;
  707.     }
  708.     else if (c == '\t') /* HT */
  709.     *buffer++ = c;
  710.     else if (c == '\n' || c == '\r') /* Don't care about mode for NL */
  711.     {
  712.     *buffer = '\0';
  713.     return(1);
  714.     }
  715.     else if ( (buffer - start) >= maxlen || c < 32)
  716.     continue; /* Ignore CTRLs and flush overage to NL */
  717.     else
  718.     *buffer++ = c;
  719.   }
  720.   return(0); /* Get here only if read fails */
  721. }
  722.