1/*
2 * init.c - main loop and initialization routines
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose.  The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30#include "zsh.mdh"
31
32#include "zshpaths.h"
33#include "zshxmods.h"
34
35#include "init.pro"
36
37#include "version.h"
38
39/**/
40int noexitct = 0;
41
42/* buffer for $_ and its length */
43
44/**/
45char *zunderscore;
46
47/**/
48int underscorelen, underscoreused;
49
50/* what level of sourcing we are at */
51
52/**/
53int sourcelevel;
54
55/* the shell tty fd */
56
57/**/
58mod_export int SHTTY;
59
60/* the FILE attached to the shell tty */
61
62/**/
63mod_export FILE *shout;
64
65/* termcap strings */
66
67/**/
68mod_export char *tcstr[TC_COUNT];
69
70/* lengths of each termcap string */
71
72/**/
73mod_export int tclen[TC_COUNT];
74
75/* Values of the li, co and am entries */
76
77/**/
78int tclines, tccolumns;
79/**/
80mod_export int hasam, hasxn, hasye;
81
82/* Value of the Co (max_colors) entry: may not be set */
83
84/**/
85mod_export int tccolours;
86
87/* SIGCHLD mask */
88
89/**/
90mod_export sigset_t sigchld_mask;
91
92/**/
93mod_export struct hookdef zshhooks[] = {
94    HOOKDEF("exit", NULL, HOOKF_ALL),
95    HOOKDEF("before_trap", NULL, HOOKF_ALL),
96    HOOKDEF("after_trap", NULL, HOOKF_ALL),
97};
98
99/* keep executing lists until EOF found */
100
101/**/
102enum loop_return
103loop(int toplevel, int justonce)
104{
105    Eprog prog;
106    int err, non_empty = 0;
107
108    pushheap();
109    if (!toplevel)
110	lexsave();
111    for (;;) {
112	freeheap();
113	if (stophist == 3)	/* re-entry via preprompt() */
114	    hend(NULL);
115	hbegin(1);		/* init history mech        */
116	if (isset(SHINSTDIN)) {
117	    setblock_stdin();
118	    if (interact && toplevel) {
119	        int hstop = stophist;
120		stophist = 3;
121		preprompt();
122		if (stophist != 3)
123		    hbegin(1);
124		else
125		    stophist = hstop;
126		errflag = 0;
127	    }
128	}
129	use_exit_printed = 0;
130	intr();			/* interrupts on            */
131	lexinit();              /* initialize lexical state */
132	if (!(prog = parse_event())) {	/* if we couldn't parse a list */
133	    hend(NULL);
134	    if ((tok == ENDINPUT && !errflag) ||
135		(tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) ||
136		justonce)
137		break;
138	    if (exit_pending) {
139		/*
140		 * Something down there (a ZLE function?) decided
141		 * to exit when there was stuff to clear up.
142		 * Handle that now.
143		 */
144		stopmsg = 1;
145		zexit(exit_pending >> 1, 0);
146	    }
147	    if (tok == LEXERR && !lastval)
148		lastval = 1;
149	    continue;
150	}
151	if (hend(prog)) {
152	    enum lextok toksav = tok;
153
154	    non_empty = 1;
155	    if (toplevel &&
156		(getshfunc("preexec") ||
157		 paramtab->getnode(paramtab, "preexec" HOOK_SUFFIX))) {
158		LinkList args;
159		char *cmdstr;
160
161		/*
162		 * As we're about to freeheap() or popheap()
163		 * anyway, there's no gain in using permanent
164		 * storage here.
165		 */
166		args = newlinklist();
167		addlinknode(args, "preexec");
168		/* If curline got dumped from the history, we don't know
169		 * what the user typed. */
170		if (hist_ring && curline.histnum == curhist)
171		    addlinknode(args, hist_ring->node.nam);
172		else
173		    addlinknode(args, "");
174		addlinknode(args, dupstring(getjobtext(prog, NULL)));
175		addlinknode(args, cmdstr = getpermtext(prog, NULL, 0));
176
177		callhookfunc("preexec", args, 1, NULL);
178
179		/* The only permanent storage is from getpermtext() */
180		zsfree(cmdstr);
181		errflag = 0;
182	    }
183	    if (stopmsg)	/* unset 'you have stopped jobs' flag */
184		stopmsg--;
185	    execode(prog, 0, 0, toplevel ? "toplevel" : "file");
186	    tok = toksav;
187	    if (toplevel)
188		noexitct = 0;
189	}
190	if (ferror(stderr)) {
191	    zerr("write error");
192	    clearerr(stderr);
193	}
194	if (subsh)		/* how'd we get this far in a subshell? */
195	    exit(lastval);
196	if (((!interact || sourcelevel) && errflag) || retflag)
197	    break;
198	if (isset(SINGLECOMMAND) && toplevel) {
199	    if (sigtrapped[SIGEXIT])
200		dotrap(SIGEXIT);
201	    exit(lastval);
202	}
203	if (justonce)
204	    break;
205    }
206    err = errflag;
207    if (!toplevel)
208	lexrestore();
209    popheap();
210
211    if (err)
212	return LOOP_ERROR;
213    if (!non_empty)
214	return LOOP_EMPTY;
215    return LOOP_OK;
216}
217
218/* Shared among parseargs(), parseopts(), init_io(), and init_misc() */
219static char *cmd;
220static int restricted;
221
222/**/
223static void
224parseargs(char **argv, char **runscript)
225{
226    char **x;
227    LinkList paramlist;
228
229    argzero = *argv++;
230    SHIN = 0;
231
232    /* There's a bit of trickery with opts[INTERACTIVE] here.  It starts *
233     * at a value of 2 (instead of 1) or 0.  If it is explicitly set on  *
234     * the command line, it goes to 1 or 0.  If input is coming from     *
235     * somewhere that normally makes the shell non-interactive, we do    *
236     * "opts[INTERACTIVE] &= 1", so that only a *default* on state will  *
237     * be changed.  At the end of the function, a value of 2 gets        *
238     * changed to 1.                                                     */
239    opts[INTERACTIVE] = isatty(0) ? 2 : 0;
240    /*
241     * MONITOR is similar:  we initialise it to 2, and if it's
242     * still 2 at the end, we set it to the value of INTERACTIVE.
243     */
244    opts[MONITOR] = 2;   /* may be unset in init_io() */
245    opts[HASHDIRS] = 2;  /* same relationship to INTERACTIVE */
246    opts[SHINSTDIN] = 0;
247    opts[SINGLECOMMAND] = 0;
248
249    if (parseopts(NULL, &argv, opts, &cmd, NULL))
250	exit(1);
251
252    paramlist = znewlinklist();
253    if (*argv) {
254	if (unset(SHINSTDIN)) {
255	    if (cmd)
256		argzero = *argv;
257	    else
258		*runscript = *argv;
259	    opts[INTERACTIVE] &= 1;
260	    argv++;
261	}
262	while (*argv)
263	    zaddlinknode(paramlist, ztrdup(*argv++));
264    } else if (!cmd)
265	opts[SHINSTDIN] = 1;
266    if(isset(SINGLECOMMAND))
267	opts[INTERACTIVE] &= 1;
268    opts[INTERACTIVE] = !!opts[INTERACTIVE];
269    if (opts[MONITOR] == 2)
270	opts[MONITOR] = opts[INTERACTIVE];
271    if (opts[HASHDIRS] == 2)
272	opts[HASHDIRS] = opts[INTERACTIVE];
273    pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
274
275    while ((*x++ = (char *)getlinknode(paramlist)));
276    free(paramlist);
277    argzero = ztrdup(argzero);
278}
279
280/* Insert into list in order of pointer value */
281
282/**/
283static void
284parseopts_insert(LinkList optlist, char *base, int optno)
285{
286    LinkNode node;
287    void *ptr = base + (optno < 0 ? -optno : optno);
288
289    for (node = firstnode(optlist); node; incnode(node)) {
290	if (ptr < getdata(node)) {
291	    insertlinknode(optlist, prevnode(node), ptr);
292	    return;
293	}
294    }
295
296    addlinknode(optlist, ptr);
297}
298
299/*
300 * Parse shell options.
301 * If nam is not NULL, this is called from a command; don't
302 * exit on failure.
303 *
304 * If optlist is not NULL, it used to form a list of pointers
305 * into new_opts indicating which options have been changed.
306 */
307
308/**/
309mod_export int
310parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
311	  LinkList optlist)
312{
313    int optionbreak = 0;
314    int action, optno;
315    char **argv = *argvp;
316
317    *cmdp = 0;
318#define WARN_OPTION(F, S)						\
319    do {								\
320	if (nam)							\
321	    zwarnnam(nam, F, S);					\
322	else								\
323	    zerr(F, S);							\
324    } while (0)
325#define LAST_OPTION(N)	       \
326    do {		       \
327	if (nam) {	       \
328	    if (*argv)	       \
329		argv++;	       \
330	    goto doneargv;     \
331	} else exit(N);	       \
332    } while(0)
333
334    /* loop through command line options (begins with "-" or "+") */
335    while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) {
336	char *args = *argv;
337	action = (**argv == '-');
338	if (!argv[0][1])
339	    *argv = "--";
340	while (*++*argv) {
341	    if (**argv == '-') {
342		if(!argv[0][1]) {
343		    /* The pseudo-option `--' signifies the end of options. */
344		    argv++;
345		    goto doneoptions;
346		}
347		if(*argv != args+1 || **argv != '-')
348		    goto badoptionstring;
349		/* GNU-style long options */
350		++*argv;
351		if (!strcmp(*argv, "version")) {
352		    printf("zsh %s (%s-%s-%s)\n",
353			    ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE);
354		    LAST_OPTION(0);
355		}
356		if (!strcmp(*argv, "help")) {
357		    printhelp();
358		    LAST_OPTION(0);
359		}
360		/* `-' characters are allowed in long options */
361		for(args = *argv; *args; args++)
362		    if(*args == '-')
363			*args = '_';
364		goto longoptions;
365	    }
366
367	    if (unset(SHOPTIONLETTERS) && **argv == 'b') {
368		/* -b ends options at the end of this argument */
369		optionbreak = 1;
370	    } else if (**argv == 'c') {
371		/* -c command */
372		*cmdp = *argv;
373		new_opts[INTERACTIVE] &= 1;
374		scriptname = scriptfilename = ztrdup("zsh");
375	    } else if (**argv == 'o') {
376		if (!*++*argv)
377		    argv++;
378		if (!*argv) {
379		    WARN_OPTION("string expected after -o", NULL);
380		    return 1;
381		}
382	    longoptions:
383		if (!(optno = optlookup(*argv))) {
384		    WARN_OPTION("no such option: %s", *argv);
385		    return 1;
386		} else if (optno == RESTRICTED && !nam) {
387		    restricted = action;
388		} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
389		    WARN_OPTION("can't change option: %s", *argv);
390		} else {
391		    if (dosetopt(optno, action, !nam, new_opts) && nam) {
392			WARN_OPTION("can't change option: %s", *argv);
393		    } else if (optlist) {
394			parseopts_insert(optlist, new_opts, optno);
395		    }
396		}
397              break;
398	    } else if (isspace(STOUC(**argv))) {
399		/* zsh's typtab not yet set, have to use ctype */
400		while (*++*argv)
401		    if (!isspace(STOUC(**argv))) {
402		     badoptionstring:
403			WARN_OPTION("bad option string: '%s'", args);
404			return 1;
405		    }
406		break;
407	    } else {
408	    	if (!(optno = optlookupc(**argv))) {
409		    WARN_OPTION("bad option: -%c", **argv);
410		    return 1;
411		} else if (optno == RESTRICTED && !nam) {
412		    restricted = action;
413		} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
414		    WARN_OPTION("can't change option: %s", *argv);
415		} else {
416		    if (dosetopt(optno, action, !nam, new_opts) && nam) {
417			WARN_OPTION("can't change option: -%c", **argv);
418		    } else if (optlist) {
419			parseopts_insert(optlist, new_opts, optno);
420		    }
421		}
422	    }
423	}
424	argv++;
425    }
426 doneoptions:
427    if (*cmdp) {
428	if (!*argv) {
429	    WARN_OPTION("string expected after -%s", *cmdp);
430	    return 1;
431	}
432	*cmdp = *argv++;
433    }
434 doneargv:
435    *argvp = argv;
436    return 0;
437}
438
439/**/
440static void
441printhelp(void)
442{
443    printf("Usage: %s [<options>] [<argument> ...]\n", argzero);
444    printf("\nSpecial options:\n");
445    printf("  --help     show this message, then exit\n");
446    printf("  --version  show zsh version number, then exit\n");
447    if(unset(SHOPTIONLETTERS))
448	printf("  -b         end option processing, like --\n");
449    printf("  -c         take first argument as a command to execute\n");
450    printf("  -o OPTION  set an option by name (see below)\n");
451    printf("\nNormal options are named.  An option may be turned on by\n");
452    printf("`-o OPTION', `--OPTION', `+o no_OPTION' or `+-no-OPTION'.  An\n");
453    printf("option may be turned off by `-o no_OPTION', `--no-OPTION',\n");
454    printf("`+o OPTION' or `+-OPTION'.  Options are listed below only in\n");
455    printf("`--OPTION' or `--no-OPTION' form.\n");
456    printoptionlist();
457}
458
459/**/
460mod_export void
461init_io(void)
462{
463    static char outbuf[BUFSIZ], errbuf[BUFSIZ];
464
465#ifdef RSH_BUG_WORKAROUND
466    int i;
467#endif
468
469/* stdout, stderr fully buffered */
470#ifdef _IOFBF
471    setvbuf(stdout, outbuf, _IOFBF, BUFSIZ);
472    setvbuf(stderr, errbuf, _IOFBF, BUFSIZ);
473#else
474    setbuffer(stdout, outbuf, BUFSIZ);
475    setbuffer(stderr, errbuf, BUFSIZ);
476#endif
477
478/* This works around a bug in some versions of in.rshd. *
479 * Currently this is not defined by default.            */
480#ifdef RSH_BUG_WORKAROUND
481    if (cmd) {
482	for (i = 3; i < 10; i++)
483	    close(i);
484    }
485#endif
486
487    if (shout) {
488	/*
489	 * Check if shout was set to stderr, if so don't close it.
490	 * We do this if we are interactive but don't have a
491	 * terminal.
492	 */
493	if (shout != stderr)
494	    fclose(shout);
495	shout = 0;
496    }
497    if (SHTTY != -1) {
498	zclose(SHTTY);
499	SHTTY = -1;
500    }
501
502    /* Send xtrace output to stderr -- see execcmd() */
503    xtrerr = stderr;
504
505    /* Make sure the tty is opened read/write. */
506    if (isatty(0)) {
507	zsfree(ttystrname);
508	if ((ttystrname = ztrdup(ttyname(0)))) {
509	    SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY));
510#ifdef TIOCNXCL
511	    /*
512	     * See if the terminal claims to be busy.  If so, and fd 0
513	     * is a terminal, try and set non-exclusive use for that.
514	     * This is something to do with Solaris over-cleverness.
515	     */
516	    if (SHTTY == -1 && errno == EBUSY)
517		ioctl(0, TIOCNXCL, 0);
518#endif
519	}
520	/*
521	 * xterm, rxvt and probably all terminal emulators except
522	 * dtterm on Solaris 2.6 & 7 have a bug. Applications are
523	 * unable to open /dev/tty or /dev/pts/<terminal number here>
524	 * because something in Sun's STREAMS modules doesn't like
525	 * it. The open() call fails with EBUSY which is not even
526	 * listed as a possibility in the open(2) man page.  So we'll
527	 * try to outsmart The Company.  -- <dave@srce.hr>
528	 *
529	 * Presumably there's no harm trying this on any OS, given that
530	 * isatty(0) worked but opening the tty didn't.  Possibly we won't
531	 * get the tty read/write, but it's the best we can do -- pws
532	 *
533	 * Try both stdin and stdout before trying /dev/tty. -- Bart
534	 */
535#if defined(HAVE_FCNTL_H) && defined(F_GETFL)
536#define rdwrtty(fd)	((fcntl(fd, F_GETFL, 0) & O_RDWR) == O_RDWR)
537#else
538#define rdwrtty(fd)	1
539#endif
540	if (SHTTY == -1 && rdwrtty(0)) {
541	    SHTTY = movefd(dup(0));
542	}
543    }
544    if (SHTTY == -1 && isatty(1) && rdwrtty(1) &&
545	(SHTTY = movefd(dup(1))) != -1) {
546	zsfree(ttystrname);
547	ttystrname = ztrdup(ttyname(1));
548    }
549    if (SHTTY == -1 &&
550	(SHTTY = movefd(open("/dev/tty", O_RDWR | O_NOCTTY))) != -1) {
551	zsfree(ttystrname);
552	ttystrname = ztrdup(ttyname(SHTTY));
553    }
554    if (SHTTY == -1) {
555	zsfree(ttystrname);
556	ttystrname = ztrdup("");
557    } else {
558#ifdef FD_CLOEXEC
559	long fdflags = fcntl(SHTTY, F_GETFD, 0);
560	if (fdflags != (long)-1) {
561	    fdflags |= FD_CLOEXEC;
562	    fcntl(SHTTY, F_SETFD, fdflags);
563	}
564#endif
565	if (!ttystrname)
566	    ttystrname = ztrdup("/dev/tty");
567    }
568
569    /* We will only use zle if shell is interactive, *
570     * SHTTY != -1, and shout != 0                   */
571    if (interact) {
572	init_shout();
573	if(!SHTTY || !shout)
574	    opts[USEZLE] = 0;
575    } else
576	opts[USEZLE] = 0;
577
578#ifdef JOB_CONTROL
579    /* If interactive, make sure the shell is in the foreground and is the
580     * process group leader.
581     */
582    mypid = (zlong)getpid();
583    if (opts[MONITOR] && (SHTTY != -1)) {
584	origpgrp = GETPGRP();
585        acquire_pgrp(); /* might also clear opts[MONITOR] */
586    } else
587	opts[MONITOR] = 0;
588#else
589    opts[MONITOR] = 0;
590#endif
591}
592
593/**/
594mod_export void
595init_shout(void)
596{
597    static char shoutbuf[BUFSIZ];
598#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
599    int ldisc;
600#endif
601
602    if (SHTTY == -1)
603    {
604	/* Since we're interative, it's nice to have somewhere to write. */
605	shout = stderr;
606	return;
607    }
608
609#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
610    ldisc = NTTYDISC;
611    ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
612#endif
613
614    /* Associate terminal file descriptor with a FILE pointer */
615    shout = fdopen(SHTTY, "w");
616#ifdef _IOFBF
617    setvbuf(shout, shoutbuf, _IOFBF, BUFSIZ);
618#endif
619
620    gettyinfo(&shttyinfo);	/* get tty state */
621#if defined(__sgi)
622    if (shttyinfo.tio.c_cc[VSWTCH] <= 0)	/* hack for irises */
623	shttyinfo.tio.c_cc[VSWTCH] = CSWTCH;
624#endif
625}
626
627/* names of the termcap strings we want */
628
629static char *tccapnams[TC_COUNT] = {
630    "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
631    "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
632    "md", "so", "us", "me", "se", "ue", "ch",
633    "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB"
634};
635
636/**/
637mod_export char *
638tccap_get_name(int cap)
639{
640    if (cap >= TC_COUNT) {
641#ifdef DEBUG
642	dputs("name of invalid capability %d requested", cap);
643#endif
644	return "";
645    }
646    return tccapnams[cap];
647}
648
649/* Initialise termcap */
650
651/**/
652mod_export int
653init_term(void)
654{
655#ifndef TGETENT_ACCEPTS_NULL
656    static char termbuf[2048];	/* the termcap buffer */
657#endif
658
659    if (!*term) {
660	termflags |= TERM_UNKNOWN;
661	return 0;
662    }
663
664    /* unset zle if using zsh under emacs */
665    if (!strcmp(term, "emacs"))
666	opts[USEZLE] = 0;
667
668#ifdef TGETENT_ACCEPTS_NULL
669    /* If possible, we let tgetent allocate its own termcap buffer */
670    if (tgetent(NULL, term) != TGETENT_SUCCESS)
671#else
672    if (tgetent(termbuf, term) != TGETENT_SUCCESS)
673#endif
674    {
675	if (isset(INTERACTIVE))
676	    zerr("can't find terminal definition for %s", term);
677	errflag = 0;
678	termflags |= TERM_BAD;
679	return 0;
680    } else {
681	char tbuf[1024], *pp;
682	int t0;
683
684	termflags &= ~TERM_BAD;
685	termflags &= ~TERM_UNKNOWN;
686	for (t0 = 0; t0 != TC_COUNT; t0++) {
687	    pp = tbuf;
688	    zsfree(tcstr[t0]);
689	/* AIX tgetstr() ignores second argument */
690	    if (!(pp = tgetstr(tccapnams[t0], &pp)))
691		tcstr[t0] = NULL, tclen[t0] = 0;
692	    else {
693		tclen[t0] = strlen(pp);
694		tcstr[t0] = (char *) zalloc(tclen[t0] + 1);
695		memcpy(tcstr[t0], pp, tclen[t0] + 1);
696	    }
697	}
698
699	/* check whether terminal has automargin (wraparound) capability */
700	hasam = tgetflag("am");
701	hasxn = tgetflag("xn"); /* also check for newline wraparound glitch */
702	hasye = tgetflag("YE"); /* print in last column does carriage return */
703
704	tclines = tgetnum("li");
705	tccolumns = tgetnum("co");
706	tccolours = tgetnum("Co");
707
708	/* if there's no termcap entry for cursor up, use single line mode: *
709	 * this is flagged by termflags which is examined in zle_refresh.c  *
710	 */
711	if (tccan(TCUP))
712	    termflags &= ~TERM_NOUP;
713	else {
714	    zsfree(tcstr[TCUP]);
715	    tcstr[TCUP] = NULL;
716	    termflags |= TERM_NOUP;
717	}
718
719	/* most termcaps don't define "bc" because they use \b. */
720	if (!tccan(TCBACKSPACE)) {
721	    zsfree(tcstr[TCBACKSPACE]);
722	    tcstr[TCBACKSPACE] = ztrdup("\b");
723	    tclen[TCBACKSPACE] = 1;
724	}
725
726	/* if there's no termcap entry for cursor left, use backspace. */
727	if (!tccan(TCLEFT)) {
728	    zsfree(tcstr[TCLEFT]);
729	    tcstr[TCLEFT] = ztrdup(tcstr[TCBACKSPACE]);
730	    tclen[TCLEFT] = tclen[TCBACKSPACE];
731	}
732
733	if (tccan(TCSAVECURSOR) && !tccan(TCRESTRCURSOR)) {
734	    tclen[TCSAVECURSOR] = 0;
735	    zsfree(tcstr[TCSAVECURSOR]);
736	    tcstr[TCSAVECURSOR] = NULL;
737	}
738
739	/* if the termcap entry for down is \n, don't use it. */
740	if (tccan(TCDOWN) && tcstr[TCDOWN][0] == '\n') {
741	    tclen[TCDOWN] = 0;
742	    zsfree(tcstr[TCDOWN]);
743	    tcstr[TCDOWN] = NULL;
744	}
745
746	/* if there's no termcap entry for clear, use ^L. */
747	if (!tccan(TCCLEARSCREEN)) {
748	    zsfree(tcstr[TCCLEARSCREEN]);
749	    tcstr[TCCLEARSCREEN] = ztrdup("\14");
750	    tclen[TCCLEARSCREEN] = 1;
751	}
752#if 0	/* This might work, but there may be more to it */
753	rprompt_indent = (hasye || !tccan(TCLEFT)) ? 1 : 0;
754#endif
755    }
756    return 1;
757}
758
759/* Initialize lots of global variables and hash tables */
760
761/**/
762void
763setupvals(void)
764{
765#ifdef USE_GETPWUID
766    struct passwd *pswd;
767#endif
768    struct timezone dummy_tz;
769    char *ptr;
770    int i, j;
771#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH)
772    char **fpathptr;
773# if defined(FPATH_DIR) && defined(FPATH_SUBDIRS)
774    char *fpath_subdirs[] = FPATH_SUBDIRS;
775# endif
776# if defined(ADDITIONAL_FPATH)
777    char *more_fndirs[] = ADDITIONAL_FPATH;
778    int more_fndirs_len;
779# endif
780# ifdef SITEFPATH_DIR
781    int fpathlen = 1;
782# else
783    int fpathlen = 0;
784# endif
785#endif
786    int close_fds[10], tmppipe[2];
787
788    /*
789     * Workaround a problem with NIS (in one guise or another) which
790     * grabs file descriptors and keeps them for future reference.
791     * We don't want these to be in the range where the user can
792     * open fd's, i.e. 0 to 9 inclusive.  So we make sure all
793     * fd's in that range are in use.
794     */
795    memset(close_fds, 0, 10*sizeof(int));
796    if (pipe(tmppipe) == 0) {
797	/*
798	 * Strategy:  Make sure we have at least fd 0 open (hence
799	 * the pipe).  From then on, keep dup'ing until we are
800	 * up to 9.  If we go over the top, close immediately, else
801	 * mark for later closure.
802	 */
803	i = -1;			/* max fd we have checked */
804	while (i < 9) {
805	    /* j is current fd */
806	    if (i < tmppipe[0])
807		j = tmppipe[0];
808	    else if (i < tmppipe[1])
809		j = tmppipe[1];
810	    else {
811		j = dup(0);
812		if (j == -1)
813		    break;
814	    }
815	    if (j < 10)
816		close_fds[j] = 1;
817	    else
818		close(j);
819	    if (i < j)
820		i = j;
821	}
822	if (i < tmppipe[0])
823	    close(tmppipe[0]);
824	if (i < tmppipe[1])
825	    close(tmppipe[1]);
826    }
827
828    (void)addhookdefs(NULL, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks));
829
830    init_eprog();
831
832    zero_mnumber.type = MN_INTEGER;
833    zero_mnumber.u.l = 0;
834
835    noeval = 0;
836    curhist = 0;
837    histsiz = DEFAULT_HISTSIZE;
838    inithist();
839
840    cmdstack = (unsigned char *) zalloc(CMDSTACKSZ);
841    cmdsp = 0;
842
843    bangchar = '!';
844    hashchar = '#';
845    hatchar = '^';
846    termflags = TERM_UNKNOWN;
847    curjob = prevjob = coprocin = coprocout = -1;
848    gettimeofday(&shtimer, &dummy_tz);	/* init $SECONDS */
849    srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */
850
851    /* Set default path */
852    path    = (char **) zalloc(sizeof(*path) * 5);
853    path[0] = ztrdup("/bin");
854    path[1] = ztrdup("/usr/bin");
855    path[2] = ztrdup("/usr/ucb");
856    path[3] = ztrdup("/usr/local/bin");
857    path[4] = NULL;
858
859    cdpath   = mkarray(NULL);
860    manpath  = mkarray(NULL);
861    fignore  = mkarray(NULL);
862
863#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined(ADDITIONAL_FPATH)
864# ifdef FPATH_DIR
865#  ifdef FPATH_SUBDIRS
866    fpathlen += sizeof(fpath_subdirs)/sizeof(char *);
867#  else
868    fpathlen++;
869#  endif
870# endif
871# if defined(ADDITIONAL_FPATH)
872    more_fndirs_len = sizeof(more_fndirs)/sizeof(char *);
873    fpathlen += more_fndirs_len;
874# endif
875    fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *));
876# ifdef SITEFPATH_DIR
877    *fpathptr++ = ztrdup(SITEFPATH_DIR);
878    fpathlen--;
879# endif
880# if defined(ADDITIONAL_FPATH)
881    for (j = 0; j < more_fndirs_len; j++)
882	*fpathptr++ = ztrdup(more_fndirs[j]);
883# endif
884# ifdef FPATH_DIR
885#  ifdef FPATH_SUBDIRS
886#   ifdef ADDITIONAL_FPATH
887    for (j = more_fndirs_len; j < fpathlen; j++)
888	*fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j - more_fndirs_len]);
889#   else
890    for (j = 0; j < fpathlen; j++)
891	*fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j]);
892#endif
893#  else
894    *fpathptr++ = ztrdup(FPATH_DIR);
895#  endif
896# endif
897    *fpathptr = NULL;
898#else
899    fpath    = mkarray(NULL);
900#endif
901
902    mailpath = mkarray(NULL);
903    watch    = mkarray(NULL);
904    psvar    = mkarray(NULL);
905    module_path = mkarray(ztrdup(MODULE_DIR));
906    modulestab = newmoduletable(17, "modules");
907    linkedmodules = znewlinklist();
908
909    /* Set default prompts */
910    if(unset(INTERACTIVE)) {
911	prompt = ztrdup("");
912	prompt2 = ztrdup("");
913    } else if (EMULATION(EMULATE_KSH|EMULATE_SH)) {
914	prompt  = ztrdup(privasserted() ? "# " : "$ ");
915	prompt2 = ztrdup("> ");
916    } else {
917	prompt  = ztrdup("%m%# ");
918	prompt2 = ztrdup("%_> ");
919    }
920    prompt3 = ztrdup("?# ");
921    prompt4 = EMULATION(EMULATE_KSH|EMULATE_SH)
922	? ztrdup("+ ") : ztrdup("+%N:%i> ");
923    sprompt = ztrdup("zsh: correct '%R' to '%r' [nyae]? ");
924
925    ifs         = EMULATION(EMULATE_KSH|EMULATE_SH) ?
926	ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS);
927    wordchars   = ztrdup(DEFAULT_WORDCHARS);
928    postedit    = ztrdup("");
929    zunderscore  = (char *) zalloc(underscorelen = 32);
930    underscoreused = 1;
931    *zunderscore = '\0';
932
933    zoptarg = ztrdup("");
934    zoptind = 1;
935
936    ppid  = (zlong) getppid();
937    mypid = (zlong) getpid();
938    term  = ztrdup("");
939
940    nullcmd     = ztrdup("cat");
941    readnullcmd = ztrdup(DEFAULT_READNULLCMD);
942
943    /* We cache the uid so we know when to *
944     * recheck the info for `USERNAME'     */
945    cached_uid = getuid();
946
947    /* Get password entry and set info for `USERNAME' */
948#ifdef USE_GETPWUID
949    if ((pswd = getpwuid(cached_uid))) {
950	if (EMULATION(EMULATE_ZSH))
951	    home = metafy(pswd->pw_dir, -1, META_DUP);
952	cached_username = ztrdup(pswd->pw_name);
953    }
954    else
955#endif /* USE_GETPWUID */
956    {
957	if (EMULATION(EMULATE_ZSH))
958	    home = ztrdup("/");
959	cached_username = ztrdup("");
960    }
961
962    /*
963     * Try a cheap test to see if we can initialize `PWD' from `HOME'.
964     * In non-native emulations HOME must come from the environment;
965     * we're not allowed to set it locally.
966     */
967    if (EMULATION(EMULATE_ZSH))
968	ptr = home;
969    else
970	ptr = zgetenv("HOME");
971    if (ptr && ispwd(ptr))
972	pwd = ztrdup(ptr);
973    else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) &&
974	     (ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr)))
975	pwd = ztrdup(ptr);
976    else {
977	pwd = NULL;
978	pwd = metafy(zgetcwd(), -1, META_DUP);
979    }
980
981    oldpwd = ztrdup(pwd);  /* initialize `OLDPWD' = `PWD' */
982
983    inittyptab();     /* initialize the ztypes table */
984    initlextabs();    /* initialize lexing tables    */
985
986    createreswdtable();     /* create hash table for reserved words    */
987    createaliastables();    /* create hash tables for aliases           */
988    createcmdnamtable();    /* create hash table for external commands */
989    createshfunctable();    /* create hash table for shell functions   */
990    createbuiltintable();   /* create hash table for builtin commands  */
991    createnameddirtable();  /* create hash table for named directories */
992    createparamtable();     /* create parameter hash table             */
993
994    condtab = NULL;
995    wrappers = NULL;
996
997#ifdef TIOCGWINSZ
998    adjustwinsize(0);
999#else
1000    /* columns and lines are normally zero, unless something different *
1001     * was inhereted from the environment.  If either of them are zero *
1002     * the setiparam calls below set them to the defaults from termcap */
1003    setiparam("COLUMNS", zterm_columns);
1004    setiparam("LINES", zterm_lines);
1005#endif
1006    {
1007	/* Import from environment, overrides init_term() */
1008	struct value vbuf;
1009	char *name = "ZLE_RPROMPT_INDENT";
1010	if (getvalue(&vbuf, &name, 1) && !(vbuf.flags & PM_UNSET))
1011	    rprompt_indent = getintvalue(&vbuf);
1012	else
1013	    rprompt_indent = 1;
1014    }
1015
1016#ifdef HAVE_GETRLIMIT
1017    for (i = 0; i != RLIM_NLIMITS; i++) {
1018	getrlimit(i, current_limits + i);
1019	limits[i] = current_limits[i];
1020    }
1021#endif
1022
1023    breaks = loops = 0;
1024    lastmailcheck = time(NULL);
1025    locallevel = sourcelevel = 0;
1026    sfcontext = SFC_NONE;
1027    trap_return = 0;
1028    trap_state = TRAP_STATE_INACTIVE;
1029    noerrexit = -1;
1030    nohistsave = 1;
1031    dirstack = znewlinklist();
1032    bufstack = znewlinklist();
1033    hsubl = hsubr = NULL;
1034    lastpid = 0;
1035    lastpid_status = -1L;
1036
1037    get_usage();
1038
1039    /* Close the file descriptors we opened to block off 0 to 9 */
1040    for (i = 0; i < 10; i++)
1041	if (close_fds[i])
1042	    close(i);
1043
1044    /* Colour sequences for outputting colours in prompts and zle */
1045    set_default_colour_sequences();
1046}
1047
1048/*
1049 * Setup shell input, opening any script file (runscript, may be NULL).
1050 * This is deferred until we have a path to search, in case
1051 * PATHSCRIPT is set for sh-compatible behaviour.
1052 */
1053static void
1054setupshin(char *runscript)
1055{
1056    if (runscript) {
1057	char *funmeta, *sfname = NULL;
1058	struct stat st;
1059
1060	funmeta = unmeta(runscript);
1061	/*
1062	 * Always search the current directory first.
1063	 */
1064	if (access(funmeta, F_OK) == 0 &&
1065	    stat(funmeta, &st) >= 0 &&
1066	    !S_ISDIR(st.st_mode))
1067	    sfname = runscript;
1068	else if (isset(PATHSCRIPT) && !strchr(runscript, '/')) {
1069	    /*
1070	     * With the PATHSCRIPT option, search the path if no
1071	     * path was given in the script name.
1072	     */
1073	    funmeta = pathprog(runscript, &sfname);
1074	}
1075	if (!sfname ||
1076	    (SHIN = movefd(open(funmeta, O_RDONLY | O_NOCTTY)))
1077	    == -1) {
1078	    zerr("can't open input file: %s", runscript);
1079	    exit(127);
1080	}
1081	scriptfilename = sfname;
1082	zsfree(argzero); /* ztrdup'd in parseargs */
1083	argzero = runscript;
1084    }
1085    /*
1086     * We only initialise line numbering once there is a script to
1087     * read commands from.
1088     */
1089    lineno = 1;
1090    /*
1091     * Finish setting up SHIN and its relatives.
1092     */
1093    bshin = SHIN ? fdopen(SHIN, "r") : stdin;
1094    if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
1095#ifdef _IONBF
1096	setvbuf(stdin, NULL, _IONBF, 0);
1097#else
1098	setlinebuf(stdin);
1099#endif
1100    }
1101}
1102
1103/* Initialize signal handling */
1104
1105/**/
1106void
1107init_signals(void)
1108{
1109    if (interact) {
1110	int i;
1111	signal_setmask(signal_mask(0));
1112	for (i=0; i<NSIG; ++i)
1113	    signal_default(i);
1114    }
1115    sigchld_mask = signal_mask(SIGCHLD);
1116
1117    intr();
1118
1119#ifndef QDEBUG
1120    signal_ignore(SIGQUIT);
1121#endif
1122
1123    if (signal_ignore(SIGHUP) == SIG_IGN)
1124	opts[HUP] = 0;
1125    else
1126	install_handler(SIGHUP);
1127    install_handler(SIGCHLD);
1128#ifdef SIGWINCH
1129    install_handler(SIGWINCH);
1130    winch_block();	/* See utils.c:preprompt() */
1131#endif
1132    if (interact) {
1133	install_handler(SIGALRM);
1134	signal_ignore(SIGTERM);
1135    }
1136    if (jobbing) {
1137	signal_ignore(SIGTTOU);
1138	signal_ignore(SIGTSTP);
1139	signal_ignore(SIGTTIN);
1140    }
1141}
1142
1143/* Source the init scripts.  If called as "ksh" or "sh"  *
1144 * then we source the standard sh/ksh scripts instead of *
1145 * the standard zsh scripts                              */
1146
1147/**/
1148void
1149run_init_scripts(void)
1150{
1151    noerrexit = -1;
1152
1153    if (EMULATION(EMULATE_KSH|EMULATE_SH)) {
1154	if (islogin)
1155	    source("/etc/profile");
1156	if (unset(PRIVILEGED)) {
1157	    char *s = getsparam("ENV");
1158	    if (islogin)
1159		sourcehome(".profile");
1160	    noerrs = 2;
1161	    if (s && !parsestr(s)) {
1162		singsub(&s);
1163		noerrs = 0;
1164		source(s);
1165	    }
1166	    noerrs = 0;
1167	} else
1168	    source("/etc/suid_profile");
1169    } else {
1170#ifdef GLOBAL_ZSHENV
1171	source(GLOBAL_ZSHENV);
1172#endif
1173
1174	if (isset(RCS) && unset(PRIVILEGED))
1175	{
1176	    if (isset(INTERACTIVE)) {
1177		/*
1178		 * Always attempt to load the newuser module to perform
1179		 * checks for new zsh users.  Don't care if we can't load it.
1180		 */
1181		if (!load_module("zsh/newuser", NULL, 1)) {
1182		    /* Unload it immediately. */
1183		    unload_named_module("zsh/newuser", "zsh", 1);
1184		}
1185	    }
1186
1187	    sourcehome(".zshenv");
1188	}
1189	if (islogin) {
1190#ifdef GLOBAL_ZPROFILE
1191	    if (isset(RCS) && isset(GLOBALRCS))
1192		    source(GLOBAL_ZPROFILE);
1193#endif
1194	    if (isset(RCS) && unset(PRIVILEGED))
1195		sourcehome(".zprofile");
1196	}
1197	if (interact) {
1198#ifdef GLOBAL_ZSHRC
1199	    if (isset(RCS) && isset(GLOBALRCS))
1200		source(GLOBAL_ZSHRC);
1201#endif
1202	    if (isset(RCS) && unset(PRIVILEGED))
1203		sourcehome(".zshrc");
1204	}
1205	if (islogin) {
1206#ifdef GLOBAL_ZLOGIN
1207	    if (isset(RCS) && isset(GLOBALRCS))
1208		source(GLOBAL_ZLOGIN);
1209#endif
1210	    if (isset(RCS) && unset(PRIVILEGED))
1211		sourcehome(".zlogin");
1212	}
1213    }
1214    noerrexit = 0;
1215    nohistsave = 0;
1216}
1217
1218/* Miscellaneous initializations that happen after init scripts are run */
1219
1220/**/
1221void
1222init_misc(void)
1223{
1224#ifndef RESTRICTED_R
1225    if ( restricted )
1226#else
1227    if (*zsh_name == 'r' || restricted)
1228#endif
1229	dosetopt(RESTRICTED, 1, 0, opts);
1230    if (cmd) {
1231	if (SHIN >= 10)
1232	    fclose(bshin);
1233	SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
1234	bshin = fdopen(SHIN, "r");
1235	execstring(cmd, 0, 1, "cmdarg");
1236	stopmsg = 1;
1237	zexit(lastval, 0);
1238    }
1239
1240    if (interact && isset(RCS))
1241	readhistfile(NULL, 0, HFILE_USE_OPTIONS);
1242}
1243
1244/*
1245 * source a file
1246 * Returns one of the SOURCE_* enum values.
1247 */
1248
1249/**/
1250mod_export enum source_return
1251source(char *s)
1252{
1253    Eprog prog;
1254    int tempfd = -1, fd, cj;
1255    zlong oldlineno;
1256    int oldshst, osubsh, oloops;
1257    FILE *obshin;
1258    char *old_scriptname = scriptname, *us;
1259    char *old_scriptfilename = scriptfilename;
1260    unsigned char *ocs;
1261    int ocsp;
1262    int otrap_return = trap_return, otrap_state = trap_state;
1263    struct funcstack fstack;
1264    enum source_return ret = SOURCE_OK;
1265
1266    if (!s ||
1267	(!(prog = try_source_file((us = unmeta(s)))) &&
1268	 (tempfd = movefd(open(us, O_RDONLY | O_NOCTTY))) == -1)) {
1269	return SOURCE_NOT_FOUND;
1270    }
1271
1272    /* save the current shell state */
1273    fd        = SHIN;            /* store the shell input fd                  */
1274    obshin    = bshin;          /* store file handle for buffered shell input */
1275    osubsh    = subsh;           /* store whether we are in a subshell        */
1276    cj        = thisjob;         /* store our current job number              */
1277    oldlineno = lineno;          /* store our current lineno                  */
1278    oloops    = loops;           /* stored the # of nested loops we are in    */
1279    oldshst   = opts[SHINSTDIN]; /* store current value of this option        */
1280    ocs = cmdstack;
1281    ocsp = cmdsp;
1282    cmdstack = (unsigned char *) zalloc(CMDSTACKSZ);
1283    cmdsp = 0;
1284
1285    if (!prog) {
1286	SHIN = tempfd;
1287	bshin = fdopen(SHIN, "r");
1288    }
1289    subsh  = 0;
1290    lineno = 1;
1291    loops  = 0;
1292    dosetopt(SHINSTDIN, 0, 1, opts);
1293    scriptname = s;
1294    scriptfilename = s;
1295
1296    if (isset(SOURCETRACE)) {
1297	printprompt4();
1298	fprintf(xtrerr ? xtrerr : stderr, "<sourcetrace>\n");
1299    }
1300
1301    /*
1302     * The special return behaviour of traps shouldn't
1303     * trigger in files sourced from traps; the return
1304     * is just a return from the file.
1305     */
1306    trap_state = TRAP_STATE_INACTIVE;
1307
1308    sourcelevel++;
1309
1310    fstack.name = scriptfilename;
1311    fstack.caller = funcstack ? funcstack->name :
1312	dupstring(old_scriptfilename ? old_scriptfilename : "zsh");
1313    fstack.flineno = 0;
1314    fstack.lineno = oldlineno;
1315    fstack.filename = scriptfilename;
1316    fstack.prev = funcstack;
1317    fstack.tp = FS_SOURCE;
1318    funcstack = &fstack;
1319
1320    if (prog) {
1321	pushheap();
1322	errflag = 0;
1323	execode(prog, 1, 0, "filecode");
1324	popheap();
1325	if (errflag)
1326	    ret = SOURCE_ERROR;
1327    } else {
1328	/* loop through the file to be sourced  */
1329	switch (loop(0, 0))
1330	{
1331	case LOOP_OK:
1332	    /* nothing to do but compilers like a complete enum */
1333	    break;
1334
1335	case LOOP_EMPTY:
1336	    /* Empty code resets status */
1337	    lastval = 0;
1338	    break;
1339
1340	case LOOP_ERROR:
1341	    ret = SOURCE_ERROR;
1342	    break;
1343	}
1344    }
1345    funcstack = funcstack->prev;
1346    sourcelevel--;
1347
1348    trap_state = otrap_state;
1349    trap_return = otrap_return;
1350
1351    /* restore the current shell state */
1352    if (prog)
1353	freeeprog(prog);
1354    else {
1355	fclose(bshin);
1356	fdtable[SHIN] = FDT_UNUSED;
1357	SHIN = fd;		     /* the shell input fd                   */
1358	bshin = obshin;		     /* file handle for buffered shell input */
1359    }
1360    subsh = osubsh;                  /* whether we are in a subshell         */
1361    thisjob = cj;                    /* current job number                   */
1362    lineno = oldlineno;              /* our current lineno                   */
1363    loops = oloops;                  /* the # of nested loops we are in      */
1364    dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option               */
1365    errflag = 0;
1366    if (!exit_pending)
1367	retflag = 0;
1368    scriptname = old_scriptname;
1369    scriptfilename = old_scriptfilename;
1370    free(cmdstack);
1371    cmdstack = ocs;
1372    cmdsp = ocsp;
1373
1374    return ret;
1375}
1376
1377/* Try to source a file in the home directory */
1378
1379/**/
1380void
1381sourcehome(char *s)
1382{
1383    char *h;
1384
1385    queue_signals();
1386    if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam("ZDOTDIR"))) {
1387	h = home;
1388	if (!h)
1389	    return;
1390    }
1391
1392    {
1393	/* Let source() complain if path is too long */
1394	VARARR(char, buf, strlen(h) + strlen(s) + 2);
1395	sprintf(buf, "%s/%s", h, s);
1396	unqueue_signals();
1397	source(buf);
1398    }
1399}
1400
1401/**/
1402void
1403init_bltinmods(void)
1404{
1405
1406#include "bltinmods.list"
1407
1408    (void)load_module("zsh/main", NULL, 0);
1409}
1410
1411/**/
1412mod_export void
1413noop_function(void)
1414{
1415    /* do nothing */
1416}
1417
1418/**/
1419mod_export void
1420noop_function_int(UNUSED(int nothing))
1421{
1422    /* do nothing */
1423}
1424
1425/*
1426 * ZLE entry point pointer.
1427 * No other source file needs to know which modules are linked in.
1428 */
1429/**/
1430mod_export ZleEntryPoint zle_entry_ptr;
1431
1432/*
1433 * State of loading of zle.
1434 * 0 = Not loaded, not attempted.
1435 * 1 = Loaded successfully
1436 * 2 = Failed to load.
1437 */
1438/**/
1439mod_export int zle_load_state;
1440
1441/**/
1442mod_export char *
1443zleentry(VA_ALIST1(int cmd))
1444VA_DCL
1445{
1446    char *ret = NULL;
1447    va_list ap;
1448    VA_DEF_ARG(int cmd);
1449
1450    VA_START(ap, cmd);
1451    VA_GET_ARG(ap, cmd, int);
1452
1453#if defined(LINKED_XMOD_zshQszle) || defined(UNLINKED_XMOD_zshQszle)
1454    /* autoload */
1455    switch (zle_load_state) {
1456    case 0:
1457	/*
1458	 * Some commands don't require us to load ZLE.
1459	 * These also have no fallback.
1460	 */
1461	if (cmd != ZLE_CMD_TRASH && cmd != ZLE_CMD_RESET_PROMPT &&
1462	    cmd != ZLE_CMD_REFRESH)
1463	{
1464	    if (load_module("zsh/zle", NULL, 0) != 1) {
1465		(void)load_module("zsh/compctl", NULL, 0);
1466		ret = zle_entry_ptr(cmd, ap);
1467		/* Don't execute fallback code */
1468		cmd = -1;
1469	    } else {
1470		zle_load_state = 2;
1471		/* Execute fallback code below */
1472	    }
1473	}
1474	break;
1475
1476    case 1:
1477	ret = zle_entry_ptr(cmd, ap);
1478	/* Don't execute fallback code */
1479	cmd = -1;
1480	break;
1481
1482    case 2:
1483	/* Execute fallback code */
1484	break;
1485    }
1486#endif
1487
1488    switch (cmd) {
1489	/*
1490	 * Only the read command really needs a fallback if zle
1491	 * is not available.  ZLE_CMD_GET_LINE has traditionally
1492	 * had local code in bufferwords() to do this, but that'
1493	 * probably only because bufferwords() is part of completion
1494	 * and so everything to do with it is horribly complicated.
1495	 */
1496    case ZLE_CMD_READ:
1497    {
1498	char *pptbuf, **lp;
1499	int pptlen;
1500
1501	lp = va_arg(ap, char **);
1502
1503	pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL,
1504				       NULL),
1505			  &pptlen);
1506	write_loop(2, pptbuf, pptlen);
1507	free(pptbuf);
1508
1509	ret = shingetline();
1510	break;
1511    }
1512
1513    case ZLE_CMD_GET_LINE:
1514    {
1515	int *ll, *cs;
1516
1517	ll = va_arg(ap, int *);
1518	cs = va_arg(ap, int *);
1519	*ll = *cs = 0;
1520	ret = ztrdup("");
1521	break;
1522    }
1523    }
1524
1525    va_end(ap);
1526    return ret;
1527}
1528
1529/* compctl entry point pointers.  Similar to the ZLE ones. */
1530
1531/**/
1532mod_export CompctlReadFn compctlreadptr = fallback_compctlread;
1533
1534/**/
1535mod_export int
1536fallback_compctlread(char *name, UNUSED(char **args), UNUSED(Options ops), UNUSED(char *reply))
1537{
1538    zwarnnam(name, "option valid only in functions called from completion");
1539    return 1;
1540}
1541
1542/*
1543 * Used by zle to indicate it has already printed a "use 'exit' to exit"
1544 * message.
1545 */
1546/**/
1547mod_export int use_exit_printed;
1548
1549/*
1550 * This is real main entry point. This has to be mod_export'ed
1551 * so zsh.exe can found it on Cygwin
1552 */
1553
1554/**/
1555mod_export int
1556zsh_main(int argc, char **argv)
1557{
1558    char **t, *runscript = NULL;
1559    int t0;
1560#ifdef USE_LOCALE
1561    setlocale(LC_ALL, "");
1562#endif
1563
1564    if (argc < 1) {
1565	argzero = "zsh";
1566	zerr("too few arguments", NULL, 0);
1567	exit(1);
1568    }
1569
1570    init_jobs(argv, environ);
1571
1572    /*
1573     * Provisionally set up the type table to allow metafication.
1574     * This will be done properly when we have decided if we are
1575     * interactive
1576     */
1577    typtab['\0'] |= IMETA;
1578    typtab[STOUC(Meta)  ] |= IMETA;
1579    typtab[STOUC(Marker)] |= IMETA;
1580    for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++)
1581	typtab[t0] |= ITOK | IMETA;
1582
1583    for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
1584
1585    zsh_name = argv[0];
1586    do {
1587      char *arg0 = zsh_name;
1588      if (!(zsh_name = strrchr(arg0, '/')))
1589	  zsh_name = arg0;
1590      else
1591	  zsh_name++;
1592      if (*zsh_name == '-')
1593	  zsh_name++;
1594      if (strcmp(zsh_name, "su") == 0) {
1595	  char *sh = zgetenv("SHELL");
1596	  if (sh && *sh && arg0 != sh)
1597	      zsh_name = sh;
1598	  else
1599	      break;
1600      } else
1601	  break;
1602    } while (zsh_name);
1603
1604    fdtable_size = zopenmax();
1605    fdtable = zshcalloc(fdtable_size*sizeof(*fdtable));
1606    fdtable[0] = fdtable[1] = fdtable[2] = FDT_EXTERNAL;
1607
1608    createoptiontable();
1609    emulate(zsh_name, 1, &emulation, opts);   /* initialises most options */
1610    opts[LOGINSHELL] = (**argv == '-');
1611    opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
1612    opts[USEZLE] = 1;   /* may be unset in init_io() */
1613    /* sets INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
1614    parseargs(argv, &runscript);
1615
1616    SHTTY = -1;
1617    init_io();
1618    setupvals();
1619
1620    init_signals();
1621    init_bltinmods();
1622    init_builtins();
1623    run_init_scripts();
1624    setupshin(runscript);
1625    init_misc();
1626
1627    for (;;) {
1628	/*
1629	 * See if we can free up some of jobtab.
1630	 * We only do this at top level, because if we are
1631	 * executing stuff we may refer to them by job pointer.
1632	 */
1633	int errexit = 0;
1634	maybeshrinkjobtab();
1635
1636	do {
1637	    /* Reset return from top level which gets us back here */
1638	    retflag = 0;
1639	    loop(1,0);
1640	    if (errflag && !interact && !isset(CONTINUEONERROR)) {
1641		errexit = 1;
1642		break;
1643	    }
1644	} while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN)));
1645	if (tok == LEXERR || errexit) {
1646	    /* Make sure a fatal error exits with non-zero status */
1647	    if (!lastval)
1648		lastval = 1;
1649	    stopmsg = 1;
1650	    zexit(lastval, 0);
1651	}
1652	if (!(isset(IGNOREEOF) && interact)) {
1653#if 0
1654	    if (interact)
1655		fputs(islogin ? "logout\n" : "exit\n", shout);
1656#endif
1657	    zexit(lastval, 0);
1658	    continue;
1659	}
1660	noexitct++;
1661	if (noexitct >= 10) {
1662	    stopmsg = 1;
1663	    zexit(lastval, 0);
1664	}
1665	/*
1666	 * Don't print the message if it was already handled by
1667	 * zle, since that makes special arrangements to keep
1668	 * the display tidy.
1669	 */
1670	if (!use_exit_printed)
1671	    zerrnam("zsh", (!islogin) ? "use 'exit' to exit."
1672		    : "use 'logout' to logout.");
1673    }
1674}
1675