xref: /freebsd/usr.bin/calendar/io.c (revision 1462201c)
1fd1efedcSConrad Meyer /*-
2fd1efedcSConrad Meyer  * SPDX-License-Identifier: BSD-3-Clause
3fd1efedcSConrad Meyer  *
4fd1efedcSConrad Meyer  * Copyright (c) 1989, 1993, 1994
5fd1efedcSConrad Meyer  *	The Regents of the University of California.  All rights reserved.
6fd1efedcSConrad Meyer  *
7fd1efedcSConrad Meyer  * Redistribution and use in source and binary forms, with or without
8fd1efedcSConrad Meyer  * modification, are permitted provided that the following conditions
9fd1efedcSConrad Meyer  * are met:
10fd1efedcSConrad Meyer  * 1. Redistributions of source code must retain the above copyright
11fd1efedcSConrad Meyer  *    notice, this list of conditions and the following disclaimer.
12fd1efedcSConrad Meyer  * 2. Redistributions in binary form must reproduce the above copyright
13fd1efedcSConrad Meyer  *    notice, this list of conditions and the following disclaimer in the
14fd1efedcSConrad Meyer  *    documentation and/or other materials provided with the distribution.
15fd1efedcSConrad Meyer  * 3. Neither the name of the University nor the names of its contributors
16fd1efedcSConrad Meyer  *    may be used to endorse or promote products derived from this software
17fd1efedcSConrad Meyer  *    without specific prior written permission.
18fd1efedcSConrad Meyer  *
19fd1efedcSConrad Meyer  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20fd1efedcSConrad Meyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21fd1efedcSConrad Meyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22fd1efedcSConrad Meyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23fd1efedcSConrad Meyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24fd1efedcSConrad Meyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25fd1efedcSConrad Meyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26fd1efedcSConrad Meyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27fd1efedcSConrad Meyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28fd1efedcSConrad Meyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29fd1efedcSConrad Meyer  * SUCH DAMAGE.
30fd1efedcSConrad Meyer  */
31fd1efedcSConrad Meyer 
32fd1efedcSConrad Meyer #ifndef lint
33fd1efedcSConrad Meyer static const char copyright[] =
34fd1efedcSConrad Meyer "@(#) Copyright (c) 1989, 1993\n\
35fd1efedcSConrad Meyer 	The Regents of the University of California.  All rights reserved.\n";
36fd1efedcSConrad Meyer #endif
37fd1efedcSConrad Meyer 
38fd1efedcSConrad Meyer #if 0
39fd1efedcSConrad Meyer #ifndef lint
40fd1efedcSConrad Meyer static char sccsid[] = "@(#)calendar.c  8.3 (Berkeley) 3/25/94";
41fd1efedcSConrad Meyer #endif
42fd1efedcSConrad Meyer #endif
43fd1efedcSConrad Meyer 
44fd1efedcSConrad Meyer #include <sys/cdefs.h>
45fd1efedcSConrad Meyer __FBSDID("$FreeBSD$");
46fd1efedcSConrad Meyer 
47fd1efedcSConrad Meyer #include <sys/param.h>
48fd1efedcSConrad Meyer #include <sys/stat.h>
49fd1efedcSConrad Meyer #include <sys/wait.h>
50fd1efedcSConrad Meyer #include <ctype.h>
51fd1efedcSConrad Meyer #include <err.h>
52fd1efedcSConrad Meyer #include <errno.h>
53fd1efedcSConrad Meyer #include <langinfo.h>
54fd1efedcSConrad Meyer #include <locale.h>
55fd1efedcSConrad Meyer #include <pwd.h>
56fd1efedcSConrad Meyer #include <stdbool.h>
57fd1efedcSConrad Meyer #include <stdio.h>
58fd1efedcSConrad Meyer #include <stdlib.h>
59fd1efedcSConrad Meyer #include <string.h>
60fd1efedcSConrad Meyer #include <stringlist.h>
61fd1efedcSConrad Meyer #include <time.h>
62fd1efedcSConrad Meyer #include <unistd.h>
63fd1efedcSConrad Meyer 
64fd1efedcSConrad Meyer #include "pathnames.h"
65fd1efedcSConrad Meyer #include "calendar.h"
66fd1efedcSConrad Meyer 
67fd1efedcSConrad Meyer enum {
68fd1efedcSConrad Meyer 	T_OK = 0,
69fd1efedcSConrad Meyer 	T_ERR,
70fd1efedcSConrad Meyer 	T_PROCESS,
71fd1efedcSConrad Meyer };
72fd1efedcSConrad Meyer 
73fd1efedcSConrad Meyer const char *calendarFile = "calendar";	/* default calendar file */
7434b38e12SStefan Eßer static const char *calendarHomes[] = {".calendar", _PATH_INCLUDE_LOCAL, _PATH_INCLUDE}; /* HOME */
75fd1efedcSConrad Meyer static const char *calendarNoMail = "nomail";/* don't sent mail if file exist */
76fd1efedcSConrad Meyer 
77fd1efedcSConrad Meyer static char path[MAXPATHLEN];
781462201cSStefan Eßer static const char *cal_home;
791462201cSStefan Eßer static const char *cal_dir;
801462201cSStefan Eßer static const char *cal_file;
811462201cSStefan Eßer static int cal_line;
82fd1efedcSConrad Meyer 
83fd1efedcSConrad Meyer struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
84fd1efedcSConrad Meyer struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice;
85fd1efedcSConrad Meyer 
86fd1efedcSConrad Meyer static int cal_parse(FILE *in, FILE *out);
87fd1efedcSConrad Meyer 
88fd1efedcSConrad Meyer static StringList *definitions = NULL;
89fd1efedcSConrad Meyer static struct event *events[MAXCOUNT];
90fd1efedcSConrad Meyer static char *extradata[MAXCOUNT];
91fd1efedcSConrad Meyer 
92fd1efedcSConrad Meyer static void
93fd1efedcSConrad Meyer trimlr(char **buf)
94fd1efedcSConrad Meyer {
95fd1efedcSConrad Meyer 	char *walk = *buf;
96fd1efedcSConrad Meyer 	char *last;
97fd1efedcSConrad Meyer 
98fd1efedcSConrad Meyer 	while (isspace(*walk))
99fd1efedcSConrad Meyer 		walk++;
100fd1efedcSConrad Meyer 	if (*walk != '\0') {
101fd1efedcSConrad Meyer 		last = walk + strlen(walk) - 1;
102fd1efedcSConrad Meyer 		while (last > walk && isspace(*last))
103fd1efedcSConrad Meyer 			last--;
104fd1efedcSConrad Meyer 		*(last+1) = 0;
105fd1efedcSConrad Meyer 	}
106fd1efedcSConrad Meyer 
107fd1efedcSConrad Meyer 	*buf = walk;
108fd1efedcSConrad Meyer }
109fd1efedcSConrad Meyer 
110fd1efedcSConrad Meyer static FILE *
111fd1efedcSConrad Meyer cal_fopen(const char *file)
112fd1efedcSConrad Meyer {
113fd1efedcSConrad Meyer 	FILE *fp;
114fd1efedcSConrad Meyer 	char *home = getenv("HOME");
115fd1efedcSConrad Meyer 	unsigned int i;
116d20d6550SWarner Losh 	struct stat sb;
117d20d6550SWarner Losh 	static bool warned = false;
118fd1efedcSConrad Meyer 
119fd1efedcSConrad Meyer 	if (home == NULL || *home == '\0') {
120fd1efedcSConrad Meyer 		warnx("Cannot get home directory");
121fd1efedcSConrad Meyer 		return (NULL);
122fd1efedcSConrad Meyer 	}
123fd1efedcSConrad Meyer 
124fd1efedcSConrad Meyer 	if (chdir(home) != 0) {
1251462201cSStefan Eßer 		warnx("Cannot enter home directory \"%s\"", home);
126fd1efedcSConrad Meyer 		return (NULL);
127fd1efedcSConrad Meyer 	}
128fd1efedcSConrad Meyer 
129fd1efedcSConrad Meyer 	for (i = 0; i < nitems(calendarHomes); i++) {
130fd1efedcSConrad Meyer 		if (chdir(calendarHomes[i]) != 0)
131fd1efedcSConrad Meyer 			continue;
132fd1efedcSConrad Meyer 
1331462201cSStefan Eßer 		if ((fp = fopen(file, "r")) != NULL) {
1341462201cSStefan Eßer 			cal_home = home;
1351462201cSStefan Eßer 			cal_dir = calendarHomes[i];
1361462201cSStefan Eßer 			cal_file = file;
137fd1efedcSConrad Meyer 			return (fp);
138fd1efedcSConrad Meyer 		}
1391462201cSStefan Eßer 	}
140fd1efedcSConrad Meyer 
141fd1efedcSConrad Meyer 	warnx("can't open calendar file \"%s\"", file);
142d20d6550SWarner Losh 	if (!warned && stat(_PATH_INCLUDE_LOCAL, &sb) != 0) {
143d20d6550SWarner Losh 		warnx("calendar data files now provided by calendar-data pkg.");
144d20d6550SWarner Losh 		warned = true;
145d20d6550SWarner Losh 	}
146fd1efedcSConrad Meyer 
147fd1efedcSConrad Meyer 	return (NULL);
148fd1efedcSConrad Meyer }
149fd1efedcSConrad Meyer 
1501462201cSStefan Eßer #define	WARN0(format)		   \
1511462201cSStefan Eßer 	warnx(format " in %s/%s/%s line %d", cal_home, cal_dir, cal_file, cal_line)
1521462201cSStefan Eßer #define	WARN1(format, arg1)		   \
1531462201cSStefan Eßer 	warnx(format " in %s/%s/%s line %d", arg1, cal_home, cal_dir, cal_file, cal_line)
1541462201cSStefan Eßer 
155fd1efedcSConrad Meyer static int
15619b5c307SStefan Eßer token(char *line, FILE *out, int *skip)
157fd1efedcSConrad Meyer {
158fd1efedcSConrad Meyer 	char *walk, c, a;
1591462201cSStefan Eßer 	const char *this_cal_home;
1601462201cSStefan Eßer 	const char *this_cal_dir;
1611462201cSStefan Eßer 	const char *this_cal_file;
1621462201cSStefan Eßer 	int this_cal_line;
163fd1efedcSConrad Meyer 
164fd1efedcSConrad Meyer 	if (strncmp(line, "endif", 5) == 0) {
16519b5c307SStefan Eßer 		if (*skip > 0)
16619b5c307SStefan Eßer 			--*skip;
167fd1efedcSConrad Meyer 		return (T_OK);
168fd1efedcSConrad Meyer 	}
169fd1efedcSConrad Meyer 
17019b5c307SStefan Eßer 	if (strncmp(line, "ifdef", 5) == 0) {
17119b5c307SStefan Eßer 		walk = line + 5;
17219b5c307SStefan Eßer 		trimlr(&walk);
17319b5c307SStefan Eßer 
17419b5c307SStefan Eßer 		if (*walk == '\0') {
1751462201cSStefan Eßer 			WARN0("Expecting arguments after #ifdef");
17619b5c307SStefan Eßer 			return (T_ERR);
17719b5c307SStefan Eßer 		}
17819b5c307SStefan Eßer 
17919b5c307SStefan Eßer 		if (*skip != 0 || definitions == NULL || sl_find(definitions, walk) == NULL)
18019b5c307SStefan Eßer 			++*skip;
18119b5c307SStefan Eßer 
18219b5c307SStefan Eßer 		return (T_OK);
18319b5c307SStefan Eßer 	}
18419b5c307SStefan Eßer 
18519b5c307SStefan Eßer 	if (strncmp(line, "ifndef", 6) == 0) {
18619b5c307SStefan Eßer 		walk = line + 6;
18719b5c307SStefan Eßer 		trimlr(&walk);
18819b5c307SStefan Eßer 
18919b5c307SStefan Eßer 		if (*walk == '\0') {
1901462201cSStefan Eßer 			WARN0("Expecting arguments after #ifndef");
19119b5c307SStefan Eßer 			return (T_ERR);
19219b5c307SStefan Eßer 		}
19319b5c307SStefan Eßer 
19419b5c307SStefan Eßer 		if (*skip != 0 || (definitions != NULL && sl_find(definitions, walk) != NULL))
19519b5c307SStefan Eßer 			++*skip;
19619b5c307SStefan Eßer 
19719b5c307SStefan Eßer 		return (T_OK);
19819b5c307SStefan Eßer 	}
19919b5c307SStefan Eßer 
20019b5c307SStefan Eßer 	if (strncmp(line, "else", 4) == 0) {
20119b5c307SStefan Eßer 		walk = line + 4;
20219b5c307SStefan Eßer 		trimlr(&walk);
20319b5c307SStefan Eßer 
20419b5c307SStefan Eßer 		if (*walk != '\0') {
2051462201cSStefan Eßer 			WARN0("Expecting no arguments after #else");
20619b5c307SStefan Eßer 			return (T_ERR);
20719b5c307SStefan Eßer 		}
20819b5c307SStefan Eßer 
20919b5c307SStefan Eßer 		if (*skip == 0)
21019b5c307SStefan Eßer 			*skip = 1;
21119b5c307SStefan Eßer 		else if (*skip == 1)
21219b5c307SStefan Eßer 			*skip = 0;
21319b5c307SStefan Eßer 
21419b5c307SStefan Eßer 		return (T_OK);
21519b5c307SStefan Eßer 	}
21619b5c307SStefan Eßer 
21719b5c307SStefan Eßer 	if (*skip != 0)
218fd1efedcSConrad Meyer 		return (T_OK);
219fd1efedcSConrad Meyer 
220fd1efedcSConrad Meyer 	if (strncmp(line, "include", 7) == 0) {
221fd1efedcSConrad Meyer 		walk = line + 7;
222fd1efedcSConrad Meyer 
223fd1efedcSConrad Meyer 		trimlr(&walk);
224fd1efedcSConrad Meyer 
225fd1efedcSConrad Meyer 		if (*walk == '\0') {
2261462201cSStefan Eßer 			WARN0("Expecting arguments after #include");
227fd1efedcSConrad Meyer 			return (T_ERR);
228fd1efedcSConrad Meyer 		}
229fd1efedcSConrad Meyer 
230fd1efedcSConrad Meyer 		if (*walk != '<' && *walk != '\"') {
2311462201cSStefan Eßer 			WARN0("Excecting '<' or '\"' after #include");
232fd1efedcSConrad Meyer 			return (T_ERR);
233fd1efedcSConrad Meyer 		}
234fd1efedcSConrad Meyer 
235ac04cf18SStefan Eßer 		a = *walk == '<' ? '>' : '\"';
236fd1efedcSConrad Meyer 		walk++;
237fd1efedcSConrad Meyer 		c = walk[strlen(walk) - 1];
238fd1efedcSConrad Meyer 
239ac04cf18SStefan Eßer 		if (a != c) {
2401462201cSStefan Eßer 			WARN1("Unterminated include expecting '%c'", a);
241fd1efedcSConrad Meyer 			return (T_ERR);
242fd1efedcSConrad Meyer 		}
243fd1efedcSConrad Meyer 		walk[strlen(walk) - 1] = '\0';
244fd1efedcSConrad Meyer 
2451462201cSStefan Eßer 		this_cal_home = cal_home;
2461462201cSStefan Eßer 		this_cal_dir = cal_dir;
2471462201cSStefan Eßer 		this_cal_file = cal_file;
2481462201cSStefan Eßer 		this_cal_line = cal_line;
249fd1efedcSConrad Meyer 		if (cal_parse(cal_fopen(walk), out))
250fd1efedcSConrad Meyer 			return (T_ERR);
2511462201cSStefan Eßer 		cal_home = this_cal_home;
2521462201cSStefan Eßer 		cal_dir = this_cal_dir;
2531462201cSStefan Eßer 		cal_file = this_cal_file;
2541462201cSStefan Eßer 		cal_line = this_cal_line;
255fd1efedcSConrad Meyer 
256fd1efedcSConrad Meyer 		return (T_OK);
257fd1efedcSConrad Meyer 	}
258fd1efedcSConrad Meyer 
259fd1efedcSConrad Meyer 	if (strncmp(line, "define", 6) == 0) {
260fd1efedcSConrad Meyer 		if (definitions == NULL)
261fd1efedcSConrad Meyer 			definitions = sl_init();
262fd1efedcSConrad Meyer 		walk = line + 6;
263fd1efedcSConrad Meyer 		trimlr(&walk);
264fd1efedcSConrad Meyer 
265fd1efedcSConrad Meyer 		if (*walk == '\0') {
2661462201cSStefan Eßer 			WARN0("Expecting arguments after #define");
267fd1efedcSConrad Meyer 			return (T_ERR);
268fd1efedcSConrad Meyer 		}
269fd1efedcSConrad Meyer 
270fd1efedcSConrad Meyer 		sl_add(definitions, strdup(walk));
271fd1efedcSConrad Meyer 		return (T_OK);
272fd1efedcSConrad Meyer 	}
273fd1efedcSConrad Meyer 
274fd1efedcSConrad Meyer 	return (T_PROCESS);
275fd1efedcSConrad Meyer 
276fd1efedcSConrad Meyer }
277fd1efedcSConrad Meyer 
278fd1efedcSConrad Meyer #define	REPLACE(string, slen, struct_) \
279fd1efedcSConrad Meyer 		if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \
280fd1efedcSConrad Meyer 			if (struct_.name != NULL)			      \
281fd1efedcSConrad Meyer 				free(struct_.name);			      \
282fd1efedcSConrad Meyer 			if ((struct_.name = strdup(buf + (slen))) == NULL)    \
283fd1efedcSConrad Meyer 				errx(1, "cannot allocate memory");	      \
284fd1efedcSConrad Meyer 			struct_.len = strlen(buf + (slen));		      \
285fd1efedcSConrad Meyer 			continue;					      \
286fd1efedcSConrad Meyer 		}
287fd1efedcSConrad Meyer static int
288fd1efedcSConrad Meyer cal_parse(FILE *in, FILE *out)
289fd1efedcSConrad Meyer {
290fd1efedcSConrad Meyer 	char *line = NULL;
291fd1efedcSConrad Meyer 	char *buf;
292fd1efedcSConrad Meyer 	size_t linecap = 0;
293fd1efedcSConrad Meyer 	ssize_t linelen;
294fd1efedcSConrad Meyer 	ssize_t l;
295fd1efedcSConrad Meyer 	static int d_first = -1;
296fd1efedcSConrad Meyer 	static int count = 0;
297fd1efedcSConrad Meyer 	int i;
298fd1efedcSConrad Meyer 	int month[MAXCOUNT];
299fd1efedcSConrad Meyer 	int day[MAXCOUNT];
300fd1efedcSConrad Meyer 	int year[MAXCOUNT];
30119b5c307SStefan Eßer 	int skip = 0;
302fd1efedcSConrad Meyer 	char dbuf[80];
303fd1efedcSConrad Meyer 	char *pp, p;
304fd1efedcSConrad Meyer 	struct tm tm;
305fd1efedcSConrad Meyer 	int flags;
3060f352f4eSStefan Eßer 	char *c, *cc;
3070f352f4eSStefan Eßer 	bool incomment = false;
308fd1efedcSConrad Meyer 
309fd1efedcSConrad Meyer 	/* Unused */
310fd1efedcSConrad Meyer 	tm.tm_sec = 0;
311fd1efedcSConrad Meyer 	tm.tm_min = 0;
312fd1efedcSConrad Meyer 	tm.tm_hour = 0;
313fd1efedcSConrad Meyer 	tm.tm_wday = 0;
314fd1efedcSConrad Meyer 
315fd1efedcSConrad Meyer 	if (in == NULL)
316fd1efedcSConrad Meyer 		return (1);
317fd1efedcSConrad Meyer 
3181462201cSStefan Eßer 	cal_line = 0;
319fd1efedcSConrad Meyer 	while ((linelen = getline(&line, &linecap, in)) > 0) {
3201462201cSStefan Eßer 		cal_line++;
3210f352f4eSStefan Eßer 		buf = line;
3220f352f4eSStefan Eßer 		if (buf[linelen - 1] == '\n')
3230f352f4eSStefan Eßer 			buf[--linelen] = '\0';
3240f352f4eSStefan Eßer 
3250f352f4eSStefan Eßer 		if (incomment) {
3260f352f4eSStefan Eßer 			c = strstr(buf, "*/");
3270f352f4eSStefan Eßer 			if (c) {
3280f352f4eSStefan Eßer 				c += 2;
3290f352f4eSStefan Eßer 				linelen -= c - buf;
3300f352f4eSStefan Eßer 				buf = c;
3310f352f4eSStefan Eßer 				incomment = false;
3320f352f4eSStefan Eßer 			} else {
3330f352f4eSStefan Eßer 				continue;
3340f352f4eSStefan Eßer 			}
3350f352f4eSStefan Eßer 		}
3360f352f4eSStefan Eßer 		if (!incomment) {
3370f352f4eSStefan Eßer 			do {
3380f352f4eSStefan Eßer 				c = strstr(buf, "//");
3390f352f4eSStefan Eßer 				cc = strstr(buf, "/*");
3400f352f4eSStefan Eßer 				if (c != NULL && (cc == NULL || c - cc < 0)) {
3416bdb89a8SStefan Eßer 					/* single line comment */
3420f352f4eSStefan Eßer 					*c = '\0';
3430f352f4eSStefan Eßer 					linelen = c - buf;
3440f352f4eSStefan Eßer 					break;
3450f352f4eSStefan Eßer 				} else if (cc != NULL) {
3460f352f4eSStefan Eßer 					c = strstr(cc + 2, "*/");
3470f352f4eSStefan Eßer 					if (c != NULL) {
3486bdb89a8SStefan Eßer 						/* multi-line comment ending on same line */
3490f352f4eSStefan Eßer 						c += 2;
3506bdb89a8SStefan Eßer 						memmove(cc, c, buf + linelen + 1 - c);
3510f352f4eSStefan Eßer 						linelen -= c - cc;
3520f352f4eSStefan Eßer 					} else {
3536bdb89a8SStefan Eßer 						/* multi-line comment */
3540f352f4eSStefan Eßer 						*cc = '\0';
3550f352f4eSStefan Eßer 						linelen = cc - buf;
3560f352f4eSStefan Eßer 						incomment = true;
3570f352f4eSStefan Eßer 						break;
3580f352f4eSStefan Eßer 					}
3590f352f4eSStefan Eßer 				}
3600f352f4eSStefan Eßer 			} while (c != NULL || cc != NULL);
3610f352f4eSStefan Eßer 		}
3620f352f4eSStefan Eßer 
3630f352f4eSStefan Eßer 		for (l = linelen;
3640f352f4eSStefan Eßer 		     l > 0 && isspace((unsigned char)buf[l - 1]);
3650f352f4eSStefan Eßer 		     l--)
3660f352f4eSStefan Eßer 			;
3670f352f4eSStefan Eßer 		buf[l] = '\0';
3680f352f4eSStefan Eßer 		if (buf[0] == '\0')
3690f352f4eSStefan Eßer 			continue;
3700f352f4eSStefan Eßer 
3710f352f4eSStefan Eßer 		if (buf == line && *buf == '#') {
3720f352f4eSStefan Eßer 			switch (token(buf+1, out, &skip)) {
373fd1efedcSConrad Meyer 			case T_ERR:
374fd1efedcSConrad Meyer 				free(line);
375fd1efedcSConrad Meyer 				return (1);
376fd1efedcSConrad Meyer 			case T_OK:
377fd1efedcSConrad Meyer 				continue;
378fd1efedcSConrad Meyer 			case T_PROCESS:
379fd1efedcSConrad Meyer 				break;
380fd1efedcSConrad Meyer 			default:
381fd1efedcSConrad Meyer 				break;
382fd1efedcSConrad Meyer 			}
383fd1efedcSConrad Meyer 		}
384fd1efedcSConrad Meyer 
38519b5c307SStefan Eßer 		if (skip != 0)
386fd1efedcSConrad Meyer 			continue;
387fd1efedcSConrad Meyer 
388fd1efedcSConrad Meyer 		/*
389fd1efedcSConrad Meyer 		 * Setting LANG in user's calendar was an old workaround
390fd1efedcSConrad Meyer 		 * for 'calendar -a' being run with C locale to properly
391fd1efedcSConrad Meyer 		 * print user's calendars in their native languages.
392fd1efedcSConrad Meyer 		 * Now that 'calendar -a' does fork with setusercontext(),
393fd1efedcSConrad Meyer 		 * and does not run iconv(), this variable has little use.
394fd1efedcSConrad Meyer 		 */
395fd1efedcSConrad Meyer 		if (strncmp(buf, "LANG=", 5) == 0) {
396fd1efedcSConrad Meyer 			(void)setlocale(LC_ALL, buf + 5);
397fd1efedcSConrad Meyer 			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
398fd1efedcSConrad Meyer #ifdef WITH_ICONV
399fd1efedcSConrad Meyer 			if (!doall)
400fd1efedcSConrad Meyer 				set_new_encoding();
401fd1efedcSConrad Meyer #endif
402fd1efedcSConrad Meyer 			setnnames();
403fd1efedcSConrad Meyer 			continue;
404fd1efedcSConrad Meyer 		}
405fd1efedcSConrad Meyer 		/* Parse special definitions: Easter, Paskha etc */
406fd1efedcSConrad Meyer 		REPLACE("Easter=", 7, neaster);
407fd1efedcSConrad Meyer 		REPLACE("Paskha=", 7, npaskha);
408fd1efedcSConrad Meyer 		REPLACE("ChineseNewYear=", 15, ncny);
409fd1efedcSConrad Meyer 		REPLACE("NewMoon=", 8, nnewmoon);
410fd1efedcSConrad Meyer 		REPLACE("FullMoon=", 9, nfullmoon);
411fd1efedcSConrad Meyer 		REPLACE("MarEquinox=", 11, nmarequinox);
412fd1efedcSConrad Meyer 		REPLACE("SepEquinox=", 11, nsepequinox);
413fd1efedcSConrad Meyer 		REPLACE("JunSolstice=", 12, njunsolstice);
414fd1efedcSConrad Meyer 		REPLACE("DecSolstice=", 12, ndecsolstice);
415fd1efedcSConrad Meyer 		if (strncmp(buf, "SEQUENCE=", 9) == 0) {
416fd1efedcSConrad Meyer 			setnsequences(buf + 9);
417fd1efedcSConrad Meyer 			continue;
418fd1efedcSConrad Meyer 		}
419fd1efedcSConrad Meyer 
420fd1efedcSConrad Meyer 		/*
421fd1efedcSConrad Meyer 		 * If the line starts with a tab, the data has to be
422fd1efedcSConrad Meyer 		 * added to the previous line
423fd1efedcSConrad Meyer 		 */
424fd1efedcSConrad Meyer 		if (buf[0] == '\t') {
425fd1efedcSConrad Meyer 			for (i = 0; i < count; i++)
426fd1efedcSConrad Meyer 				event_continue(events[i], buf);
427fd1efedcSConrad Meyer 			continue;
428fd1efedcSConrad Meyer 		}
429fd1efedcSConrad Meyer 
430fd1efedcSConrad Meyer 		/* Get rid of leading spaces (non-standard) */
431fd1efedcSConrad Meyer 		while (isspace((unsigned char)buf[0]))
432fd1efedcSConrad Meyer 			memcpy(buf, buf + 1, strlen(buf));
433fd1efedcSConrad Meyer 
434fd1efedcSConrad Meyer 		/* No tab in the line, then not a valid line */
435fd1efedcSConrad Meyer 		if ((pp = strchr(buf, '\t')) == NULL)
436fd1efedcSConrad Meyer 			continue;
437fd1efedcSConrad Meyer 
438fd1efedcSConrad Meyer 		/* Trim spaces in front of the tab */
439fd1efedcSConrad Meyer 		while (isspace((unsigned char)pp[-1]))
440fd1efedcSConrad Meyer 			pp--;
441fd1efedcSConrad Meyer 
442fd1efedcSConrad Meyer 		p = *pp;
443fd1efedcSConrad Meyer 		*pp = '\0';
444fd1efedcSConrad Meyer 		if ((count = parsedaymonth(buf, year, month, day, &flags,
445fd1efedcSConrad Meyer 		    extradata)) == 0)
446fd1efedcSConrad Meyer 			continue;
447fd1efedcSConrad Meyer 		*pp = p;
448fd1efedcSConrad Meyer 		if (count < 0) {
449fd1efedcSConrad Meyer 			/* Show error status based on return value */
450fd1efedcSConrad Meyer 			if (debug)
451fd1efedcSConrad Meyer 				fprintf(stderr, "Ignored: %s\n", buf);
452fd1efedcSConrad Meyer 			if (count == -1)
453fd1efedcSConrad Meyer 				continue;
454fd1efedcSConrad Meyer 			count = -count + 1;
455fd1efedcSConrad Meyer 		}
456fd1efedcSConrad Meyer 
457fd1efedcSConrad Meyer 		/* Find the last tab */
458fd1efedcSConrad Meyer 		while (pp[1] == '\t')
459fd1efedcSConrad Meyer 			pp++;
460fd1efedcSConrad Meyer 
461fd1efedcSConrad Meyer 		if (d_first < 0)
462fd1efedcSConrad Meyer 			d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
463fd1efedcSConrad Meyer 
464fd1efedcSConrad Meyer 		for (i = 0; i < count; i++) {
465fd1efedcSConrad Meyer 			tm.tm_mon = month[i] - 1;
466fd1efedcSConrad Meyer 			tm.tm_mday = day[i];
467fd1efedcSConrad Meyer 			tm.tm_year = year[i] - 1900;
468fd1efedcSConrad Meyer 			(void)strftime(dbuf, sizeof(dbuf),
469fd1efedcSConrad Meyer 			    d_first ? "%e %b" : "%b %e", &tm);
470fd1efedcSConrad Meyer 			if (debug)
471fd1efedcSConrad Meyer 				fprintf(stderr, "got %s\n", pp);
472fd1efedcSConrad Meyer 			events[i] = event_add(year[i], month[i], day[i], dbuf,
473fd1efedcSConrad Meyer 			    ((flags &= F_VARIABLE) != 0) ? 1 : 0, pp,
474fd1efedcSConrad Meyer 			    extradata[i]);
475fd1efedcSConrad Meyer 		}
476fd1efedcSConrad Meyer 	}
477fd1efedcSConrad Meyer 
478fd1efedcSConrad Meyer 	free(line);
479fd1efedcSConrad Meyer 	fclose(in);
480fd1efedcSConrad Meyer 
481fd1efedcSConrad Meyer 	return (0);
482fd1efedcSConrad Meyer }
483fd1efedcSConrad Meyer 
484fd1efedcSConrad Meyer void
485fd1efedcSConrad Meyer cal(void)
486fd1efedcSConrad Meyer {
487fd1efedcSConrad Meyer 	FILE *fpin;
488fd1efedcSConrad Meyer 	FILE *fpout;
489fd1efedcSConrad Meyer 	int i;
490fd1efedcSConrad Meyer 
491fd1efedcSConrad Meyer 	for (i = 0; i < MAXCOUNT; i++)
492fd1efedcSConrad Meyer 		extradata[i] = (char *)calloc(1, 20);
493fd1efedcSConrad Meyer 
494fd1efedcSConrad Meyer 
495fd1efedcSConrad Meyer 	if ((fpin = opencalin()) == NULL)
496fd1efedcSConrad Meyer 		return;
497fd1efedcSConrad Meyer 
498fd1efedcSConrad Meyer 	if ((fpout = opencalout()) == NULL) {
499fd1efedcSConrad Meyer 		fclose(fpin);
500fd1efedcSConrad Meyer 		return;
501fd1efedcSConrad Meyer 	}
502fd1efedcSConrad Meyer 
503fd1efedcSConrad Meyer 	if (cal_parse(fpin, fpout))
504fd1efedcSConrad Meyer 		return;
505fd1efedcSConrad Meyer 
506fd1efedcSConrad Meyer 	event_print_all(fpout);
507fd1efedcSConrad Meyer 	closecal(fpout);
508fd1efedcSConrad Meyer }
509fd1efedcSConrad Meyer 
510fd1efedcSConrad Meyer FILE *
511fd1efedcSConrad Meyer opencalin(void)
512fd1efedcSConrad Meyer {
513fd1efedcSConrad Meyer 	struct stat sbuf;
514fd1efedcSConrad Meyer 	FILE *fpin;
515fd1efedcSConrad Meyer 
516fd1efedcSConrad Meyer 	/* open up calendar file */
517fd1efedcSConrad Meyer 	if ((fpin = fopen(calendarFile, "r")) == NULL) {
518fd1efedcSConrad Meyer 		if (doall) {
519fd1efedcSConrad Meyer 			if (chdir(calendarHomes[0]) != 0)
520fd1efedcSConrad Meyer 				return (NULL);
521fd1efedcSConrad Meyer 			if (stat(calendarNoMail, &sbuf) == 0)
522fd1efedcSConrad Meyer 				return (NULL);
523fd1efedcSConrad Meyer 			if ((fpin = fopen(calendarFile, "r")) == NULL)
524fd1efedcSConrad Meyer 				return (NULL);
525fd1efedcSConrad Meyer 		} else {
526fd1efedcSConrad Meyer 			fpin = cal_fopen(calendarFile);
527fd1efedcSConrad Meyer 		}
528fd1efedcSConrad Meyer 	}
529fd1efedcSConrad Meyer 	return (fpin);
530fd1efedcSConrad Meyer }
531fd1efedcSConrad Meyer 
532fd1efedcSConrad Meyer FILE *
533fd1efedcSConrad Meyer opencalout(void)
534fd1efedcSConrad Meyer {
535fd1efedcSConrad Meyer 	int fd;
536fd1efedcSConrad Meyer 
537fd1efedcSConrad Meyer 	/* not reading all calendar files, just set output to stdout */
538fd1efedcSConrad Meyer 	if (!doall)
539fd1efedcSConrad Meyer 		return (stdout);
540fd1efedcSConrad Meyer 
541fd1efedcSConrad Meyer 	/* set output to a temporary file, so if no output don't send mail */
542fd1efedcSConrad Meyer 	snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
543fd1efedcSConrad Meyer 	if ((fd = mkstemp(path)) < 0)
544fd1efedcSConrad Meyer 		return (NULL);
545fd1efedcSConrad Meyer 	return (fdopen(fd, "w+"));
546fd1efedcSConrad Meyer }
547fd1efedcSConrad Meyer 
548fd1efedcSConrad Meyer void
549fd1efedcSConrad Meyer closecal(FILE *fp)
550fd1efedcSConrad Meyer {
551fd1efedcSConrad Meyer 	struct stat sbuf;
552fd1efedcSConrad Meyer 	int nread, pdes[2], status;
553fd1efedcSConrad Meyer 	char buf[1024];
554fd1efedcSConrad Meyer 
555fd1efedcSConrad Meyer 	if (!doall)
556fd1efedcSConrad Meyer 		return;
557fd1efedcSConrad Meyer 
558fd1efedcSConrad Meyer 	rewind(fp);
559fd1efedcSConrad Meyer 	if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
560fd1efedcSConrad Meyer 		goto done;
561fd1efedcSConrad Meyer 	if (pipe(pdes) < 0)
562fd1efedcSConrad Meyer 		goto done;
563fd1efedcSConrad Meyer 	switch (fork()) {
564fd1efedcSConrad Meyer 	case -1:			/* error */
565fd1efedcSConrad Meyer 		(void)close(pdes[0]);
566fd1efedcSConrad Meyer 		(void)close(pdes[1]);
567fd1efedcSConrad Meyer 		goto done;
568fd1efedcSConrad Meyer 	case 0:
569fd1efedcSConrad Meyer 		/* child -- set stdin to pipe output */
570fd1efedcSConrad Meyer 		if (pdes[0] != STDIN_FILENO) {
571fd1efedcSConrad Meyer 			(void)dup2(pdes[0], STDIN_FILENO);
572fd1efedcSConrad Meyer 			(void)close(pdes[0]);
573fd1efedcSConrad Meyer 		}
574fd1efedcSConrad Meyer 		(void)close(pdes[1]);
575fd1efedcSConrad Meyer 		execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
576fd1efedcSConrad Meyer 		    "\"Reminder Service\"", (char *)NULL);
577fd1efedcSConrad Meyer 		warn(_PATH_SENDMAIL);
578fd1efedcSConrad Meyer 		_exit(1);
579fd1efedcSConrad Meyer 	}
580fd1efedcSConrad Meyer 	/* parent -- write to pipe input */
581fd1efedcSConrad Meyer 	(void)close(pdes[0]);
582fd1efedcSConrad Meyer 
583fd1efedcSConrad Meyer 	write(pdes[1], "From: \"Reminder Service\" <", 26);
584fd1efedcSConrad Meyer 	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
585fd1efedcSConrad Meyer 	write(pdes[1], ">\nTo: <", 7);
586fd1efedcSConrad Meyer 	write(pdes[1], pw->pw_name, strlen(pw->pw_name));
587fd1efedcSConrad Meyer 	write(pdes[1], ">\nSubject: ", 11);
588fd1efedcSConrad Meyer 	write(pdes[1], dayname, strlen(dayname));
589fd1efedcSConrad Meyer 	write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30);
590fd1efedcSConrad Meyer 
591fd1efedcSConrad Meyer 	while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
592fd1efedcSConrad Meyer 		(void)write(pdes[1], buf, nread);
593fd1efedcSConrad Meyer 	(void)close(pdes[1]);
594fd1efedcSConrad Meyer done:	(void)fclose(fp);
595fd1efedcSConrad Meyer 	(void)unlink(path);
596fd1efedcSConrad Meyer 	while (wait(&status) >= 0);
597fd1efedcSConrad Meyer }
598