1/*	$OpenBSD: main.c,v 1.31 2021/10/23 11:22:48 mestre Exp $	*/
2/*	$NetBSD: main.c,v 1.4 1995/04/27 21:22:25 mycroft Exp $	*/
3
4/*-
5 * Copyright (c) 1990, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Ed James.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36/*
37 * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
38 *
39 * Copy permission is hereby granted provided that this notice is
40 * retained on all partial or complete copies.
41 *
42 * For more info on this and all of my stuff, mail edjames@berkeley.edu.
43 */
44
45#include <err.h>
46#include <signal.h>
47#include <stdlib.h>
48#include <string.h>
49#include <termios.h>
50#include <time.h>
51#include <unistd.h>
52
53#include "extern.h"
54#include "pathnames.h"
55
56int
57main(int argc, char *argv[])
58{
59	int			ch;
60	int			f_usage = 0, f_list = 0, f_showscore = 0;
61	int			f_printpath = 0;
62	const char		*file = NULL;
63	char			*seed;
64	struct sigaction	sa;
65	struct itimerval	itv;
66
67	open_score_file();
68
69	start_time = time(0);
70	makenoise = 1;
71	seed = NULL;
72
73	while ((ch = getopt(argc, argv, "f:g:hlpqr:st")) != -1) {
74		switch (ch) {
75		case 'f':
76		case 'g':
77			file = optarg;
78			break;
79		case 'l':
80			f_list = 1;
81			break;
82		case 'p':
83			f_printpath = 1;
84			break;
85		case 'q':
86			makenoise = 0;
87			break;
88		case 'r':
89			seed = optarg;
90			break;
91		case 's':
92		case 't':
93			f_showscore = 1;
94			break;
95		case 'h':
96		default:
97			f_usage = 1;
98			break;
99		}
100	}
101	argc -= optind;
102	argv += optind;
103
104	if (argc > 0)
105		f_usage = 1;
106
107	if (seed != NULL)
108		setseed(seed);
109
110	if (f_usage)
111		fprintf(stderr,
112		    "usage: %s [-lpqst] [-f game] [-g game] [-r seed]\n",
113		    getprogname());
114	if (f_showscore)
115		log_score(1);
116	if (f_list)
117		list_games();
118	if (f_printpath) {
119		size_t	len;
120		char	buf[256];
121
122		strlcpy(buf, _PATH_GAMES, sizeof buf);
123		len = strlen(buf);
124		if (len != 0 && buf[len - 1] == '/')
125			buf[len - 1] = '\0';
126		puts(buf);
127	}
128
129	if (f_usage || f_showscore || f_list || f_printpath)
130		return 0;
131
132	if (file == NULL)
133		file = default_game();
134	else
135		file = okay_game(file);
136
137	if (file == NULL || read_file(file) < 0)
138		return 1;
139
140	setup_screen(sp);
141
142	if (pledge("stdio rpath wpath cpath flock tty", NULL) == -1)
143		err(1, "pledge");
144
145	addplane();
146
147	signal(SIGINT, quit);
148	signal(SIGQUIT, quit);
149	signal(SIGTSTP, SIG_IGN);
150	signal(SIGSTOP, SIG_IGN);
151	signal(SIGHUP, log_score_quit);
152	signal(SIGTERM, log_score_quit);
153
154	tcgetattr(fileno(stdin), &tty_start);
155	tty_new = tty_start;
156	tty_new.c_lflag &= ~(ICANON|ECHO);
157	tty_new.c_iflag |= ICRNL;
158	tty_new.c_cc[VMIN] = 1;
159	tty_new.c_cc[VTIME] = 0;
160	tcsetattr(fileno(stdin), TCSADRAIN, &tty_new);
161
162	memset(&sa, 0, sizeof sa);
163	sa.sa_handler = update;
164	sigemptyset(&sa.sa_mask);
165	sigaddset(&sa.sa_mask, SIGALRM);
166	sigaddset(&sa.sa_mask, SIGINT);
167	sa.sa_flags = 0;
168	sigaction(SIGALRM, &sa, (struct sigaction *)0);
169
170	itv.it_value.tv_sec = 0;
171	itv.it_value.tv_usec = 1;
172	itv.it_interval.tv_sec = sp->update_secs;
173	itv.it_interval.tv_usec = 0;
174	setitimer(ITIMER_REAL, &itv, NULL);
175
176	for (;;) {
177		if (getcommand() != 1)
178			planewin();
179		else {
180			itv.it_value.tv_sec = 0;
181			itv.it_value.tv_usec = 0;
182			setitimer(ITIMER_REAL, &itv, NULL);
183
184			update(0);
185
186			itv.it_value.tv_sec = sp->update_secs;
187			itv.it_value.tv_usec = 0;
188			itv.it_interval.tv_sec = sp->update_secs;
189			itv.it_interval.tv_usec = 0;
190			setitimer(ITIMER_REAL, &itv, NULL);
191		}
192	}
193}
194
195int
196read_file(const char *s)
197{
198	extern FILE	*yyin;
199	int		retval;
200
201	file = s;
202	yyin = fopen(s, "r");
203	if (yyin == NULL) {
204		warn("fopen %s", s);
205		return (-1);
206	}
207	retval = yyparse();
208	fclose(yyin);
209
210	if (retval != 0)
211		return (-1);
212	else
213		return (0);
214}
215
216const char	*
217default_game(void)
218{
219	FILE		*fp;
220	static char	file[256];
221	char		line[256], games[256];
222
223	strlcpy(games, _PATH_GAMES, sizeof games);
224	strlcat(games, GAMES, sizeof games);
225
226	if ((fp = fopen(games, "r")) == NULL) {
227		warn("fopen %s", games);
228		return (NULL);
229	}
230	if (fgets(line, sizeof(line), fp) == NULL) {
231		warnx("%s: no default game available", games);
232		fclose(fp);
233		return (NULL);
234	}
235	fclose(fp);
236
237	line[strcspn(line, "\n")] = '\0';
238	if (strlen(line) + strlen(_PATH_GAMES) >= sizeof(file)) {
239		warnx("default game name too long");
240		return (NULL);
241	}
242	strlcpy(file, _PATH_GAMES, sizeof file);
243	strlcat(file, line, sizeof file);
244	return (file);
245}
246
247const char	*
248okay_game(const char *s)
249{
250	FILE		*fp;
251	static char	file[256];
252	const char	*ret = NULL;
253	char		line[256], games[256];
254
255	strlcpy(games, _PATH_GAMES, sizeof games);
256	strlcat(games, GAMES, sizeof games);
257
258	if ((fp = fopen(games, "r")) == NULL) {
259		warn("fopen %s", games);
260		return (NULL);
261	}
262	while (fgets(line, sizeof(line), fp) != NULL) {
263		line[strcspn(line, "\n")] = '\0';
264		if (strcmp(s, line) == 0) {
265			if (strlen(line) + strlen(_PATH_GAMES) >= sizeof(file)) {
266				warnx("game name too long");
267				return (NULL);
268			}
269			strlcpy(file, _PATH_GAMES, sizeof file);
270			strlcat(file, line, sizeof file);
271			ret = file;
272			break;
273		}
274	}
275	fclose(fp);
276	if (ret == NULL) {
277		test_mode = 1;
278		ret = s;
279		fprintf(stderr, "%s: %s: game not found\n", games, s);
280		fprintf(stderr, "Your score will not be logged.\n");
281		sleep(2);	/* give the guy time to read it */
282	}
283	return (ret);
284}
285
286int
287list_games(void)
288{
289	FILE		*fp;
290	char		line[256], games[256];
291	int		num_games = 0;
292
293	strlcpy(games, _PATH_GAMES, sizeof games);
294	strlcat(games, GAMES, sizeof games);
295
296	if ((fp = fopen(games, "r")) == NULL) {
297		warn("fopen %s", games);
298		return (-1);
299	}
300	puts("available games:");
301	while (fgets(line, sizeof(line), fp) != NULL) {
302		line[strcspn(line, "\n")] = '\0';
303		printf("	%s\n", line);
304		num_games++;
305	}
306	fclose(fp);
307	if (num_games == 0) {
308		fprintf(stderr, "%s: no games available\n", games);
309		return (-1);
310	}
311	return (0);
312}
313