More changes for gcc2 to use lib.
[unix-history] / bin / sh / main.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38char copyright[] =
39"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
40 All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)main.c 5.2 (Berkeley) 3/13/91";
45#endif /* not lint */
46
47#include <signal.h>
48#include <fcntl.h>
49#include "shell.h"
50#include "main.h"
51#include "mail.h"
52#include "options.h"
53#include "output.h"
54#include "parser.h"
55#include "nodes.h"
56#include "eval.h"
57#include "jobs.h"
58#include "input.h"
59#include "trap.h"
60#if ATTY
61#include "var.h"
62#endif
63#include "memalloc.h"
64#include "error.h"
65#include "init.h"
66#include "mystring.h"
67
68#define PROFILE 0
69
70int rootpid;
71int rootshell;
72STATIC union node *curcmd;
73STATIC union node *prevcmd;
74extern int errno;
75#if PROFILE
76short profile_buf[16384];
77extern int etext();
78#endif
79
80#ifdef __STDC__
81STATIC void read_profile(char *);
82char *getenv(char *);
83#else
84STATIC void read_profile();
85char *getenv();
86#endif
87
88
89/*
90 * Main routine. We initialize things, parse the arguments, execute
91 * profiles if we're a login shell, and then call cmdloop to execute
92 * commands. The setjmp call sets up the location to jump to when an
93 * exception occurs. When an exception occurs the variable "state"
94 * is used to figure out how far we had gotten.
95 */
96
97main(argc, argv) char **argv; {
98 struct jmploc jmploc;
99 struct stackmark smark;
100 volatile int state;
101 char *shinit;
102
103#if PROFILE
104 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
105#endif
106 state = 0;
107 if (setjmp(jmploc.loc)) {
108 /*
109 * When a shell procedure is executed, we raise the
110 * exception EXSHELLPROC to clean up before executing
111 * the shell procedure.
112 */
113 if (exception == EXSHELLPROC) {
114 rootpid = getpid();
115 rootshell = 1;
116 minusc = NULL;
117 state = 3;
118 } else if (state == 0 || iflag == 0 || ! rootshell)
119 exitshell(2);
120 reset();
121#if ATTY
122 if (exception == EXINT
123 && (! attyset() || equal(termval(), "emacs"))) {
124#else
125 if (exception == EXINT) {
126#endif
127 out2c('\n');
128 flushout(&errout);
129 }
130 popstackmark(&smark);
131 FORCEINTON; /* enable interrupts */
132 if (state == 1)
133 goto state1;
134 else if (state == 2)
135 goto state2;
136 else
137 goto state3;
138 }
139 handler = &jmploc;
140#ifdef DEBUG
141 opentrace();
142 trputs("Shell args: "); trargs(argv);
143#endif
144 rootpid = getpid();
145 rootshell = 1;
146 init();
147 setstackmark(&smark);
148 procargs(argc, argv);
149 if (argv[0] && argv[0][0] == '-') {
150 state = 1;
151 read_profile("/etc/profile");
152state1:
153 state = 2;
154 read_profile(".profile");
155 } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) {
156 state = 2;
157 evalstring(shinit);
158 }
159state2:
160 state = 3;
161 if (minusc) {
162 evalstring(minusc);
163 }
164 if (sflag || minusc == NULL) {
165state3:
166 cmdloop(1);
167 }
168#if PROFILE
169 monitor(0);
170#endif
171 exitshell(exitstatus);
172}
173
174
175/*
176 * Read and execute commands. "Top" is nonzero for the top level command
177 * loop; it turns on prompting if the shell is interactive.
178 */
179
180void
181cmdloop(top) {
182 union node *n;
183 struct stackmark smark;
184 int inter;
185 int numeof;
186
187 TRACE(("cmdloop(%d) called\n", top));
188 setstackmark(&smark);
189 numeof = 0;
190 for (;;) {
191 if (pendingsigs)
192 dotrap();
193 inter = 0;
194 if (iflag && top) {
195 inter++;
196 showjobs(1);
197 chkmail(0);
198 flushout(&output);
199 }
200 n = parsecmd(inter);
201#ifdef DEBUG
202 /* showtree(n); */
203#endif
204 if (n == NEOF) {
205 if (Iflag == 0 || numeof >= 50)
206 break;
207 out2str("\nUse \"exit\" to leave shell.\n");
208 numeof++;
209 } else if (n != NULL && nflag == 0) {
210 if (inter) {
211 INTOFF;
212 if (prevcmd)
213 freefunc(prevcmd);
214 prevcmd = curcmd;
215 curcmd = copyfunc(n);
216 INTON;
217 }
218 evaltree(n, 0);
219#ifdef notdef
220 if (exitstatus) /*DEBUG*/
221 outfmt(&errout, "Exit status 0x%X\n", exitstatus);
222#endif
223 }
224 popstackmark(&smark);
225 }
226 popstackmark(&smark); /* unnecessary */
227}
228
229
230
231/*
232 * Read /etc/profile or .profile. Return on error.
233 */
234
235STATIC void
236read_profile(name)
237 char *name;
238 {
239 int fd;
240
241 INTOFF;
242 if ((fd = open(name, O_RDONLY)) >= 0)
243 setinputfd(fd, 1);
244 INTON;
245 if (fd < 0)
246 return;
247 cmdloop(0);
248 popfile();
249}
250
251
252
253/*
254 * Read a file containing shell functions.
255 */
256
257void
258readcmdfile(name)
259 char *name;
260 {
261 int fd;
262
263 INTOFF;
264 if ((fd = open(name, O_RDONLY)) >= 0)
265 setinputfd(fd, 1);
266 else
267 error("Can't open %s", name);
268 INTON;
269 cmdloop(0);
270 popfile();
271}
272
273
274
275/*
276 * Take commands from a file. To be compatable we should do a path
277 * search for the file, but a path search doesn't make any sense.
278 */
279
280dotcmd(argc, argv) char **argv; {
281 exitstatus = 0;
282 if (argc >= 2) { /* That's what SVR2 does */
283 setinputfile(argv[1], 1);
284 commandname = argv[1];
285 cmdloop(0);
286 popfile();
287 }
288 return exitstatus;
289}
290
291
292exitcmd(argc, argv) char **argv; {
293 if (argc > 1)
294 exitstatus = number(argv[1]);
295 exitshell(exitstatus);
296}
297
298
299lccmd(argc, argv) char **argv; {
300 if (argc > 1) {
301 defun(argv[1], prevcmd);
302 return 0;
303 } else {
304 INTOFF;
305 freefunc(curcmd);
306 curcmd = prevcmd;
307 prevcmd = NULL;
308 INTON;
309 evaltree(curcmd, 0);
310 return exitstatus;
311 }
312}
313
314
315
316#ifdef notdef
317/*
318 * Should never be called.
319 */
320
321void
322exit(exitstatus) {
323 _exit(exitstatus);
324}
325#endif