1/*	$NetBSD: dc.c,v 1.2 2017/04/10 16:37:48 christos Exp $	*/
2/*	$OpenBSD: dc.c,v 1.18 2016/07/17 17:30:47 otto Exp $	*/
3
4/*
5 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19#include <sys/cdefs.h>
20__RCSID("$NetBSD: dc.c,v 1.2 2017/04/10 16:37:48 christos Exp $");
21
22#include <sys/stat.h>
23#include <err.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "extern.h"
30
31static __dead void	usage(void);
32
33static __dead void
34usage(void)
35{
36	(void)fprintf(stderr, "usage: %s [-x] [-e expression] [file]\n",
37	    getprogname());
38	exit(1);
39}
40
41int
42dc_main(int argc, char *argv[])
43{
44	int		ch;
45	bool		extended_regs = false;
46	FILE		*file;
47	struct source	src;
48	char		*buf, *p;
49	struct stat	st;
50
51	if ((buf = strdup("")) == NULL)
52		err(1, NULL);
53	/* accept and ignore a single dash to be 4.4BSD dc(1) compatible */
54	optind = 1;
55	optreset = 1;
56	while ((ch = getopt(argc, argv, "e:x-")) != -1) {
57		switch (ch) {
58		case 'e':
59			p = buf;
60			if (asprintf(&buf, "%s %s", buf, optarg) == -1)
61				err(1, NULL);
62			free(p);
63			break;
64		case 'x':
65			extended_regs = true;
66			break;
67		case '-':
68			break;
69		default:
70			usage();
71		}
72	}
73	argc -= optind;
74	argv += optind;
75
76	init_bmachine(extended_regs);
77	(void)setvbuf(stdout, NULL, _IOLBF, 0);
78	(void)setvbuf(stderr, NULL, _IOLBF, 0);
79
80	if (argc > 1)
81		usage();
82	if (buf[0] != '\0') {
83		src_setstring(&src, buf);
84		reset_bmachine(&src);
85		eval();
86		free(buf);
87		if (argc == 0)
88			return (0);
89	}
90	if (argc == 1) {
91		file = fopen(argv[0], "r");
92		if (file == NULL)
93			err(1, "cannot open file %s", argv[0]);
94
95#ifdef __OpenBSD__
96		if (pledge("stdio", NULL) == -1)
97			err(1, "pledge");
98#endif
99
100		if (fstat(fileno(file), &st) == -1)
101			err(1, "%s", argv[0]);
102		if (S_ISDIR(st.st_mode))
103			errc(1, EISDIR, "%s", argv[0]);
104		src_setstream(&src, file);
105		reset_bmachine(&src);
106		eval();
107		(void)fclose(file);
108		/*
109		 * BSD and Solaris dc(1) continue with stdin after processing
110		 * the file given as the argument. We follow GNU dc(1).
111		 */
112		 return (0);
113	}
114
115#ifdef __OpenBSD__
116	if (pledge("stdio", NULL) == -1)
117		err(1, "pledge");
118#endif
119
120	src_setstream(&src, stdin);
121	reset_bmachine(&src);
122	eval();
123
124	return (0);
125}
126