1 #include "config.h"
2
3 /* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <ctype.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #if TM_IN_SYS_TIME
32 # if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 # else
36 # if HAVE_SYS_TIME_H
37 # include <sys/time.h>
38 # else
39 # include <time.h>
40 # endif
41 # endif
42 #else
43 #include <time.h>
44 #endif
45
46 #include <X11/Xlib.h>
47 #include <X11/Xatom.h>
48 #include <X11/xpm.h>
49
50 #include "wmweather+.h"
51 #include "convert.h"
52 #include "download.h"
53 #include "dock.h"
54 #include "die.h"
55 #include "animation.h"
56
57
58 char *ProgName;
59 char *bigbuf;
60 int devnull;
61 char *monthnames[]={ "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
62 char *monthnames2[]={ "", "", "", "", "", "", "JUNE", "JULY", "", "SEPT", "", "", "" };
63 char *wdaynames[]={ "SUNDAY", "MONDAY", "TUESDAY", "WEDN'SDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
64 char *directions[]={"VRB", "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
65
66 char *error;
67 char *unknown_option="Unknown option";
68
69 #define F(a) fprintf(stderr, a "\n");
70
71 /***************************************************
72 * Configuration parameters
73 ***************************************************/
74 char *email_address=NULL;
75 char *metar_station=NULL;
76 char *metar_uri=NULL;
77 char *metar_post=NULL;
78 char **warning_zones=NULL;
79 char *warning_uri=NULL;
80 char *warning_post=NULL;
81 char *avn_station=NULL;
82 char *avn_uri=NULL;
83 char *avn_post=NULL;
84 char *eta_station=NULL;
85 char *eta_uri=NULL;
86 char *eta_post=NULL;
87 char *mrf_station=NULL;
88 char *mrf_uri=NULL;
89 char *mrf_post=NULL;
90 char *radar_uri=NULL;
91 char *radar_post=NULL;
92 char *radar_crop=NULL;
93 char *radar_cross=NULL;
94 char *viewer=NULL;
95 int pressure_mode=0;
96 int windspeed_mode=0;
97 int temp_mode=0;
98 int length_mode=0;
99 double latitude=999, longitude=999;
100 int start_do_animation=1;
101 int starting_mode=0;
102
103
104 /**********************************
105 * Prototypes
106 **********************************/
107 void usage(int i);
108 void printversion(void);
109 int readconf(char *file);
110 int parse_option(char *option, char *value);
111 char *get_filename(char *file);
112
113 /**********************************
114 * Functions
115 **********************************/
116
sigchld(int i)117 void sigchld(int i){
118 while(waitpid(-1, NULL, WNOHANG)>0);
119 }
120
parse_option(char * option,char * value)121 int parse_option(char *option, char *value){
122 int i;
123 void *v;
124
125 errno=0;
126 error=unknown_option;
127 if(option[0]=='-') option++;
128 if(option[0]=='-' && option[1]!='\0' && option[2]!='\0') option++;
129 if(option[0]=='\0') return 0;
130 if(value!=NULL && value[0]=='\0') value=NULL;
131
132 switch (option[0]){
133 case 'a':
134 if(!strncmp(option, "avn-", 4)){
135 if(!strcmp(option+4, "station")){
136 if(value==NULL){
137 error="avn-station given with no station ID";
138 return 0;
139 }
140 if(avn_station!=NULL) free(avn_station);
141 avn_station=strdup(value);
142 if(avn_station==NULL) die("avn-station strdup");
143 return 2;
144 } else if(!strcmp(option+4, "uri")){
145 if(value==NULL){
146 error="avn-uri given with no URI";
147 return 0;
148 }
149 if(avn_uri!=NULL) free(avn_uri);
150 avn_uri=strdup(value);
151 if(avn_uri==NULL) die("avn-uri strdup");
152 if(avn_post!=NULL) free(avn_post);
153 avn_post=NULL;
154 return 2;
155 } else if(!strcmp(option+4, "post")){
156 if(value==NULL){
157 error="avn-post given with no data";
158 return 0;
159 }
160 if(avn_uri==NULL){
161 error="avn-post must come after avn-uri";
162 return 0;
163 }
164 if(avn_post!=NULL) free(avn_post);
165 avn_post=strdup(value);
166 if(avn_post==NULL) die("avn-post strdup");
167 return 2;
168 }
169 break;
170 } else if(!strcmp(option, "atm")){
171 pressure_mode=3;
172 return 1;
173 } else if(!strcmp(option, "animate")){
174 start_do_animation=1;
175 return 1;
176 }
177 break;
178 case 'b':
179 if(!strcmp(option, "beaufort")){
180 windspeed_mode=4;
181 return 1;
182 }
183 break;
184 case 'c':
185 if(option[1]=='\0') return 2; /* -c handled earlier */
186 else if(!strcmp(option, "cm")){
187 length_mode=1;
188 return 1;
189 }
190 break;
191 case 'd':
192 if(!strcmp(option, "display-mode")){
193 if(value==NULL){
194 error="display-mode given with no mode specified";
195 return 0;
196 }
197 if(!strcasecmp(value, "cur") || !strcasecmp(value, "current")){
198 starting_mode=0;
199 return 2;
200 } else if(!strcasecmp(value, "fcst") || !strcasecmp(value, "forecast")){
201 starting_mode=1;
202 return 2;
203 } else if(!strcasecmp(value, "map") || !strcasecmp(value, "radar")){
204 starting_mode=2;
205 return 2;
206 } else {
207 error="display-mode given with unrecognized mode";
208 return 0;
209 }
210 } else if(!strcmp(option, "display")){
211 return 1;
212 }
213 break;
214 case 'e':
215 if(!strncmp(option, "eta-", 4)){
216 if(!strcmp(option+4, "station")){
217 if(value==NULL){
218 error="eta-station given with no station ID";
219 return 0;
220 }
221 if(eta_station!=NULL) free(eta_station);
222 eta_station=strdup(value);
223 if(eta_station==NULL) die("eta-station strdup");
224 return 2;
225 } else if(!strcmp(option+4, "uri")){
226 if(value==NULL){
227 error="eta-uri given with no URI";
228 return 0;
229 }
230 if(eta_uri!=NULL) free(eta_uri);
231 eta_uri=strdup(value);
232 if(eta_uri==NULL) die("eta-uri strdup");
233 if(eta_post!=NULL) free(eta_post);
234 eta_post=NULL;
235 return 2;
236 } else if(!strcmp(option+4, "post")){
237 if(value==NULL){
238 error="eta-post given with no data";
239 return 0;
240 }
241 if(eta_uri==NULL){
242 error="eta-post must come after eta-uri";
243 return 0;
244 }
245 if(eta_post!=NULL) free(eta_post);
246 eta_post=strdup(value);
247 if(eta_post==NULL) die("eta-post strdup");
248 return 2;
249 }
250 break;
251 } else if(option[1]=='\0' || !strcmp(option, "email")){
252 if(value==NULL){
253 error="-e/email given with no address";
254 return 0;
255 }
256 if(email_address!=NULL) free(email_address);
257 email_address=strdup(value);
258 if(email_address==NULL) die("email strdup");
259 return 2;
260 }
261 break;
262 case 'f':
263 if(!strncmp(option, "forget-", 7)){
264 if(!strcmp(option+7, "warning-zones")){
265 if(warning_zones) free(warning_zones);
266 warning_zones=NULL;
267 return 1;
268 }
269 break;
270 }
271 break;
272 case 'h':
273 if(!strcmp(option, "hPa")){
274 pressure_mode=1;
275 return 1;
276 }
277 break;
278 case 'i':
279 if(!strcmp(option, "inHg")){
280 pressure_mode=0;
281 return 1;
282 } else if(!strcmp(option, "in")){
283 length_mode=0;
284 return 1;
285 }
286 break;
287 case 'k':
288 if(!strcmp(option, "kph")){
289 windspeed_mode=1;
290 return 1;
291 } else if(!strcmp(option, "knots")){
292 windspeed_mode=2;
293 return 1;
294 }
295 break;
296 case 'l':
297 if(!strcmp(option, "location")){
298 if(value==NULL){
299 error="location given with no value";
300 return 0;
301 }
302 if(!str2dd(value, &latitude, &longitude)){
303 error="location should be of the form \"dd'mm'ssN dd'mm'ssW\" or \"dd.ddddN dd.dddddW\"\n Note that, if you're using '-location' on the command line, you will need\n to quote the value, e.g. '-location \"dd.ddddN dd.dddddW\"'";
304 return 0;
305 }
306 if(latitude>90 || latitude<-90 || longitude>180 || longitude<-180){
307 error="latitude or longitude out of range";
308 return 0;
309 }
310 return 2;
311 }
312 break;
313 case 'm':
314 if(option[1]=='\0' || !strcmp(option, "metric")){
315 pressure_mode=windspeed_mode=temp_mode=length_mode=1;
316 return 1;
317 } else if(!strncmp(option, "metar-", 6)){
318 if(!strcmp(option+6, "station")){
319 if(value==NULL){
320 error="metar-station given with no station ID";
321 return 0;
322 }
323 if(metar_station!=NULL) free(metar_station);
324 metar_station=strdup(value);
325 if(metar_station==NULL) die("metar-station strdup");
326 return 2;
327 } else if(!strcmp(option+6, "uri")){
328 if(value==NULL){
329 error="metar-uri given with no URI";
330 return 0;
331 }
332 if(metar_uri!=NULL) free(metar_uri);
333 metar_uri=strdup(value);
334 if(metar_uri==NULL) die("metar-uri strdup");
335 if(metar_post!=NULL) free(metar_post);
336 metar_post=NULL;
337 return 2;
338 } else if(!strcmp(option+6, "post")){
339 if(value==NULL){
340 error="metar-post given with no data";
341 return 0;
342 }
343 if(metar_uri==NULL){
344 error="metar-post must come after metar-uri";
345 return 0;
346 }
347 if(metar_post!=NULL) free(metar_post);
348 metar_post=strdup(value);
349 if(metar_post==NULL) die("metar-post strdup");
350 return 2;
351 }
352 break;
353 } else if(!strncmp(option, "mrf-", 4)){
354 if(!strcmp(option+4, "station")){
355 if(value==NULL){
356 error="mrf-station given with no station ID";
357 return 0;
358 }
359 if(mrf_station!=NULL) free(mrf_station);
360 mrf_station=strdup(value);
361 if(mrf_station==NULL) die("mrf-station strdup");
362 return 2;
363 } else if(!strcmp(option+4, "uri")){
364 if(value==NULL){
365 error="mrf-uri given with no URI";
366 return 0;
367 }
368 if(mrf_uri!=NULL) free(mrf_uri);
369 mrf_uri=strdup(value);
370 if(mrf_uri==NULL) die("mrf-uri strdup");
371 if(mrf_post!=NULL) free(mrf_post);
372 mrf_post=NULL;
373 return 2;
374 } else if(!strcmp(option+4, "post")){
375 if(value==NULL){
376 error="mrf-post given with no data";
377 return 0;
378 }
379 if(mrf_uri==NULL){
380 error="mrf-post must come after mrf-uri";
381 return 0;
382 }
383 if(mrf_post!=NULL) free(mrf_post);
384 mrf_post=strdup(value);
385 if(mrf_post==NULL) die("mrf-post strdup");
386 return 2;
387 }
388 break;
389 } else if(!strcmp(option, "mmHg")){
390 pressure_mode=2;
391 return 1;
392 } else if(!strcmp(option, "mph")){
393 windspeed_mode=0;
394 return 1;
395 } else if(!strcmp(option, "mps")){
396 windspeed_mode=3;
397 return 1;
398 } else if(!strcmp(option, "mbar")){
399 pressure_mode=1;
400 return 1;
401 }
402 break;
403 case 'n':
404 if(!strcmp(option, "noradar")){
405 if(radar_uri!=NULL) free(radar_uri);
406 radar_uri=NULL;
407 return 1;
408 } else if(!strcmp(option, "noanimate")){
409 start_do_animation=0;
410 return 1;
411 }
412 break;
413 case 'r':
414 if(!strcmp(option, "radar")){
415 warn("'radar' is deprecated, please use 'radar-uri' instead");
416 return parse_option("radar-uri", value);
417 } else if(!strncmp(option, "radar-", 6)){
418 if(!strcmp(option+6, "uri")){
419 if(value==NULL){
420 error="radar-uri given with no URI";
421 return 0;
422 }
423 if(radar_uri!=NULL) free(radar_uri);
424 radar_uri=strdup(value);
425 if(radar_uri==NULL) die("radar-uri strdup");
426 if(radar_post!=NULL) free(radar_post);
427 radar_post=NULL;
428 return 2;
429 } else if(!strcmp(option+6, "post")){
430 if(value==NULL){
431 error="radar-post given with no data";
432 return 0;
433 }
434 if(radar_uri==NULL){
435 error="radar-post must come after radar-uri";
436 return 0;
437 }
438 if(radar_post!=NULL) free(radar_post);
439 radar_post=strdup(value);
440 if(radar_post==NULL) die("radar-post strdup");
441 return 2;
442 } else if(!strcmp(option+6, "crop")){
443 if(value==NULL){
444 error="radar-crop given with no value";
445 return 0;
446 }
447 if(radar_crop!=NULL) free(radar_crop);
448 radar_crop=strdup(value);
449 if(radar_crop==NULL) die("radar-crop strdup");
450 return 2;
451 } else if(!strcmp(option+6, "cross")){
452 if(value==NULL){
453 error="radar-cross given with no value";
454 return 0;
455 }
456 if(radar_cross!=NULL) free(radar_cross);
457 radar_cross=strdup(value);
458 if(radar_cross==NULL) die("radar-cross strdup");
459 return 2;
460 }
461 break;
462 }
463 break;
464 case 's':
465 if(option[1]=='\0' || !strcmp(option, "station")){
466 if(value==NULL){
467 error="-s/station given with no value";
468 return 0;
469 }
470 if(parse_option("metar-station", value)==2
471 && parse_option("avn-station", value)==2
472 && parse_option("eta-station", value)==2
473 && parse_option("mrf-station", value)==2)
474 return 2;
475 return 0;
476 }
477 break;
478 case 't':
479 if(!strcmp(option, "tempf")){
480 temp_mode=0;
481 return 1;
482 } else if(!strcmp(option, "tempc")){
483 temp_mode=1;
484 return 1;
485 }
486 break;
487 case 'v':
488 if(option[1]=='\0' || !strcmp(option, "version")){
489 printversion();
490 exit(0);
491 } else if(!strcmp(option, "viewer")){
492 if(value==NULL){
493 error="viewer given with no value";
494 return 0;
495 }
496 if(viewer!=NULL) free(viewer);
497 viewer=strdup(value);
498 if(viewer==NULL) die("viewer strdup");
499 return 2;
500 }
501 break;
502 case 'w':
503 if(!strncmp(option, "warning-", 8)){
504 if(!strcmp(option+8, "zone")){
505 if(value==NULL){
506 error="warning-zone given with no zone ID";
507 return 0;
508 }
509 if(warning_zones!=NULL){
510 for(i=0; warning_zones[i]!=NULL; i++);
511 } else {
512 i=0;
513 }
514 v=realloc(warning_zones, sizeof(*warning_zones)*(i+2));
515 if(v==NULL) die("warning-zone realloc");
516 warning_zones=v;
517 warning_zones[i+1]=NULL;
518 warning_zones[i]=strdup(value);
519 if(warning_zones[i]==NULL) die("warning-zone strdup");
520 return 2;
521 } else if(!strcmp(option+8, "uri")){
522 if(value==NULL){
523 error="warning-uri given with no URI";
524 return 0;
525 }
526 if(warning_uri!=NULL) free(warning_uri);
527 warning_uri=strdup(value);
528 if(warning_uri==NULL) die("warning-uri strdup");
529 if(warning_post!=NULL) free(warning_post);
530 warning_post=NULL;
531 return 2;
532 } else if(!strcmp(option+8, "post")){
533 if(value==NULL){
534 error="warning-post given with no data";
535 return 0;
536 }
537 if(warning_uri==NULL){
538 error="warning-post must come after warning-uri";
539 return 0;
540 }
541 if(warning_post!=NULL) free(warning_post);
542 warning_post=strdup(value);
543 if(warning_post==NULL) die("warning-post strdup");
544 return 2;
545 }
546 break;
547 }
548 break;
549 case 'z':
550 if(!strcmp(option, "zone")){
551 warn("'zone' is deprecated, please use 'warning-zone' instead");
552 return parse_option("warning-zone", value);
553 }
554 break;
555 default:
556 break;
557 }
558 return 0;
559 }
560
readconf(char * file)561 int readconf(char *file){
562 char *c, *d;
563 int i, l, flag=1;
564 FILE *fp;
565
566 if(file==NULL){
567 flag=0;
568 file=get_filename("conf");
569 }
570
571 if((fp=fopen(file, "r"))==NULL){
572 if(!flag){
573 free(file);
574 return 0;
575 }
576 return 1;
577 }
578
579 l=0;
580 while(fgets(bigbuf, BIGBUF_LEN, fp)!=NULL){
581 l++;
582 for(i=strlen(bigbuf)-1; i>=0; i--){
583 if (!isspace(bigbuf[i])) break;
584 bigbuf[i]='\0';
585 }
586 c=bigbuf+strspn(bigbuf, " \t");
587 if(*c=='#' || *c=='\0') continue;
588 d=c+strcspn(c, " \t");
589 if(*d=='\0') d=NULL;
590 else {
591 *d='\0';
592 d++;
593 d+=strspn(d+1, " \t");
594 if(*d=='\0') d=NULL;
595 }
596 if(!parse_option(c, d)){
597 warn("%s[%d]: %s", file, l, error);
598 fclose(fp);
599 if(!flag) free(file);
600 return 2;
601 }
602 }
603 fclose(fp);
604 if(!flag) free(file);
605 return 0;
606 }
607
608
check_dir(void)609 int check_dir(void){
610 char *c;
611 struct stat statbuf;
612 int i;
613
614 c=get_filename("");
615 i=stat(c, &statbuf);
616 if(i<0){
617 if(errno==ENOENT){
618 if(mkdir(c, 0777)<0) die("Couldn't create directory %s", c);
619 errno=0;
620 warn("Created directory %s", c);
621 i=stat(c, &statbuf);
622 }
623 if(i<0) die("Couldn't stat %s", c);
624 }
625 if(!S_ISDIR(statbuf.st_mode)) die("%s is not a directory", c);
626 free(c);
627 c=get_filename(".dir-test");
628 if(unlink(c)<0 && errno!=ENOENT) die("Couldn't delete %s", c);
629 if((i=stat(c, &statbuf))!=-1 || errno!=ENOENT){
630 if(i!=-1) errno=EEXIST;
631 die("Couldn't verify nonexistence of %s", c);
632 }
633 if((i=creat(c, 0))<0) die("Couldn't create %s", c);
634 close(i);
635 if(stat(c, &statbuf)<0) die("Couldn't stat %s", c);
636 unlink(c);
637 free(c);
638 return 1;
639 }
640
sigint(int i)641 void sigint(int i){
642 exit(0);
643 }
644
main(int argc,char ** argv)645 int main(int argc, char **argv){
646 int i, j;
647 char *c;
648
649 ProgName = argv[0];
650 if((c=strrchr(ProgName, '/'))!=NULL && *(c+1)!='\0'){
651 ProgName=c+1;
652 }
653
654 if((bigbuf=malloc(BIGBUF_LEN))==NULL) die("bigbuf malloc");
655 check_dir();
656
657 devnull=open("/dev/null", O_RDWR);
658 if(devnull<0) die("opening /dev/null");
659 /* Parse Command Line */
660
661 c=NULL;
662 for(i=1;i<argc;i++){
663 if(!strcmp(argv[i], "-c")){
664 i++;
665 if(!(i<argc)){
666 F("-c given with no value");
667 exit(1);
668 }
669 c=argv[i];
670 break;
671 }
672 }
673 if(readconf("/usr/local/etc/wmweather+.conf")>1) exit(1);
674 if((i=readconf(c))==1) warn("Couldn't open %s", c);
675 if(i) exit(1);
676
677 for(i=1;i<argc;i++){
678 char *arg = argv[i];
679
680 if(*arg=='-'){
681 j=parse_option(argv[i], (i+1<argc)?argv[i+1]:NULL);
682 if(j==0){
683 if(error==unknown_option) usage(1);
684 fprintf(stderr, "%s\n", error);
685 exit(1);
686 }
687 i+=j-1;
688 }
689 }
690
691 {
692 struct sigaction act;
693 sigemptyset(&act.sa_mask);
694 act.sa_handler=sigchld;
695 act.sa_flags=SA_RESTART;
696 sigaction(SIGCHLD, &act, NULL);
697 act.sa_handler=sigint;
698 sigaction(SIGINT, &act, NULL);
699 }
700
701 i=0;
702 if(metar_station==NULL){
703 i=1;
704 F("Please specify a METAR station.\n See http://www.nws.noaa.gov/tg/siteloc.php\n");
705 }
706 if(latitude==999){{
707 time_t t;
708 int flag=0;
709
710 /* note: if time_t isn't an arithmetic type, mkgmtime is screwed
711 * anyway. So t=0 is as appropriate as anything else. */
712 t=0;
713 longitude=-mkgmtime(localtime(&t))/240.0;
714 latitude=0;
715 if(longitude<0){
716 flag=1;
717 longitude=-longitude;
718 }
719 fprintf(stderr, "-location not given. Guessing you're at 0N %d'%d'%d%c\n", (int)longitude, (int)(longitude*60)%60, (int)(longitude*3600)%60, flag?'E':'W');
720 if(flag) longitude=-longitude;
721 }} else if(latitude>89.8){
722 F("Latitude greater then 89.9N automatically truncated.\n");
723 latitude=89.8;
724 } else if(latitude<-89.8){
725 F("Latitude greater then 89.9S automatically truncated.\n");
726 latitude=-89.8;
727 }
728 if(i) exit(1);
729 if(viewer==NULL) viewer="xless";
730 if(metar_uri==NULL) metar_uri="http://tgftp.nws.noaa.gov/data/observations/metar/stations/%s.TXT";
731 if(avn_uri==NULL) avn_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmav.pl?sta=%s";
732 if(eta_uri==NULL) eta_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmet.pl?sta=%s";
733 if(mrf_uri==NULL) mrf_uri="http://www.nws.noaa.gov/cgi-bin/mos/getmex.pl?sta=%s";
734 if(warning_uri==NULL) warning_uri="http://tgftp.nws.noaa.gov/data/watches_warnings/%f/%.2z/%z.txt";
735
736 download_init(email_address);
737 init_dock(argc, argv);
738 while(1){
739 update_dock();
740 download_process(100000);
741 }
742 }
743
usage(int i)744 void usage(int i) {
745 F("Option Value Description");
746 F("------ ----- -----------");
747 F("-c <file> Specify a configuration file");
748 F("-e <address> Alias for -email");
749 F("-email <address> Specify anonymous FTP password");
750 F("-location <lat+lon> Specify latitude and longitude. See manpage.");
751 F("-v Alias for -version");
752 F("-version Display version number");
753 F("-viewer <program> Program to display text from stdin");
754 F("-[no]animate Turn animation on or off");
755 F("");
756 F("-s <ID> Alias for -station");
757 F("-station <ID> Station ID (all stations)");
758 F("-metar-station <ID> Station ID for METAR observations");
759 F("-avn-station <ID> Station ID for AVN forecasts");
760 F("-eta-station <ID> Station ID for ETA forecasts");
761 F("-mrf-station <ID> Station ID for MRF forecasts");
762 F("-warning-zone <zoneID> Zone ID for weather warnings");
763 F("-*-uri <URI> URI for the weather data (see docs for details)");
764 F("-*-post <DATA> Post data for the weather data (see docs)");
765 F(" '*' can be metar, avn, eta, mrf, warning");
766 F("-noradar Do not display a radar image.");
767 F("-radar-uri <URI> URI for radar image");
768 F("-radar-post <DATA> Post data for radar image");
769 F("-radar-crop <string> How to crop the radar image. XxY+W+H format.");
770 F("-radar-cross <string> Where to draw radar crosshairs. XxY format.");
771 F("");
772 F("-m Alias for -metric");
773 F("-metric Same as -cm -hPa -kph -tempc");
774 F("");
775 F("-in Display precipitation amounts in inches");
776 F("-cm Display precipitation amounts in centimeters");
777 F("");
778 F("-inHg Display pressure in inHg");
779 F("-hPa Display pressure in hPa (millibars)");
780 F("-mbar Alias for -hPa");
781 F("-mmHg Display pressure in mmHg");
782 F("-atm Display pressure in atmospheres");
783 F("");
784 F("-mph Display windspeed in miles/hour");
785 F("-kph Display windspeed in kilometers/hour");
786 F("-knots Display windspeed in knots");
787 F("-mps Display windspeed in meters/second");
788 F("-beaufort Display windspeed on the Beaufort scale");
789 F("");
790 F("-tempf Display temperature in degrees Fahrenheit");
791 F("-tempc Display temperature in degrees Celcius");
792
793 exit(i);
794 }
795
printversion(void)796 void printversion(void) {
797 fprintf(stderr, "%s\n", VERSION);
798 }
799
get_filename(char * file)800 char *get_filename(char *file){
801 char *f, *c;
802
803 c=getenv("HOME");
804 if((f=malloc(strlen(c)+strlen(file)+14))==NULL) die("get_filename");
805 strcpy(f, c);
806 strcat(f, "/.wmweather+/");
807 strcat(f, file);
808 return f;
809 }
810
get_pid_filename(char * file)811 char *get_pid_filename(char *file){
812 char *f, *c;
813 static unsigned short seq=0;
814 char buf[15];
815
816 snprintf(buf, sizeof(buf), "%08X.%04X-", getpid(), seq++);
817 c=getenv("HOME");
818 if((f=malloc(strlen(c)+strlen(file)+14+14))==NULL) die("get_pid_filename");
819 strcpy(f, c);
820 strcat(f, "/.wmweather+/");
821 strcat(f, buf);
822 strcat(f, file);
823 return f;
824 }
825