/*
 * $Id: init.c,v 1.40 1995/05/30 06:21:41 coleman Exp coleman $
 *
 * init.c - main loop and initialization routines
 *
 * This file is part of zsh, the Z shell.
 *
 * Copyright (c) 1992-1995 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 its documentation 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.
 *
 */

#define GLOBALS

#include "zsh.h"

extern int sigtrapped[VSIGCOUNT];
extern List sigfuncs[VSIGCOUNT];

static int noexitct = 0;

/**/
void
main(int argc, char **argv, char **envp)
{
    char *zshname;

#ifdef LC_ALL
    setlocale(LC_ALL, "");
#endif
    environ = envp;
    permalloc();
    if (!(zshname = strrchr(argv[0], '/')))
	zshname = argv[0];
    else
	zshname++;
    if (*zshname == '-')
	zshname++;
    setflags(zshname);
    parseargs(argv);
    setmoreflags();
    setupvals(zshname);
    initialize();
    heapalloc();
    runscripts(zshname);
    for (;;) {
	do
	    loop(1);
	while (tok != ENDINPUT);
	if (!(isset(IGNOREEOF) && interact)) {
#if 0
	    if (interact)
		fputs(islogin ? "logout\n" : "exit\n", stderr);
#endif
	    zexit(lastval);
	    continue;
	}
	noexitct++;
	if (noexitct >= 10) {
	    stopmsg = 1;
	    zexit(lastval);
	}
	zerrnam("zsh", (!islogin) ? "use 'exit' to exit."
		: "use 'logout' to logout.", NULL, 0);
    }
}

/* keep executing lists until EOF found */

/**/
void
loop(int toplevel)
{
    List list;

    pushheap();
    for (;;) {
	freeheap();
	errflag = 0;
	if (interact && isset(SHINSTDIN))
	    preprompt();
	hbegin();		/* init history mech        */
	intr();			/* interrupts on            */
	ainit();		/* init alias mech          */
	lexinit();              /* initialize lexical state */
	if (!(list = parse_event())) {	/* if we couldn't parse a list */
	    hend();
	    if (tok == ENDINPUT && !errflag)
		break;
	    continue;
	}
	if (hend()) {
	    if (stopmsg)	/* unset 'you have stopped jobs' flag */
		stopmsg--;
	    execlist(list, 0);
	    if (toplevel)
		noexitct = 0;
	}
	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('t') && toplevel) {
	    if (sigtrapped[SIGEXIT])
		dotrap(SIGEXIT);
	    exit(lastval);
	}
    }
    popheap();
}

/**/
void
setflags(const char *zshname)
{
    int c;

    for (c = 0; c != 47; c++)
	opts[c] = OPT_UNSET;
    for (c = 47; c != 128; c++)
	opts[c] = OPT_INVALID;
    for (c = 'a'; c <= 'z'; c++)
	opts[c] = opts[c - 'a' + 'A'] = OPT_UNSET;
    for (c = '0'; c <= '9'; c++)
	opts[c] = OPT_UNSET;

    opts['A'] = OPT_INVALID;

    /* These are the flags we turn on by default in zsh */
    opts[BGNICE]      = OPT_SET;
    opts[NOTIFY]      = OPT_SET;
    opts[HASHCMDS]    = OPT_SET;
    opts[HASHLISTALL] = OPT_SET;
    opts[HASHDIRS]    = OPT_SET;
    opts[INTERACTIVE] = (isatty(0)) ? OPT_SET : OPT_UNSET;

    /* USEZLE is now set in setmoreflags() after attempt to open terminal   */
    /* opts[USEZLE]      = (interact && SHTTY != -1) ? OPT_SET : OPT_UNSET; */

    if (getuid() != geteuid() || getgid() != getegid())
	opts[PRIVILEGED] = OPT_SET;

    /* The following options cause zsh to behave more like   *
     * Bourne and Korn shells when invoked as "sh" or "ksh". *
     * NOBANGHIST - don't recognize csh-style history subst  *
     * INTERACTIVECOMMENTS - allow interactive comments      *
     * IGNOREBRACES - don't perform brace expansion          *
     * NONOMATCH - don't print error for unmatched wildcards *
     * RMSTARSILENT - don't query 'rm *'                     *
     * SHWORDSPLIT - split parameters using IFS              *
     * KSHOPTIONPRINT - print options ksh-like               *
     * GLOBSUBST - text from parameters can be globbed       *
     * LOCALOPTIONS - option settings are local to functions *
     * NOEQUALS - Don't perform equals substitution          *
     * NOBADPATTERN - Leave bad glob patterns alone.         *
     * PROMPTSUBST - Perform substitutions in prompts        */

    if (strcmp(zshname, "sh") == 0 || strcmp(zshname, "ksh") == 0) {
	opts[NOBANGHIST]          = OPT_SET;
	opts[INTERACTIVECOMMENTS] = OPT_SET;
	opts[IGNOREBRACES]        = OPT_SET;
	opts[NONOMATCH]           = OPT_SET;
	opts[RMSTARSILENT]        = OPT_SET;
	opts[SHWORDSPLIT]         = OPT_SET;
	opts[KSHOPTIONPRINT]      = OPT_SET;
	opts[GLOBSUBST]           = OPT_SET;
	opts[LOCALOPTIONS]        = OPT_SET;
	opts[NOEQUALS]            = OPT_SET;
	opts[NOBADPATTERN]        = OPT_SET;
	opts[PROMPTSUBST]         = OPT_SET;
    }

    /* If we are invoked as "sh", ignore escapes in echo.         *
     * This is not the final solution: configure should be added  *
     * to make echo compatible with /bin/echo or the echo builtin *
     * of /bin/sh.  This hack makes echo compatible with the bash *
     * echo on linux.                                             */

    if (strcmp(zshname, "sh") == 0)
        opts[BSDECHO] = OPT_SET;
}

