This is general.c in view mode; [Download] [Up]
/*
** Astrolog (Version 4.10) File: general.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1994 by Walter D. Pullen
** (cruiser1@stein.u.washington.edu). Permission is granted to freely
** use and distribute these routines provided one doesn't sell,
** restrict, or profit from them in any way. Modification is allowed
** provided these notices remain with any altered or edited versions of
** the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 3/19/1994.
*/
#include "astrolog.h"
/*
******************************************************************************
** General Functions.
******************************************************************************
*/
/* Swap two real floating point values. */
void SwapReal(d1, d2)
real *d1, *d2;
{
real temp;
temp = *d1; *d1 = *d2; *d2 = temp;
}
/* Return the length of a string. */
int StringLen(line)
char *line;
{
int i;
for (i = 0; *line++; i++)
;
return i;
}
/* Return whether one string is greater than another. */
int StringCmp(s1, s2)
char *s1, *s2;
{
while (*s1 && *s1 == *s2)
s1++, s2++;
return *s1 - *s2;
}
/* Determine the sign of a number: -1 if value negative, +1 if value */
/* positive, and 0 if it's zero. */
real Sgn(d)
real d;
{
return d == 0.0 ? 0.0 : SGN2(d);
}
/* Given an x and y coordinate, return the angle formed by a line from the */
/* origin to this coordinate. This is just converting from rectangular to */
/* polar coordinates; however, we don't determine the radius here. */
real Angle(x, y)
real x, y;
{
real a;
if (x != 0.0)
a = ATAN(y/x);
else
a = Sgn(y)*PI/2.0;
if (a < 0.0)
a += PI;
if (y < 0.0)
a += PI;
return a;
}
/* Modulus function for floating point values. The modulus value itself */
/* has been specified earlier: it is usually either 360.0 or PI/2.0. */
real Mod(d)
real d;
{
if (d >= modulus) /* In most cases, our value is only slightly */
d -= modulus; /* out of range, so we can test for it and */
else if (d < 0.0) /* avoid the more complicated arithmetic. */
d += modulus;
if (d >= 0 && d < modulus)
return d;
return (d - floor(d/modulus)*modulus);
}
/* Integer division - like the "/" operator but always rounds result down. */
long Dvd(x, y)
long x, y;
{
long z;
if (y == 0)
return x;
z = x / y;
if (((x >= 0) == (y >= 0)) || x-z*y == 0)
return z;
return z - 1;
}
/*
******************************************************************************
** General Astrology Functions.
******************************************************************************
*/
/* A similar modulus function: convert an integer to value from 1..12. */
int Mod12(i)
int i;
{
while (i > SIGNS)
i -= SIGNS;
while (i < 1)
i += SIGNS;
return i;
}
/* Convert an inputed fractional degrees/minutes value to a true decimal */
/* degree quantity. For example, the user enters the decimal value "10.30" */
/* to mean 10 degrees and 30 minutes; this will return 10.5, i.e. 10 */
/* degrees and 30 minutes expressed as a floating point degree value. */
real DecToDeg(d)
real d;
{
return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*100.0/60.0);
}
/* This is the inverse of the above function. Given a true decimal value */
/* for a zodiac degree, adjust it so the degrees are in the integer part */
/* and the minute expressed as hundredths, e.g. 10.5 degrees -> 10.30 */
real DegToDec(d)
real d;
{
return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*60.0/100.0);
}
/* Return the shortest distance between two degrees in the zodiac. This is */
/* normally their difference, but we have to check if near the Aries point. */
real MinDistance(deg1, deg2)
real deg1, deg2;
{
real i;
i = dabs(deg1-deg2);
return i < DEGHALF ? i : DEGREES - i;
}
/* This is just like the above routine, except the min distance value */
/* returned will either be positive or negative based on whether the */
/* second value is ahead or behind the first one in a circular zodiac. */
real MinDifference(deg1, deg2)
real deg1, deg2;
{
real i;
i = deg2 - deg1;
if (dabs(i) < DEGHALF)
return i;
return Sgn(i)*(dabs(i) - DEGREES);
}
/* Return the degree of the midpoint between two zodiac positions, making */
/* sure we return the true midpoint closest to the positions in question. */
real Midpoint(deg1, deg2)
real deg1, deg2;
{
real mid;
mid = (deg1+deg2)/2.0;
return MinDistance(deg1, mid) < DEGQUAD ? mid : Mod(mid+DEGHALF);
}
/* Given a planet and sign, determine whether: The planet rules the sign, */
/* the planet has its fall in the sign, the planet exalts in the sign, or */
/* is debilitated in the sign; and return an appropriate character. */
char Dignify(body, sign)
int body, sign;
{
if (body > U_HI)
return ' ';
if (ruler1[body] == sign || ruler2[body] == sign)
return 'R';
if (ruler1[body] == Mod12(sign+6) || ruler2[body] == Mod12(sign+6))
return 'F';
if (exalt[body] == sign)
return 'e';
if (exalt[body] == Mod12(sign+6))
return 'd';
return '-';
}
/* Determine the number of days in a particular month. The year is needed, */
/* too, because we have to check for leap years in the case of February. */
int DayInMonth(month, year)
int month, year;
{
int d;
if (month == _SEP || month == _APR || month == _JUN || month == _NOV)
d = 30;
else if (month != _FEB)
d = 31;
else {
d = 28;
if (year % 4 == 0 &&
(year % 100 != 0 || year % 400 == 0 || year <= G2JYEA))
d++;
}
return d;
}
/* Return the actual number of days in a particular month. Normally, this */
/* is the same as the above routine which determines the index of the last */
/* day of the month, but the values can differ when changing between */
/* calendar systems (Julian to Gregorian) in which one can jump over days. */
int DaysInMonth(month, year)
int month, year;
{
int d;
d = DayInMonth(month, year);
if (year == G2JYEA && month == G2JMON)
d -= (G2JDAY2 - G2JDAY1 - 1);
return d;
}
/* Return the day of the week (Sunday is 0) of the specified given date. */
int DayOfWeek(month, day, year)
int month, day, year;
{
int d;
d = (int)((MdyToJulian(month, day, year) + 1) % 7);
return d < 0 ? d+7 : d;
}
/* Given a day, and the month and year it falls in, add a number of days */
/* to it and return the new day index. As month changes are not checked for */
/* here, this is mostly just adding the offset to the day; however we need */
/* to check for calendar changes for when days in a month may be skipped. */
/* We do not check for month crossings. only for G2J. */
int AddDay(month, day, year, delta)
int month, day, year, delta;
{
int d;
d = day + delta;
if (year == G2JYEA && month == G2JMON) {
if (d > G2JDAY1 && d < G2JDAY2)
d += SGN(delta)*(G2JDAY2-G2JDAY1-1);
}
return d;
}
/* Given an aspect and two objects making that aspect with each other, */
/* return the maximum orb allowed for such an aspect. Normally this only */
/* depends on the aspect itself, but some objects require narrow orbs, */
/* and some allow wider orbs, so check for these cases. */
real Orb(body1, body2, aspect)
int body1, body2, aspect;
{
real orb, i;
orb = aspectorb[aspect];
i = body1 > BASE ? 2.0 : planetorb[body1];
orb = MIN(orb, i);
i = body2 > BASE ? 2.0 : planetorb[body2];
orb = MIN(orb, i);
if (body1 <= BASE)
orb += planetadd[body1];
if (body2 <= BASE)
orb += planetadd[body2];
return orb;
}
/*
******************************************************************************
** File IO Routines.
******************************************************************************
*/
/* Exit the program, and do any cleanup necessary. Note that if we had */
/* a non-fatal error, and we are in the -Q loop mode, then we won't */
/* actually terminate the program, but drop back to the command line loop. */
void Terminate(value)
int value;
{
if (value == _FORCE) {
AnsiColor(WHITE);
fprintf(stdout, "\n%s terminated.\n", appname);
}
if (value == _ERROR && (operation & DASHQ) > 0)
return;
if (ansi)
fprintf(S, "%c[0m", ESCAPE); /* Get out of any Ansi color mode. */
exit(abs(value));
}
/* Print a warning message given a string. This is called in non-fatal */
/* cases where we return to normal execution after printing the string. */
void PrintWarning(string)
char *string;
{
AnsiColor(RED);
fprintf(stderr, "%s\n", string);
AnsiColor(DEFAULT);
}
/* Print an error message. This is called in more serious cases which halt */
/* running of the current chart sequence, which can terminate the program */
/* but isn't a fatal error in that we can still fall back to the -Q loop. */
void PrintError(string)
char *string;
{
AnsiColor(RED);
fprintf(stderr, "%s: %s\n", appname, string);
Terminate(_ERROR);
AnsiColor(DEFAULT);
}
/* Simplification for a commonly printed error message. */
void TooFew(option)
char *option;
{
char string[STRING];
sprintf(string, "Too few options to switch -%s", option);
PrintError(string);
}
/* Another simplification for a commonly printed error message. */
void BadVal(option, value)
char *option;
int value;
{
char string[STRING];
sprintf(string, "Value %d passed to switch -%s out of range.\n",
value, option);
PrintError(string);
}
/* A simple procedure used throughout Astrolog: Print a particular */
/* character on the screen 'n' times. */
void PrintTab(chr, count)
char chr;
int count;
{
int i;
for (i = 0; i < count; i++)
printc(chr);
}
/* Set an Ansi text color. */
void AnsiColor(col)
int col;
{
/* Special case: If we are passed the value REVERSE, and ansi is not */
/* only on but set to a value > 1, then we'll enter reverse video mode. */
if (!ansi || (col == REVERSE && ansi < 2))
return;
fprintf(S, "%c[", ESCAPE);
if (col == DEFAULT)
printc('0');
else if (col == REVERSE) {
printc('7');
} else
fprintf(S, "%c;%d", col > 7 ? '1' : '0', 30 + (col & 7));
printc('m');
}
/* Print a zodiac position on the screen. This basically just prints the */
/* string returned from CharZodiac() below, except we take care of color. */
void PrintZodiac(deg)
real deg;
{
AnsiColor(elemansi[(int) (deg / 30.0) & 3]);
fprintf(S, "%s", CharZodiac(deg));
AnsiColor(DEFAULT);
}
/* Given a zodiac position, return a string containing it as it's */
/* formatted for display to the user. */
char *CharZodiac(deg)
real deg;
{
static char zod[11];
int sign, d, m;
real s;
if (!(operation & DASHs0)) {
/* Normally, we format the position in degrees/sign/minutes format: */
deg = Mod(deg + (seconds < 0 ? 1.0/60.0/60.0/2.0 : 1.0/60.0/2.0));
sign = (int) (deg / 30.0);
d = (int) deg - sign*30;
m = (int) (FRACT(deg)*60.0);
sprintf(zod, "%2d%c%c%c%02d", d, SIGNAM(sign + 1), m);
if (seconds < 0) {
s = FRACT(deg)*60.0; s = FRACT(s)*60.0;
sprintf(zod, "%s'%02d\"", zod, (int)s);
}
} else {
/* However, if -s0 switch in effect, get position in hours/minutes: */
deg = Mod(deg + (seconds < 0 ? 1.0/4.0/60.0/2.0 : 1.0/4.0/2.0));
d = (int) (deg / 15.0);
m = (int) ((deg - (real)d*15.0)*60.0/24.0);
sprintf(zod, "%2dh,%02dm", d, m);
if (seconds < 0) {
s = FRACT(deg)*4.0; s = FRACT(s)*60.0;
sprintf(zod, "%s,%02ds", zod, (int)s);
}
}
return zod;
}
/* This is similar to formatting a zodiac degree, but here we return a */
/* string of a (signed) declination value in degrees and minutes. */
char *CharAltitude(deg)
real deg;
{
static char alt[8];
int d, m, s;
while (deg > DEGQUAD) /* Ensure declination is from -90..+90 degrees. */
deg -= DEGHALF;
while (deg < -DEGQUAD)
deg += DEGHALF;
s = deg < 0.0;
deg = dabs(deg) + 1.0/60.0/2.0;
d = (int) deg;
m = (int) (FRACT(deg)*60.0);
sprintf(alt, "%c%2d%c%02d'", s ? '-' : '+', d, DEGR1, m);
return alt;
}
/* Another string formatter, here we return a date string given a month, */
/* day, and year. We format with the day or month first based on whether */
/* the "European" date variable is set or not. The routine also takes a */
/* parameter to indicate how much the string should be abbreviated, if any. */
char *CharDate(mon, day, yea, full)
int mon, day, yea, full;
{
static char dat[20];
if (full > FALSE) {
if (eurodate) {
if (full > TRUE)
sprintf(dat, "%2d %c%c%c%5d", day, MONNAM(mon), yea);
else
sprintf(dat, "%d %s %d", day, monthname[mon], yea);
} else {
if (full > TRUE)
sprintf(dat, "%c%c%c %2d%5d", MONNAM(mon), day, yea);
else
sprintf(dat, "%s %d, %d", monthname[mon], day, yea);
}
} else {
if (eurodate) {
if (full)
sprintf(dat, "%2d-%2d-%2d", day, mon, yea%100);
else
sprintf(dat, "%2d-%2d-%4d", day, mon, yea);
} else {
if (full)
sprintf(dat, "%2d/%2d/%2d", mon, day, yea%100);
else
sprintf(dat, "%2d/%2d/%4d", mon, day, yea);
}
}
return dat;
}
/* Return a string containing the given time expressed as an hour and */
/* minute quantity. This is formatted in 24 hour or am/pm time based */
/* on whether the "European" time format flag is set or not. */
char *CharTime(hr, min)
int hr, min;
{
static char tim[8];
if (eurotime)
sprintf(tim, "%2d:%02d", hr, min);
else
sprintf(tim, "%2d:%02d%cm", Mod12(hr), min, hr < 12 ? 'a' : 'p');
return tim;
}
/* Return a string containing the given time zone, given as a real value */
/* having the hours before GMT in the integer part and minutes fractionally. */
char *CharZone(zon)
real zon;
{
static char tim[7];
sprintf(tim, "%c%d:%02d", Zon > 0.0 ? '-' : '+', (int)dabs(Zon),
(int)(FRACT(dabs(Zon))*100.0+ROUND/60.0));
return tim;
}
/* Nicely format the given longitude and latitude locations and return */
/* them in a string. Various parts of the program display a chart header, */
/* and this allows the similar computations to be coded only once. */
char *CharLocation(lon, lat, norm)
real lon, lat, norm;
{
static char loc[14];
int i, j;
i = (int) (FRACT(dabs(lon))*norm+ROUND);
j = (int) (FRACT(dabs(lat))*norm+ROUND);
sprintf(loc, "%3.0f%c%02d%c%3.0f%c%02d%c",
floor(dabs(lon)), DEGR1, i, lon < 0.0 ? 'E' : 'W',
floor(dabs(lat)), DEGR1, j, lat < 0.0 ? 'S' : 'N');
return loc;
}
#ifdef TIME
/* Compute the date and time it is right now as the program is running */
/* using the computer's internal clock. We do this by getting the number */
/* of seconds which have passed since January 1, 1970 and going from there. */
/* The time return value filled is expressed in the given zone parameter. */
void GetTimeNow(Mon, Day, Yea, Tim, Zon)
int *Mon, *Day, *Yea;
real *Tim, Zon;
{
dword curtimer;
int min, sec;
real hr;
time(&curtimer);
sec = (int) (curtimer % 60);
curtimer /= 60;
min = (int) (curtimer % 60);
curtimer /= 60;
hr = (real) (curtimer % 24) - Zon;
curtimer /= 24;
while (hr < 0.0) {
curtimer--;
hr += 24.0;
}
while (hr >= 24.0) {
curtimer++;
hr -= 24.0;
}
#ifdef PC
curtimer += 2415020L; /* Number of days between 1/1/1970 and 1/1/4713 BC. */
#else
curtimer += 2440588L; /* Number of days in 70 years different than above. */
#endif
JulianToMdy((real)curtimer, Mon, Day, Yea);
*Tim = hr + (real) min / 100.0 + (real) sec / 6000.0;
}
#endif
/* Stop and wait for the user to enter a line of text given a prompt to */
/* display and a string buffer to fill with it. */
void InputString(prompt, string)
char *prompt, *string;
{
FILE *data;
data = S; S = stdout;
fprintf(S, "%s", prompt);
AnsiColor(YELLOW);
fprintf(S, " > ");
AnsiColor(DEFAULT);
if (gets(string) == NULL) /* Pressing control-D will terminate the */
Terminate(_FORCE); /* program (at least on some machines.) */
S = data;
}
/* Prompt the user for a floating point value, and make sure it conforms */
/* to the specified bounds before returning it. If a non-numeric value is */
/* entered, then assume it's the name of a month, and try to convert it */
/* to the appropriate number from 1 to 12; and also check for an "AM" or */
/* "PM" suffix to hour values, and adjust the number appropriately. */
real Input(prompt, low, high)
char *prompt;
real low, high;
{
char line[STRING], c;
real x;
int i, j;
loop {
InputString(prompt, line);
i = StringLen(line);
for (j = 0; j < i; j++)
if (line[j] == ':') /* Convert all colons in the */
line[j] = '.'; /* entered line to periods. */
c = CAP(line[0]);
/* If they entered a string, then check to see if it's a month name. */
if (c >= 'A' && c <= 'Z') {
switch (c) {
case 'J': x = CAP(line[1]) == 'U' ? /* January, */
(CAP(line[2]) == 'L' ? 7.0 : 6.0) : 1.0; break; /* June,July */
case 'F': x = 2.0; break; /* February */
case 'M': x = CAP(line[2]) == 'Y' ? 5.0 : 3.0; break; /* March,May */
case 'A': x = CAP(line[1]) == 'U' ? 8.0 : 4.0; break; /* April,August */
case 'S': x = 9.0; break; /* September */
case 'O': x = 10.0; break; /* October */
case 'N': x = 11.0; break; /* November */
case 'D': x = 12.0; break; /* December */
default: x = 0.0;
}
} else {
sscanf(line, "%lf", &x); /* Convert entered line to number. */
i = StringLen(line)-1;
if (i > 0 && CAP(line[i]) == 'M')
i--;
if (i > 0) {
c = CAP(line[i]);
if (c == 'A') /* Adjust value appropriately */
x = x >= 12.0 ? x-12.0 : x; /* if 'AM' or 'PM' suffix. */
else if (c == 'P')
x = x >= 12.0 ? x : x+12.0;
}
}
if (x >= low && x <= high)
return x;
sprintf(line, "Value out of range of from %.0f to %.0f.", low, high);
PrintWarning(line);
}
}
/* Given a string representing the complete pathname to a file, strip off */
/* all the path information leaving just the filename itself. This is called */
/* by the main program to determine the name of the Astrolog executable. */
char *ProcessProgname(name)
char *name;
{
char *b, *c, *e;
b = c = name;
while (*c) {
#ifdef PC
*c = UNCAP(*c); /* Because DOS filenames are case insensitive. */
#endif
c++;
}
e = c;
while (c > b && *c != '.')
c--;
if (c > b)
*c = 0;
else
c = e;
while (c > b && *c != DIR_SEP)
c--;
if (c > b)
name = c+1;
return name;
}
/* This important procedure gets all the parameters defining the chart that */
/* will be worked with later. Given a "filename", it gets from it all the */
/* pertinent chart information. This is more than just reading from a file - */
/* the procedure also takes care of the cases of prompting the user for the */
/* information and using the time functions to determine the date now - the */
/* program considers these cases "virtual" files. Furthermore, when reading */
/* from a real file, we have to check if it was written in the -o0 format. */
bool InputData(filename)
char *filename;
{
FILE *data;
char name[STRING], c;
int i;
real k, l, m;
/* If we are to read from the virtual file "set" then that means use a */
/* particular set of chart information generated earlier in the program. */
if (StringCmp(filename, "set") == 0) {
autom = 1;
SetCore(MonX, DayX, YeaX, TimX, ZonX, LonX, LatX);
return TRUE;
}
#ifdef TIME
/* If we are to read from the file "now" then that means use the time */
/* functions to calculate the present date and time. */
if (StringCmp(filename, "now") == 0) {
autom = 1;
ZZ = defzone; OO = deflong; AA = deflat;
GetTimeNow(&MM, &DD, &YY, &TT, ZZ);
return TRUE;
}
#endif
/* If we are to read from the file "tty" then that means prompt the user */
/* for all the chart information. */
if (StringCmp(filename, "tty") == 0) {
if (!noswitches) {
/* Temporarily disable and internal redirection of output to a file */
/* because we always want user headers and prompts to be displayed. */
data = S; S = stdout;
AnsiColor(WHITE);
fprintf(S, "** %s version %s ", appname, VERSION);
fprintf(S, "(See '%cHc' switch for copyrights and credits.) **\n", DASH);
AnsiColor(DEFAULT);
fprintf(S, " Invoke as '%s %cH' for list of command line options.\n",
ProcessProgname(progname), DASH);
S = data;
}
MM = (int)Input("Enter month of birth (e.g. '3', 'Mar')", 1.0, 12.0);
DD = (int)Input("Enter day of birth (e.g. '1', '31') ", 1.0,
(real) DayInMonth(MM, 0));
YY = (int)Input("Enter year of birth (e.g. '1994') ", -5000.0, 5000.0);
if (YY >= 0 && YY <= 99) {
sprintf(name,
"Assuming first century A.D. is really meant instead of %d.",
1900 + YY);
PrintWarning(name);
}
fprintf(stdout, "Subtract one hour if Daylight Saving time in effect.\n");
TT = Input("Enter time of birth (e.g. '18:30' '6:30pm')", -2.0, 24.0);
fprintf(stdout,
"Negative values indicate time zones east of Greenwich.\n");
ZZ = Input("Time zone in hours before GMT (5=Eastern, 8=Pacific)",
-24.0, 24.0);
fprintf(stdout,
"Negative values indicate eastern and southern locations.\n");
OO = Input("Longitude west of place (i.e. DEG:MIN)", -DEGHALF, DEGHALF);
AA = Input("Latitude north of place (i.e. DEG:MIN)", -DEGQUAD, DEGQUAD);
printl();
return TRUE;
}
/* Now that the special cases are taken care of, we can assume we are */
/* to read from a real file. */
autom = 1;
data = OpenFile(filename, 1);
/* Read the chart parameters from a normal file. */
if ((c = getc(data)) != 'S') {
ungetc(c, data);
fscanf(data, "%d%d%d", &MM, &DD, &YY);
fscanf(data, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
/* Read the actual chart positions from a file produced with the -o0. */
} else {
/* Hack: A negative month value means the chart parameters are invalid, */
/* hence -o0 is in effect and we can assume the chart positions are */
/* already in memory so we don't have to calculate them later. */
MM = -1;
for (i = 1; i <= BASE; i++) {
fscanf(data, "%s%lf%lf%lf", name, &k, &l, &m);
planet[i] = (l-1.0)*30.0+k+m/60.0;
fscanf(data, "%s%lf%lf", name, &k, &l);
planetalt[i] = k+l/60.0;
ret[i] = DTOR(name[1] == 'D' ? 1.0 : -1.0);
/* -o0 files from version 3.05 and before don't have the uranians in */
/* them. Be prepared to skip over them in old files for compatibility. */
if (i == OBJECTS) {
while (getc(data) >= ' ')
;
if ((c = getc(data)) != 'H')
i = C_HI;
else
i = total;
}
}
for (i = 1; i <= SIGNS/2; i++) {
fscanf(data, "%s%lf%lf%lf", name, &k, &l, &m);
house[i+6] = Mod((house[i] = Mod((l-1.0)*30.0+k+m/60.0))+DEGHALF);
}
}
fclose(data);
return TRUE;
}
/* Open the file indicated by the given string and return the file's stream */
/* pointer, or NULL if the file couldn't be found or opened. All parts of */
/* the program which open files to read call this routine. We look in */
/* several various locations and directories for the file before giving up. */
FILE *OpenFile(filename, filemode)
char *filename;
int filemode;
{
FILE *data;
char name[STRING], mode[3];
#ifdef ENVIRON
char *env;
#endif
/* Some file types we want to open as binary instead of Ascii. */
sprintf(mode, "r%s", filemode == 2 ? "b" : "");
/* First look for the file in the current directory. */
data = fopen(filename, mode);
if (data != NULL)
return data;
#ifdef ENVIRON
/* Next look for the file in the directory indicated by the version */
/* specific system environment variable. */
sprintf(name, "%s%s", ENVIRONVER, VERSION);
env = getenv(name);
if (env && *env) {
sprintf(name, "%s%c%s", env, DIR_SEP, filename);
data = fopen(name, mode);
if (data != NULL)
return data;
}
/* Next look in the directory in the general environment variable. */
env = getenv(ENVIRONALL);
if (env && *env) {
sprintf(name, "%s%c%s", env, DIR_SEP, filename);
data = fopen(name, mode);
if (data != NULL)
return data;
}
/* Next look in the directory in the version prefix environment variable. */
env = getenv(ENVIRONVER);
if (env && *env) {
sprintf(name, "%s%c%s", env, DIR_SEP, filename);
data = fopen(name, mode);
if (data != NULL)
return data;
}
#endif
/* Finally look in one of several directories specified at compile time. */
sprintf(name, "%s%c%s", filemode == 0 ? DEFAULT_DIR :
(filemode == 1 ? CHART_DIR : EPHE_DIR), DIR_SEP, filename);
data = fopen(name, mode);
if (data == NULL && filemode == 1) {
/* If the file was never found, print an error (unless we were looking */
/* for a certain file type, e.g. the optional astrolog.dat file). */
sprintf(name, "File '%s' not found.", filename);
PrintError(name);
}
return data;
}
/* general.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.