# 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); } } }