static char *cmd;
static int opti = OPT_UNSET;

/**/
void
parseargs(char **argv)
{
    char **x;
    int breakouter = 0, action;
    Lklist paramlist;

    hackzero = argzero = *argv;
    /* If started with name beginning with '-' *
     * then assume it is a login shell         */
    opts[LOGINSHELL] = (**(argv++) == '-') ? OPT_SET : OPT_UNSET;
    SHIN = 0;

    /* loop through command line options (begins with "-" or "+") */
    while (!breakouter && *argv && (**argv == '-' || **argv == '+')) {
	action = (**argv == '-') ? OPT_SET : OPT_UNSET;
	while (*++*argv) {
	    /* option '-b' or '--' signifies end of options */
	    if (**argv == 'b' || **argv == '-') {
		breakouter = 1;          /* fall out of the outer while loop */
		break;
	    }
	    if (opts[(int)**argv] == OPT_INVALID) {
		zerr("bad option: -%c", NULL, **argv);
		exit(1);
	    }
	    if (**argv == 'c') {         /* -c command */
		argv++;
		if (!*argv) {
		    zerr("string expected after -c", NULL, 0);
		    exit(1);
		}
		cmd = *argv;
		opts[INTERACTIVE] = opti;
		opts['c'] = OPT_SET;
		breakouter = 1;          /* fall out of the outer while loop */
		break;
	    } else if (**argv == 'o') {
		int c;

		if (!*++*argv)
		    argv++;
		if (!*argv) {
		    zerr("string expected after -o", NULL, 0);
		    exit(1);
		}
		c = optlookup(*argv);   /* find the code for this option */
		if (c == -1)
		    zerr("no such option: %s", *argv, 0);
		else {
		    if (c == 'i')
			opti = action;
		    opts[c] = action;
#ifdef HAVE_SETUID
		    if (c == PRIVILEGED && action == OPT_UNSET)
			setuid(getuid()), setgid(getgid());;
#endif
		}
		break;
	    } else {
		if (**argv == 'i')
		    opti = action;
		opts[(int)**argv] = action;
#ifdef HAVE_SETUID
		if ((int)**argv == PRIVILEGED && action == OPT_UNSET)
		    setuid(getuid()), setgid(getgid());;
#endif
	    }
	}
	argv++;
    }
    paramlist = newlist();
    if (*argv) {
	if (opts[SHINSTDIN] == OPT_UNSET) {
	    argzero = *argv;
	    if (opts['c'] == OPT_UNSET)
		SHIN = movefd(open(argzero, O_RDONLY));
	    if (SHIN == -1) {
		zerr("can't open input file: %s", argzero, 0);
		exit(1);
	    }
	    opts[INTERACTIVE] = opti;
	    argv++;
	}
	while (*argv)
	    addnode(paramlist, ztrdup(*argv++));
    } else
	opts[SHINSTDIN] = OPT_SET;
    pparams = x = (char **)zcalloc((countnodes(paramlist) + 1) * sizeof(char *));

    while ((*x++ = (char *)getnode(paramlist)));
    free(paramlist);
    argzero = ztrdup(argzero);
}

