1202719Sgabor/*	$OpenBSD: dc.c,v 1.11 2009/10/27 23:59:37 deraadt Exp $	*/
2202719Sgabor
3202719Sgabor/*
4202719Sgabor * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
5202719Sgabor * Copyright (c) 2009, Gabor Kovesdan <gabor@FreeBSD.org>
6202719Sgabor *
7202719Sgabor * Permission to use, copy, modify, and distribute this software for any
8202719Sgabor * purpose with or without fee is hereby granted, provided that the above
9202719Sgabor * copyright notice and this permission notice appear in all copies.
10202719Sgabor *
11202719Sgabor * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12202719Sgabor * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13202719Sgabor * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14202719Sgabor * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15202719Sgabor * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16202719Sgabor * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17202719Sgabor * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18202719Sgabor */
19202719Sgabor
20202719Sgabor#include <sys/cdefs.h>
21202719Sgabor__FBSDID("$FreeBSD: stable/11/usr.bin/dc/dc.c 332463 2018-04-13 03:30:10Z kevans $");
22202719Sgabor
23202719Sgabor#include <sys/stat.h>
24202719Sgabor
25332463Skevans#include <capsicum_helpers.h>
26202719Sgabor#include <ctype.h>
27202719Sgabor#include <err.h>
28202719Sgabor#include <errno.h>
29332463Skevans#include <fcntl.h>
30202719Sgabor#include <getopt.h>
31202719Sgabor#include <stdio.h>
32202719Sgabor#include <stdlib.h>
33202719Sgabor#include <string.h>
34202719Sgabor#include <unistd.h>
35202719Sgabor
36202719Sgabor#include "extern.h"
37202719Sgabor
38202719Sgabor#define	DC_VER		"1.3-FreeBSD"
39202719Sgabor
40202719Sgaborstatic void		 usage(void);
41202719Sgabor
42202719Sgaborextern char		*__progname;
43202719Sgabor
44227163Sedstatic struct source	 src;
45202719Sgabor
46227163Sedstatic const struct option long_options[] =
47202719Sgabor{
48202719Sgabor	{"expression",		required_argument,	NULL,	'e'},
49202719Sgabor	{"file",		required_argument,	NULL,	'f'},
50202719Sgabor	{"help",		no_argument,		NULL,	'h'},
51202719Sgabor	{"version",		no_argument,		NULL,	'V'}
52202719Sgabor};
53202719Sgabor
54202719Sgaborstatic void
55202719Sgaborusage(void)
56202719Sgabor{
57202719Sgabor	fprintf(stderr, "usage: %s [-hVx] [-e expression] [file]\n",
58202719Sgabor	    __progname);
59202719Sgabor	exit(1);
60202719Sgabor}
61202719Sgabor
62202719Sgaborstatic void
63332463Skevansprocfd(int fd, char *fname) {
64203443Sgabor	struct stat st;
65203443Sgabor	FILE *file;
66202719Sgabor
67332463Skevans	file = fdopen(fd, "r");
68202719Sgabor	if (file == NULL)
69202719Sgabor		err(1, "cannot open file %s", fname);
70202719Sgabor	if (fstat(fileno(file), &st) == -1)
71202719Sgabor		err(1, "%s", fname);
72202719Sgabor	if (S_ISDIR(st.st_mode)) {
73202719Sgabor		errno = EISDIR;
74202719Sgabor		err(1, "%s", fname);
75202719Sgabor	}
76202719Sgabor	src_setstream(&src, file);
77202719Sgabor	reset_bmachine(&src);
78202719Sgabor	eval();
79202719Sgabor	fclose(file);
80202719Sgabor}
81202719Sgabor
82202719Sgaborint
83202719Sgabormain(int argc, char *argv[])
84202719Sgabor{
85332463Skevans	int ch, fd;
86203443Sgabor	bool extended_regs = false, preproc_done = false;
87202719Sgabor
88202719Sgabor	/* accept and ignore a single dash to be 4.4BSD dc(1) compatible */
89247441Sgjb	while ((ch = getopt_long(argc, argv, "e:f:hVx", long_options, NULL)) != -1) {
90202719Sgabor		switch (ch) {
91202719Sgabor		case 'e':
92208974Sgabor			if (!preproc_done)
93208867Sgabor				init_bmachine(extended_regs);
94202719Sgabor			src_setstring(&src, optarg);
95202719Sgabor			reset_bmachine(&src);
96202719Sgabor			eval();
97202719Sgabor			preproc_done = true;
98202719Sgabor			break;
99202719Sgabor		case 'f':
100208974Sgabor			if (!preproc_done)
101208867Sgabor				init_bmachine(extended_regs);
102332463Skevans			fd = open(optarg, O_RDONLY);
103332463Skevans			if (fd < 0)
104332463Skevans				err(1, "cannot open file %s", optarg);
105332463Skevans			procfd(fd, optarg);
106202719Sgabor			preproc_done = true;
107202719Sgabor			break;
108202719Sgabor		case 'x':
109202719Sgabor			extended_regs = true;
110202719Sgabor			break;
111202719Sgabor		case 'V':
112202719Sgabor			fprintf(stderr, "%s (BSD bc) %s\n", __progname, DC_VER);
113202719Sgabor			exit(0);
114202719Sgabor			break;
115202719Sgabor		case '-':
116202719Sgabor			break;
117202719Sgabor		case 'h':
118202719Sgabor			/* FALLTHROUGH */
119202719Sgabor		default:
120202719Sgabor			usage();
121202719Sgabor		}
122202719Sgabor	}
123202719Sgabor	argc -= optind;
124202719Sgabor	argv += optind;
125202719Sgabor
126208867Sgabor	if (!preproc_done)
127208867Sgabor		init_bmachine(extended_regs);
128315134Spfg	(void)setvbuf(stdout, NULL, _IOLBF, 0);
129315134Spfg	(void)setvbuf(stderr, NULL, _IOLBF, 0);
130203438Sgabor
131202719Sgabor	if (argc > 1)
132202719Sgabor		usage();
133202719Sgabor	if (argc == 1) {
134332463Skevans		fd = open(argv[0], O_RDONLY);
135332463Skevans		if (fd < 0)
136332463Skevans			err(1, "cannot open file %s", argv[0]);
137332463Skevans
138332463Skevans		if (caph_limit_stream(fd, CAPH_READ) < 0 ||
139332463Skevans		    caph_limit_stdio() < 0 ||
140332463Skevans		    (cap_enter() < 0 && errno != ENOSYS))
141332463Skevans			err(1, "capsicum");
142332463Skevans
143332463Skevans		procfd(fd, argv[0]);
144202719Sgabor		preproc_done = true;
145202719Sgabor	}
146202719Sgabor	if (preproc_done)
147202719Sgabor		return (0);
148202719Sgabor
149332463Skevans	if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS))
150332463Skevans		err(1, "capsicum");
151202719Sgabor	src_setstream(&src, stdin);
152202719Sgabor	reset_bmachine(&src);
153202719Sgabor	eval();
154202719Sgabor
155202719Sgabor	return (0);
156202719Sgabor}
157