home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource1 / ast40dos / general.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-04  |  23.6 KB  |  818 lines

  1. /*
  2. ** Astrolog (Version 4.00) File: general.c
  3. **
  4. ** IMPORTANT NOTICE: the graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
  6. ** (cruiser1@stein.u.washington.edu). Permission is granted to freely
  7. ** use and distribute these routines provided one doesn't sell,
  8. ** restrict, or profit from them in any way. Modification is allowed
  9. ** provided these notices remain with any altered or edited versions of
  10. ** the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 12/31/1993.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. /*
  42. ******************************************************************************
  43. ** General Functions.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Swap two real floating point values. */
  48.  
  49. void SwapReal(d1, d2)
  50. real *d1, *d2;
  51. {
  52.   real temp;
  53.  
  54.   temp = *d1; *d1 = *d2; *d2 = temp;
  55. }
  56.  
  57.  
  58. /* Return the length of a string. */
  59.  
  60. int StringLen(line)
  61. char *line;
  62. {
  63.   int i;
  64.  
  65.   for (i = 0; *line++; i++)
  66.     ;
  67.   return i;
  68. }
  69.  
  70.  
  71. /* Return whether one string is greater than another. */
  72.  
  73. int StringCmp(s1, s2)
  74. char *s1, *s2;
  75. {
  76.   while (*s1 && *s1 == *s2)
  77.     s1++, s2++;
  78.   return *s1 - *s2;
  79. }
  80.  
  81.  
  82. /* Determine the sign of a number: -1 if value negative, +1 if value */
  83. /* positive, and 0 if it's zero.                                     */
  84.  
  85. real Sgn(d)
  86. real d;
  87. {
  88.   return d == 0.0 ? 0.0 : SGN2(d);
  89. }
  90.  
  91.  
  92. /* Given an x and y coordinate, return the angle formed by a line from the */
  93. /* origin to this coordinate. This is just converting from rectangular to  */
  94. /* polar coordinates; however, we don't determine the radius here.         */
  95.  
  96. real Angle(x, y)
  97. real x, y;
  98. {
  99.   real a;
  100.  
  101.   if (x != 0.0)
  102.     a = ATAN(y/x);
  103.   else
  104.     a = Sgn(y)*PI/2.0;
  105.   if (a < 0.0)
  106.     a += PI;
  107.   if (y < 0.0)
  108.     a += PI;
  109.   return a;
  110. }
  111.  
  112.  
  113. /* Modulus function for floating point values. The modulus value itself */
  114. /* has been specified earlier: it is usually either 360.0 or PI/2.0.    */
  115.  
  116. real Mod(d)
  117. real d;
  118. {
  119.   if (d > modulus)         /* In most cases, our value is only slightly */
  120.     d -= modulus;          /* out of range, so we can test for it and   */
  121.   else if (d < modulus)    /* avoid the more complicated arithmetic.    */
  122.     d += modulus;
  123.   if (d >= 0 && d < modulus)
  124.     return d;
  125.   return (d - floor(d/modulus)*modulus);
  126. }
  127.  
  128.  
  129. /*
  130. ******************************************************************************
  131. ** General Astrology Functions.
  132. ******************************************************************************
  133. */
  134.  
  135. /* A similar modulus function: convert an integer to value from 1..12. */
  136.  
  137. int Mod12(i)
  138. int i;
  139. {
  140.   while (i > SIGNS)
  141.     i -= SIGNS;
  142.   while (i < 1)
  143.     i += SIGNS;
  144.   return i;
  145. }
  146.  
  147.  
  148. /* Convert an inputed fractional degrees/minutes value to a true decimal   */
  149. /* degree quantity. For example, the user enters the decimal value "10.30" */
  150. /* to mean 10 degrees and 30 minutes; this will return 10.5, i.e. 10       */
  151. /* degrees and 30 minutes expressed as a floating point degree value.      */
  152.  
  153. real DecToDeg(d)
  154. real d;
  155. {
  156.   return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*100.0/60.0);
  157. }
  158.  
  159.  
  160. /* This is the inverse of the above function. Given a true decimal value */
  161. /* for a zodiac degree, adjust it so the degrees are in the integer part */
  162. /* and the minute expressed as hundredths, e.g. 10.5 degrees -> 10.30    */
  163.  
  164. real DegToDec(d)
  165. real d;
  166. {
  167.   return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*60.0/100.0);
  168. }
  169.  
  170.  
  171. /* Return the shortest distance between two degrees in the zodiac. This is  */
  172. /* normally their difference, but we have to check if near the Aries point. */
  173.  
  174. real MinDistance(deg1, deg2)
  175. real deg1, deg2;
  176. {
  177.   real i;
  178.  
  179.   i = dabs(deg1-deg2);
  180.   return i < DEGHALF ? i : DEGREES - i;
  181. }
  182.  
  183.  
  184. /* This is just like the above routine, except the min distance value  */
  185. /* returned will either be positive or negative based on whether the   */
  186. /* second value is ahead or behind the first one in a circular zodiac. */
  187.  
  188. real MinDifference(deg1, deg2)
  189. real deg1, deg2;
  190. {
  191.   real i;
  192.  
  193.   i = deg2 - deg1;
  194.   if (dabs(i) < DEGHALF)
  195.     return i;
  196.   return Sgn(i)*(dabs(i) - DEGREES);
  197. }
  198.  
  199.  
  200. /* Return the degree of the midpoint between two zodiac positions, making */
  201. /* sure we return the true midpoint closest to the positions in question. */
  202.  
  203. real Midpoint(deg1, deg2)
  204. real deg1, deg2;
  205. {
  206.   real mid;
  207.  
  208.   mid = (deg1+deg2)/2.0;
  209.   return MinDistance(deg1, mid) < DEGQUAD ? mid : Mod(mid+DEGHALF);
  210. }
  211.  
  212.  
  213. /* Given a planet and sign, determine whether: The planet rules the sign, */
  214. /* the planet has its fall in the sign, the planet exalts in the sign, or */
  215. /* is debilitated in the sign; and return an appropriate character.       */
  216.  
  217. char Dignify(body, sign)
  218. int body, sign;
  219. {
  220.   if (body > U_HI)
  221.     return ' ';
  222.   if (ruler1[body] == sign || ruler2[body] == sign)
  223.     return 'R';
  224.   if (ruler1[body] == Mod12(sign+6) || ruler2[body] == Mod12(sign+6))
  225.     return 'F';
  226.   if (exalt[body] == sign)
  227.     return 'e';
  228.   if (exalt[body] == Mod12(sign+6))
  229.     return 'd';
  230.   return '-';
  231. }
  232.  
  233.  
  234. /* Determine the number of days in a particular month. The year is needed, */
  235. /* too, because we have to check for leap years in the case of February.   */
  236.  
  237. int DayInMonth(month, year)
  238. int month, year;
  239. {
  240.   return (month == 9 || month == 4 || month == 6 || month == 11 ? 30 :
  241.     (month != 2 ? 31 : 28 +
  242.     (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))));
  243. }
  244.  
  245.  
  246. /* Given an aspect and two objects making that aspect with each other,   */
  247. /* return the maximum orb allowed for such an aspect. Normally this only */
  248. /* depends on the aspect itself, but some objects require narrow orbs,   */
  249. /* and some allow wider orbs, so check for these cases.                  */
  250.  
  251. real Orb(body1, body2, aspect)
  252. int body1, body2, aspect;
  253. {
  254.   real orb, i;
  255.  
  256.   orb = aspectorb[aspect];
  257.   i = body1 > BASE ? 2.0 : planetorb[body1];
  258.   orb = MIN(orb, i);
  259.   i = body2 > BASE ? 2.0 : planetorb[body2];
  260.   orb = MIN(orb, i);
  261.   if (body1 <= BASE)
  262.     orb += planetadd[body1];
  263.   if (body2 <= BASE)
  264.     orb += planetadd[body2];
  265.   return orb;
  266. }
  267.  
  268.  
  269. /*
  270. ******************************************************************************
  271. ** File IO Routines.
  272. ******************************************************************************
  273. */
  274.  
  275. /* Exit the program, and do any cleanup necessary. Note that if we had     */
  276. /* a non-fatal error, and we are in the -Q loop mode, then we won't        */
  277. /* actually terminate the program, but drop back to the command line loop. */
  278.  
  279. void Terminate(value)
  280. int value;
  281. {
  282.   if (value == _FORCE) {
  283.     AnsiColor(WHITE);
  284.     fprintf(stdout, "\n%s terminated.\n", appname);
  285.   }
  286.   if (value == _ERROR && (operation & DASHQ) > 0)
  287.     return;
  288.   if (ansi)
  289.     fprintf(S, "%c[0m", ESCAPE);    /* Get out of any Ansi color mode. */
  290.   exit(abs(value));
  291. }
  292.  
  293.  
  294. /* Print a warning message given a string. This is called in non-fatal  */
  295. /* cases where we return to normal execution after printing the string. */
  296.  
  297. void PrintWarning(string)
  298. char *string;
  299. {
  300.   AnsiColor(RED);
  301.   fprintf(stderr, "%s\n", string);
  302.   AnsiColor(DEFAULT); 
  303. }
  304.  
  305.  
  306. /* Print an error message. This is called in more serious cases which halt */
  307. /* running of the current chart sequence, which can terminate the program  */
  308. /* but isn't a fatal error in that we can still fall back to the -Q loop.  */
  309.  
  310. void PrintError(string)
  311. char *string;
  312. {
  313.   AnsiColor(RED);
  314.   fprintf(stderr, "%s: %s\n", appname, string);
  315.   Terminate(_ERROR);
  316.   AnsiColor(DEFAULT); 
  317. }
  318.  
  319.  
  320. /* Simplification for a commonly printed error message. */
  321.  
  322. void TooFew(option)
  323. char *option;
  324. {
  325.   char string[STRING];
  326.  
  327.   sprintf(string, "Too few options to switch -%s", option);
  328.   PrintError(string);
  329. }
  330.  
  331.  
  332. /* Another simplification for a commonly printed error message. */
  333.  
  334. void BadVal(option, value)
  335. char *option;
  336. int value;
  337. {
  338.   char string[STRING];
  339.  
  340.   sprintf(string, "Value %d passed to switch -%s out of range.\n",
  341.     value, option);
  342.   PrintError(string);
  343. }
  344.  
  345.  
  346. /* A simple procedure used throughout Astrolog: Print a particular */
  347. /* character on the screen 'n' times.                              */
  348.  
  349. void PrintTab(chr, count)
  350. char chr;
  351. int count;
  352. {
  353.   int i;
  354.  
  355.   for (i = 0; i < count; i++)
  356.     printc(chr);
  357. }
  358.  
  359.  
  360. /* Set an Ansi text color. */
  361.  
  362. void AnsiColor(col)
  363. int col;
  364. {
  365.   /* Special case: If we are passed the value REVERSE, and ansi is not    */
  366.   /* only on but set to a value > 1, then we'll enter reverse video mode. */
  367.  
  368.   if (!ansi || (col == REVERSE && ansi < 2))
  369.     return;
  370.   fprintf(S, "%c[", ESCAPE);
  371.   if (col == DEFAULT)
  372.     printc('0');
  373.   else if (col == REVERSE) {
  374.     printc('7');
  375.   } else
  376.     fprintf(S, "%c;%d", col > 7 ? '1' : '0', 30 + (col & 7));
  377.   printc('m');
  378. }
  379.  
  380.  
  381. /* Print a zodiac position on the screen. This is basically just auto-   */
  382. /* matically prints the string returned from CharZodiac() below, except  */
  383. /* we round here to the nearest minute or second and take care of color. */
  384.  
  385. void PrintZodiac(deg)
  386. real deg;
  387. {
  388.   if (!(operation & DASHs0))
  389.     deg = Mod(deg + (seconds < 0 ? 1.0/60.0/60.0/2.0 : 1.0/60.0/2.0));
  390.   else
  391.     deg = Mod(deg + (seconds < 0 ? 1.0/4.0/60.0/2.0 : 1.0/4.0/2.0));
  392.   AnsiColor(elemansi[(int) (deg / 30.0) & 3]);
  393.   fprintf(S, "%s", CharZodiac(deg));
  394.   AnsiColor(DEFAULT);
  395. }
  396.  
  397.  
  398. /* Given a zodiac position, return a string containing it as it's */
  399. /* formatted for display to the user.                             */
  400.  
  401. char *CharZodiac(deg)
  402. real deg;
  403. {
  404.   static char zod[11];
  405.   int sign, d, m;
  406.   real s;
  407.  
  408.   if (!(operation & DASHs0)) {
  409.  
  410.     /* Normally, we format the position in degrees/sign/minutes format: */
  411.  
  412.     sign = (int) (deg / 30.0);
  413.     d = (int) deg - sign*30;
  414.     m = (int) (FRACT(deg)*60.0);
  415.     sprintf(zod, "%2d%c%c%c%02d", d, SIGNAM(sign + 1), m);
  416.     if (seconds < 0) {
  417.       s = FRACT(deg)*60.0; s = FRACT(s)*60.0;
  418.       sprintf(zod, "%s'%02d\"", zod, (int)s);
  419.     }
  420.   } else {
  421.  
  422.     /* However, if -s0 switch in effect, get position in hours/minutes: */
  423.  
  424.     d = (int) (deg / 15.0);
  425.     m = (int) ((deg - (real)d*15.0)*60.0/24.0);
  426.     sprintf(zod, "%2dh,%02dm", d, m);
  427.     if (seconds < 0) {
  428.       s = FRACT(deg)*4.0; s = FRACT(s)*60.0;
  429.       sprintf(zod, "%s,%02ds", zod, (int)s);
  430.     }
  431.   }
  432.   return zod;
  433. }
  434.  
  435.  
  436. /* This is similar to formatting a zodiac degree, but here we return a */
  437. /* string of a (signed) declination value in degrees and minutes.      */
  438.  
  439. char *CharAltitude(deg)
  440. real deg;
  441. {
  442.   static char alt[8];
  443.   int d, m;
  444.  
  445.   while (deg > DEGQUAD)    /* Ensure declination is from -90..+90 degrees. */
  446.     deg -= DEGHALF;
  447.   while (deg < -DEGQUAD)
  448.     deg += DEGHALF;
  449.   sprintf(alt, "%c", deg < 0.0 ? '-' : '+');
  450.   deg = dabs(deg) + 1.0/60.0/2.0;
  451.   d = (int) deg;
  452.   m = (int) (FRACT(deg)*60.0);
  453.   sprintf(alt, "%s%2d%c%02d'", alt, d, DEGR2, m);
  454.   return alt;
  455. }
  456.  
  457.  
  458. /* Another string formatter, here we return a date string given a month,    */
  459. /* day, and year. We format with the day or month first based on whether    */
  460. /* the "European" date variable is set or not. The routine also takes a     */
  461. /* parameter to indicate how much the string should be abbreviated, if any. */
  462.  
  463. char *CharDate(mon, day, yea, full)
  464. int mon, day, yea, full;
  465. {
  466.   static char dat[20];
  467.  
  468.   if (full > FALSE) {
  469.     if (eurodate) {
  470.       if (full > TRUE)
  471.         sprintf(dat, "%2d %c%c%c%5d", day, MONNAM(mon), yea);
  472.       else
  473.         sprintf(dat, "%d %s %d", day, monthname[mon], yea);
  474.     } else {
  475.       if (full > TRUE)
  476.         sprintf(dat, "%c%c%c %2d%5d", MONNAM(mon), day, yea);
  477.       else
  478.         sprintf(dat, "%s %d, %d", monthname[mon], day, yea);
  479.     }
  480.   } else {
  481.     if (eurodate) {
  482.       if (full)
  483.         sprintf(dat, "%2d-%2d-%2d", day, mon, yea%100);
  484.       else
  485.         sprintf(dat, "%2d-%2d-%4d", day, mon, yea);
  486.     } else {
  487.       if (full)
  488.         sprintf(dat, "%2d/%2d/%2d", mon, day, yea%100);
  489.       else
  490.         sprintf(dat, "%2d/%2d/%4d", mon, day, yea);
  491.     }
  492.   }
  493.   return dat;
  494. }
  495.  
  496.  
  497. /* Return a string containing the given time expressed as an hour and */
  498. /* minute quantity. This is formatted in 24 hour or am/pm time based  */
  499. /* on whether the "European" time format flag is set or not.          */
  500.  
  501. char *CharTime(hr, min)
  502. int hr, min;
  503. {
  504.   static char tim[8];
  505.  
  506.   if (eurotime)
  507.     sprintf(tim, "%2d:%02d", hr, min);
  508.   else
  509.     sprintf(tim, "%2d:%02d%cm", Mod12(hr), min, hr < 12 ? 'a' : 'p');
  510.   return tim;
  511. }
  512.  
  513.  
  514. /* Nicely format the given longitude and latitude locations and return    */
  515. /* them in a string. Various parts of the program display a chart header, */
  516. /* and this allows the similar computations to be coded only once.        */
  517.  
  518. char *CharLocation(lon, lat, norm)
  519. real lon, lat, norm;
  520. {
  521.   static char loc[14];
  522.   int i, j;
  523.  
  524.   i = (int) (FRACT(dabs(lon))*norm+ROUND);
  525.   j = (int) (FRACT(dabs(lat))*norm+ROUND);
  526.   sprintf(loc, "%3.0f%c%02d%c%3.0f%c%02d%c",
  527.     floor(dabs(lon)), DEGR3, i, lon < 0.0 ? 'E' : 'W',
  528.     floor(dabs(lat)), DEGR3, j, lat < 0.0 ? 'S' : 'N');
  529.   return loc;
  530. }
  531.  
  532.  
  533. #ifdef TIME
  534. /* Compute the date and time it is right now as the program is running      */
  535. /* using the computer's internal clock. We do this by getting the number    */
  536. /* of seconds which have passed since January 1, 1970 and going from there. */
  537. /* The time return value filled is expressed in the given zone parameter.   */
  538.  
  539. void GetTimeNow(Mon, Day, Yea, Tim, Zon)
  540. int *Mon, *Day, *Yea;
  541. real *Tim, Zon;
  542. {
  543.   dword curtimer;
  544.   int min, sec;
  545.   real hr;
  546.  
  547.   time(&curtimer);
  548.   sec = (int) (curtimer % 60);
  549.   curtimer /= 60;
  550.   min = (int) (curtimer % 60);
  551.   curtimer /= 60;
  552.   hr = (real) (curtimer % 24) - Zon;
  553.   curtimer /= 24;
  554.   while (hr < 0.0) {
  555.     curtimer--;
  556.     hr += 24.0;
  557.   }
  558.   while (hr >= 24.0) {
  559.     curtimer++;
  560.     hr -= 24.0;
  561.   }
  562. #ifdef PC
  563.   curtimer += 2415020L;  /* Number of days between 1/1/1970 and 1/1/4713 BC. */
  564. #else
  565.   curtimer += 2440588L;  /* Number of days in 70 years different than above. */
  566. #endif
  567.   JulianToMdy((real)curtimer, Mon, Day, Yea);
  568.   *Tim = hr + (real) min / 100.0 + (real) sec / 6000.0;
  569. }
  570. #endif
  571.  
  572.  
  573. /* Stop and wait for the user to enter a line of text given a prompt to */
  574. /* display and a string buffer to fill with it.                         */
  575.  
  576. void InputString(prompt, string)
  577. char *prompt, *string;
  578. {
  579.   FILE *data;
  580.  
  581.   data = S; S = stdout;
  582.   fprintf(S, "%s", prompt);
  583.   AnsiColor(YELLOW);
  584.   fprintf(S, " > ");
  585.   AnsiColor(DEFAULT);
  586.   if (gets(string) == NULL)    /* Pressing control-D will terminate the */
  587.     Terminate(_FORCE);         /* program (at least on some machines.)  */
  588.   S = data;
  589. }
  590.  
  591.  
  592. /* Prompt the user for a floating point value, and make sure it conforms  */
  593. /* to the specified bounds before returning it. If a non-numeric value is */
  594. /* entered, then assume it's the name of a month, and try to convert it   */
  595. /* to the appropriate number from 1 to 12; and also check for an "AM" or  */
  596. /* "PM" suffix to hour values, and adjust the number appropriately.       */
  597.  
  598. real Input(prompt, low, high)
  599. char *prompt;
  600. real low, high;
  601. {
  602.   char line[STRING], c;
  603.   real x;
  604.   int i, j;
  605.  
  606.   loop {
  607.     InputString(prompt, line);
  608.     i = StringLen(line);
  609.     for (j = 0; j < i; j++)
  610.       if (line[j] == ':')      /* Convert all colons in the */
  611.         line[j] = '.';         /* entered line to periods.  */
  612.     c = CAP(line[0]);
  613.  
  614.     /* If they entered a string, then check to see if it's a month name. */
  615.  
  616.     if (c >= 'A' && c <= 'Z') {
  617.       switch (c) {
  618.       case 'J': x = CAP(line[1]) == 'U' ?                   /* January,     */
  619.         (CAP(line[2]) == 'L' ? 7.0 : 6.0) : 1.0; break;     /* June,July    */
  620.       case 'F': x = 2.0; break;                             /* February     */
  621.       case 'M': x = CAP(line[2]) == 'Y' ? 5.0 : 3.0; break; /* March,May    */
  622.       case 'A': x = CAP(line[1]) == 'U' ? 8.0 : 4.0; break; /* April,August */
  623.       case 'S': x = 9.0; break;                             /* September    */
  624.       case 'O': x = 10.0; break;                            /* October      */
  625.       case 'N': x = 11.0; break;                            /* November     */
  626.       case 'D': x = 12.0; break;                            /* December     */
  627.       default: x = 0.0;
  628.       }
  629.     } else {
  630.       sscanf(line, "%lf", &x);    /* Convert entered line to number. */
  631.       i = StringLen(line)-1;
  632.       if (i > 0 && CAP(line[i]) == 'M')
  633.         i--;
  634.       if (i > 0) {
  635.         c = CAP(line[i]);
  636.         if (c == 'A')                    /* Adjust value appropriately */
  637.           x = x >= 12.0 ? x-12.0 : x;    /* if 'AM' or 'PM' suffix.    */
  638.         else if (c == 'P')
  639.           x = x >= 12.0 ? x : x+12.0;
  640.       }
  641.     }
  642.     if (x >= low && x <= high)
  643.       return x;
  644.     sprintf(line, "Value out of range of from %.0f to %.0f.", low, high);
  645.     PrintWarning(line);
  646.   }
  647. }
  648.  
  649.  
  650. /* Given a string representing the complete pathname to a file, strip off    */
  651. /* all the path information leaving just the filename itself. This is called */
  652. /* by the main program to determine the name of the Astrolog executable.     */
  653.  
  654. char *ProcessProgname(name)
  655. char *name;
  656. {
  657.   char *b, *c, *e;
  658.  
  659.   b = c = name;
  660.   while (*c) {
  661. #ifdef PC
  662.     *c = UNCAP(*c);    /* Because DOS filenames are case insensitive. */
  663. #endif
  664.     c++;
  665.   }
  666.   e = c;
  667.   while (c > b && *c != '.')
  668.     c--;
  669.   if (c > b)
  670.     *c = 0;
  671.   else
  672.     c = e;
  673.   while (c > b && *c != '/' && *c != '\\')
  674.     c--;
  675.   if (c > b)
  676.     name = c+1;
  677.   return name;
  678. }
  679.  
  680.  
  681. /* This important procedure gets all the parameters defining the chart that  */
  682. /* will be worked with later. Given a "filename", it gets from it all the    */
  683. /* pertinent chart information. This is more than just reading from a file - */
  684. /* the procedure also takes care of the cases of prompting the user for the  */
  685. /* information and using the time functions to determine the date now - the  */
  686. /* program considers these cases "virtual" files. Furthermore, when reading  */
  687. /* from a real file, we have to check if it was written in the -o0 format.   */
  688.  
  689. bool InputData(filename)
  690. char *filename;
  691. {
  692.   FILE *data;
  693.   char name[STRING], c;
  694.   int i;
  695.   real k, l, m;
  696.  
  697.   /* If we are to read from the virtual file "set" then that means use a   */
  698.   /* particular set of chart information generated earlier in the program. */
  699.  
  700.   if (StringCmp(filename, "set") == 0) {
  701.     autom = 1;
  702.     SetCore(MonX, DayX, YeaX, TimX, ZonX, LonX, LatX);
  703.     return TRUE;
  704.   }
  705.  
  706. #ifdef TIME
  707.   /* If we are to read from the file "now" then that means use the time */
  708.   /* functions to calculate the present date and time.                  */
  709.  
  710.   if (StringCmp(filename, "now") == 0) {
  711.     autom = 1;
  712.     ZZ = defzone; OO = deflong; AA = deflat;
  713.     GetTimeNow(&MM, &DD, &YY, &TT, ZZ);
  714.     return TRUE;
  715.   }
  716. #endif
  717.  
  718.   /* If we are to read from the file "tty" then that means prompt the user */
  719.   /* for all the chart information.                                        */
  720.  
  721.   if (StringCmp(filename, "tty") == 0) {
  722.     if (!noswitches) {
  723.       /* Temporarily disable and internal redirection of output to a file */
  724.       /* because we always want user headers and prompts to be displayed. */
  725.       data = S; S = stdout;
  726.       AnsiColor(WHITE);
  727.       fprintf(S, "** %s version %s ", appname, VERSION);
  728.       fprintf(S, "(See '%cHc' switch for copyrights and credits.) **\n", DASH);
  729.       AnsiColor(DEFAULT);
  730.       fprintf(S, "   Invoke as '%s %cH' for list of command line options.\n",
  731.         progname, DASH);
  732.       S = data;
  733.     }
  734.     MM = (int)Input("Enter month of birth (e.g. '7', 'Jul')", 1.0, 12.0);
  735.     DD = (int)Input("Enter day   of birth (e.g. '1', '31') ", 1.0,
  736.       (real) DayInMonth(MM, 0));
  737.     YY = (int)Input("Enter year  of birth (e.g. '1993')    ", -5000.0, 5000.0);
  738.     if (YY >= 0 && YY <= 99) {
  739.       sprintf(name,
  740.         "Assuming first century A.D. is really meant instead of %d.",
  741.         1900 + YY);
  742.       PrintWarning(name);
  743.     }
  744.     fprintf(stdout, "Subtract one hour if Daylight Saving time in effect.\n");
  745.     TT = Input("Enter time  of birth (e.g. '18:30' '6:30pm')", -2.0, 24.0);
  746.     fprintf(stdout,
  747.       "Negative values indicate time zones east of Greenwich.\n");
  748.     ZZ = Input("Time zone in hours before GMT (5=Eastern, 8=Pacific)",
  749.       -24.0, 24.0);
  750.     fprintf(stdout,
  751.       "Negative values indicate eastern and southern locations.\n");
  752.     OO = Input("Longitude west of place (i.e. DEG:MIN)", -DEGHALF, DEGHALF);
  753.     AA = Input("Latitude north of place (i.e. DEG:MIN)", -DEGQUAD, DEGQUAD);
  754.     printl();
  755.     return TRUE;
  756.   }
  757.  
  758.   /* Now that the special cases are taken care of, we can assume we are */
  759.   /* to read from a real file.                                          */
  760.  
  761.   autom = 1;
  762.   data = fopen(filename, "r");      /* Look for file in current directory. */
  763.   if (data == NULL) {
  764.     sprintf(name, "%s%s", CHART_DIR, filename);    /* Look for file in   */
  765.     data = fopen(name, "r");                       /* default directory. */
  766.     if (data == NULL) {
  767.       sprintf(name, "File '%s' not found.", filename);
  768.       PrintError(name);
  769.       return FALSE;
  770.     }
  771.   }
  772.  
  773.   /* Read the chart parameters from a normal file. */
  774.  
  775.   if ((c = getc(data)) != 'S') {
  776.     ungetc(c, data);
  777.     fscanf(data, "%d%d%d", &MM, &DD, &YY);
  778.     fscanf(data, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
  779.  
  780.   /* Read the actual chart positions from a file produced with the -o0. */
  781.  
  782.   } else {
  783.  
  784.     /* Hack: A negative month value means the chart parameters are invalid, */
  785.     /* hence -o0 is in effect and we can assume the chart positions are     */
  786.     /* already in memory so we don't have to calculate them later.          */
  787.  
  788.     MM = -1;
  789.     for (i = 1; i <= BASE; i++) {
  790.       fscanf(data, "%s%lf%lf%lf", name, &k, &l, &m);
  791.       planet[i] = (l-1.0)*30.0+k+m/60.0;
  792.       fscanf(data, "%s%lf%lf", name, &k, &l);
  793.       planetalt[i] = k+l/60.0;
  794.       ret[i] = DTOR(name[1] == 'D' ? 1.0 : -1.0);
  795.  
  796.       /* -o0 files from version 3.05 and before don't have the uranians in   */
  797.       /* them. Be prepared to skip over them in old files for compatibility. */
  798.  
  799.       if (i == OBJECTS) {
  800.         while (getc(data) >= ' ')
  801.           ;
  802.         if ((c = getc(data)) != 'H')
  803.           i = C_HI;
  804.         else
  805.           i = total;
  806.       }
  807.     }
  808.     for (i = 1; i <= SIGNS/2; i++) {
  809.       fscanf(data, "%s%lf%lf%lf", name, &k, &l, &m);
  810.       house[i+6] = Mod((house[i] = Mod((l-1.0)*30.0+k+m/60.0))+DEGHALF);
  811.     }
  812.   }
  813.   fclose(data);
  814.   return TRUE;
  815. }
  816.  
  817. /* general.c */
  818.