|
|
1.1 root 1: # include "stdio.h"
2: # include "cbt.h"
3: # include "ctype.h"
4: # include "assert.h"
5: # include "weath.h"
6: # include "signal.h"
7: # include "setjmp.h"
8: # include "math.h"
9: # include "sys/types.h"
10: # include "time.h"
11: # include "sys/timeb.h"
12: # define SAME 0
13:
14: double md=1000., dist();
15: struct timeb ftb;
16: struct tm *tp;
17: bfile *bf;
18: char *index(), *timezone(), *relhum(), *getlogin(), *ctime();
19: struct tm *localtime();
20: bfile *townfile;
21: char *logname = "/usr/spool/weather/wlog";
22: int marine=0, intr();
23: jmp_buf env;
24: char *direct[] =
25: {"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N", "xx", "yy"};
26:
27: main(argc,argv)
28: char *argv[];
29: {
30: char request[100];
31: townfile = bopen("/usr/spool/town/ustowns", 0);
32: if (townfile==NULL)
33: {
34: fprintf(stderr, "No town list - is /crp mounted?\n");
35: exit(1);
36: }
37: bf = bopen("/usr/spool/weather/air", 0);
38: assert(bf!=NULL);
39: ftime(&ftb);
40: tp = localtime(&ftb.time);
41: argc--; argv++;
42: while (argc>0 && argv[0][0]=='-')
43: {
44: switch(argv[0][1])
45: {
46: case 'm': marine=1; break;
47: case 'h': strcpy(request, "murray hill, nj"); break;
48: case 'n': strcpy(request, "newark, nj"); break;
49: default:
50: fprintf(stderr, "Unknown arg: %s\n", argv[0]);
51: break;
52: }
53: argc--; argv++;
54: }
55: if (argc>1)
56: {
57: fprintf(stderr, "Sorry: weather changed to expect town on standard input.\n");
58: fprintf(stderr, "Default MH is now 'weather -h'\n");
59: return(0);
60: }
61: if (request[0])
62: {
63: wprint(request);
64: record(request);
65: }
66: else
67: while (1) /* this loop is basically while (gets(request)) with interrupt */
68: {
69: setjmp(env);
70: signal(SIGINT, SIG_DFL);
71: if (gets(request)==NULL)
72: break;
73: signal(SIGINT, intr);
74: if (strcmp(request, "q")==SAME)
75: break;
76: wprint(request);
77: record(request);
78: }
79: return(0);
80: }
81: wprint(request)
82: char *request;
83: {
84: char sna[100], rka[100], rra[300], *normalize();
85: double lat, lng;
86: mbuf key, rkey, rrec;
87: int townfind;
88: rkey.mdata = rka; rrec.mdata = rra;
89: request=normalize(request);
90: if (*request==0) return;
91: townfind=0;
92: key.mdata = request; key.mlen = strlen(request);
93: bseek(townfile, key);
94: while (bread(townfile, &rkey, &rrec)==NULL)
95: {
96: rkey.mdata[rkey.mlen]=0;
97: rrec.mdata[rrec.mlen]=0;
98: if (strncmp(rkey.mdata, request, key.mlen)!=SAME)
99: break;
100: townfind++;
101: md=1000;
102: sscanf(rra, "%lf%lf", &lat, &lng);
103: caps(rka);
104: printf("%s: (%.3f N, %.3f W)\n", rka, lat, lng);
105: strcpy(sna, rka);
106: /* floating remainder not defined, so... */
107: weather(lat, lng);
108: lfmfore(lat, lng);
109: forecast(lat, lng);
110: }
111: if (townfind==0)
112: fprintf(stderr, "No such town\n");
113: return;
114: }
115: concat (out, ac, av)
116: char *out, *av[];
117: {
118: int i;
119: out[0]=0;
120: for(i=1; i<ac; i++)
121: {
122: strcat(out, av[i]);
123: if (i+1<ac)
124: strcat(out, " ");
125: }
126: return;
127: }
128: double
129: dist (aplat, aplon, bplat, bplon)
130: double aplon, aplat, bplon, bplat;
131: {
132: /* this code is from the picadad manual. I don't pretend
133: to understand it. */
134: double as, bs, ac, bc, p, cd, d, er;
135: double rad=0.0174532925;
136: er = aplon-bplon;
137: if (er<0) er= -er;
138: if (er<0.001)
139: {
140: d = aplat-bplat;
141: if (d<0) d= -d;
142: return(d*69.055);
143: }
144: as = sin(rad*aplat);
145: bs = sin(rad*bplat);
146: ac = cos(rad*aplat);
147: bc = cos(rad*bplat);
148: p = cos(er*rad);
149: cd = (as*bs+ac*bc*p);
150: return( acos(cd)*3956.56);
151: }
152: bearing (lat, lng, alat, alng)
153: double lat, lng, alat, alng;
154: { /* gives bearing of alat, alng from lat, lng as 0-7 */
155: # define PI 3.1415926
156: double dlat, dlng, b;
157: dlat = alat-lat;
158: dlng = (alng-lng)*cos(PI*(lat+alat)/360.);
159: b = atan2(-dlng, dlat); /* range -pi to +pi */
160: b = b*(180./PI);
161: if (b<0) b=360+b;
162: return( (int) (b+22.5)/45.0);
163: }
164: lcase (s)
165: char *s;
166: {
167: int c;
168: for( ; c= *s; s++)
169: if (isupper(c))
170: *s = tolower(c);
171: }
172: caps(s)
173: char *s;
174: {
175: int c;
176: if (islower(*s)) *s = toupper(*s);
177: for( s++; c= *s; s++)
178: {
179: if (islower(c) && (s[-1]==' ' || s[-1]=='-'))
180: if (strncmp(s, "of ", 3)!=SAME)
181: *s = toupper(c);
182: if (*s==',') break;
183: }
184: for(s++; c= *s; s++)
185: if (islower(c)) *s=toupper(c);
186: }
187: weather(north, west)
188: double north, west;
189: {
190: double d, dist(), md=5000., tnf, twf;
191: char tn[10], tw[10], *x, *y, fname[100], *vis(), odata[2000], *airname();
192: char *ampm, *tz, tb[10];
193: int hr, min;
194: struct wline *wp, *bwp;
195: int n, w, f, kbear, isair, windsp, wdir, gust;
196: n = north;
197: n = n-n%4;
198: w = west;
199: w = w-w%4;
200: bwp=NULL;
201: sprintf(fname, "/usr/spool/weather/obs/%.2d.%.2d", n, w);
202: f = open(fname, 0);
203: if (f<0) return;
204: n=read(f, odata, 2000);
205: assert(n<2000);
206: /* next line is for(wp=odata; wp<odata+n; wp++) after delinting */
207: for(wp=(struct wline *) odata; wp< (struct wline *)(odata+n); wp++)
208: {
209: if (wp->anam[0]=='-') continue;
210: strncpy(tn, wp->nlat, 5); tn[5]=0;
211: strncpy(tw, wp->nlng, 6); tw[6]=0;
212: d = dist(tnf=atof(tn), twf=atof(tw), north, west);
213: if (d<md)
214: {
215: md=d;
216: kbear = bearing(north, west, tnf, twf);
217: bwp=wp;
218: }
219: }
220: close(f);
221: if (bwp==NULL) return;
222: strncpy(tn, bwp->anam, 3); tn[3]=0;
223: x = airname(tn);
224: x = index(x, ' ');
225: while (isspace(*x))x++;
226: for(y=x+1; *y != ','; y++)
227: if (isupper(*y) && isalpha(y[-1]))
228: *y = tolower(*y);
229: y = index(x, '*');
230: if (y==NULL)
231: isair=1;
232: else
233: {
234: *y=0;
235: isair=0;
236: }
237: strncpy(tw, bwp->wweath, 6); tw[6]=0;
238: y = vis(tw, bwp->wcloud[0]);
239: if (y==NULL) return;
240: printf("%.1f miles %s at%s %s", md, direct[kbear],
241: isair ? " the airport in" : "", x);
242: strncpy(tb, bwp->wtime, 4); tb[4]=0;
243: hr = atoi(tb);
244: min = hr%100;
245: hr = hr/100;
246: hr = hr - ftb.timezone/60;
247: if (tp->tm_isdst) hr++;
248: if (hr < 0) hr+=24;
249: ampm = (hr>11) ? "PM" : "AM";
250: if (hr>12) hr -= 12;
251: tz = timezone(ftb.timezone, tp->tm_isdst);
252: printf(" (%d:%.2d %s %s):\n", hr, min, ampm, tz);
253: strncpy(tb, bwp->wtemp, 3); tb[3]=0;
254: strncpy(tn, bwp->wdewpt, 3); tn[3]=0;
255: printf(" temperature %.3s, humidity %s, weather%s",
256: bwp->wtemp, relhum(atoi(tb), atoi(tn)), y);
257: windsp = atoi(bwp->wwind+2);
258: if (windsp >10)
259: {
260: bwp->wwind[2]=0;
261: wdir = atoi(bwp->wwind);
262: if (bwp->wwind[4]=='G')
263: gust = atoi(bwp->wwind+5);
264: else
265: gust=0;
266: wdir = (wdir*10+22.5)/45.0;
267: printf(",\n winds at %d knots", windsp);
268: printf(" from the %s", direct[wdir]);
269: if (gust) printf(" gusting to %d", gust);
270: }
271: printf("\n");
272: }
273: char *
274: vis(s, cloud)
275: char *s;
276: {
277: int d;
278: static char temp[80];
279: char tb[30];
280: while (isspace(*s)) s++;
281: d= atoi(s);
282: while (isdigit(*s)) s++;
283: if (!isalpha(*s))
284: {
285: switch(cloud)
286: {
287: case 'C': s= "clear"; break;
288: case 'P': s= "partly cloudy"; break;
289: case 'O': s= "overcast"; break;
290: default: s= "ordinary"; break;
291: }
292: sprintf(temp, " %s, visibility %d miles", s, d);
293: return(temp);
294: }
295: temp[0]=0;
296: for( ; *s; s++)
297: switch(*s)
298: {
299: case 'A': strcat(temp, " hail"); break;
300: case 'D': strcat(temp, " dust"); break;
301: case 'F': strcat(temp, " fog"); break;
302: case 'H': strcat(temp, " haze"); break;
303: case 'I': if (s[1]=='P') strcat(temp, " sleet"); break;
304: case 'K': strcat(temp, " smoke"); break;
305: case 'L': strcat(temp, " drizzle"); break;
306: case 'R': strcat(temp, " rain"); break;
307: case 'W': strcat(temp, " showers"); break;
308: case 'S': strcat(temp, " snow"); break;
309: case 'T': strcat(temp, " thunderstorms"); break;
310: case 'Z': strcat(temp, " freezing"); break;
311: case ' ':
312: case '-': break;
313: default: return(NULL);
314: }
315: sprintf(tb, ", visibility %d miles", d);
316: strcat(temp, tb);
317: return(temp);
318: }
319: char *
320: airname(s)
321: char *s;
322: {
323: int i;
324: mbuf key, rkey, rec;
325: static char rb[100], rkb[100];
326: key.mdata = s;
327: key.mlen = strlen(s);
328: i=bseek(bf, key);
329: if (i!=1) return(NULL);
330: rkey.mdata =rkb; rec.mdata = rb;
331: bread(bf, &rkey, &rec);
332: rkey.mdata[rkey.mlen]=0;
333: assert(strcmp(rkey.mdata, key.mdata)==0);
334: rkey.mdata[rkey.mlen]=0;
335: rec.mdata[rec.mlen]=0;
336: return(rec.mdata);
337: }
338: lfmfore(north, west)
339: double north, west;
340: {
341: double d, dist(), md=5000., tnf, twf;
342: char aname[10], *x, *y, fname[60], xl[30], ln[60], lf1[60], ltime[20];
343: int n, w, in, jw, iw, jn;
344: int p1, p2, max, min, hr, dy; char *ampm, *revampm, *tz;
345: FILE *f;
346: n = north;
347: n = n-n%4;
348: w = west;
349: w = w-w%4;
350: in = jn = n;
351: if ( (int) north %4 >=2) jn+=4; else in-=4;
352: iw = jw = w;
353: if ( (int) west %4 >=2 ) jw+=4; else iw-=4;
354: aname[0]=0;
355: for(n=in; n<=jn; n+=4)
356: for(w=iw; w<=jw; w+=4)
357: {
358: sprintf(fname, "/usr/spool/weather/lfm/%.2d.%.2d", n, w);
359: f = fopen(fname, "r");
360: if (f==NULL) continue;
361: while (fgets(xl, 20, f))
362: {
363: tnf = atof(xl+4);
364: twf = atof(xl+9);
365: d = dist(tnf, twf, north, west);
366: if (d<md)
367: {
368: md=d;
369: strncpy(aname, xl, 3);
370: aname[3]=0;
371: }
372: }
373: fclose(f);
374: }
375: if (aname[0]==0) return;
376: sprintf(fname, "/usr/spool/weather/lfm/%s", aname);
377: f = fopen(fname, "r");
378: if (f==NULL) return;
379: puts("");
380: fgets(ln, 60, f);
381: trimnl(ln);
382: for(x=ln+1; *x!= ','; x++)
383: if (isupper(*x) && isalpha(x[-1]))
384: *x = tolower(*x);
385: y = index(ln, '*');
386: if (y!=NULL) *y=0;
387: printf("Next 48 hours at %s\n", ln);
388: while (fgets(lf1, 60, f))
389: {
390: sscanf(lf1, "%s %d %d %d %d", ltime, &max, &min, &p1, &p2);
391: hr = atoi(ltime+3);
392: dy = atoi(ltime);
393: hr = hr - ftb.timezone/60;
394: hr += 12; /* question is whether the periods end or start as shown
395: in forecast ; this converts to ending */
396: if (hr>=24)
397: {
398: /* this should not be executed ever,since orign hr is 0 or 12 and
399: then we subract 4; */
400: hr-=24; dy++;
401: }
402: if (tp->tm_isdst) hr++;
403: if (hr<0) {
404: hr += 24;
405: dy = down(dy);
406: }
407: ampm = (hr>11) ? "PM" : "AM";
408: revampm = (hr>11) ? "AM" : "PM";
409: if (hr>12) hr -= 12;
410: tz = timezone(ftb.timezone, tp->tm_isdst);
411: printf("To %d %s %s /%d: high %d low %d, prob. precip. to %d %s %d%% to %d %s %d%%\n",
412: hr, ampm, tz, dy, max, min, hr, revampm, p1, hr, ampm, p2);
413: }
414: fclose(f);
415: }
416: int monlen[12] =
417: /*Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
418: { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
419: down(dy)
420: { /* subtracts one from the day */
421: int mn;
422: if (--dy>0) return(dy);
423: mn = tp->tm_mon;
424: if (tp->tm_mday<10) mn--;
425: dy = monlen[mn];
426: if (dy==28 && tp->tm_year%4==0)
427: dy++;
428: return(dy);
429: }
430: forecast(north, west)
431: double north, west;
432: {
433: double d, dist(), md=5000., tnf, twf;
434: char aname[10], fname[100], xl[30];
435: int n, w, in, jw, iw, jn;
436: FILE *f;
437: n = north;
438: n = n-n%4;
439: w = west;
440: w = w-w%4;
441: in = jn = n;
442: if ( (int) north %4 >=2) jn+=4; else in-=4;
443: iw = jw = w;
444: if ( (int) west %4 >=2 ) jw+=4; else iw-=4;
445: aname[0]=0;
446: for(n=in; n<=jn; n+=4)
447: for(w=iw; w<=jw; w+=4)
448: {
449: sprintf(fname, "/usr/spool/weather/fore/f_%.2d.%.2d", n, w);
450: f = fopen(fname, "r");
451: if (f==NULL) continue;
452: while (fgets(xl, 20, f))
453: {
454: tnf = atof(xl+4);
455: twf = atof(xl+9);
456: d = dist(tnf, twf, north, west);
457: if (d<md)
458: {
459: md=d;
460: strncpy(aname, xl, 3);
461: aname[3]=0;
462: }
463: }
464: fclose(f);
465: }
466: if (aname[0]==0) return;
467: sprintf(fname, "/usr/spool/weather/fore/f_%s", aname);
468: f = fopen(fname, "r");
469: if (f!=NULL)
470: {
471: puts("");
472: printfile(f);
473: fclose(f);
474: }
475: if (marine)
476: {
477: sprintf(fname, "/usr/spool/weather/fore/m_%s", aname);
478: f = fopen(fname, "r");
479: if (f!=NULL)
480: {
481: if (f==NULL) return;
482: puts("");
483: printfile(f);
484: fclose(f);
485: }
486: }
487: puts("");
488: }
489: trimnl(s)
490: char *s;
491: {
492: while (*s)s++;
493: if (*--s=='\n')*s=0;
494: }
495: intr()
496: {
497: longjmp(env, 0);
498: }
499: struct table {
500: int temp;
501: int rh[15];
502: }tab[21] = {
503: {100,100,94,88,83,78,73,69,65,61,57,53,45,38,32,27},
504: {95,100,94,88,83,78,73,68,64,60,56,53,44,37,31,26},
505: {90,100,94,88,83,77,73,68,64,59,56,52,44,37,31,25},
506: {85,100,94,88,82,77,72,67,63,58,55,51,43,36,30,25},
507: {80,100,94,88,82,77,72,67,62,58,54,51,42,35,29,24},
508: {75,100,94,87,82,76,71,66,62,58,54,50,42,34,28,23},
509: {70,100,93,87,81,76,71,66,61,57,53,49,41,34,28,23},
510: {65,100,93,87,81,75,70,65,61,57,52,49,40,33,27,22},
511: {60,100,93,87,81,75,70,65,60,56,52,48,39,32,26,21},
512: {55,100,93,86,80,75,69,64,59,55,51,47,39,31,25,20},
513: {50,100,93,86,80,74,69,64,59,54,50,46,38,31,25,20},
514: {45,100,93,86,80,74,68,63,58,54,49,46,37,30,24,19},
515: {40,100,93,86,79,73,68,62,57,53,49,45,36,29,23,18},
516: {35,100,92,85,79,73,67,61,57,52,48,44,35,28,22,18},
517: {30,100,92,85,78,72,66,61,56,51,47,43,34,27,21,17},
518: {25,100,92,85,78,72,66,60,55,51,46,42,33,26,21,16},
519: {20,100,92,84,77,71,65,60,54,50,45,41,33,25,20,15},
520: {15,100,92,84,77,70,64,59,54,49,44,40,32,25,19,14},
521: {10,100,92,84,76,70,64,58,53,48,43,39,31,24,18,14},
522: {5,100,92,83,76,69,63,57,52,47,42,38,30,23,17,13},
523: {0,100,91,83,75,68,63,56,51,46,41,37,29,22,16,12}
524: };
525: int ddline[15] = {0,2,4,6,8,10,12,14,16,18,20,25,30,35,40};
526: char *
527: relhum(temp, dewpt)
528: {
529: int del1,del2,dd, i, j;
530: static char val[20];
531: dd = temp - dewpt;
532: if (dd < 0)
533: return("??");
534: if (dd > 40)
535: return("dry");
536: temp = ((temp+2)/5)*5;
537: for (i=0;i<15;i++) {
538: if (dd <= ddline[i]) {
539: del1 = ddline[i]-dd;
540: del2 = ddline[i]-ddline[i-1];
541: break;
542: }
543: }
544: for(j=0;j<22;j++) {
545: if (j==21)
546: return("??");
547: else if (tab[j].temp == temp) {
548: sprintf(val, "%d",
549: tab[j].rh[i]+((del1*(tab[j].rh[i-1]-tab[j].rh[i]))/del2));
550: return(val);
551: }
552: }
553: }
554: static int nr=0;
555: record(s)
556: char *s;
557: {
558: FILE *logfile;
559: if (nr != 0) return;
560: nr=1;
561: logfile = fopen(logname, "a");
562: if (logfile !=NULL)
563: {
564: fprintf(logfile, "weather %s\t%s\t%s", s, getlogin(), ctime(&ftb.time));
565: fclose(logfile);
566: }
567: }
568: static char nname[100];
569: char *
570: normalize(s)
571: char *s;
572: {
573: /* takes a town name and makes it right format */
574: char *p;
575: while (*s==' ')s++;
576: lcase(s);
577: for (p=nname; *s; s++)
578: {
579: if (*s==',')
580: {
581: *p++=',';
582: *p++=' ';
583: while (s[1]==' ')s++;
584: continue;
585: }
586: *p++ = *s;
587: }
588: *p=0;
589: return(nname);
590: }
591: char *nxword();
592: printfile(f)
593: FILE *f;
594: {
595: int seendate=0, seendot=0, seenfore=0, k;
596: char line[200], wd[100], *p, *np;
597: while (fgets(line, 200,f))
598: {
599: trimnl(line);
600: if (seenfore) {seendate=1; seendot=1; seenfore=0;}
601: for(p=line; np=nxword(p,wd); p=np)
602: {
603: if (abbrev(wd))
604: ;
605: else
606: if (k=propname(p))
607: {
608: lowercase(p+1, k, 1);
609: np=p+k;
610: }
611: else
612: if (seendate==0 || seendot==1)
613: lowercase(p+1, np-p-1, 0);
614: else
615: lowercase(p, np-p, 0);
616: if (strcmp(wd, "1982")==SAME)
617: seendate=1;
618: if (strcmp(wd, "FORECAST")==SAME)
619: seenfore=1;
620: if (strcmp(wd, ".")==SAME)
621: seendot=1;
622: else
623: seendot=0;
624: }
625: puts(line);
626: }
627: }
628: lowercase(p, n, k)
629: char *p;
630: {
631: for (; n-- >0; p++)
632: if (isupper(*p) && (k==0 || p[-1]!=' '))
633: *p= tolower(*p);
634: }
635: char *
636: nxword(p, b)
637: char *p, *b;
638: {
639: *b=0;
640: if (p==NULL || *p==NULL) return(NULL);
641: if (!isalpha (*b++ = *p++))
642: {
643: *b=0;
644: while (isspace(*p))
645: p++;
646: return(p);
647: }
648: while (isalpha(*p))
649: *b++ = *p++;
650: *b=0;
651: while (isspace(*p))
652: p++;
653: return(p);
654: }
655: abbrev(s)
656: char *s;
657: {
658: char *p;
659: for(p=s; *p; p++)
660: if (!isalpha(*p))
661: return(1);
662: for(p=s; *p; p++)
663: switch(*p)
664: {
665: case 'A': case 'E': case 'I': case 'O': case 'U':
666: return(0);
667: case 'Y':
668: if (p[1]==0) return(0);
669: }
670: return(1);
671: }
672: char wspace[4000];
673: char *wsp=wspace;
674: char *words[500];
675: int nwd=0;
676: propname(s)
677: char *s;
678: {
679: char **wp;
680: int cn;
681: initlist();
682: for(wp=words; wp<words+nwd; wp++)
683: {
684: if (strncmp(*wp, s, cn=strlen(*wp))==SAME &&
685: !isalpha(s[cn]) )
686: return(cn);
687: }
688: return(0);
689: }
690: initlist()
691: {
692: static int once=0;
693: FILE *f;
694: if (once>0) return;
695: once++;
696: f = fopen("/usr/spool/weather/propnames", "r");
697: while (fgets(wsp, 200, f))
698: {
699: trimnl(wsp);
700: words[nwd++]=wsp;
701: wsp+=strlen(wsp)+1;
702: }
703: fclose(f);
704: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.