V10/cmd/weather/xwe.c
# include "stdio.h"
# include "cbt.h"
# include "ctype.h"
# include "assert.h"
# include "weath.h"
# include "signal.h"
# include "setjmp.h"
# include "math.h"
# include "sys/types.h"
# include "time.h"
# include "sys/timeb.h"
# define SAME 0
double md=1000., dist();
struct timeb ftb;
bfile *bf;
char *index(), *timezone(), *relhum();
struct tm *localtime();
bfile *townfile;
int marine=0, intr();
jmp_buf env;
char *direct[] =
{"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N", "xx", "yy"};
main(argc,argv)
char *argv[];
{
char request[100];
townfile = bopen("/usr/mel/ustowns/ustownsn", 0);
if (townfile==NULL)
{
fprintf(stderr, "No town list - is /crp mounted?\n");
exit(1);
}
bf = bopen("/data/weather/airn", 0);
assert(bf!=NULL);
ftime(&ftb);
argc--; argv++;
while (argc>0 && argv[0][0]=='-')
{
switch(argv[0][1])
{
case 'm': marine=1; break;
case 'h': strcpy(request, "murray hill, nj"); break;
default:
fprintf(stderr, "Unknown arg: %s\n", argv[0]);
break;
}
argc--; argv++;
}
if (argc>1)
{
fprintf(stderr, "Sorry: weather changed to expect town on standard input.\n");
fprintf(stderr, "Default MH is now 'weather -h'\n");
return(0);
}
if (request[0])
wprint(request);
else
while (1) /* this loop is basically while (gets(request)) with interrupt */
{
setjmp(env);
signal(SIGINT, SIG_DFL);
if (gets(request)==NULL)
break;
signal(SIGINT, intr);
wprint(request);
}
return(0);
}
wprint(request)
char *request;
{
char sna[100], rka[100], rra[300];
double lat, lng;
mbuf key, rkey, rrec;
int townfind;
rkey.mdata = rka; rrec.mdata = rra;
lcase(request);
while (isspace(*request)) request++;
if (*request==0) return;
townfind=0;
key.mdata = request; key.mlen = strlen(request);
bseek(townfile, key);
while (bread(townfile, &rkey, &rrec)==NULL)
{
rkey.mdata[rkey.mlen]=0;
rrec.mdata[rrec.mlen]=0;
if (strncmp(rkey.mdata, request, key.mlen)!=SAME)
break;
townfind++;
md=1000;
sscanf(rra, "%lf%lf", &lat, &lng);
caps(rka);
printf("%s: (%.3f N, %.3f W)\n", rka, lat, lng);
strcpy(sna, rka);
/* floating remainder not defined, so... */
weather(lat, lng);
lfmfore(lat, lng);
forecast(lat, lng);
}
if (townfind==0)
fprintf(stderr, "No such town\n");
return;
}
concat (out, ac, av)
char *out, *av[];
{
int i;
out[0]=0;
for(i=1; i<ac; i++)
{
strcat(out, av[i]);
if (i+1<ac)
strcat(out, " ");
}
return;
}
double
dist (aplat, aplon, bplat, bplon)
double aplon, aplat, bplon, bplat;
{
/* this code is from the picadad manual. I don't pretend
to understand it. */
double as, bs, ac, bc, p, cd, d, er;
double rad=0.0174532925;
er = aplon-bplon;
if (er<0) er= -er;
if (er<0.001)
{
d = aplat-bplat;
if (d<0) d= -d;
return(d*69.055);
}
as = sin(rad*aplat);
bs = sin(rad*bplat);
ac = cos(rad*aplat);
bc = cos(rad*bplat);
p = cos(er*rad);
cd = (as*bs+ac*bc*p);
return( acos(cd)*3956.56);
}
bearing (lat, lng, alat, alng)
double lat, lng, alat, alng;
{ /* gives bearing of alat, alng from lat, lng as 0-7 */
# define PI 3.1415926
double dlat, dlng, b;
dlat = alat-lat;
dlng = (alng-lng)*cos(PI*(lat+alat)/360.);
b = atan2(-dlng, dlat); /* range -pi to +pi */
b = b*(180./PI);
if (b<0) b=360+b;
return( (int) (b+22.5)/45.0);
}
lcase (s)
char *s;
{
int c;
for( ; c= *s; s++)
if (isupper(c))
*s = tolower(c);
}
caps(s)
char *s;
{
int c;
if (islower(*s)) *s = toupper(*s);
for( s++; c= *s; s++)
{
if (islower(c) && (s[-1]==' ' || s[-1]=='-'))
if (strncmp(s, "of ", 3)!=SAME)
*s = toupper(c);
if (*s==',') break;
}
for(s++; c= *s; s++)
if (islower(c)) *s=toupper(c);
}
weather(north, west)
double north, west;
{
double d, dist(), md=5000., tnf, twf;
char tn[10], tw[10], *x, *y, fname[100], *vis(), odata[2000], *airname();
char *ampm, *tz, tb[10];
int hr, min;
struct wline *wp, *bwp;
int n, w, f, kbear, isair, windsp, wdir, gust;
n = north;
n = n-n%4;
w = west;
w = w-w%4;
bwp=NULL;
sprintf(fname, "/data/weather/obs/%.2d.%.2d", n, w);
f = open(fname, 0);
if (f<0) return;
printf("fname %s\n", fname);
n=read(f, odata, 2000);
assert(n<2000);
/* next line is for(wp=odata; wp<odata+n; wp++) after delinting */
for(wp=(struct wline *) odata; wp< (struct wline *)(odata+n); wp++)
{
strncpy(tn, wp->nlat, 5); tn[5]=0;
strncpy(tw, wp->nlng, 6); tw[6]=0;
d = dist(tnf=atof(tn), twf=atof(tw), north, west);
printf("airport %.3s dist %f\n", wp, d);
if (d<md)
{
md=d;
kbear = bearing(north, west, tnf, twf);
bwp=wp;
}
}
close(f);
if (bwp==NULL) return;
strncpy(tn, bwp->anam, 3); tn[3]=0;
x = airname(tn);
x = index(x, ' ');
while (isspace(*x))x++;
for(y=x+1; *y != ','; y++)
if (isupper(*y) && isalpha(y[-1]))
*y = tolower(*y);
y = index(x, '*');
if (y==NULL)
isair=1;
else
{
*y=0;
isair=0;
}
strncpy(tw, bwp->wweath, 6); tw[6]=0;
y = vis(tw, bwp->wcloud[0]);
if (y==NULL) return;
printf("%.1f miles %s at%s %s", md, direct[kbear],
isair ? " the airport in" : "", x);
strncpy(tb, bwp->wtime, 4); tb[4]=0;
hr = atoi(tb);
min = hr%100;
hr = hr/100;
hr = hr - ftb.timezone/60;
if (ftb.dstflag) hr++;
if (hr < 0) hr+=24;
ampm = (hr>11) ? "PM" : "AM";
if (hr>12) hr -= 12;
tz = timezone(ftb.timezone, ftb.dstflag);
printf(" (%d:%.2d %s %s):\n", hr, min, ampm, tz);
strncpy(tb, bwp->wtemp, 3); tb[3]=0;
strncpy(tn, bwp->wdewpt, 3); tn[3]=0;
printf(" temperature %.3s, humidity %s, weather%s",
bwp->wtemp, relhum(atoi(tb), atoi(tn)), y);
windsp = atoi(bwp->wwind+2);
if (windsp >10)
{
bwp->wwind[2]=0;
wdir = atoi(bwp->wwind);
if (bwp->wwind[4]=='G')
gust = atoi(bwp->wwind+5);
else
gust=0;
wdir = (wdir*10+22.5)/45.0;
printf(",\n winds at %d knots", windsp);
printf(" from the %s", direct[wdir]);
if (gust) printf(" gusting to %d", gust);
}
printf("\n");
}
char *
vis(s, cloud)
char *s;
{
int d;
static char temp[80];
char tb[30];
while (isspace(*s)) s++;
d= atoi(s);
while (isdigit(*s)) s++;
if (!isalpha(*s))
{
switch(cloud)
{
case 'C': s= "clear"; break;
case 'P': s= "partly cloudy"; break;
case 'O': s= "overcast"; break;
default: s= "ordinary"; break;
}
sprintf(temp, " %s, visibility %d miles", s, d);
return(temp);
}
temp[0]=0;
for( ; *s; s++)
switch(*s)
{
case 'A': strcat(temp, " hail"); break;
case 'D': strcat(temp, " dust"); break;
case 'F': strcat(temp, " fog"); break;
case 'H': strcat(temp, " haze"); break;
case 'I': if (s[1]=='P') strcat(temp, " sleet"); break;
case 'K': strcat(temp, " smoke"); break;
case 'L': strcat(temp, " drizzle"); break;
case 'R': strcat(temp, " rain"); break;
case 'W': strcat(temp, " showers"); break;
case 'S': strcat(temp, " snow"); break;
case 'T': strcat(temp, " thunderstorms"); break;
case 'Z': strcat(temp, " freezing"); break;
case ' ':
case '-': break;
default: return(NULL);
}
sprintf(tb, ", visibility %d miles", d);
strcat(temp, tb);
return(temp);
}
char *
airname(s)
char *s;
{
int i;
mbuf key, rkey, rec;
static char rb[100], rkb[100];
key.mdata = s;
key.mlen = strlen(s);
i=bseek(bf, key);
if (i!=1) return(NULL);
rkey.mdata =rkb; rec.mdata = rb;
bread(bf, &rkey, &rec);
rkey.mdata[rkey.mlen]=0;
assert(strcmp(rkey.mdata, key.mdata)==0);
rkey.mdata[rkey.mlen]=0;
rec.mdata[rec.mlen]=0;
return(rec.mdata);
}
lfmfore(north, west)
double north, west;
{
double d, dist(), md=5000., tnf, twf;
char aname[10], *x, *y, fname[60], xl[30], ln[60], lf1[60], ltime[20];
int n, w, in, jw, iw, jn;
int p1, p2, max, min, hr, dy; char *ampm, *revampm, *tz;
FILE *f;
n = north;
n = n-n%4;
w = west;
w = w-w%4;
in = jn = n;
if ( (int) north %4 >=2) jn+=4; else in-=4;
iw = jw = w;
if ( (int) west %4 >=2 ) jw+=4; else iw-=4;
aname[0]=0;
for(n=in; n<=jn; n+=4)
for(w=iw; w<=jw; w+=4)
{
sprintf(fname, "/data/weather/lfm/%.2d.%.2d", n, w);
f = fopen(fname, "r");
if (f==NULL) continue;
while (fgets(xl, 20, f))
{
tnf = atof(xl+4);
twf = atof(xl+9);
d = dist(tnf, twf, north, west);
if (d<md)
{
md=d;
strncpy(aname, xl, 3);
aname[3]=0;
}
}
fclose(f);
}
if (aname[0]==0) return;
sprintf(fname, "/data/weather/lfm/%s", aname);
f = fopen(fname, "r");
if (f==NULL) return;
puts("");
fgets(ln, 60, f);
trimnl(ln);
for(x=ln+1; *x!= ','; x++)
if (isupper(*x) && isalpha(x[-1]))
*x = tolower(*x);
y = index(ln, '*');
if (y!=NULL) *y=0;
printf("Next 48 hours at %s\n", ln);
while (fgets(lf1, 60, f))
{
sscanf(lf1, "%s %d %d %d %d", ltime, &max, &min, &p1, &p2);
hr = atoi(ltime+3);
dy = atoi(ltime);
hr = hr - ftb.timezone/60;
hr += 12; /* question is whether the periods end or start as shown
in forecast ; this converts to ending */
if (hr>=24)
{
/* this should not be executed ever,since orign hr is 0 or 12 and
then we subract 4; */
hr-=24; dy++;
}
if (ftb.dstflag) hr++;
if (hr<0) {
hr += 24;
dy = down(dy);
}
ampm = (hr>11) ? "PM" : "AM";
revampm = (hr>11) ? "AM" : "PM";
if (hr>12) hr -= 12;
tz = timezone(ftb.timezone, ftb.dstflag);
printf("To %d %s %s /%d: high %d low %d, prob. precip. to %d %s %d%% to %d %s %d%%\n",
hr, ampm, tz, dy, max, min, hr, revampm, p1, hr, ampm, p2);
}
fclose(f);
}
int monlen[12] =
/*Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
down(dy)
{ /* subtracts one from the day */
struct tm *tp;
int mn;
if (--dy>0) return(dy);
tp = localtime(&ftb.time);
mn = tp->tm_mon;
if (tp->tm_mday<10) mn--;
dy = monlen[mn];
if (dy==28 && tp->tm_year%4==0)
dy++;
return(dy);
}
forecast(north, west)
double north, west;
{
double d, dist(), md=5000., tnf, twf;
char aname[10], fname[100], xl[30];
int n, w, in, jw, iw, jn;
FILE *f;
n = north;
n = n-n%4;
w = west;
w = w-w%4;
in = jn = n;
if ( (int) north %4 >=2) jn+=4; else in-=4;
iw = jw = w;
if ( (int) west %4 >=2 ) jw+=4; else iw-=4;
aname[0]=0;
for(n=in; n<=jn; n+=4)
for(w=iw; w<=jw; w+=4)
{
sprintf(fname, "/data/weather/fore/f_%.2d.%.2d", n, w);
f = fopen(fname, "r");
if (f==NULL) continue;
while (fgets(xl, 20, f))
{
tnf = atof(xl+4);
twf = atof(xl+9);
d = dist(tnf, twf, north, west);
if (d<md)
{
md=d;
strncpy(aname, xl, 3);
aname[3]=0;
}
}
fclose(f);
}
if (aname[0]==0) return;
sprintf(fname, "/data/weather/fore/f_%s", aname);
f = fopen(fname, "r");
if (f!=NULL)
{
puts("");
while (fgets(fname, 100, f))
fputs(fname, stdout);
fclose(f);
}
if (marine)
{
sprintf(fname, "/data/weather/fore/m_%s", aname);
f = fopen(fname, "r");
if (f!=NULL)
{
if (f==NULL) return;
puts("");
while (fgets(fname, 100, f))
fputs(fname, stdout);
fclose(f);
}
}
puts("");
}
trimnl(s)
char *s;
{
while (*s)s++;
if (*--s=='\n')*s=0;
}
intr()
{
longjmp(env, 0);
}
struct table {
int temp;
int rh[15];
}tab[21] = {
{100,100,94,88,83,78,73,69,65,61,57,53,45,38,32,27},
{95,100,94,88,83,78,73,68,64,60,56,53,44,37,31,26},
{90,100,94,88,83,77,73,68,64,59,56,52,44,37,31,25},
{85,100,94,88,82,77,72,67,63,58,55,51,43,36,30,25},
{80,100,94,88,82,77,72,67,62,58,54,51,42,35,29,24},
{75,100,94,87,82,76,71,66,62,58,54,50,42,34,28,23},
{70,100,93,87,81,76,71,66,61,57,53,49,41,34,28,23},
{65,100,93,87,81,75,70,65,61,57,52,49,40,33,27,22},
{60,100,93,87,81,75,70,65,60,56,52,48,39,32,26,21},
{55,100,93,86,80,75,69,64,59,55,51,47,39,31,25,20},
{50,100,93,86,80,74,69,64,59,54,50,46,38,31,25,20},
{45,100,93,86,80,74,68,63,58,54,49,46,37,30,24,19},
{40,100,93,86,79,73,68,62,57,53,49,45,36,29,23,18},
{35,100,92,85,79,73,67,61,57,52,48,44,35,28,22,18},
{30,100,92,85,78,72,66,61,56,51,47,43,34,27,21,17},
{25,100,92,85,78,72,66,60,55,51,46,42,33,26,21,16},
{20,100,92,84,77,71,65,60,54,50,45,41,33,25,20,15},
{15,100,92,84,77,70,64,59,54,49,44,40,32,25,19,14},
{10,100,92,84,76,70,64,58,53,48,43,39,31,24,18,14},
{5,100,92,83,76,69,63,57,52,47,42,38,30,23,17,13},
{0,100,91,83,75,68,63,56,51,46,41,37,29,22,16,12}
};
int ddline[15] = {0,2,4,6,8,10,12,14,16,18,20,25,30,35,40};
char *
relhum(temp, dewpt)
{
int del1,del2,dd, i, j;
static char val[20];
dd = temp - dewpt;
if (dd < 0)
return("??");
if (dd > 40)
return("dry");
temp = ((temp+2)/5)*5;
for (i=0;i<15;i++) {
if (dd <= ddline[i]) {
del1 = ddline[i]-dd;
del2 = ddline[i]-ddline[i-1];
break;
}
}
for(j=0;j<22;j++) {
if (j==21)
return("??");
else if (tab[j].temp == temp) {
sprintf(val, "%d",
tab[j].rh[i]+((del1*(tab[j].rh[i-1]-tab[j].rh[i]))/del2));
return(val);
}
}
}