/*
 * Copyright (c) 1983 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *  This product includes software developed by the University of
 *  California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)subr.c  5.10 (Berkeley) 2/26/91";
#endif /* not lint */

/*
 * Melbourne getty.
 */
#define USE_OLD_TTY
#include <stddef.h>
#include <sgtty.h>
#include <unistd.h>
#include <shell.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include "gettytab.h"

extern  struct sgttyb tmode;
extern  struct tchars tc;
extern  struct ltchars ltc;

/*
 * Get a table entry.
 */
void
gettable(char *name, char *buf, char *area)
{
    register struct gettystrs *sp;
    register struct gettynums *np;
    register struct gettyflags *fp;
    register n;

    hopcount = 0;       /* new lookup, start fresh */
    if (getent(buf, name) != 1)
        return;

    for (sp = gettystrs; sp->field; sp++)
        sp->value = getstr(sp->field, &area);
    for (np = gettynums; np->field; np++) {
        n = getnum(np->field);
        if (n == -1)
            np->set = 0;
        else {
            np->set = 1;
            np->value = n;
        }
    }
    for (fp = gettyflags; fp->field; fp++) {
        n = getflag(fp->field);
        if (n == -1)
            fp->set = 0;
        else {
            fp->set = 1;
            fp->value = n ^ fp->invrt;
        }
    }
}

void
gendefaults(void)
{
    register struct gettystrs *sp;
    register struct gettynums *np;
    register struct gettyflags *fp;

    for (sp = gettystrs; sp->field; sp++)
        if (sp->value)
            sp->defalt = sp->value;
    for (np = gettynums; np->field; np++)
        if (np->set)
            np->defalt = np->value;
    for (fp = gettyflags; fp->field; fp++)
        if (fp->set)
            fp->defalt = fp->value;
        else
            fp->defalt = fp->invrt;
}

void
setdefaults(void)
{
    register struct gettystrs *sp;
    register struct gettynums *np;
    register struct gettyflags *fp;

    for (sp = gettystrs; sp->field; sp++)
        if (!sp->value)
            sp->value = sp->defalt;
    for (np = gettynums; np->field; np++)
        if (!np->set)
            np->value = np->defalt;
    for (fp = gettyflags; fp->field; fp++)
        if (!fp->set)
            fp->value = fp->defalt;
}

static char **
charnames[] = {
    &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
    &SU, &DS, &RP, &FL, &WE, &LN, 0
};

static char *
charvars[] = {
    &tmode.sg_erase, &tmode.sg_kill, &tc.t_intrc,
    &tc.t_quitc, &tc.t_startc, &tc.t_stopc,
    &tc.t_eofc, &tc.t_brkc, &ltc.t_suspc,
    &ltc.t_dsuspc, &ltc.t_rprntc, &ltc.t_flushc,
    &ltc.t_werasc, &ltc.t_lnextc, 0
};

void
setchars(void)
{
    register int i;
    register char *p;

    for (i = 0; charnames[i]; i++) {
        p = *charnames[i];
        if (p && *p)
            *charvars[i] = *p;
        else
            *charvars[i] = '\377';
    }
}

long
setflags(int n)
{
    register long f;

    switch (n) {
    case 0:
        if (F0set)
            return(F0);
        break;
    case 1:
        if (F1set)
            return(F1);
        break;
    default:
        if (F2set)
            return(F2);
        break;
    }

    f = 0;

    if (AP)
        f |= ANYP;
    else if (OP)
        f |= ODDP;
    else if (EP)
        f |= EVENP;

    if (UC)
        f |= LCASE;

    if (NL)
        f |= CRMOD;

    f |= delaybits();

    if (n == 1) {       /* read mode flags */
        if (RW)
            f |= RAW;
        else
            f |= CBREAK;
        return (f);
    }

    if (!HT)
        f |= XTABS;

    if (n == 0)
        return (f);

    if (CB)
        f |= CRTBS;

    if (CE)
        f |= CRTERA;

    if (CK)
        f |= CRTKIL;

    if (PE)
        f |= PRTERA;

    if (EC)
        f |= ECHO;

    if (XC)
        f |= CTLECH;

    if (DX)
        f |= DECCTQ;

    return (f);
}