/**/
void
setmoreflags(void)
{
    long ttpgrp;

/* stdout,stderr fully buffered */
#ifdef _IOFBF
    setvbuf(stdout, malloc(BUFSIZ), _IOFBF, BUFSIZ);
    setvbuf(stderr, malloc(BUFSIZ), _IOFBF, BUFSIZ);
#else
    setbuffer(stdout, malloc(BUFSIZ), BUFSIZ);
    setbuffer(stderr, malloc(BUFSIZ), BUFSIZ);
#endif

    /* Make sure the tty is opened read/write. */
    if (isatty(0))
	SHTTY = movefd(open(ttyname(0), O_RDWR));
    else
	SHTTY = movefd(open("/dev/tty", O_RDWR));

    if (SHTTY != -1) {
#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");

        /* We will only use zle if shell is interactive, *
         * SHTTY != -1, and shout != 0                   */
	opts[USEZLE] = (interact && shout) ? OPT_SET : OPT_UNSET;

	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
    } else {
	opts[USEZLE] = OPT_UNSET;
    }

#ifdef JOB_CONTROL
    if (interact && (SHTTY != -1)) {
	attachtty(GETPGRP());
	if ((mypgrp = GETPGRP()) > 0) {
	    opts[MONITOR] = OPT_SET;
	    while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
		sleep(1);
		mypgrp = GETPGRP();
		if (mypgrp == gettygrp())
		    break;
		killpg(mypgrp, SIGTTIN);
		mypgrp = GETPGRP();
	    }
	} else {
	    opts[MONITOR] = OPT_UNSET;
	}
    } else {
	opts[MONITOR] = OPT_UNSET;
    }
#else
    opts[MONITOR] = OPT_UNSET;
#endif
}

/* Re-initialize the terminal in execcmd.  Probably *
 * needs to be merged with setmoreflags             */

/**/
void
initterm(void)
{
    if (isatty(0)) {
	if (shout) {
	    fclose(shout);
	    shout = 0;
	}
	SHTTY = movefd(open(ttyname(0), O_RDWR));
	if (SHTTY != -1)
	    shout = fdopen(SHTTY, "w");
	else
	    opts[MONITOR] = OPT_UNSET;
	opts[USEZLE] = shout ? OPT_UNSET : OPT_SET;
    } else {
	opts[USEZLE] = OPT_UNSET;
    }
}

