home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / init.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  21.6 KB  |  878 lines

  1. /*
  2.  * $Id: init.c,v 2.46 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * init.c - main loop and initialization routines
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #define GLOBALS
  33. #include "zsh.h"
  34.  
  35. static int noexitct = 0;
  36.  
  37. /**/
  38. int
  39. main(int argc, char **argv)
  40. {
  41.     char **t;
  42. #ifdef LC_ALL
  43.     setlocale(LC_ALL, "");
  44. #endif
  45.  
  46.     global_permalloc();
  47.  
  48.     for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
  49.  
  50.     if (!(zsh_name = strrchr(argv[0], '/')))
  51.     zsh_name = argv[0];
  52.     else
  53.     zsh_name++;
  54.     if (*zsh_name == '-')
  55.     zsh_name++;
  56.  
  57.     fdtable_size = OPEN_MAX;
  58.     fdtable = zcalloc(fdtable_size);
  59.  
  60.     emulate(zsh_name, 1);   /* initialises most options */
  61.     opts[LOGINSHELL] = (**argv == '-');
  62.     opts[MONITOR] = 1;   /* may be unset in init_io() */
  63.     opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
  64.     opts[USEZLE] = 1;   /* may be unset in init_io() */
  65.     parseargs(argv);   /* sets INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
  66.  
  67.     SHTTY = -1;
  68.     init_io();
  69.     setupvals();
  70.     init_signals();
  71.     global_heapalloc();
  72.     run_init_scripts();
  73.     init_misc();
  74.  
  75.     for (;;) {
  76.     do
  77.         loop(1);
  78.     while (tok != ENDINPUT);
  79.     if (!(isset(IGNOREEOF) && interact)) {
  80. #if 0
  81.         if (interact)
  82.         fputs(islogin ? "logout\n" : "exit\n", stderr);
  83. #endif
  84.         zexit(lastval, 0);
  85.         continue;
  86.     }
  87.     noexitct++;
  88.     if (noexitct >= 10) {
  89.         stopmsg = 1;
  90.         zexit(lastval, 0);
  91.     }
  92.     zerrnam("zsh", (!islogin) ? "use 'exit' to exit."
  93.         : "use 'logout' to logout.", NULL, 0);
  94.     }
  95. }
  96.  
  97. /* keep executing lists until EOF found */
  98.  
  99. /**/
  100. void
  101. loop(int toplevel)
  102. {
  103.     List list;
  104. #ifdef DEBUG
  105.     int oasp = toplevel ? 0 : alloc_stackp;
  106. #endif
  107.  
  108.     pushheap();
  109.     for (;;) {
  110.     freeheap();
  111.     errflag = 0;
  112.     if (isset(SHINSTDIN)) {
  113.         setblock_stdin();
  114.         if (interact)
  115.         preprompt();
  116.     }
  117.     hbegin();        /* init history mech        */
  118.     intr();            /* interrupts on            */
  119.     lexinit();              /* initialize lexical state */
  120.     if (!(list = parse_event())) {    /* if we couldn't parse a list */
  121.         hend();
  122.         if (tok == ENDINPUT && !errflag)
  123.         break;
  124.         continue;
  125.     }
  126.     if (hend()) {
  127.         int toksav = tok;
  128.  
  129.         if (stopmsg)    /* unset 'you have stopped jobs' flag */
  130.         stopmsg--;
  131.         execlist(list, 0, 0);
  132.         tok = toksav;
  133.         if (toplevel)
  134.         noexitct = 0;
  135.     }
  136.     DPUTS(alloc_stackp != oasp, "BUG: alloc_stackp changed in loop()");
  137.     if (ferror(stderr)) {
  138.         zerr("write error", NULL, 0);
  139.         clearerr(stderr);
  140.     }
  141.     if (subsh)        /* how'd we get this far in a subshell? */
  142.         exit(lastval);
  143.     if (((!interact || sourcelevel) && errflag) || retflag)
  144.         break;
  145.     if (trapreturn) {
  146.         lastval = trapreturn;
  147.         trapreturn = 0;
  148.     }
  149.     if (isset(SINGLECOMMAND) && toplevel) {
  150.         if (sigtrapped[SIGEXIT])
  151.         dotrap(SIGEXIT);
  152.         exit(lastval);
  153.     }
  154.     }
  155.     popheap();
  156. }
  157.  
  158. /**/
  159. void
  160. emulate(const char *zsh_name, int fully)
  161. {
  162.     int optno;
  163.  
  164.     /* Work out the new emulation mode */
  165.     if(!strcmp(zsh_name, "csh"))
  166.     emulation = EMULATE_CSH;
  167.     else if(!strcmp(zsh_name, "ksh"))
  168.     emulation = EMULATE_KSH;
  169.     else if(!strcmp(zsh_name, "sh"))
  170.     emulation = EMULATE_SH;
  171.     else
  172.     emulation = EMULATE_ZSH;
  173.  
  174.     /* Set options: each non-special option is set according to the *
  175.      * current emulation mode if either it is considered relevant   *
  176.      * to emulation or we are doing a full emulation (as indicated  *
  177.      * by the `fully' parameter).                                   */
  178.     for(optno = OPT_SIZE; --optno; )
  179.     if((fully && !(optns[optno].flags & OPT_SPECIAL)) ||
  180.             (optns[optno].flags & OPT_EMULATE))
  181.         opts[optno] = defset(optno);
  182. }
  183.  
  184. static char *cmd;
  185.  
  186. /**/
  187. void
  188. parseargs(char **argv)
  189. {
  190.     char **x;
  191.     int action, optno;
  192.     LinkList paramlist;
  193.     int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH);
  194.  
  195.     hackzero = argzero = *argv++;
  196.     SHIN = 0;
  197.  
  198.     /* There's a bit of trickery with opts[INTERACTIVE] here.  It starts *
  199.      * at a value of 2 (instead of 1) or 0.  If it is explicitly set on  *
  200.      * the command line, it goes to 1 or 0.  If input is coming from     *
  201.      * somewhere that normally makes the shell non-interactive, we do    *
  202.      * "opts[INTERACTIVE] &= 1", so that only a *default* on state will  *
  203.      * be changed.  At the end of the function, a value of 2 gets        *
  204.      * changed to 1.                                                     */
  205.     opts[INTERACTIVE] = isatty(0) ? 2 : 0;
  206.     opts[SHINSTDIN] = 0;
  207.     opts[SINGLECOMMAND] = 0;
  208.  
  209.     /* loop through command line options (begins with "-" or "+") */
  210.     while (*argv && (**argv == '-' || **argv == '+')) {
  211.     action = (**argv == '-');
  212.     if(!argv[0][1])
  213.         *argv = "--";
  214.     while (*++*argv) {
  215.         /* The pseudo-option `--' signifies the end of options. *
  216.          * `-b' does too, csh-style, unless we're emulating a   *
  217.          * Bourne style shell.                                  */
  218.         if (**argv == '-' || (!bourne && **argv == 'b')) {
  219.         argv++;
  220.         goto doneoptions;
  221.         }
  222.  
  223.         if (**argv == 'c') {         /* -c command */
  224.         if (!*++argv) {
  225.             zerr("string expected after -c", NULL, 0);
  226.             exit(1);
  227.         }
  228.         cmd = *argv++;
  229.         opts[INTERACTIVE] &= 1;
  230.         opts[SHINSTDIN] = 0;
  231.         goto doneoptions;
  232.         } else if (**argv == 'o') {
  233.         if (!*++*argv)
  234.             argv++;
  235.         if (!*argv) {
  236.             zerr("string expected after -o", NULL, 0);
  237.             exit(1);
  238.         }
  239.         if(!(optno = optlookup(*argv)))
  240.             zerr("no such option: %s", *argv, 0);
  241.         else
  242.             dosetopt(optno, action, 1);
  243.         break;
  244.         } else {
  245.             if (!(optno = optlookupc(**argv))) {
  246.             zerr("bad option: -%c", NULL, **argv);
  247.             exit(1);
  248.         } else
  249.             dosetopt(optno, action, 1);
  250.         }
  251.     }
  252.     argv++;
  253.     }
  254.     doneoptions:
  255.     paramlist = newlinklist();
  256.     if (*argv) {
  257.     if (unset(SHINSTDIN)) {
  258.         argzero = *argv;
  259.         if (!cmd)
  260.         SHIN = movefd(open(unmeta(argzero), O_RDONLY));
  261.         if (SHIN == -1) {
  262.         zerr("can't open input file: %s", argzero, 0);
  263.         exit(1);
  264.         }
  265.         opts[INTERACTIVE] &= 1;
  266.         argv++;
  267.     }
  268.     while (*argv)
  269.         addlinknode(paramlist, ztrdup(*argv++));
  270.     } else
  271.     opts[SHINSTDIN] = 1;
  272.     if(isset(SINGLECOMMAND))
  273.     opts[INTERACTIVE] &= 1;
  274.     opts[INTERACTIVE] = !!opts[INTERACTIVE];
  275.     pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
  276.  
  277.     while ((*x++ = (char *)getlinknode(paramlist)));
  278.     free(paramlist);
  279.     argzero = ztrdup(argzero);
  280. }
  281.  
  282.  
  283. /**/
  284. void
  285. init_io(void)
  286. {
  287.     long ttpgrp;
  288.     static char outbuf[BUFSIZ], errbuf[BUFSIZ];
  289.  
  290. #ifdef RSH_BUG_WORKAROUND
  291.     int i;
  292. #endif
  293.  
  294. /* stdout, stderr fully buffered */
  295. #ifdef _IOFBF
  296.     setvbuf(stdout, outbuf, _IOFBF, BUFSIZ);
  297.     setvbuf(stderr, errbuf, _IOFBF, BUFSIZ);
  298. #else
  299.     setbuffer(stdout, outbuf, BUFSIZ);
  300.     setbuffer(stderr, errbuf, BUFSIZ);
  301. #endif
  302.  
  303. /* This works around a bug in some versions of in.rshd. *
  304.  * Currently this is not defined by default.            */
  305. #ifdef RSH_BUG_WORKAROUND
  306.     if (cmd) {
  307.     for (i = 3; i < 10; i++)
  308.         close(i);
  309.     }
  310. #endif
  311.  
  312.     if (shout) {
  313.     fclose(shout);
  314.     shout = 0;
  315.     }
  316.     if (SHTTY != -1) {
  317.     zclose(SHTTY);
  318.     SHTTY = -1;
  319.     }
  320.  
  321.     /* Make sure the tty is opened read/write. */
  322.     if (isatty(0)) {
  323.     zsfree(ttystrname);
  324.     if ((ttystrname = ztrdup(ttyname(0))))
  325.         SHTTY = movefd(open(ttystrname, O_RDWR));
  326.     }
  327.     if (SHTTY == -1 && (SHTTY = movefd(open("/dev/tty", O_RDWR))) != -1) {
  328.     zsfree(ttystrname);
  329.     ttystrname = ztrdup("/dev/tty");
  330.     }
  331.     if (SHTTY == -1) {
  332.     zsfree(ttystrname);
  333.     ttystrname = ztrdup("");
  334.     }
  335.  
  336.     /* We will only use zle if shell is interactive, *
  337.      * SHTTY != -1, and shout != 0                   */
  338.     if (interact && SHTTY != -1) {
  339.     init_shout();
  340.     if(!shout)
  341.         opts[USEZLE] = 0;
  342.     } else
  343.     opts[USEZLE] = 0;
  344.  
  345. #ifdef JOB_CONTROL
  346.     /* If interactive, make the shell the foreground process */
  347.     if (opts[MONITOR] && interact && (SHTTY != -1)) {
  348.     attachtty(GETPGRP());
  349.     if ((mypgrp = GETPGRP()) > 0) {
  350.         while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
  351.         sleep(1);
  352.         mypgrp = GETPGRP();
  353.         if (mypgrp == gettygrp())
  354.             break;
  355.         killpg(mypgrp, SIGTTIN);
  356.         mypgrp = GETPGRP();
  357.         }
  358.     } else
  359.         opts[MONITOR] = 0;
  360.     } else
  361.     opts[MONITOR] = 0;
  362. #else
  363.     opts[MONITOR] = 0;
  364. #endif
  365. }
  366.  
  367. /**/
  368. void
  369. init_shout(void)
  370. {
  371.     static char shoutbuf[BUFSIZ];
  372. #if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
  373.     int ldisc = NTTYDISC;
  374.  
  375.     ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
  376. #endif
  377.  
  378.     /* Associate terminal file descriptor with a FILE pointer */
  379.     shout = fdopen(SHTTY, "w");
  380. #ifdef _IOFBF
  381.     setvbuf(shout, shoutbuf, _IOFBF, BUFSIZ);
  382. #endif
  383.   
  384.     gettyinfo(&shttyinfo);    /* get tty state */
  385. #if defined(__sgi)
  386.     if (shttyinfo.tio.c_cc[VSWTCH] <= 0)    /* hack for irises */
  387.     shttyinfo.tio.c_cc[VSWTCH] = CSWTCH;
  388. #endif
  389. }
  390.  
  391. /* flag for whether terminal has automargin (wraparound) capability */
  392. extern hasam;
  393.  
  394. /* Initialise termcap */
  395.  
  396. /**/
  397. int
  398. init_term(void)
  399. {
  400. #ifndef TGETENT_ACCEPTS_NULL
  401.     static char termbuf[2048];    /* the termcap buffer */
  402. #endif
  403.  
  404.     if (!*term) {
  405.     termflags |= TERM_UNKNOWN;
  406.     return 0;
  407.     }
  408.  
  409.     /* unset zle if using zsh under emacs */
  410.     if (!strcmp(term, "emacs"))
  411.     opts[USEZLE] = 0;
  412.  
  413. #ifdef TGETENT_ACCEPTS_NULL
  414.     /* If possible, we let tgetent allocate its own termcap buffer */
  415.     if (tgetent(NULL, term) != 1) {
  416. #else
  417.     if (tgetent(termbuf, term) != 1) {
  418. #endif
  419.  
  420.     if (isset(INTERACTIVE))
  421.         zerr("can't find termcap info for %s", term, 0);
  422.     errflag = 0;
  423.     termflags |= TERM_BAD;
  424.     return 0;
  425.     } else {
  426.     char tbuf[1024], *pp;
  427.     int t0;
  428.  
  429.     termflags &= ~TERM_BAD;
  430.     termflags &= ~TERM_UNKNOWN;
  431.     for (t0 = 0; t0 != TC_COUNT; t0++) {
  432.         pp = tbuf;
  433.         zsfree(tcstr[t0]);
  434.     /* AIX tgetstr() ignores second argument */
  435.         if (!(pp = tgetstr(tccapnams[t0], &pp)))
  436.         tcstr[t0] = NULL, tclen[t0] = 0;
  437.         else {
  438.         tclen[t0] = strlen(pp);
  439.         tcstr[t0] = (char *) zalloc(tclen[t0] + 1);
  440.         memcpy(tcstr[t0], pp, tclen[t0] + 1);
  441.         }
  442.     }
  443.  
  444.     /* check whether terminal has automargin (wraparound) capability */
  445.     hasam = tgetflag("am");
  446.  
  447.     tclines = tgetnum("li");
  448.     tccolumns = tgetnum("co");
  449.  
  450.     /* if there's no termcap entry for cursor up, use single line mode: *
  451.      * this is flagged by termflags which is examined in zle_refresh.c  *
  452.      */
  453.     if (tccan(TCUP))
  454.         termflags &= ~TERM_NOUP;
  455.     else {
  456.         tcstr[TCUP] = NULL;
  457.         termflags |= TERM_NOUP;
  458.     }
  459.  
  460.     /* if there's no termcap entry for cursor left, use \b. */
  461.     if (!tccan(TCLEFT)) {
  462.         tcstr[TCLEFT] = ztrdup("\b");
  463.         tclen[TCLEFT] = 1;
  464.     }
  465.  
  466.     /* if the termcap entry for down is \n, don't use it. */
  467.     if (tccan(TCDOWN) && tcstr[TCDOWN][0] == '\n') {
  468.         tclen[TCDOWN] = 0;
  469.         zsfree(tcstr[TCDOWN]);
  470.         tcstr[TCDOWN] = NULL;
  471.     }
  472.  
  473.     /* if there's no termcap entry for clear, use ^L. */
  474.     if (!tccan(TCCLEARSCREEN)) {
  475.         tcstr[TCCLEARSCREEN] = ztrdup("\14");
  476.         tclen[TCCLEARSCREEN] = 1;
  477.     }
  478.     }
  479.     return 1;
  480. }
  481.  
  482. /* Initialize lots of global variables and hash tables */
  483.  
  484. /**/
  485. void
  486. setupvals(void)
  487. {
  488.     struct passwd *pswd;
  489.     struct timezone dummy_tz;
  490.     char *ptr;
  491. #ifdef HAVE_GETRLIMIT
  492.     int i;
  493. #endif
  494.  
  495.     noeval = 0;
  496.     curhist = 0;
  497.     histsiz = DEFAULT_HISTSIZE;
  498.     inithist();
  499.     clwords = (char **) zcalloc((clwsize = 16) * sizeof(char *));
  500.  
  501.     cmdstack = (unsigned char *) zalloc(256);
  502.     cmdsp = 0;
  503.  
  504.     bangchar = '!';
  505.     hashchar = '#';
  506.     hatchar = '^';
  507.     termflags = TERM_UNKNOWN;
  508.     curjob = prevjob = coprocin = coprocout = -1;
  509.     gettimeofday(&shtimer, &dummy_tz);    /* init $SECONDS */
  510.     srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */
  511.  
  512.     hostnam     = (char *) zalloc(256);
  513.     gethostname(hostnam, 256);
  514.  
  515.     /* Set default path */
  516.     path    = (char **) zalloc(sizeof(*path) * 5);
  517.     path[0] = ztrdup("/bin");
  518.     path[1] = ztrdup("/usr/bin");
  519.     path[2] = ztrdup("/usr/ucb");
  520.     path[3] = ztrdup("/usr/local/bin");
  521.     path[4] = NULL;
  522.  
  523.     cdpath   = mkarray(NULL);
  524.     manpath  = mkarray(NULL);
  525.     fignore  = mkarray(NULL);
  526.     fpath    = mkarray(NULL);
  527.     mailpath = mkarray(NULL);
  528.     watch    = mkarray(NULL);
  529.     psvar    = mkarray(NULL);
  530.  
  531.     /* Set default prompts */
  532.     if (opts[INTERACTIVE]) {
  533.     prompt  = ztrdup("%m%# ");
  534.     prompt2 = ztrdup("%_> ");
  535.     } else {
  536.     prompt = ztrdup("");
  537.     prompt2 = ztrdup("");
  538.     }
  539.     prompt3 = ztrdup("?# ");
  540.     prompt4 = ztrdup("+ ");
  541.     sprompt = ztrdup("zsh: correct '%R' to '%r' [nyae]? ");
  542.  
  543.     ifs         = ztrdup(DEFAULT_IFS);
  544.     wordchars   = ztrdup(DEFAULT_WORDCHARS);
  545.     postedit    = ztrdup("");
  546.     underscore  = ztrdup("");
  547.  
  548.     zoptarg = ztrdup("");
  549.     zoptind = 1;
  550.     schedcmds = NULL;
  551.  
  552.     ppid  = (long) getppid();
  553.     mypid = (long) getpid();
  554.     term  = ztrdup("");
  555.  
  556.     /* The following variable assignments cause zsh to behave more *
  557.      * like Bourne and Korn shells when invoked as "sh" or "ksh".  *
  558.      * NULLCMD=":" and READNULLCMD=":"                             */
  559.  
  560.     if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
  561.     nullcmd     = ztrdup(":");
  562.     readnullcmd = ztrdup(":");
  563.     } else {
  564.     nullcmd     = ztrdup("cat");
  565.     readnullcmd = ztrdup("more");
  566.     }
  567.  
  568.     /* We cache the uid so we know when to *
  569.      * recheck the info for `USERNAME'     */
  570.     cached_uid = getuid();
  571.  
  572.     /* Get password entry and set info for `HOME' and `USERNAME' */
  573.     if ((pswd = getpwuid(cached_uid))) {
  574.     home = metafy(pswd->pw_dir, -1, META_DUP);
  575.     cached_username = ztrdup(pswd->pw_name);
  576.     } else {
  577.     home = ztrdup("/");
  578.     cached_username = ztrdup("");
  579.     }
  580.  
  581.     /* Try a cheap test to see if we can *
  582.      * initialize `PWD' from `HOME'      */
  583.     if (ispwd(home))
  584.     pwd = ztrdup(home);
  585.     else if ((ptr = zgetenv("PWD")) && ispwd(ptr))
  586.     pwd = ztrdup(ptr);
  587.     else
  588.     pwd = metafy(zgetcwd(), -1, META_REALLOC);
  589.  
  590.     oldpwd = ztrdup(pwd);  /* initialize `OLDPWD' = `PWD' */
  591.  
  592.     inittyptab();     /* initialize the ztypes table */
  593.     initlextabs();    /* initialize lexing tables    */
  594.  
  595.     createreswdtable();     /* create hash table for reserved words    */
  596.     createaliastable();     /* create hash table for aliases           */
  597.     createcmdnamtable();    /* create hash table for external commands */
  598.     createshfunctable();    /* create hash table for shell functions   */
  599.     createbuiltintable();   /* create hash table for builtin commands  */
  600.     createcompctltable();   /* create hash table for compctls          */
  601.     createnameddirtable();  /* create hash table for named directories */
  602.     createparamtable();     /* create paramater hash table             */
  603.  
  604. #ifdef TIOCGWINSZ
  605.     adjustwinsize(0);
  606. #else
  607.     /* columns and lines are normally zero, unless something different *
  608.      * was inhereted from the environment.  If either of them are zero *
  609.      * the setiparam calls below set them to the defaults from termcap */
  610.     setiparam("COLUMNS", columns);
  611.     setiparam("LINES", lines);
  612. #endif
  613.  
  614.     /* create hash table for multi-character emacs bindings */
  615.     createemkeybindtable();
  616.  
  617.     /* create hash table for multi-character vi bindings */
  618.     createvikeybindtable();
  619.  
  620.     initkeybindings();        /* initialize key bindings */
  621.     compctlsetup();
  622.  
  623. #ifdef HAVE_GETRLIMIT
  624.     for (i = 0; i != RLIM_NLIMITS; i++) {
  625.     getrlimit(i, current_limits + i);
  626.     limits[i] = current_limits[i];
  627.     }
  628. #endif
  629.  
  630.     breaks = loops = 0;
  631.     lastmailcheck = time(NULL);
  632.     locallist = NULL;
  633.     locallevel = sourcelevel = 0;
  634.     trapreturn = 0;
  635.     noerrexit = -1;
  636.     nohistsave = 1;
  637.     dirstack = newlinklist();
  638.     bufstack = newlinklist();
  639.     hsubl = hsubr = NULL;
  640.     lastpid = 0;
  641.     bshin = SHIN ? fdopen(SHIN, "r") : stdin;
  642.     if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
  643. #ifdef _IONBF
  644.     setvbuf(stdin, NULL, _IONBF, 0);
  645. #else
  646.     setlinebuf(stdin);
  647. #endif
  648.     }
  649.  
  650.     times(&shtms);
  651. }
  652.  
  653. /* Initialize signal handling */
  654.  
  655. /**/
  656. void
  657. init_signals(void)
  658. {
  659.     intr();
  660.  
  661. #ifndef QDEBUG
  662.     signal_ignore(SIGQUIT);
  663. #endif
  664.  
  665.     install_handler(SIGHUP);
  666.     install_handler(SIGCHLD);
  667. #ifdef SIGWINCH
  668.     install_handler(SIGWINCH);
  669. #endif
  670.     if (interact) {
  671.     install_handler(SIGALRM);
  672.     signal_ignore(SIGTERM);
  673.     }
  674.     if (jobbing) {
  675.     long ttypgrp;
  676.  
  677.     while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
  678.         kill(0, SIGTTIN);
  679.     if (ttypgrp == -1) {
  680.         opts[MONITOR] = 0;
  681.     } else {
  682.         signal_ignore(SIGTTOU);
  683.         signal_ignore(SIGTSTP);
  684.         signal_ignore(SIGTTIN);
  685.         attachtty(mypgrp);
  686.     }
  687.     }
  688.     if (islogin) {
  689.     signal_setmask(signal_mask(0));
  690.     } else if (interact) {
  691.     sigset_t set;
  692.  
  693.     sigemptyset(&set);
  694.     sigaddset(&set, SIGINT);
  695.     sigaddset(&set, SIGQUIT);
  696.     signal_unblock(set);
  697.     }
  698. }
  699.  
  700. /* Source the init scripts.  If called as "ksh" or "sh"  *
  701.  * then we source the standard sh/ksh scripts instead of *
  702.  * the standard zsh scripts                              */
  703.  
  704. /**/
  705. void
  706. run_init_scripts(void)
  707. {
  708.     noerrexit = -1;
  709.  
  710.     if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
  711.     if (islogin)
  712.         source("/etc/profile");
  713.     if (unset(PRIVILEGED)) {
  714.         char *s = getsparam("ENV");
  715.         if (islogin)
  716.         sourcehome(".profile");
  717.         noerrs = 1;
  718.         if (s && !parsestr(s)) {
  719.         singsub(&s);
  720.         noerrs = 0;
  721.         source(s);
  722.         }
  723.         noerrs = 0;
  724.     } else
  725.         source("/etc/suid_profile");
  726.     } else {
  727. #ifdef GLOBAL_ZSHENV
  728.     source(GLOBAL_ZSHENV);
  729. #endif
  730.     if (isset(RCS)) {
  731.         if (unset(PRIVILEGED))
  732.         sourcehome(".zshenv");
  733.         if (islogin) {
  734. #ifdef GLOBAL_ZPROFILE
  735.         source(GLOBAL_ZPROFILE);
  736. #endif
  737.         if (unset(PRIVILEGED))
  738.             sourcehome(".zprofile");
  739.         }
  740.         if (interact) {
  741. #ifdef GLOBAL_ZSHRC
  742.         source(GLOBAL_ZSHRC);
  743. #endif
  744.         if (unset(PRIVILEGED))
  745.             sourcehome(".zshrc");
  746.         }
  747.         if (islogin) {
  748. #ifdef GLOBAL_ZLOGIN
  749.         source(GLOBAL_ZLOGIN);
  750. #endif
  751.         if (unset(PRIVILEGED))
  752.             sourcehome(".zlogin");
  753.         }
  754.     }
  755.     }
  756.     noerrexit = 0;
  757.     nohistsave = 0;
  758. }
  759.  
  760. /* Miscellaneous initializations that happen after init scripts are run */
  761.  
  762. /**/
  763. void
  764. init_misc(void)
  765. {
  766.     if (cmd) {
  767.     if (SHIN >= 10)
  768.         fclose(bshin);
  769.     SHIN = movefd(open("/dev/null", O_RDONLY));
  770.     bshin = fdopen(SHIN, "r");
  771.     execstring(cmd, 0, 1);
  772.     stopmsg = 1;
  773.     zexit(lastval, 0);
  774.     }
  775.  
  776.     if (interact && isset(RCS))
  777.     readhistfile(getsparam("HISTFILE"), 0);
  778. }
  779.  
  780. /* source a file */
  781.  
  782. /**/
  783. int
  784. source(char *s)
  785. {
  786.     int tempfd, fd, cj, oldlineno;
  787.     int oldshst, osubsh, oloops;
  788.     FILE *obshin;
  789.     char *old_scriptname = scriptname;
  790.  
  791.     if (!s || (tempfd = movefd(open(unmeta(s), O_RDONLY))) == -1) {
  792.     return 1;
  793.     }
  794.  
  795.     /* save the current shell state */
  796.     fd        = SHIN;            /* store the shell input fd                  */
  797.     obshin    = bshin;          /* store file handle for buffered shell input */
  798.     osubsh    = subsh;           /* store whether we are in a subshell        */
  799.     cj        = thisjob;         /* store our current job number              */
  800.     oldlineno = lineno;          /* store our current lineno                  */
  801.     oloops    = loops;           /* stored the # of nested loops we are in    */
  802.     oldshst   = opts[SHINSTDIN]; /* store current value of this option        */
  803.  
  804.     SHIN = tempfd;
  805.     bshin = fdopen(SHIN, "r");
  806.     subsh  = 0;
  807.     lineno = 0;
  808.     loops  = 0;
  809.     dosetopt(SHINSTDIN, 0, 1);
  810.     scriptname = s;
  811.  
  812.     sourcelevel++;
  813.     loop(0);            /* loop through the file to be sourced        */
  814.     sourcelevel--;
  815.     fclose(bshin);
  816.     fdtable[SHIN] = 0;
  817.  
  818.     /* restore the current shell state */
  819.     SHIN = fd;                       /* the shell input fd                   */
  820.     bshin = obshin;                  /* file handle for buffered shell input */
  821.     subsh = osubsh;                  /* whether we are in a subshell         */
  822.     thisjob = cj;                    /* current job number                   */
  823.     lineno = oldlineno;              /* our current lineno                   */
  824.     loops = oloops;                  /* the # of nested loops we are in      */
  825.     dosetopt(SHINSTDIN, oldshst, 1); /* SHINSTDIN option                     */
  826.     errflag = 0;
  827.     retflag = 0;
  828.     scriptname = old_scriptname;
  829.  
  830.     return 0;
  831. }
  832.  
  833. /* Try to source a file in the home directory */
  834.  
  835. /**/
  836. void
  837. sourcehome(char *s)
  838. {
  839.     char buf[PATH_MAX];
  840.     char *h;
  841.  
  842.     if (emulation == EMULATE_SH || emulation == EMULATE_KSH ||
  843.     !(h = getsparam("ZDOTDIR")))
  844.     h = home;
  845.     if (strlen(h) + strlen(s) + 1 >= PATH_MAX) {
  846.     zerr("path too long: %s", s, 0);
  847.     return;
  848.     }
  849.     sprintf(buf, "%s/%s", h, s);
  850.     source(buf);
  851. }
  852.  
  853. /**/
  854. void
  855. compctlsetup(void)
  856. {
  857.     static char
  858.         *os[] =
  859.     {"setopt", "unsetopt", NULL}, *vs[] =
  860.     {"export", "typeset", "vared", "unset", NULL}, *cs[] =
  861.     {"which", "builtin", NULL}, *bs[] =
  862.     {"bindkey", NULL};
  863.  
  864.     compctl_process(os, CC_OPTIONS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  865.             NULL, NULL, 0);
  866.     compctl_process(vs, CC_VARS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  867.             NULL, NULL, 0);
  868.     compctl_process(bs, CC_BINDINGS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  869.             NULL, NULL, 0);
  870.     compctl_process(cs, CC_COMMPATH, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  871.             NULL, NULL, 0);
  872.     cc_compos.mask = CC_COMMPATH;
  873.     cc_default.refc = 10000;
  874.     cc_default.mask = CC_FILES;
  875.     cc_first.refc = 10000;
  876.     cc_first.mask = 0;
  877. }
  878.