struct delayval {
    unsigned    delay;      /* delay in ms */
    int     bits;
};

/*
 * below are random guesses, I can't be bothered checking
 */

struct delayval crdelay[] = {
    1,      CR1,
    2,      CR2,
    3,      CR3,
    83,     CR1,
    166,        CR2,
    0,      CR3,
};

struct delayval nldelay[] = {
    1,      NL1,        /* special, calculated */
    2,      NL2,
    3,      NL3,
    100,        NL2,
    0,      NL3,
};

struct delayval bsdelay[] = {
    1,      BS1,
    0,      0,
};

struct delayval ffdelay[] = {
    1,      FF1,
    1750,       FF1,
    0,      FF1,
};

struct delayval tbdelay[] = {
    1,      TAB1,
    2,      TAB2,
    3,      XTABS,      /* this is expand tabs */
    100,        TAB1,
    0,      TAB2,
};

int
delaybits (void)
{
    register f;

    f  = adelay(CD, crdelay);
    f |= adelay(ND, nldelay);
    f |= adelay(FD, ffdelay);
    f |= adelay(TD, tbdelay);
    f |= adelay(BD, bsdelay);
    return (f);
}

int
adelay(long ms, struct delayval *dp)
{
    if (ms == 0)
        return (0);
    while (dp->delay && ms > dp->delay)
        dp++;
    return (dp->bits);
}

char    editedhost[32];

void
edithost(char *pat)
{
    register char *host = HN;
    register char *res = editedhost;

    if (pat == NULL)
        pat = "";
    while (*pat) {
        switch (*pat) {

        case '#':
            if (*host)
                host++;
            break;

        case '@':
            if (*host)
                *res++ = *host++;
            break;

        default:
            *res++ = *pat;
            break;

        }
        if (res == &editedhost[sizeof editedhost - 1]) {
            *res = '\0';
            return;
        }
        pat++;
    }
    if (*host)
        strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
    else
        *res = '\0';
    editedhost[sizeof editedhost - 1] = '\0';
}

struct speedtab {
    int speed;
    int uxname;
} speedtab[] = {
    50, B50,
    75, B75,
    110,    B110,
    134,    B134,
    150,    B150,
    200,    B200,
    300,    B300,
    600,    B600,
    1200,   B1200,
    1800,   B1800,
    2400,   B2400,
    4800,   B4800,
    9600,   B9600,
    19200,  EXTA,
    19, EXTA,       /* for people who say 19.2K */
    38400,  EXTB,
    38, EXTB,
    7200,   EXTB,       /* alternative */
    0
};

int
speed(long val)
{
    register struct speedtab *sp;

    if (val <= 15)
        return (val);

    for (sp = speedtab; sp->speed; sp++)
        if (sp->speed == val)
            return (sp->uxname);
    
    return (B300);      /* default in impossible cases */
}

#ifdef __ORCAC__

#if 0
void
addenv(char *vdef)
{
char *q,*vdef2;
static Set_VarPB setp;
static ExportPB exp;

    if (q = index(vdef,'=')) {
        vdef2 = q + 1;
        {
        char *a,*p;
        char sz;

            sz = strlen(vdef2);
            p = vdef2 + sz;
            for (a=p;a>vdef2;*(a--) = *(--p));
            *a = sz;
            sz = q - vdef;
            for (a=q;a>vdef;*(a--) = *(--q));
            *a = sz;
        }
        setp.var_name = vdef;
        setp.value = vdef2;
        SET_VAR(&setp);
        exp.name = vdef;
        exp.flags = 1;
        EXPORT(&exp);
    }
}
#endif	/* 0 */

