Commit | Line | Data |
---|---|---|
dbf02a84 WJ |
1 | /* |
2 | * | |
3 | * init.c - main loop and initialization routines | |
4 | * | |
5 | * This file is part of zsh, the Z shell. | |
6 | * | |
7 | * This software is Copyright 1992 by Paul Falstad | |
8 | * | |
9 | * Permission is hereby granted to copy, reproduce, redistribute or otherwise | |
10 | * use this software as long as: there is no monetary profit gained | |
11 | * specifically from the use or reproduction of this software, it is not | |
12 | * sold, rented, traded or otherwise marketed, and this copyright notice is | |
13 | * included prominently in any copy made. | |
14 | * | |
15 | * The author make no claims as to the fitness or correctness of this software | |
16 | * for any use whatsoever, and it is provided as is. Any use of this software | |
17 | * is at the user's own risk. | |
18 | * | |
19 | */ | |
20 | ||
21 | #define GLOBALS | |
22 | #include "zsh.h" | |
23 | #include <pwd.h> | |
24 | ||
25 | void main(argc,argv,envp) /**/ | |
26 | int argc; char **argv; char **envp; | |
27 | { | |
28 | int notect = 0; | |
29 | ||
30 | #ifdef LC_ALL | |
31 | setlocale(LC_ALL, ""); | |
32 | #endif | |
33 | environ = envp; | |
34 | meminit(); | |
35 | setflags(); | |
36 | parseargs(argv); | |
37 | setmoreflags(); | |
38 | setupvals(); | |
39 | initialize(); | |
40 | heapalloc(); | |
41 | runscripts(); | |
42 | for(;;) | |
43 | { | |
44 | do | |
45 | loop(); | |
46 | while (tok != ENDINPUT); | |
47 | if (!(isset(IGNOREEOF) && interact)) | |
48 | { | |
49 | #if 0 | |
50 | if (interact) | |
51 | fputs(islogin ? "logout\n" : "exit\n",stderr); | |
52 | #endif | |
53 | zexit(NULL); | |
54 | continue; | |
55 | } | |
56 | zerrnam("zsh",(!islogin) ? "use 'exit' to exit." | |
57 | : "use 'logout' to logout.",NULL,0); | |
58 | notect++; | |
59 | if (notect == 10) | |
60 | zexit(NULL); | |
61 | } | |
62 | } | |
63 | ||
64 | /* keep executing lists until EOF found */ | |
65 | ||
66 | void loop() /**/ | |
67 | { | |
68 | List list; | |
69 | Heap h = (Heap) peekfirst(heaplist); | |
70 | ||
71 | pushheap(); | |
72 | for(;;) | |
73 | { | |
74 | freeheap(); | |
75 | if (interact && isset(SHINSTDIN)) | |
76 | preprompt(); | |
77 | hbegin(); /* init history mech */ | |
78 | intr(); /* interrupts on */ | |
79 | ainit(); /* init alias mech */ | |
80 | lexinit(); | |
81 | errflag = 0; | |
82 | if (!(list = parse_event())) | |
83 | { /* if we couldn't parse a list */ | |
84 | hend(); | |
85 | if (tok == ENDINPUT && !errflag) | |
86 | break; | |
87 | continue; | |
88 | } | |
89 | if (hend()) | |
90 | { | |
91 | if (stopmsg) /* unset 'you have stopped jobs' flag */ | |
92 | stopmsg--; | |
93 | execlist(list); | |
94 | } | |
95 | if (ferror(stderr)) | |
96 | { | |
97 | zerr("write error",NULL,0); | |
98 | clearerr(stderr); | |
99 | } | |
100 | if (subsh) /* how'd we get this far in a subshell? */ | |
101 | exit(lastval); | |
102 | if ((!interact && errflag) || retflag) | |
103 | break; | |
104 | if ((opts['t'] == OPT_SET) || (lastval && opts[ERREXIT] == OPT_SET)) | |
105 | { | |
106 | if (sigtrapped[SIGEXIT]) | |
107 | dotrap(SIGEXIT); | |
108 | exit(lastval); | |
109 | } | |
110 | } | |
111 | while ((Heap) peekfirst(heaplist) != h) | |
112 | popheap(); | |
113 | } | |
114 | ||
115 | void setflags() /**/ | |
116 | { | |
117 | int c; | |
118 | ||
119 | for (c = 0; c != 32; c++) opts[c] = OPT_UNSET; | |
120 | for (c = 32; c != 128; c++) opts[c] = OPT_INVALID; | |
121 | for (c = 'a'; c <= 'z'; c++) opts[c] = opts[c-'a'+'A'] = OPT_UNSET; | |
122 | for (c = '0'; c <= '9'; c++) opts[c] = OPT_UNSET; | |
123 | opts['A'] = OPT_INVALID; | |
124 | opts['i'] = (isatty(0)) ? OPT_SET : OPT_UNSET; | |
125 | opts[BGNICE] = opts[NOTIFY] = OPT_SET; | |
126 | opts[USEZLE] = (interact && SHTTY != -1) ? OPT_SET : OPT_UNSET; | |
127 | opts[HASHCMDS] = opts[HASHLISTALL] = opts[HASHDIRS] = OPT_SET; | |
128 | } | |
129 | ||
130 | static char *cmd; | |
131 | ||
132 | void parseargs(argv) /**/ | |
133 | char **argv; | |
134 | { | |
135 | char **x; | |
136 | int bk = 0,action; | |
137 | Lklist paramlist; | |
138 | ||
139 | hackzero = argzero = *argv; | |
140 | opts[LOGINSHELL] = (**(argv++) == '-') ? OPT_SET : OPT_UNSET; | |
141 | SHIN = 0; | |
142 | while (!bk && *argv && (**argv == '-' || **argv == '+')) | |
143 | { | |
144 | action = (**argv == '-') ? OPT_SET : OPT_UNSET; | |
145 | while (*++*argv) { | |
146 | if (opts[**argv] == OPT_INVALID) { | |
147 | zerr("bad option: -%c",NULL,**argv); | |
148 | exit(1); | |
149 | } | |
150 | if (bk = **argv == 'b') break; | |
151 | if (**argv == 'c') { /* -c command */ | |
152 | argv++; | |
153 | if (!*argv) { | |
154 | zerr("string expected after -c",NULL,0); | |
155 | exit(1); | |
156 | } | |
157 | cmd = *argv; | |
158 | opts[INTERACTIVE] = OPT_UNSET; | |
159 | opts['c'] = OPT_SET; | |
160 | break; | |
161 | } else if (**argv == 'o') { | |
162 | int c; | |
163 | ||
164 | if (!*++*argv) | |
165 | argv++; | |
166 | if (!*argv) { | |
167 | zerr("string expected after -o",NULL,0); | |
168 | exit(1); | |
169 | } | |
170 | c = optlookup(*argv); | |
171 | if (c == -1) | |
172 | zerr("no such option: %s",*argv,0); | |
173 | else | |
174 | opts[c] = action; | |
175 | break; | |
176 | } else opts[**argv] = action; | |
177 | } | |
178 | argv++; | |
179 | } | |
180 | paramlist = newlist(); | |
181 | if (*argv) | |
182 | { | |
183 | if (opts[SHINSTDIN] == OPT_UNSET) | |
184 | { | |
185 | SHIN = movefd(open(argzero = *argv,O_RDONLY)); | |
186 | if (SHIN == -1) | |
187 | { | |
188 | zerr("can't open input file: %s",*argv,0); | |
189 | exit(1); | |
190 | } | |
191 | opts[INTERACTIVE] = OPT_UNSET; | |
192 | argv++; | |
193 | } | |
194 | while (*argv) | |
195 | addnode(paramlist,ztrdup(*argv++)); | |
196 | } | |
197 | else | |
198 | opts[SHINSTDIN] = OPT_SET; | |
199 | pparams = x = zcalloc((countnodes(paramlist)+1)*sizeof(char *)); | |
200 | while (*x++ = getnode(paramlist)); | |
201 | free(paramlist); | |
202 | argzero = ztrdup(argzero); | |
203 | } | |
204 | ||
205 | void setmoreflags() /**/ | |
206 | { | |
207 | int t0; | |
208 | long ttpgrp; | |
209 | ||
210 | /* stdout,stderr fully buffered */ | |
211 | #ifdef _IOFBF | |
212 | setvbuf(stdout,malloc(BUFSIZ),_IOFBF,BUFSIZ); | |
213 | setvbuf(stderr,malloc(BUFSIZ),_IOFBF,BUFSIZ); | |
214 | #else | |
215 | setbuffer(stdout,malloc(BUFSIZ),BUFSIZ); | |
216 | setbuffer(stderr,malloc(BUFSIZ),BUFSIZ); | |
217 | #endif | |
218 | subsh = 0; | |
219 | #ifndef NOCLOSEFUNNYFDS | |
220 | /* this works around a bug in some versions of in.rshd */ | |
221 | for (t0 = 3; t0 != 10; t0++) | |
222 | close(t0); | |
223 | #endif | |
224 | #ifdef JOB_CONTROL | |
225 | opts[MONITOR] = (interact) ? OPT_SET : OPT_UNSET; | |
226 | if (jobbing) { | |
227 | SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR)); | |
228 | if (SHTTY == -1) | |
229 | opts[MONITOR] = OPT_UNSET; | |
230 | else { | |
231 | #ifdef TIOCSETD | |
232 | #ifdef NTTYDISC | |
233 | int ldisc = NTTYDISC; | |
234 | ioctl(SHTTY, TIOCSETD, &ldisc); | |
235 | #endif | |
236 | #endif | |
237 | gettyinfo(&shttyinfo); /* get tty state */ | |
238 | #ifdef sgi | |
239 | if (shttyinfo.tio.c_cc[VSWTCH] <= 0) /* hack for irises */ | |
240 | shttyinfo.tio.c_cc[VSWTCH] = CSWTCH; | |
241 | #endif | |
242 | savedttyinfo = shttyinfo; | |
243 | } | |
244 | #ifdef sgi | |
245 | setpgrp(0,getpgrp(0)); | |
246 | #endif | |
247 | if ((mypgrp = getpgrp(0)) <= 0) | |
248 | opts[MONITOR] = OPT_UNSET; | |
249 | else while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) { | |
250 | sleep(1); | |
251 | mypgrp = getpgrp(0); | |
252 | if (mypgrp == gettygrp()) break; | |
253 | killpg(mypgrp,SIGTTIN); | |
254 | mypgrp = getpgrp(0); | |
255 | } | |
256 | } else | |
257 | SHTTY = -1; | |
258 | #else | |
259 | opts[MONITOR] = OPT_UNSET; | |
260 | SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR)); | |
261 | if (SHTTY != -1) { | |
262 | gettyinfo(&shttyinfo); | |
263 | savedttyinfo = shttyinfo; | |
264 | } | |
265 | #endif | |
266 | } | |
267 | ||
268 | void setupvals() /**/ | |
269 | { | |
270 | struct passwd *pswd; | |
271 | char *ptr,*s; | |
272 | static long bauds[] = { | |
273 | 0,50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400 | |
274 | }; | |
275 | ||
276 | curhist = 0; | |
277 | histsiz = DEFAULT_HISTSIZE; | |
278 | lithistsiz = 5; | |
279 | inithist(); | |
280 | mailcheck = logcheck = 60; | |
281 | dirstacksize = -1; | |
282 | listmax = 100; | |
283 | reporttime = -1; | |
284 | bangchar = '!'; | |
285 | hashchar = '#'; | |
286 | hatchar = '^'; | |
287 | termok = 0; | |
288 | curjob = prevjob = coprocin = coprocout = -1; | |
289 | shtimer = time(NULL); /* init $SECONDS */ | |
290 | srand((unsigned int) shtimer); | |
291 | /* build various hash tables; argument to newhtable is table size */ | |
292 | aliastab = newhtable(37); | |
293 | addreswords(); | |
294 | paramtab = newhtable(151); | |
295 | cmdnamtab = newhtable(37); | |
296 | compctltab = newhtable(13); | |
297 | initxbindtab(); | |
298 | nullcmd = ztrdup("cat"); | |
299 | readnullcmd = ztrdup("more"); | |
300 | prompt = ztrdup("%m%# "); | |
301 | prompt2 = ztrdup("> "); | |
302 | prompt3 = ztrdup("?# "); | |
303 | prompt4 = ztrdup("+ "); | |
304 | sprompt = ztrdup("zsh: correct `%R' to `%r' [nyae]? "); | |
305 | term = ztrdup(""); | |
306 | ppid = getppid(); | |
307 | #ifdef TIO | |
308 | #ifdef HAS_TCCRAP | |
309 | baud = cfgetospeed(&shttyinfo.tio); | |
310 | if (baud < 100) baud = bauds[baud]; /* aren't "standards" great?? */ | |
311 | #else | |
312 | baud = bauds[shttyinfo.tio.c_cflag & CBAUD]; | |
313 | #endif | |
314 | #else | |
315 | baud = bauds[shttyinfo.sgttyb.sg_ospeed]; | |
316 | #endif | |
317 | #ifdef TIOCGWINSZ | |
318 | if (!(columns = shttyinfo.winsize.ws_col)) | |
319 | columns = 80; | |
320 | if (!(lines = shttyinfo.winsize.ws_row)) | |
321 | lines = 24; | |
322 | #else | |
323 | columns = 80; | |
324 | lines = 24; | |
325 | #endif | |
326 | ifs = ztrdup(" \t\n"); | |
327 | if (pswd = getpwuid(getuid())) { | |
328 | username = ztrdup(pswd->pw_name); | |
329 | home = ztrdup(pswd->pw_dir); | |
330 | } else { | |
331 | username = ztrdup(""); | |
332 | home = ztrdup("/"); | |
333 | } | |
334 | if (ptr = zgetenv("LOGNAME")) | |
335 | logname = ztrdup(ptr); | |
336 | else | |
337 | logname = ztrdup(username); | |
338 | timefmt = ztrdup(DEFTIMEFMT); | |
339 | watchfmt = ztrdup(DEFWATCHFMT); | |
340 | if (!(ttystrname = ztrdup(ttyname(SHTTY)))) | |
341 | ttystrname = ztrdup(""); | |
342 | wordchars = ztrdup(DEFWORDCHARS); | |
343 | fceditparam = ztrdup(DEFFCEDIT); | |
344 | tmpprefix = ztrdup(DEFTMPPREFIX); | |
345 | postedit = ztrdup(""); | |
346 | if (ispwd(home)) pwd = ztrdup(home); | |
347 | else if ((ptr = zgetenv("PWD")) && ispwd(ptr)) pwd = ztrdup(ptr); | |
348 | else pwd = zgetwd(); | |
349 | oldpwd = ztrdup(pwd); | |
350 | hostnam = zalloc(256); | |
351 | underscore = ztrdup(""); | |
352 | gethostname(hostnam,256); | |
353 | mypid = getpid(); | |
354 | cdpath = mkarray(NULL); | |
355 | manpath = mkarray(NULL); | |
356 | fignore = mkarray(NULL); | |
357 | fpath = mkarray(NULL); | |
358 | mailpath = mkarray(NULL); | |
359 | watch = mkarray(NULL); | |
360 | hosts = mkarray(NULL); | |
361 | compctlsetup(); | |
362 | userdirs = (char **) zcalloc(sizeof(char *)*2); | |
363 | usernames = (char **) zcalloc(sizeof(char *)*2); | |
364 | userdirsz = 2; | |
365 | userdirct = 0; | |
366 | optarg = ztrdup(""); | |
367 | zoptind = 1; | |
368 | schedcmds = NULL; | |
369 | path = (char **) zalloc(4*sizeof *path); | |
370 | path[0] = ztrdup("/bin"); path[1] = ztrdup("/usr/bin"); | |
371 | path[2] = ztrdup("/usr/ucb"); path[3] = NULL; | |
372 | inittyptab(); | |
373 | initlextabs(); | |
374 | setupparams(); | |
375 | setparams(); | |
376 | inittyptab(); | |
377 | if ((s = zgetenv("EMACS")) && !strcmp(s,"t") && !strcmp(term,"emacs")) | |
378 | opts[USEZLE] = OPT_UNSET; | |
379 | #ifndef HAS_RUSAGE | |
380 | times(&shtms); | |
381 | #endif | |
382 | } | |
383 | ||
384 | void compctlsetup() /**/ | |
385 | { | |
386 | static char | |
387 | *hs[] = {"telnet","rlogin","ftp","rup","rusers","rsh",NULL}, | |
388 | *os[] = {"setopt","unsetopt",NULL}, | |
389 | *vs[] = {"export","typeset","vared","unset",NULL}, | |
390 | *cs[] = {"which","builtin",NULL}, | |
391 | *bs[] = {"bindkey",NULL}; | |
392 | ||
393 | compctl_process(hs,CC_HOSTS|CC_FILES,NULL); | |
394 | compctl_process(os,CC_OPTIONS,NULL); | |
395 | compctl_process(vs,CC_VARS,NULL); | |
396 | compctl_process(bs,CC_BINDINGS,NULL); | |
397 | compctl_process(cs,CC_COMMPATH,NULL); | |
398 | cc_compos.mask = CC_COMMPATH; | |
399 | cc_default.mask = CC_FILES; | |
400 | } | |
401 | ||
402 | void initialize() /**/ | |
403 | { | |
404 | int t0; | |
405 | ||
406 | breaks = loops = 0; | |
407 | lastmailcheck = time(NULL); | |
408 | locallist = NULL; | |
409 | dirstack = newlist(); | |
410 | bufstack = newlist(); | |
411 | newcmdnamtab(); | |
412 | inbuf = zalloc(inbufsz = 256); | |
413 | inbufptr = inbuf+inbufsz; | |
414 | inbufct = 0; | |
415 | #ifndef QDEBUG | |
416 | signal(SIGQUIT,SIG_IGN); | |
417 | #endif | |
418 | #ifdef RLIM_INFINITY | |
419 | for (t0 = 0; t0 != RLIM_NLIMITS; t0++) | |
420 | getrlimit(t0,limits+t0); | |
421 | #endif | |
422 | hsubl = hsubr = NULL; | |
423 | lastpid = 0; | |
424 | bshin = fdopen(SHIN,"r"); | |
425 | signal(SIGCHLD,handler); | |
426 | if (jobbing) | |
427 | { | |
428 | int ttypgrp; | |
429 | for (;;) | |
430 | { | |
431 | #ifdef TIOCGPGRP | |
432 | ioctl(SHTTY, TIOCGPGRP, &ttypgrp); | |
433 | #else | |
434 | ttypgrp = tcgetpgrp(SHTTY); | |
435 | #endif | |
436 | if (ttypgrp == mypgrp) | |
437 | break; | |
438 | kill(0,SIGTTIN); | |
439 | } | |
440 | signal(SIGTTOU,SIG_IGN); | |
441 | signal(SIGTSTP,SIG_IGN); | |
442 | signal(SIGTTIN,SIG_IGN); | |
443 | signal(SIGPIPE,SIG_IGN); | |
444 | attachtty(mypgrp); | |
445 | } | |
446 | if (interact) | |
447 | { | |
448 | signal(SIGTERM,SIG_IGN); | |
449 | #ifdef SIGWINCH | |
450 | signal(SIGWINCH,handler); | |
451 | #endif | |
452 | signal(SIGALRM,handler); | |
453 | intr(); | |
454 | } | |
455 | } | |
456 | ||
457 | void addreswords() /**/ | |
458 | { | |
459 | static char *reswds[] = { | |
460 | "do", "done", "esac", "then", "elif", "else", "fi", "for", "case", | |
461 | "if", "while", "function", "repeat", "time", "until", "exec", "command", | |
462 | "select", "coproc", "noglob", "-", "nocorrect", "foreach", "end", NULL | |
463 | }; | |
464 | int t0; | |
465 | ||
466 | for (t0 = 0; reswds[t0]; t0++) | |
467 | addhperm(reswds[t0],mkanode(NULL,-1-t0),aliastab,NULL); | |
468 | } | |
469 | ||
470 | void runscripts() /**/ | |
471 | { | |
472 | #ifdef GLOBALZSHENV | |
473 | source(GLOBALZSHENV); | |
474 | #endif | |
475 | if (opts[NORCS] == OPT_SET) { | |
476 | #ifdef GLOBALZPROFILE | |
477 | if (islogin) source(GLOBALZPROFILE); | |
478 | #endif | |
479 | #ifdef GLOBALZSHRC | |
480 | source(GLOBALZSHRC); | |
481 | #endif | |
482 | #ifdef GLOBALZLOGIN | |
483 | if (islogin) source(GLOBALZLOGIN); | |
484 | #endif | |
485 | } else { | |
486 | sourcehome(".zshenv"); | |
487 | if (opts[NORCS] == OPT_SET) | |
488 | return; | |
489 | if (interact) { | |
490 | if (islogin) { | |
491 | sourcehome(".zprofile"); | |
492 | #ifdef GLOBALZPROFILE | |
493 | source(GLOBALZPROFILE); | |
494 | #endif | |
495 | } | |
496 | #ifdef GLOBALZSHRC | |
497 | source(GLOBALZSHRC); | |
498 | #endif | |
499 | sourcehome(".zshrc"); | |
500 | if (islogin) { | |
501 | #ifdef GLOBALZLOGIN | |
502 | source(GLOBALZLOGIN); | |
503 | #endif | |
504 | sourcehome(".zlogin"); | |
505 | } | |
506 | } | |
507 | } | |
508 | if (interact) | |
509 | readhistfile(getsparam("HISTFILE"),0); | |
510 | if (opts['c'] == OPT_SET) | |
511 | { | |
512 | if (SHIN >= 10) | |
513 | close(SHIN); | |
514 | SHIN = movefd(open("/dev/null",O_RDONLY)); | |
515 | execstring(cmd); | |
516 | stopmsg = 1; | |
517 | zexit(NULL); | |
518 | } | |
519 | #ifdef TIOCSWINSZ | |
520 | if (!(columns = shttyinfo.winsize.ws_col)) | |
521 | columns = 80; | |
522 | if (!(lines = shttyinfo.winsize.ws_row)) | |
523 | lines = 24; | |
524 | #endif | |
525 | } | |
526 | ||
527 | void ainit() /**/ | |
528 | { | |
529 | alstackind = 0; /* reset alias stack */ | |
530 | alstat = 0; | |
531 | isfirstln = 1; | |
532 | } | |
533 |