summaryrefslogtreecommitdiff
path: root/Src/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/init.c')
-rw-r--r--Src/init.c936
1 files changed, 936 insertions, 0 deletions
diff --git a/Src/init.c b/Src/init.c
new file mode 100644
index 000000000..33496adc6
--- /dev/null
+++ b/Src/init.c
@@ -0,0 +1,936 @@
+/*
+ * init.c - main loop and initialization routines
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1992-1997 Paul Falstad
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Paul Falstad or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Paul Falstad and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Paul Falstad and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Paul Falstad and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "zsh.mdh"
+#include "init.pro"
+
+#include "zshpaths.h"
+#include "zshxmods.h"
+
+/**/
+int noexitct = 0;
+
+/* what level of sourcing we are at */
+
+/**/
+int sourcelevel;
+
+/* the shell tty fd */
+
+/**/
+int SHTTY;
+
+/* the FILE attached to the shell tty */
+
+/**/
+FILE *shout;
+
+/* termcap strings */
+
+/**/
+char *tcstr[TC_COUNT];
+
+/* lengths of each termcap string */
+
+/**/
+int tclen[TC_COUNT];
+
+/* Values of the li, co and am entries */
+
+/**/
+int tclines, tccolumns, hasam;
+
+#ifdef DEBUG
+/* depth of allocation type stack */
+
+/**/
+int alloc_stackp;
+#endif
+
+/* keep executing lists until EOF found */
+
+/**/
+void
+loop(int toplevel, int justonce)
+{
+ List list;
+#ifdef DEBUG
+ int oasp = toplevel ? 0 : alloc_stackp;
+#endif
+
+ pushheap();
+ for (;;) {
+ freeheap();
+ errflag = 0;
+ if (isset(SHINSTDIN)) {
+ setblock_stdin();
+ if (interact)
+ preprompt();
+ }
+ hbegin(); /* init history mech */
+ intr(); /* interrupts on */
+ lexinit(); /* initialize lexical state */
+ if (!(list = parse_event())) { /* if we couldn't parse a list */
+ hend();
+ if ((tok == ENDINPUT && !errflag) ||
+ (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) ||
+ justonce)
+ break;
+ continue;
+ }
+ if (hend()) {
+ int toksav = tok;
+ List prelist;
+
+ if (toplevel && (prelist = getshfunc("preexec")) != &dummy_list) {
+ Histent he = gethistent(curhist);
+ LinkList args;
+ PERMALLOC {
+ args = newlinklist();
+ addlinknode(args, "preexec");
+ if (he && he->text)
+ addlinknode(args, he->text);
+ } LASTALLOC;
+ doshfunc(prelist, args, 0, 1);
+ freelinklist(args, (FreeFunc) NULL);
+ errflag = 0;
+ }
+ if (stopmsg) /* unset 'you have stopped jobs' flag */
+ stopmsg--;
+ execlist(list, 0, 0);
+ tok = toksav;
+ if (toplevel)
+ noexitct = 0;
+ }
+ DPUTS(alloc_stackp != oasp, "BUG: alloc_stackp changed in loop()");
+ if (ferror(stderr)) {
+ zerr("write error", NULL, 0);
+ clearerr(stderr);
+ }
+ if (subsh) /* how'd we get this far in a subshell? */
+ exit(lastval);
+ if (((!interact || sourcelevel) && errflag) || retflag)
+ break;
+ if (trapreturn) {
+ lastval = trapreturn;
+ trapreturn = 0;
+ }
+ if (isset(SINGLECOMMAND) && toplevel) {
+ if (sigtrapped[SIGEXIT])
+ dotrap(SIGEXIT);
+ exit(lastval);
+ }
+ if (justonce)
+ break;
+ }
+ popheap();
+}
+
+static char *cmd;
+static int restricted;
+
+/**/
+void
+parseargs(char **argv)
+{
+ char **x;
+ int action, optno;
+ LinkList paramlist;
+ int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH);
+
+ argzero = *argv++;
+ SHIN = 0;
+
+ /* There's a bit of trickery with opts[INTERACTIVE] here. It starts *
+ * at a value of 2 (instead of 1) or 0. If it is explicitly set on *
+ * the command line, it goes to 1 or 0. If input is coming from *
+ * somewhere that normally makes the shell non-interactive, we do *
+ * "opts[INTERACTIVE] &= 1", so that only a *default* on state will *
+ * be changed. At the end of the function, a value of 2 gets *
+ * changed to 1. */
+ opts[INTERACTIVE] = isatty(0) ? 2 : 0;
+ opts[SHINSTDIN] = 0;
+ opts[SINGLECOMMAND] = 0;
+
+ /* loop through command line options (begins with "-" or "+") */
+ while (*argv && (**argv == '-' || **argv == '+')) {
+ action = (**argv == '-');
+ if(!argv[0][1])
+ *argv = "--";
+ while (*++*argv) {
+ /* The pseudo-option `--' signifies the end of options. *
+ * `-b' does too, csh-style, unless we're emulating a *
+ * Bourne style shell. */
+ if (**argv == '-' || (!bourne && **argv == 'b')) {
+ argv++;
+ goto doneoptions;
+ }
+
+ if (**argv == 'c') { /* -c command */
+ if (!*++argv) {
+ zerr("string expected after -c", NULL, 0);
+ exit(1);
+ }
+ cmd = *argv++;
+ opts[INTERACTIVE] &= 1;
+ opts[SHINSTDIN] = 0;
+ goto doneoptions;
+ } else if (**argv == 'o') {
+ if (!*++*argv)
+ argv++;
+ if (!*argv) {
+ zerr("string expected after -o", NULL, 0);
+ exit(1);
+ }
+ if(!(optno = optlookup(*argv)))
+ zerr("no such option: %s", *argv, 0);
+ else if (optno == RESTRICTED)
+ restricted = action;
+ else
+ dosetopt(optno, action, 1);
+ break;
+ } else {
+ if (!(optno = optlookupc(**argv))) {
+ zerr("bad option: -%c", NULL, **argv);
+ exit(1);
+ } else if (optno == RESTRICTED)
+ restricted = action;
+ else
+ dosetopt(optno, action, 1);
+ }
+ }
+ argv++;
+ }
+ doneoptions:
+ paramlist = newlinklist();
+ if (*argv) {
+ if (unset(SHINSTDIN)) {
+ argzero = *argv;
+ if (!cmd)
+ SHIN = movefd(open(unmeta(argzero), O_RDONLY | O_NOCTTY));
+ if (SHIN == -1) {
+ zerr("can't open input file: %s", argzero, 0);
+ exit(1);
+ }
+ opts[INTERACTIVE] &= 1;
+ argv++;
+ }
+ while (*argv)
+ addlinknode(paramlist, ztrdup(*argv++));
+ } else
+ opts[SHINSTDIN] = 1;
+ if(isset(SINGLECOMMAND))
+ opts[INTERACTIVE] &= 1;
+ opts[INTERACTIVE] = !!opts[INTERACTIVE];
+ pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
+
+ while ((*x++ = (char *)getlinknode(paramlist)));
+ free(paramlist);
+ argzero = ztrdup(argzero);
+}
+
+
+/**/
+void
+init_io(void)
+{
+ long ttpgrp;
+ static char outbuf[BUFSIZ], errbuf[BUFSIZ];
+
+#ifdef RSH_BUG_WORKAROUND
+ int i;
+#endif
+
+/* stdout, stderr fully buffered */
+#ifdef _IOFBF
+ setvbuf(stdout, outbuf, _IOFBF, BUFSIZ);
+ setvbuf(stderr, errbuf, _IOFBF, BUFSIZ);
+#else
+ setbuffer(stdout, outbuf, BUFSIZ);
+ setbuffer(stderr, errbuf, BUFSIZ);
+#endif
+
+/* This works around a bug in some versions of in.rshd. *
+ * Currently this is not defined by default. */
+#ifdef RSH_BUG_WORKAROUND
+ if (cmd) {
+ for (i = 3; i < 10; i++)
+ close(i);
+ }
+#endif
+
+ if (shout) {
+ fclose(shout);
+ shout = 0;
+ }
+ if (SHTTY != -1) {
+ zclose(SHTTY);
+ SHTTY = -1;
+ }
+
+ /* Make sure the tty is opened read/write. */
+ if (isatty(0)) {
+ zsfree(ttystrname);
+ if ((ttystrname = ztrdup(ttyname(0))))
+ SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY));
+ }
+ if (SHTTY == -1 &&
+ (SHTTY = movefd(open("/dev/tty", O_RDWR | O_NOCTTY))) != -1) {
+ zsfree(ttystrname);
+ ttystrname = ztrdup("/dev/tty");
+ }
+ if (SHTTY == -1) {
+ zsfree(ttystrname);
+ ttystrname = ztrdup("");
+ }
+
+ /* We will only use zle if shell is interactive, *
+ * SHTTY != -1, and shout != 0 */
+ if (interact && SHTTY != -1) {
+ init_shout();
+ if(!shout)
+ opts[USEZLE] = 0;
+ } else
+ opts[USEZLE] = 0;
+
+#ifdef JOB_CONTROL
+ /* If interactive, make the shell the foreground process */
+ if (opts[MONITOR] && interact && (SHTTY != -1)) {
+ attachtty(GETPGRP());
+ if ((mypgrp = GETPGRP()) > 0) {
+ while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
+ sleep(1);
+ mypgrp = GETPGRP();
+ if (mypgrp == gettygrp())
+ break;
+ killpg(mypgrp, SIGTTIN);
+ mypgrp = GETPGRP();
+ }
+ } else
+ opts[MONITOR] = 0;
+ } else
+ opts[MONITOR] = 0;
+#else
+ opts[MONITOR] = 0;
+#endif
+}
+
+/**/
+void
+init_shout(void)
+{
+ static char shoutbuf[BUFSIZ];
+#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
+ int ldisc = NTTYDISC;
+
+ ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
+#endif
+
+ /* Associate terminal file descriptor with a FILE pointer */
+ shout = fdopen(SHTTY, "w");
+#ifdef _IOFBF
+ setvbuf(shout, shoutbuf, _IOFBF, BUFSIZ);
+#endif
+
+ gettyinfo(&shttyinfo); /* get tty state */
+#if defined(__sgi)
+ if (shttyinfo.tio.c_cc[VSWTCH] <= 0) /* hack for irises */
+ shttyinfo.tio.c_cc[VSWTCH] = CSWTCH;
+#endif
+}
+
+/* names of the termcap strings we want */
+
+static char *tccapnams[TC_COUNT] = {
+ "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
+ "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
+ "md", "so", "us", "me", "se", "ue"
+};
+
+/* Initialise termcap */
+
+/**/
+int
+init_term(void)
+{
+#ifndef TGETENT_ACCEPTS_NULL
+ static char termbuf[2048]; /* the termcap buffer */
+#endif
+
+ if (!*term) {
+ termflags |= TERM_UNKNOWN;
+ return 0;
+ }
+
+ /* unset zle if using zsh under emacs */
+ if (!strcmp(term, "emacs"))
+ opts[USEZLE] = 0;
+
+#ifdef TGETENT_ACCEPTS_NULL
+ /* If possible, we let tgetent allocate its own termcap buffer */
+ if (tgetent(NULL, term) != 1) {
+#else
+ if (tgetent(termbuf, term) != 1) {
+#endif
+
+ if (isset(INTERACTIVE))
+ zerr("can't find termcap info for %s", term, 0);
+ errflag = 0;
+ termflags |= TERM_BAD;
+ return 0;
+ } else {
+ char tbuf[1024], *pp;
+ int t0;
+
+ termflags &= ~TERM_BAD;
+ termflags &= ~TERM_UNKNOWN;
+ for (t0 = 0; t0 != TC_COUNT; t0++) {
+ pp = tbuf;
+ zsfree(tcstr[t0]);
+ /* AIX tgetstr() ignores second argument */
+ if (!(pp = tgetstr(tccapnams[t0], &pp)))
+ tcstr[t0] = NULL, tclen[t0] = 0;
+ else {
+ tclen[t0] = strlen(pp);
+ tcstr[t0] = (char *) zalloc(tclen[t0] + 1);
+ memcpy(tcstr[t0], pp, tclen[t0] + 1);
+ }
+ }
+
+ /* check whether terminal has automargin (wraparound) capability */
+ hasam = tgetflag("am");
+
+ tclines = tgetnum("li");
+ tccolumns = tgetnum("co");
+
+ /* if there's no termcap entry for cursor up, use single line mode: *
+ * this is flagged by termflags which is examined in zle_refresh.c *
+ */
+ if (tccan(TCUP))
+ termflags &= ~TERM_NOUP;
+ else {
+ tcstr[TCUP] = NULL;
+ termflags |= TERM_NOUP;
+ }
+
+ /* if there's no termcap entry for cursor left, use \b. */
+ if (!tccan(TCLEFT)) {
+ tcstr[TCLEFT] = ztrdup("\b");
+ tclen[TCLEFT] = 1;
+ }
+
+ /* if the termcap entry for down is \n, don't use it. */
+ if (tccan(TCDOWN) && tcstr[TCDOWN][0] == '\n') {
+ tclen[TCDOWN] = 0;
+ zsfree(tcstr[TCDOWN]);
+ tcstr[TCDOWN] = NULL;
+ }
+
+ /* if there's no termcap entry for clear, use ^L. */
+ if (!tccan(TCCLEARSCREEN)) {
+ tcstr[TCCLEARSCREEN] = ztrdup("\14");
+ tclen[TCCLEARSCREEN] = 1;
+ }
+ }
+ return 1;
+}
+
+/* Initialize lots of global variables and hash tables */
+
+/**/
+void
+setupvals(void)
+{
+#ifdef HAVE_GETPWUID
+ struct passwd *pswd;
+#endif
+ struct timezone dummy_tz;
+ char *ptr;
+#ifdef HAVE_GETRLIMIT
+ int i;
+#endif
+
+ noeval = 0;
+ curhist = 0;
+ histsiz = DEFAULT_HISTSIZE;
+ inithist();
+
+ cmdstack = (unsigned char *) zalloc(256);
+ cmdsp = 0;
+
+ bangchar = '!';
+ hashchar = '#';
+ hatchar = '^';
+ termflags = TERM_UNKNOWN;
+ curjob = prevjob = coprocin = coprocout = -1;
+ gettimeofday(&shtimer, &dummy_tz); /* init $SECONDS */
+ srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */
+
+ hostnam = (char *) zalloc(256);
+ gethostname(hostnam, 256);
+
+ /* Set default path */
+ path = (char **) zalloc(sizeof(*path) * 5);
+ path[0] = ztrdup("/bin");
+ path[1] = ztrdup("/usr/bin");
+ path[2] = ztrdup("/usr/ucb");
+ path[3] = ztrdup("/usr/local/bin");
+ path[4] = NULL;
+
+ cdpath = mkarray(NULL);
+ manpath = mkarray(NULL);
+ fignore = mkarray(NULL);
+ fpath = mkarray(NULL);
+ mailpath = mkarray(NULL);
+ watch = mkarray(NULL);
+ psvar = mkarray(NULL);
+#ifdef DYNAMIC
+ module_path = mkarray(ztrdup(MODULE_DIR));
+ modules = newlinklist();
+#endif
+
+ /* Set default prompts */
+ if(unset(INTERACTIVE)) {
+ prompt = ztrdup("");
+ prompt2 = ztrdup("");
+ } else if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
+ prompt = ztrdup(privasserted() ? "# " : "$ ");
+ prompt2 = ztrdup("> ");
+ } else {
+ prompt = ztrdup("%m%# ");
+ prompt2 = ztrdup("%_> ");
+ }
+ prompt3 = ztrdup("?# ");
+ prompt4 = ztrdup("+ ");
+ sprompt = ztrdup("zsh: correct '%R' to '%r' [nyae]? ");
+
+ ifs = ztrdup(DEFAULT_IFS);
+ wordchars = ztrdup(DEFAULT_WORDCHARS);
+ postedit = ztrdup("");
+ underscore = ztrdup("");
+
+ zoptarg = ztrdup("");
+ zoptind = 1;
+
+ ppid = (long) getppid();
+ mypid = (long) getpid();
+ term = ztrdup("");
+
+ /* The following variable assignments cause zsh to behave more *
+ * like Bourne and Korn shells when invoked as "sh" or "ksh". *
+ * NULLCMD=":" and READNULLCMD=":" */
+
+ if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
+ nullcmd = ztrdup(":");
+ readnullcmd = ztrdup(":");
+ } else {
+ nullcmd = ztrdup("cat");
+ readnullcmd = ztrdup("more");
+ }
+
+ /* We cache the uid so we know when to *
+ * recheck the info for `USERNAME' */
+ cached_uid = getuid();
+
+ /* Get password entry and set info for `HOME' and `USERNAME' */
+#ifdef HAVE_GETPWUID
+ if ((pswd = getpwuid(cached_uid))) {
+ home = metafy(pswd->pw_dir, -1, META_DUP);
+ cached_username = ztrdup(pswd->pw_name);
+ } else
+#endif /* HAVE_GETPWUID */
+ {
+ home = ztrdup("/");
+ cached_username = ztrdup("");
+ }
+
+ /* Try a cheap test to see if we can *
+ * initialize `PWD' from `HOME' */
+ if (ispwd(home))
+ pwd = ztrdup(home);
+ else if ((ptr = zgetenv("PWD")) && ispwd(ptr))
+ pwd = ztrdup(ptr);
+ else
+ pwd = metafy(zgetcwd(), -1, META_DUP);
+
+ oldpwd = ztrdup(pwd); /* initialize `OLDPWD' = `PWD' */
+
+ inittyptab(); /* initialize the ztypes table */
+ initlextabs(); /* initialize lexing tables */
+
+ createreswdtable(); /* create hash table for reserved words */
+ createaliastable(); /* create hash table for aliases */
+ createcmdnamtable(); /* create hash table for external commands */
+ createshfunctable(); /* create hash table for shell functions */
+ createbuiltintable(); /* create hash table for builtin commands */
+ createnameddirtable(); /* create hash table for named directories */
+ createparamtable(); /* create paramater hash table */
+
+#ifdef TIOCGWINSZ
+ adjustwinsize();
+#else
+ /* Using zero below sets the defaults from termcap */
+ setiparam("COLUMNS", 0);
+ setiparam("LINES", 0);
+#endif
+
+#ifdef HAVE_GETRLIMIT
+ for (i = 0; i != RLIM_NLIMITS; i++) {
+ getrlimit(i, current_limits + i);
+ limits[i] = current_limits[i];
+ }
+#endif
+
+ breaks = loops = 0;
+ lastmailcheck = time(NULL);
+ locallevel = sourcelevel = 0;
+ trapreturn = 0;
+ noerrexit = -1;
+ nohistsave = 1;
+ dirstack = newlinklist();
+ bufstack = newlinklist();
+ prepromptfns = newlinklist();
+ hsubl = hsubr = NULL;
+ lastpid = 0;
+ bshin = SHIN ? fdopen(SHIN, "r") : stdin;
+ if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
+#ifdef _IONBF
+ setvbuf(stdin, NULL, _IONBF, 0);
+#else
+ setlinebuf(stdin);
+#endif
+ }
+
+ times(&shtms);
+}
+
+/* Initialize signal handling */
+
+/**/
+void
+init_signals(void)
+{
+ intr();
+
+#ifndef QDEBUG
+ signal_ignore(SIGQUIT);
+#endif
+
+ install_handler(SIGHUP);
+ install_handler(SIGCHLD);
+#ifdef SIGWINCH
+ install_handler(SIGWINCH);
+#endif
+ if (interact) {
+ install_handler(SIGALRM);
+ signal_ignore(SIGTERM);
+ }
+ if (jobbing) {
+ long ttypgrp;
+
+ while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
+ kill(0, SIGTTIN);
+ if (ttypgrp == -1) {
+ opts[MONITOR] = 0;
+ } else {
+ signal_ignore(SIGTTOU);
+ signal_ignore(SIGTSTP);
+ signal_ignore(SIGTTIN);
+ attachtty(mypgrp);
+ }
+ }
+ if (islogin) {
+ signal_setmask(signal_mask(0));
+ } else if (interact) {
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ signal_unblock(set);
+ }
+}
+
+/* Source the init scripts. If called as "ksh" or "sh" *
+ * then we source the standard sh/ksh scripts instead of *
+ * the standard zsh scripts */
+
+/**/
+void
+run_init_scripts(void)
+{
+ noerrexit = -1;
+
+ if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
+ if (islogin)
+ source("/etc/profile");
+ if (unset(PRIVILEGED)) {
+ char *s = getsparam("ENV");
+ if (islogin)
+ sourcehome(".profile");
+ noerrs = 1;
+ if (s && !parsestr(s)) {
+ singsub(&s);
+ noerrs = 0;
+ source(s);
+ }
+ noerrs = 0;
+ } else
+ source("/etc/suid_profile");
+ } else {
+#ifdef GLOBAL_ZSHENV
+ source(GLOBAL_ZSHENV);
+#endif
+ if (isset(RCS)) {
+ if (unset(PRIVILEGED))
+ sourcehome(".zshenv");
+ if (islogin) {
+#ifdef GLOBAL_ZPROFILE
+ source(GLOBAL_ZPROFILE);
+#endif
+ if (unset(PRIVILEGED))
+ sourcehome(".zprofile");
+ }
+ if (interact) {
+#ifdef GLOBAL_ZSHRC
+ source(GLOBAL_ZSHRC);
+#endif
+ if (unset(PRIVILEGED))
+ sourcehome(".zshrc");
+ }
+ if (islogin) {
+#ifdef GLOBAL_ZLOGIN
+ source(GLOBAL_ZLOGIN);
+#endif
+ if (unset(PRIVILEGED))
+ sourcehome(".zlogin");
+ }
+ }
+ }
+ noerrexit = 0;
+ nohistsave = 0;
+}
+
+/* Miscellaneous initializations that happen after init scripts are run */
+
+/**/
+void
+init_misc(void)
+{
+ if (*zsh_name == 'r' || restricted)
+ dosetopt(RESTRICTED, 1, 0);
+ if (cmd) {
+ if (SHIN >= 10)
+ fclose(bshin);
+ SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
+ bshin = fdopen(SHIN, "r");
+ execstring(cmd, 0, 1);
+ stopmsg = 1;
+ zexit(lastval, 0);
+ }
+
+ if (interact && isset(RCS))
+ readhistfile(getsparam("HISTFILE"), 0);
+}
+
+/* source a file */
+
+/**/
+int
+source(char *s)
+{
+ int tempfd, fd, cj, oldlineno;
+ int oldshst, osubsh, oloops;
+ FILE *obshin;
+ char *old_scriptname = scriptname;
+
+ if (!s || (tempfd = movefd(open(unmeta(s), O_RDONLY | O_NOCTTY))) == -1) {
+ return 1;
+ }
+
+ /* save the current shell state */
+ fd = SHIN; /* store the shell input fd */
+ obshin = bshin; /* store file handle for buffered shell input */
+ osubsh = subsh; /* store whether we are in a subshell */
+ cj = thisjob; /* store our current job number */
+ oldlineno = lineno; /* store our current lineno */
+ oloops = loops; /* stored the # of nested loops we are in */
+ oldshst = opts[SHINSTDIN]; /* store current value of this option */
+
+ SHIN = tempfd;
+ bshin = fdopen(SHIN, "r");
+ subsh = 0;
+ lineno = 0;
+ loops = 0;
+ dosetopt(SHINSTDIN, 0, 1);
+ scriptname = s;
+
+ sourcelevel++;
+ loop(0, 0); /* loop through the file to be sourced */
+ sourcelevel--;
+ fclose(bshin);
+ fdtable[SHIN] = 0;
+
+ /* restore the current shell state */
+ SHIN = fd; /* the shell input fd */
+ bshin = obshin; /* file handle for buffered shell input */
+ subsh = osubsh; /* whether we are in a subshell */
+ thisjob = cj; /* current job number */
+ lineno = oldlineno; /* our current lineno */
+ loops = oloops; /* the # of nested loops we are in */
+ dosetopt(SHINSTDIN, oldshst, 1); /* SHINSTDIN option */
+ errflag = 0;
+ retflag = 0;
+ scriptname = old_scriptname;
+
+ return 0;
+}
+
+/* Try to source a file in the home directory */
+
+/**/
+void
+sourcehome(char *s)
+{
+ char buf[PATH_MAX];
+ char *h;
+
+ if (emulation == EMULATE_SH || emulation == EMULATE_KSH ||
+ !(h = getsparam("ZDOTDIR")))
+ h = home;
+ if (strlen(h) + strlen(s) + 1 >= PATH_MAX) {
+ zerr("path too long: %s", s, 0);
+ return;
+ }
+ sprintf(buf, "%s/%s", h, s);
+ source(buf);
+}
+
+/**/
+void
+init_bltinmods(void)
+{
+ static struct module mod = { NULL, 0, NULL, NULL };
+#include "bltinmods.list"
+ mod.nam = NULL;
+}
+
+/* ZLE entry point pointers. They are defined here because the initial *
+ * values depend on whether ZLE is linked in or not -- if it is, we *
+ * avoid wasting space with the fallback functions. No other source *
+ * file needs to know which modules are linked in. */
+
+#ifdef LINKED_XMOD_zle
+
+/**/
+ZleVoidFn trashzleptr;
+/**/
+ZleVoidFn gotwordptr;
+/**/
+ZleVoidFn refreshptr;
+/**/
+ZleVoidIntFn spaceinlineptr;
+/**/
+ZleReadFn zlereadptr;
+
+#else /* !LINKED_XMOD_zle */
+
+ZleVoidFn trashzleptr = noop_function;
+ZleVoidFn gotwordptr = noop_function;
+ZleVoidFn refreshptr = noop_function;
+ZleVoidIntFn spaceinlineptr = noop_function_int;
+# ifdef UNLINKED_XMOD_zle
+ZleReadFn zlereadptr = autoload_zleread;
+# else /* !UNLINKED_XMOD_zle */
+ZleReadFn zlereadptr = fallback_zleread;
+# endif /* !UNLINKED_XMOD_zle */
+
+/**/
+void
+noop_function(void)
+{
+ /* do nothing */
+}
+
+/**/
+void
+noop_function_int(int nothing)
+{
+ /* do nothing */
+}
+
+# ifdef UNLINKED_XMOD_zle
+
+/**/
+static unsigned char *
+autoload_zleread(char *lp, char *rp, int ha)
+{
+ zlereadptr = fallback_zleread;
+ load_module("zle");
+ return zleread(lp, rp, ha);
+}
+
+# endif /* UNLINKED_XMOD_zle */
+
+/**/
+unsigned char *
+fallback_zleread(char *lp, char *rp, int ha)
+{
+ char *pptbuf;
+ int pptlen;
+
+ pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen);
+ write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
+ free(pptbuf);
+ return (unsigned char *)shingetline();
+}
+
+#endif /* !LINKED_XMOD_zle */
+
+/* compctl entry point pointers. Similar to the ZLE ones. */
+
+#ifdef LINKED_XMOD_comp1
+
+/**/
+CompctlReadFn compctlreadptr;
+
+#else /* !LINKED_XMOD_comp1 */
+
+CompctlReadFn compctlreadptr = fallback_compctlread;
+
+/**/
+int
+fallback_compctlread(char *name, char **args, char *ops, char *reply)
+{
+ zwarnnam(name, "option valid only in functions called from completion",
+ NULL, 0);
+ return 1;
+}
+
+#endif /* !LINKED_XMOD_comp1 */