void makeenv(void)
{
#if 1
    char *p, *q;

    environPush();
    if (TT && *TT) {
	setenv("TERM", TT, 1);
    }
    if ((p = EV) != NULL) {
        q = p;
        while (q = strchr(q, ',')) {
            *q++ = '\0';
            putenv(p);
            p = q;
        }
        if (*p) {
            putenv(p);
        }
    }

#else	/* 1 */
#ifdef __ORCAC__
static char termbuf[128] = "TERM";
#else
static char termbuf[128] = "TERM=";
#endif
char *p, *q;

    PUSH_VARIABLES(&p);
    if (TT && *TT) {
        strcat(termbuf, TT);
        addenv(termbuf);
    }
    if (p = EV) {
        q = p;
        while (q = index(q, ',')) {
            *q++ = '\0';
            addenv(p);
            p = q;
        }
        if (*p)
            addenv(p);
    }
#endif	/* 0 */
}

#else

makeenv(env)
    char *env[];
{
    static char termbuf[128] = "TERM=";
    register char *p, *q;
    register char **ep;
/*    char *index();    */

    ep = env;
    if (TT && *TT) {
        strcat(termbuf, TT);
        *ep++ = termbuf;
    }
    if (p = EV) {
        q = p;
        while (q = index(q, ',')) {
            *q++ = '\0';
            *ep++ = p;
            p = q;
        }
        if (*p)
            *ep++ = p;
    }
    *ep = (char *)0;
}

#endif

/*
 * This speed select mechanism is written for the Develcon DATASWITCH.
 * The Develcon sends a string of the form "B{speed}\n" at a predefined
 * baud rate. This string indicates the user's actual speed.
 * The routine below returns the terminal type mapped from derived speed.
 */
struct  portselect {
    char    *ps_baud;
    char    *ps_type;
} portspeeds[] = {
    { "B110",   "std.110" },
    { "B134",   "std.134" },
    { "B150",   "std.150" },
    { "B300",   "std.300" },
    { "B600",   "std.600" },
    { "B1200",  "std.1200" },
    { "B2400",  "std.2400" },
    { "B4800",  "std.4800" },
    { "B9600",  "std.9600" },
    { "B19200", "std.19200" },
    { 0 }
};

char *
portselector(void)
{
    char c, baud[20], *type = "default";
    register struct portselect *ps;
    int len;

    alarm(5*60);
    for (len = 0; len < sizeof (baud) - 1; len++) {
        if (read(STDIN_FILENO, &c, 1) <= 0)
            break;
        c &= 0177;
        if (c == '\n' || c == '\r')
            break;
        if (c == 'B')
            len = 0;    /* in case of leading garbage */
        baud[len] = c;
    }
    baud[len] = '\0';
    for (ps = portspeeds; ps->ps_baud; ps++)
        if (strcmp(ps->ps_baud, baud) == 0) {
            type = ps->ps_type;
            break;
        }
    sleep(2);   /* wait for connection to complete */
    return (type);
}

/*
 * This auto-baud speed select mechanism is written for the Micom 600
 * portselector. Selection is done by looking at how the character '\r'
 * is garbled at the different speeds.
 */
#ifdef SYS_TIME
#include <sys/time.h>
#endif

char *
autobaud(void)
{
    char c, *type = "9600-baud";
#ifdef SYS_TIME
    int null = 0;
    int rfds;
    struct timeval timeout;

    ioctl(STDIN_FILENO, TIOCFLUSH, &null);
    rfds = 1 << 0;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
        (fd_set *)NULL, &timeout) <= 0)
        return (type);
    if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
        return (type);
    timeout.tv_sec = 0;
    timeout.tv_usec = 20;
    (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
        (fd_set *)NULL, &timeout);
    ioctl(STDIN_FILENO, TIOCFLUSH, &null);
    switch (c & 0377) {

    case 0200:      /* 300-baud */
        type = "300-baud";
        break;

    case 0346:      /* 1200-baud */
        type = "1200-baud";
        break;

    case  015:      /* 2400-baud */
    case 0215:
        type = "2400-baud";
        break;

    default:        /* 4800-baud */
        type = "4800-baud";
        break;

    case 0377:      /* 9600-baud */
        type = "9600-baud";
        break;
    }
#endif
    return (type);
}