/**/
void
setupvals(const char *zshname)
{
    struct passwd *pswd;
    char *ptr;
    struct timezone dummy_tz;

    noeval = 0;
    curhist = 0;
    histsiz = DEFAULT_HISTSIZE;
    lithistsiz = 5;
    inithist();
    mailcheck = logcheck = 60;
    keytimeout = 40;
    dirstacksize = -1;
    listmax = 100;
    clwords = (char **)zcalloc((clwsize = 16) * sizeof(char *));

    cmdstack = (unsigned char *)zalloc(256);
    cmdsp = 0;

    reporttime = -1;
    bangchar = '!';
    hashchar = '#';
    hatchar = '^';
    termok = 0;
    curjob = prevjob = coprocin = coprocout = -1;
    gettimeofday(&shtimer, &dummy_tz);	/* init $SECONDS */
    srand((unsigned int)shtimer.tv_sec);

    /* build various hash tables           *
     * argument to newhtable is table size */
    buildreswdtab();
    aliastab = newhtable(37);
    addhnode(ztrdup("run-help"), mkanode(ztrdup("man"), 1), aliastab, NULL);
    addhnode(ztrdup("which-command"),
	     mkanode(ztrdup("whence"), 1), aliastab, NULL);
    cmdnamtab = newhtable(37);
    compctltab = newhtable(13);

    initxbindtab();  /* initialize key bindings */

    /* The following variable assignments cause zsh to behave more *
     * like Bourne and Korn shells when invoked as "sh" or "ksh".  *
     * NULLCMD=":" and READNULLCMD=":"                             */

    if (strcmp(zshname, "sh") == 0 || strcmp(zshname, "ksh") == 0) {
	nullcmd     = ztrdup(":");
	readnullcmd = ztrdup(":");
    } else {
	nullcmd     = ztrdup("cat");
	readnullcmd = ztrdup("more");
    }

    prompt  = ztrdup("%m%# ");
    prompt2 = ztrdup("> ");
    prompt3 = ztrdup("?# ");
    prompt4 = ztrdup("+ ");
    sprompt = ztrdup("zsh: correct `%R' to `%r' [nyae]? ");
    term    = ztrdup("");
    ppid    = getppid();

    baud = getbaudrate(&shttyinfo);  /* get the output baudrate */

#ifdef TIOCGWINSZ
    if (!(columns = shttyinfo.winsize.ws_col))
	columns = 80;
    if (!(lines = shttyinfo.winsize.ws_row))
	lines = 24;
#else
    columns = 80;
    lines = 24;
#endif

    ifs = ztrdup(" \t\n");
    timefmt = ztrdup(DEFAULT_TIMEFMT);
    watchfmt = ztrdup(DEFAULT_WATCHFMT);
    if (!(ttystrname = ztrdup(ttyname(SHTTY))))
	ttystrname = ztrdup("");
    wordchars = ztrdup(DEFAULT_WORDCHARS);
    fceditparam = ztrdup(DEFAULT_FCEDIT);
    tmpprefix = ztrdup(DEFAULT_TMPPREFIX);
    postedit = ztrdup("");
    hostnam = (char *)zalloc(256);
    underscore = ztrdup("");

    gethostname(hostnam, 256);
    hostvar = ztrdup(hostnam);
    mypid = getpid();
    cdpath = mkarray(NULL);
    manpath = mkarray(NULL);
    fignore = mkarray(NULL);
    fpath = mkarray(NULL);
    mailpath = mkarray(NULL);
    watch = mkarray(NULL);
    psvar = mkarray(NULL);
    compctlsetup();
    namdirs = (Nameddirs) zcalloc(sizeof(*namdirs) * 2);
    userdirsz = 2;
    userdirct = 0;

#ifdef CACHE_USERNAMES
    usernamescached = 0;
#endif /* CACHE_USERNAMES */

    zoptarg = ztrdup("");
    zoptind = 1;
    schedcmds = NULL;
    path = (char **)zalloc(4 * sizeof *path);
    path[0] = ztrdup("/bin");
    path[1] = ztrdup("/usr/bin");
    path[2] = ztrdup("/usr/ucb");
    path[3] = NULL;
    inittyptab();     /* initialize the ztypes table         */
    initlextabs();

    if ((pswd = getpwuid(getuid())))
	home = ztrdup(pswd->pw_dir);
    else
	home = ztrdup("/");

    if (!(logname = getlogin())) {
	if (pswd)
	    logname = ztrdup(pswd->pw_name);
	else
	    logname = ztrdup("");
    }
    username = ztrdup(logname);

    /* 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 = zgetwd();

    oldpwd = ztrdup(pwd);  /* initialize $OLDPWD = $PWD */

    /* Set up paramater hash table *
     * and environment variables   */
    buildparamtab();

    if (!strcmp(term, "emacs"))   /* unset zle if using zsh under emacs */
	opts[USEZLE] = OPT_UNSET;
    times(&shtms);
}

/**/
void
initialize(void)
{
#ifdef HAVE_GETRLIMIT
    int i;

    for (i = 0; i != RLIM_NLIMITS; i++)
	getrlimit(i, limits + i);
#endif

    breaks = loops = 0;
    lastmailcheck = time(NULL);
    locallist = NULL;
    locallevel = sourcelevel = 0;
    trapreturn = 0;
    dirstack = newlist();
    bufstack = newlist();
    newcmdnamtab();
    inbuf = (char *)zalloc(inbufsz = 256);
    inbufptr = inbuf + inbufsz;
    inbufct = 0;
    hsubl = hsubr = NULL;
    lastpid = 0;
    bshin = fdopen(SHIN, "r");
    intr();
#ifndef QDEBUG
    signal_ignore(SIGQUIT);
#endif
    install_handler(SIGHUP);
    install_handler(SIGCHLD);
    if (interact) {
	install_handler(SIGALRM);
#ifdef SIGWINCH
	install_handler(SIGWINCH);
#endif
	signal_ignore(SIGTERM);
    }
    if (jobbing) {
	long ttypgrp;

	while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
	    kill(0, SIGTTIN);
	if (ttypgrp == -1) {
	    opts[MONITOR] = OPT_UNSET;
	} else {
	    signal_ignore(SIGTTOU);
	    signal_ignore(SIGTSTP);
	    signal_ignore(SIGTTIN);
	    signal_ignore(SIGPIPE);
	    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);
    }
}

/**/
void
runscripts(char *zshname)
{
    /* Source the init scripts.  If called as "ksh" or "sh"  *
     * then we source the standard sh/ksh scripts instead of *
     * the standard zsh scripts                              */

    sourcelevel = 32768;	/* hack to avoid errexit in init scripts */

    if (strcmp(zshname, "ksh") == 0 || strcmp(zshname, "sh") == 0) {
	if (islogin)
	    source("/etc/profile");
	if (unset(PRIVILEGED)) {
	    if (islogin)
		sourcehome(".profile");
	    source(getsparam("ENV"));
	}
	else
	    source("/etc/suid_profile");
    } else {
#ifdef GLOBAL_ZSHENV
	source(GLOBAL_ZSHENV);
#endif
	if (!isset(NORCS)) {
	    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");
	    }
	}
    }
    sourcelevel = 0;

    if (isset('c')) {
	if (SHIN >= 10)
	    close(SHIN);
	SHIN = movefd(open("/dev/null", O_RDONLY));
	execstring(cmd, 1);
	stopmsg = 1;
	zexit(lastval);
    }
    if (interact && !isset(NORCS))
	readhistfile(getsparam("HISTFILE"), 0);
    adjustwinsize();   /* check window size and adjust if necessary */
    if (isset('t') && opti == OPT_UNSET)
	prompt = ztrdup("");
}

/**/
void
ainit(void)
{
    alstackind = 0;		/* reset alias stack */
    alstat = 0;
    isfirstln = 1;
}

/* Build the hash table containing zsh's reserved words. */

/**/
void
buildreswdtab(void)
{
    static char *reswds[] =
    {
	"do", "done", "esac", "then", "elif", "else", "fi", "for", "case",
	"if", "while", "function", "repeat", "time", "until", "exec", "command",
	"select", "coproc", "noglob", "-", "nocorrect", "foreach", "end", NULL
    };
    int i;

    /* Twenty four reserved words; any advance on the following? */
    reswdtab = newhtable(23);

    /* Add the actual words, not copies, to the table, *
     * as we do not expect to modify the table again.  */
    for (i = 0; reswds[i]; i++) {
	struct reswd *ptr = (struct reswd *) zcalloc(sizeof *ptr);
	ptr->cmd = i + DO;
	addhnode(reswds[i], ptr, reswdtab, NULL);
    }
}

/**/
void
compctlsetup(void)
{
    static char
        *os[] =
    {"setopt", "unsetopt", NULL}, *vs[] =
    {"export", "typeset", "vared", "unset", NULL}, *cs[] =
    {"which", "builtin", NULL}, *bs[] =
    {"bindkey", NULL};

    compctl_process(os, CC_OPTIONS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		    NULL, NULL, 0);
    compctl_process(vs, CC_VARS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		    NULL, NULL, 0);
    compctl_process(bs, CC_BINDINGS, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		    NULL, NULL, 0);
    compctl_process(cs, CC_COMMPATH, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		    NULL, NULL, 0);
    cc_compos.mask = CC_COMMPATH;
    cc_default.refc = 10000;
    cc_default.mask = CC_FILES;
    cc_first.refc = 10000;
    cc_first.mask = 0;
}

/* Return the output baudrate */

/**/
long
getbaudrate(struct ttyinfo *shttyinfo)
{
    int speedcode;
#ifdef HAS_TIO
    long tempbaud;

# if defined(HAVE_TCGETATTR) && defined(HAVE_TERMIOS_H)
    tempbaud = cfgetospeed(&shttyinfo->tio);
    if (tempbaud >= 100)
        return tempbaud;
    else
        speedcode = (int) tempbaud;
# else
    speedcode = shttyinfo->tio.c_cflag & CBAUD;
# endif
#else
    speedcode = shttyinfo->sgttyb.sg_ospeed;
#endif

    switch (speedcode) {
    case B0:
	return (0L);
    case B50:
	return (50L);
    case B75:
	return (75L);
    case B110:
	return (110L);
    case B134:
	return (134L);
    case B150:
	return (150L);
    case B200:
	return (200L);
    case B300:
	return (300L);
    case B600:
	return (600L);
#ifdef _B900
    case _B900:
	return (900L);
#endif
    case B1200:
	return (1200L);
    case B1800:
	return (1800L);
    case B2400:
	return (2400L);
#ifdef _B3600
    case _B3600:
	return (3600L);
#endif
    case B4800:
	return (4800L);
#ifdef _B7200
    case _B7200:
	return (7200L);
#endif
    case B9600:
	return (9600L);
#ifdef B19200
    case B19200:
	return (19200L);
#else
# ifdef EXTA
    case EXTA:
	return (19200L);
# endif
#endif
#ifdef B38400
    case B38400:
	return (38400L);
#else
# ifdef EXTB
    case EXTB:
	return (38400L);
# endif
#endif
    default:
	break;
    }
    return (0L);
}

