Annotation of coherent/e/bin/cku179/ckuus4.c, revision 1.1.1.1

1.1       root        1: #ifndef NOICP
                      2: 
                      3: /*  C K U U S 4 --  "User Interface" for Unix Kermit, part 4  */
                      4:  
                      5: /*
                      6:  Author: Frank da Cruz ([email protected], [email protected]),
                      7:  Columbia University Center for Computing Activities.
                      8:  First released January 1985.
                      9:  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New 
                     10:  York.  Permission is granted to any individual or institution to use, copy, or
                     11:  redistribute this software so long as it is not sold for profit, provided this
                     12:  copyright notice is retained.
                     13: */
                     14: 
                     15: /*
                     16:   File ckuus4.c -- Functions moved from other ckuus*.c modules to even
                     17:   out their sizes.
                     18: */
                     19: #include "ckcdeb.h"
                     20: #include "ckcasc.h"
                     21: #include "ckcker.h"
                     22: #include "ckuusr.h"
                     23: #include "ckuver.h"
                     24: #include "ckcnet.h"                    /* Network symbols */
                     25: 
                     26: #ifndef NOCSETS
                     27: #include "ckcxla.h"
                     28: #endif /* NOCSETS */
                     29: 
                     30: #ifndef AMIGA
                     31: #ifndef MAC
                     32: #include <signal.h>
                     33: #include <setjmp.h>
                     34: #endif /* MAC */
                     35: #endif /* AMIGA */
                     36: 
                     37: #ifdef SUNX25
                     38: extern int revcall, closgr, cudata, npadx3;
                     39: int x25ver;
                     40: extern char udata[MAXCUDATA];
                     41: extern CHAR padparms[MAXPADPARMS+1];
                     42: extern struct keytab padx3tab[];
                     43: #endif /* SUNX25 */ 
                     44: 
                     45: #ifdef NETCONN
                     46: extern char ipaddr[];
                     47: #endif /* NETCONN */
                     48: 
                     49: #ifndef NOSPL
                     50: /* This needs to be internationalized... */
                     51: char *months[] = {
                     52:     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     53:     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                     54: };
                     55: #endif /* NOSPL */
                     56: 
                     57: #ifdef UNIX
                     58: extern int ttyfd;
                     59: #endif /* UNIX */
                     60: 
                     61: extern struct keytab colxtab[];
                     62: 
                     63: extern CHAR
                     64:   eol, mypadc, mystch, padch, seol, stchr;
                     65: 
                     66: extern char
                     67:   flfnam[], kermrc[], ttname[],
                     68:   *ckxsys, *versio, **xargv, *zinptr;
                     69: 
                     70: extern int
                     71:   atcapr, autopar, bctr, bctu, bgset, bigrbsiz, bigsbsiz, binary, carrier,
                     72:   cdtimo, cmask, crunched, delay, duplex, ebq, ebqflg, escape, flow, fmask,
                     73:   fncact, fncnv, haslock, incase, inecho, keep, len, local, lscapr, lscapu,
                     74:   maxnam, maxpath, maxrps, maxsps, maxtry, mdmspd, mdmtyp, mypadn, ncolx,
                     75:   nettype, network, nmac, noinit, npad, parity, pktlog, pkttim, quiet, rcflag,
                     76:   retrans, rpackets, rptflg, rptq, rtimo, seslog, sessft, sosi, spackets,
                     77:   spsiz, spsizf, spsizr, srvtim, stayflg, success, timef, timeouts, tralog, 
                     78:   tsecs, ttnproto, turn, turnch, urpsiz, wmax, wslotn, wslotr, xargc, xargs,
                     79:   zincnt;
                     80: 
                     81: extern long
                     82:   ffc, filcnt, rptn, speed, tfc, tlci, tlco, vernum;
                     83: 
                     84: #ifndef NOSPL
                     85: extern char fspec[], myhost[];
                     86: #endif /* NOSPL */
                     87: 
                     88: #ifdef DCMDBUF
                     89: extern char *line;
                     90: #else
                     91: extern char line[];
                     92: #endif /* DCMDBUF */
                     93: 
                     94: extern char pktfil[],                  /* Packet log file name */
                     95: #ifdef DEBUG
                     96:   debfil[],                            /* Debug log file name */
                     97: #endif /* DEBUG */
                     98: #ifdef TLOG
                     99:   trafil[],                            /* Transaction log file name */
                    100: #endif /* TLOG */
                    101:   sesfil[];                            /* Session log file name */
                    102: 
                    103: #ifndef NOXMIT                         /* TRANSMIT command variables */
                    104: extern char xmitbuf[];
                    105: extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
                    106: #endif /* NOXMIT */
                    107: 
                    108: #ifndef NOSPL
                    109: /* Script programming language items */
                    110: extern char **a_ptr[];                 /* Arrays */
                    111: extern int a_dim[];
                    112: extern char inpbuf[];                  /* Buffer for INPUT and REINPUT */
                    113: extern char *inpbp;                    /* And pointer to same */
                    114: static char *inpbps = inpbuf;          /* And another */
                    115: extern int maclvl;                     /* Macro invocation level */
                    116: extern struct mtab *mactab;            /* Macro table */
                    117: extern char *mrval[];
                    118: extern int macargc[], cmdlvl;
                    119: extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
                    120: extern char *g_var[GVARS];       /* for external 2-dimensional arrays. */
                    121: #ifdef DCMDBUF
                    122: extern int *count;
                    123: #else
                    124: extern int count[];
                    125: #endif /* DCMDBUF */
                    126: #endif /* NOSPL */
                    127: 
                    128: #ifdef VMS
                    129: extern int frecl;
                    130: #ifdef COMMENT
                    131: /* Not needed after all */
                    132: extern int frecfm, forg, fcctrl;
                    133: #endif /* COMMENT */
                    134: #endif /* VMS */
                    135: 
                    136: #ifndef NODIAL
                    137: /* DIAL-related variables */
                    138: extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialmnp;
                    139: extern char *dialini, *dialnum;
                    140: extern struct keytab mdmtab[];
                    141: #endif /* NODIAL */
                    142: 
                    143: #ifndef NOCSETS
                    144: /* Translation stuff */
                    145: extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
                    146: extern struct keytab lngtab[];
                    147: extern struct csinfo fcsinfo[], tcsinfo[];
                    148: extern struct langinfo langs[];
                    149: #ifdef CK_ANSIC
                    150: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
                    151: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
                    152: #else
                    153: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();        /* Character set */
                    154: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();        /* translation functions. */
                    155: #endif /* CK_ANSIC */
                    156: #endif /* NOCSETS */
                    157: 
                    158: #ifndef NOSPL
                    159: /* Built-in variable names, maximum length VNAML (20 characters) */
                    160: 
                    161: struct keytab vartab[] = {
                    162:     "argc",      VN_ARGC,  0,
                    163:     "args",      VN_ARGS,  0,
                    164:     "count",     VN_COUN,  CM_INV,
                    165:     "cpu",      VN_CPU,   0,
                    166:     "date",      VN_DATE,  0,
                    167:     "directory", VN_DIRE,  0,
                    168:     "filespec",  VN_FILE,  0,
                    169:     "fsize",     VN_FFC,   0,
                    170:     "home",      VN_HOME,  0,
                    171:     "host",      VN_HOST,  0,
                    172:     "input",     VN_IBUF,  0,
                    173:     "line",      VN_LINE,  0,
                    174:     "ndate",     VN_NDAT,  0,
                    175:     "ntime",     VN_NTIM,  0,
                    176:     "platform",  VN_SYSV,  0,
                    177:     "program",   VN_PROG,  0,
                    178:     "return",    VN_RET,   0,
                    179:     "speed",     VN_SPEE,  0,
                    180:     "status",    VN_SUCC,  0,
                    181:     "system",    VN_SYST,  0,
                    182:     "tfsize",    VN_TFC,   0,
                    183:     "time",      VN_TIME,  0,
                    184: #ifdef UNIX
                    185:     "ttyfd",     VN_TTYF,  0,
                    186: #endif /* UNIX */
                    187:     "version",   VN_VERS,  0
                    188: };
                    189: int nvars = (sizeof(vartab) / sizeof(struct keytab));
                    190: #endif /* NOSPL */
                    191: 
                    192: #ifndef NOSPL
                    193: struct keytab fnctab[] = {             /* Function names */
                    194:     "character",  FN_CHR, 0,           /* Character */
                    195:     "contents",   FN_CON, 0,           /* Definition (contents) of variable */
                    196:     "definition", FN_DEF, 0,           /* Return definition of given macro */
                    197:     "evaluate",   FN_EVA, 0,           /* Evaluate given arith expression */
                    198:     "execute",    FN_EXE, 0,           /* Execute given macro */
                    199:     "files",      FN_FC,  0,           /* File count */
                    200:     "index",      FN_IND, 0,           /* Index (string search) */
                    201:     "length",     FN_LEN, 0,           /* Return length of argument */
                    202:     "literal",    FN_LIT, 0,           /* Return argument literally */
                    203:     "lower",      FN_LOW, 0,           /* Return lowercased argument */
                    204:     "lpad",       FN_LPA, 0,           /* Return left-padded argument */
                    205:     "maximum",    FN_MAX, 0,           /* Return maximum of two arguments */
                    206:     "minimim",    FN_MIN, 0,           /* Return minimum of two arguments */ 
                    207: #ifdef COMMENT
                    208: /* not needed because \feval() has it */
                    209:     "modulus",    FN_MOD, 0,           /* Return modulus of two arguments */ 
                    210: #endif /* COMMENT */
                    211:     "nextfile",   FN_FIL, 0,           /* Next file in list */
                    212:     "repeat",     FN_REP, 0,           /* Repeat argument given # of times */
                    213: #ifndef NOFRILLS
                    214:     "reverse",    FN_REV, 0,           /* Reverse the argument string */
                    215: #endif /* NOFRILLS */
                    216:     "rpad",       FN_RPA, 0,           /* Right-pad the argument */
                    217:     "substring",  FN_SUB, 0,           /* Extract substring from argument */
                    218:     "upper",      FN_UPP, 0            /* Return uppercased argument */
                    219: };
                    220: int nfuncs = (sizeof(fnctab) / sizeof(struct keytab));
                    221: #endif /* NOSPL */
                    222: 
                    223: #ifndef NOSPL                          /* Buffer for expansion of */
                    224: #define VVBUFL 60                      /* built-in variables. */
                    225: char vvbuf[VVBUFL];
                    226: #endif /* NOSPL */
                    227: 
                    228: struct keytab disptb[] = {             /* Log file disposition */
                    229:     "append",    1,  0,
                    230:     "new",       0,  0
                    231: };
                    232: 
                    233: /*  P R E S C A N -- Quick look thru command-line args for init file name */
                    234: /*  Also for -d (debug), -z (force foreground), -S (stay) */
                    235: 
                    236: VOID
                    237: prescan() {
                    238:     int yargc; char **yargv;
                    239:     char x;
                    240: 
                    241:     yargc = xargc;
                    242:     yargv = xargv;
                    243:     strcpy(kermrc,KERMRC);             /* Default init file name */
                    244: #ifndef NOCMDL
                    245:     while (--yargc > 0) {              /* Look for -y on command line */
                    246:        yargv++;
                    247:        if (**yargv == '-') {           /* Option starting with dash */
                    248:            x = *(*yargv+1);            /* Get option letter */
                    249:            if (x == 'Y') {             /* Is it Y (= no init file?) */
                    250:                noinit = 1;
                    251:                continue;
                    252:            } else if (x == 'y') {      /* Is it y? */
                    253:                yargv++, yargc--;       /* Yes, count and check argument */
                    254:                if (yargc < 1) fatal("missing name in -y");
                    255:                strcpy(kermrc,*yargv);  /* Replace init file name */
                    256:                rcflag = 1;             /* Flag that this has been done */
                    257:                continue;
                    258:            } else if (x == 'd') {      /* Do this early as possible! */
                    259:                debopn("debug.log",0);
                    260:                continue;
                    261:            } else if (x == 'z') {      /* = SET BACKGROUND OFF */
                    262:                bgset = 0;
                    263:                continue;
                    264:            } else if (x == 'S') {
                    265:                stayflg = 1;
                    266:                continue;
                    267:            }
                    268:        } 
                    269:     }
                    270: #endif /* NOCMDL */
                    271: }
                    272: 
                    273: static int tr_int;                     /* Flag if TRANSMIT interrupted */
                    274: 
                    275: #ifndef MAC
                    276: SIGTYP
                    277: trtrap(foo) int foo; {                 /* TRANSMIT interrupt trap */
                    278:     tr_int = 1;                                /* (Need arg for ANSI C) */
                    279:     SIGRETURN;
                    280: }
                    281: #endif /* MAC */
                    282: 
                    283: #ifndef NOXMIT
                    284: /*  T R A N S M I T  --  Raw upload  */
                    285: 
                    286: /*  Obey current line, duplex, parity, flow, text/binary settings. */
                    287: /*  Returns 0 upon apparent success, 1 on obvious failure.  */
                    288: 
                    289: /***
                    290:  Things to add:
                    291:  . Make both text and binary mode obey set file bytesize.
                    292:  . Maybe allow user to specify terminators other than CR?
                    293:  . Maybe allow user to specify prompts other than single characters?
                    294: ***/
                    295: 
                    296: /*  T R A N S M I T  --  Raw upload  */
                    297: 
                    298: /*  s is the filename, t is the turnaround (prompt) character  */
                    299: 
                    300: /*
                    301:   Maximum number of characters to buffer.
                    302:   Must be less than LINBUFSIZ
                    303: */
                    304: #define XMBUFS 120
                    305: 
                    306: int
                    307: #ifdef CK_ANSIC
                    308: transmit(char * s, char t)
                    309: #else
                    310: transmit(s,t) char *s; char t;
                    311: #endif /* CK_ANSIC */
                    312: /* transmit */ {
                    313: #ifdef MAC
                    314:     extern char sstate;
                    315:     int count = 100;
                    316: #else
                    317:     SIGTYP (* oldsig)();               /* For saving old interrupt trap. */
                    318: #endif /* MAC */
                    319:     long zz;
                    320:     int z = 1;                         /* Return code. 0=fail, 1=succeed. */
                    321:     int x, c, i;                       /* Workers... */
                    322:     CHAR csave;
                    323:     char *p;
                    324: 
                    325: #ifndef NOCSETS
                    326:     int tcs = TC_TRANSP;               /* Intermediate (xfer) char set */
                    327:     int langsv = L_USASCII;            /* Save current language */
                    328: 
                    329:     _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
                    330:     _PROTOTYP ( CHAR (*rxo), (CHAR) ) = NULL;
                    331:     _PROTOTYP ( CHAR (*sxi), (CHAR) ) = NULL;
                    332:     _PROTOTYP ( CHAR (*rxi), (CHAR) ) = NULL;
                    333: #endif /* NOCSETS */
                    334: 
                    335:     if (zopeni(ZIFILE,s) == 0) {       /* Open the file to be transmitted */
                    336:        printf("?Can't open file %s\n",s);
                    337:        return(0);
                    338:     }
                    339:     x = -1;                            /* Open the communication line */
                    340:     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { /* (no harm if already open) */
                    341:        printf("Can't open device %s\n",ttname);
                    342:        return(0);
                    343:     }
                    344:     zz = x ? speed : -1L;
                    345:     if (binary) {                      /* Binary file transmission */
                    346:        if (ttvt(zz,flow) < 0) {        /* So no Xon/Xoff! */
                    347:            printf("Can't condition line\n");
                    348:            return(0);
                    349:        }       
                    350:     } else {
                    351:        if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
                    352:            printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
                    353:            return(0);
                    354:        }
                    355:     }
                    356: 
                    357: #ifndef NOCSETS
                    358: /* Set up character set translations */
                    359:     if (binary == 0) {
                    360: #ifdef KANJI
                    361: /* Kanji not supported yet */
                    362:        if (fcsinfo[tcsr].alphabet == AL_JAPAN ||
                    363:            fcsinfo[tcsl].alphabet == AL_JAPAN )
                    364:          tcs = TC_TRANSP;
                    365:        else
                    366: #endif /* KANJI */
                    367: #ifdef CYRILLIC
                    368:       if (fcsinfo[tcsl].alphabet == AL_CYRIL)
                    369:        tcs = TC_CYRILL;
                    370:       else
                    371: #endif /* CYRILLIC */
                    372:        tcs = TC_1LATIN;
                    373: 
                    374:        if (tcsr == tcsl || binary) {   /* Remote and local sets the same? */
                    375:            sxo = rxo = NULL;           /* Or file type is not text? */
                    376:            sxi = rxi = NULL;
                    377:        } else {                        /* Otherwise, set up */
                    378:            sxo = xls[tcs][tcsl];       /* translation function */
                    379:            rxo = xlr[tcs][tcsr];       /* pointers for output functions */
                    380:            sxi = xls[tcs][tcsr];       /* and for input functions. */
                    381:            rxi = xlr[tcs][tcsl];
                    382:        }
                    383: /*
                    384:   This is to prevent use of zmstuff() and zdstuff() by translation functions.
                    385:   They only work with disk i/o, not with communication i/o.  Luckily Russian
                    386:   translation functions don't do any stuffing...
                    387: */
                    388:        langsv = language;
                    389:        language = L_USASCII;
                    390:     }
                    391: #endif /* NOCSETS */
                    392: 
                    393:     i = 0;                             /* Beginning of buffer. */
                    394: #ifndef MAC
                    395: #ifndef AMIGA
                    396:     oldsig = signal(SIGINT, trtrap);   /* Save current interrupt trap. */
                    397: #endif /* AMIGA */
                    398: #endif /* MAC */
                    399:     tr_int = 0;                                /* Have not been interrupted (yet). */
                    400:     z = 1;                             /* Return code presumed good. */
                    401: #ifdef VMS
                    402:     conres();
                    403: #endif /* VMS */
                    404: 
                    405:     c = 0;                             /* Initial condition */
                    406:     while (c > -1) {                   /* Loop for all characters in file */
                    407: #ifdef MAC
                    408:        /*
                    409:         * It is expensive to run the miniparser so don't do it for
                    410:         * every character.
                    411:         */
                    412:        if (--count < 0) {
                    413:            count = 100;
                    414:            miniparser(1);
                    415:            if (sstate == 'a') {
                    416:                sstate = '\0';
                    417:                z = 0;
                    418:                break;
                    419:            }
                    420:        }
                    421: #else /* Not MAC */
                    422:        if (tr_int) {                   /* Interrupted? */
                    423:            printf("^C...\n");          /* Print message */
                    424:            z = 0;
                    425:            break;
                    426:        }
                    427: #endif /* MAC */
                    428:        c = zminchar();                 /* Get a file character */
                    429:        debug(F101,"transmit char","",c);
                    430: 
                    431:        if (binary) {                   /* If binary file, */
                    432:            if (c == -1)                /* if at eof, */
                    433:              break;                    /* quit, */
                    434:            else if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
                    435:                printf("?Can't transmit character\n");
                    436:                z = 0;
                    437:                break;
                    438:            }
                    439:            if (xmitw) msleep(xmitw);   /* Pause if requested */
                    440:            if (xmitx) {                /* Echoing? */
                    441:                if (duplex) {           /* for half duplex */
                    442:                    conoc((char)c);     /* echo locally. */
                    443:                } else {                /* For full duplex, */
                    444:                    x = ttinc(1);       /* try to read back echo */
                    445:                    if (x > -1) conoc((char)x); /* and display it. */
                    446:                }
                    447:            } else ttflui();            /* Not echoing, just flush input. */
                    448: 
                    449:        } else {                        /* Text mode, line at a time. */
                    450: 
                    451:            if (c == '\n') {            /* Got a line */
                    452:                if (i == 0) {           /* Blank line? */
                    453:                    if (xmitf)          /* Yes, insert fill if asked. */
                    454:                      line[i++] = dopar((char) xmitf);
                    455:                }
                    456:                if (i == 0 || line[i-1] != dopar(CR))
                    457:                  line[i++] = dopar(CR); /* Terminate it with CR */
                    458:                if (xmitl) line[i++] = dopar('\n'); /* Include LF if asked */
                    459: 
                    460:            } else if (c != -1) {       /* Not a newline, regular character */
                    461:                csave = c;              /* Remember untranslated version */
                    462: #ifndef NOCSETS
                    463:                /* Translate character sets */
                    464:                if (sxo) c = (*sxo)((CHAR)c); /* From local to intermediate */
                    465:                if (rxo) c = (*rxo)((CHAR)c); /* From intermediate to remote */
                    466: #endif /* NOCSETS */
                    467: 
                    468:                if (xmits && parity && (c & 0200)) { /* If shifting */
                    469:                    line[i++] = dopar(SO);          /* needs to be done, */
                    470:                    line[i++] = dopar((char)c);     /* do it here, */
                    471:                    line[i++] = dopar(SI);          /* crudely. */
                    472:                } else {
                    473:                    line[i++] = dopar((char)c); /* else, just char itself */
                    474:                }
                    475:            }
                    476: 
                    477: /* Send characters if buffer full, or at end of line, or at end of file */
                    478: 
                    479:            if (i >= XMBUFS || c == '\n' || c == -1) { 
                    480:                p = line;
                    481:                line[i] = '\0';
                    482:                debug(F111,"transmit buf",p,i);
                    483:                if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
                    484:                    printf("Can't send buffer\n");
                    485:                    z = 0;
                    486:                    break;
                    487:                }
                    488:                i = 0;                  /* Reset buffer pointer. */
                    489: 
                    490: /* Worry about echoing here. "xmitx" is SET TRANSMIT ECHO flag. */
                    491: 
                    492:                if (duplex && xmitx)    /* If local echo, echo it */
                    493:                  conoll(p);
                    494:                if (xmitw)              /* Give receiver time to digest. */
                    495:                  msleep(xmitw);
                    496:                if (t != 0 && c == '\n') { /* Want a turnaround character */
                    497:                    x = 0;                 /* Wait for it */
                    498:                    while (x != t) {
                    499:                        if ((x = ttinc(1)) < 0) break;
                    500:                        if (xmitx && !duplex) { /* Echo any echoes */
                    501: #ifndef NOCSETS
                    502:                            if (sxi) x = (*sxi)((CHAR)x); /* But translate */
                    503:                            if (rxi) x = (*rxi)((CHAR)x); /* them first... */
                    504: #endif /* NOCSETS */
                    505:                            conoc((char) x);
                    506:                        }
                    507:                    }
                    508:                } else if (xmitx && !duplex) { /* Otherwise, */
                    509:                    while (ttchk() > 0) {      /* echo for as long as */
                    510:                        if ((x = ttinc(0)) < 0) break; /* anything is there. */
                    511: #ifndef NOCSETS
                    512:                        if (sxi) x = (*sxi)((CHAR)x); /* Translate first */
                    513:                        if (rxi) x = (*rxi)((CHAR)x);
                    514: #endif /* NOCSETS */
                    515:                        conoc((char)x);
                    516:                    }
                    517:                } else ttflui();        /* Otherwise just flush input buffer */
                    518:            }                           /* End of buffer-dumping block */
                    519:        }                               /* End of text mode */
                    520:     }                                  /* End of character-reading loop */
                    521: 
                    522:     if (*xmitbuf) {                    /* Anything to send at EOF? */
                    523:        p = xmitbuf;                    /* Yes, point to string. */
                    524:        while (*p)                      /* Send it. */
                    525:          ttoc(dopar(*p++));            /* Don't worry about echo here. */
                    526:     }
                    527: 
                    528: #ifndef AMIGA
                    529: #ifndef MAC
                    530:     signal(SIGINT,oldsig);             /* put old signal action back. */
                    531: #endif /* MAC */
                    532: #endif /* AMIGA */
                    533: #ifdef VMS
                    534:     concb(escape);                     /* Put terminal back, */
                    535: #endif /* VMS */
                    536:     zclose(ZIFILE);                    /* close file, */
                    537: #ifndef NOCSETS
                    538:     language = langsv;                 /* restore language, */
                    539: #endif /* NOCSETS */
                    540:     return(z);                         /* and return successfully. */
                    541: }
                    542: #endif /* NOXMIT */
                    543: 
                    544: #ifdef MAC
                    545: /*
                    546:   This code is not used any more, except on the Macintosh.  Instead we call
                    547:   system to do the typing.  Revive this code if your system can't be called
                    548:   to do this.
                    549: */
                    550: 
                    551: /*  D O T Y P E  --  Type a file  */
                    552: 
                    553: int
                    554: dotype(s) char *s; {
                    555: 
                    556: #ifdef MAC
                    557:     extern char sstate;
                    558:     int count = 100;
                    559: #else
                    560:     SIGTYP (* oldsig)();               /* For saving old interrupt trap. */
                    561: #endif /* MAC */
                    562:     int z;                             /* Return code. */
                    563:     int c;                             /* Worker. */
                    564: 
                    565:     if (zopeni(ZIFILE,s) == 0) {       /* Open the file to be transmitted */
                    566:        printf("?Can't open %s\n",s);
                    567:        return(0);
                    568:     }
                    569: #ifndef AMIGA
                    570: #ifndef MAC
                    571:     oldsig = signal(SIGINT, trtrap);   /* Save current interrupt trap. */
                    572: #endif /* MAC */
                    573: #endif /* AMIGA */
                    574: 
                    575:     tr_int = 0;                                /* Have not been interrupted (yet). */
                    576:     z = 1;                             /* Return code presumed good. */
                    577: 
                    578: #ifdef VMS
                    579:     conoc(CR);                         /* On VMS, display blank line first */
                    580:     conoc(LF);
                    581:     conres();                          /* So Ctrl-C/Y will work */
                    582: #endif /* VMS */
                    583:     while ((c = zminchar()) != -1) {   /* Loop for all characters in file */
                    584: #ifdef MAC
                    585:        /*
                    586:         * It is expensive to run the miniparser so don't do it for
                    587:         * every character.
                    588:         */
                    589:        if (--count < 0) {
                    590:            count = 100;
                    591:            miniparser(1);
                    592:            if (sstate == 'a') {
                    593:                sstate = '\0';
                    594:                z = 0;
                    595:                break;
                    596:            }
                    597:        }
                    598:        putchar(c);
                    599: #else /* Not MAC */
                    600:        if (tr_int) {                   /* Interrupted? */
                    601:            printf("^C...\n");          /* Print message */
                    602:            z = 0;
                    603:            break;
                    604:        }
                    605:        conoc(c);                       /* Echo character on screen */
                    606: #endif /* MAC */
                    607:     }
                    608: #ifndef AMIGA
                    609: #ifndef MAC
                    610:     signal(SIGINT,oldsig);             /* put old signal action back. */
                    611: #endif /* MAC */
                    612: #endif /* AMIGA */
                    613: 
                    614:     tr_int = 0;
                    615: #ifdef VMS
                    616:     concb(escape);                     /* Get back in command-parsing mode, */
                    617: #endif /* VMS */
                    618:     zclose(ZIFILE);                    /* close file, */
                    619:     return(z);                         /* and return successfully. */
                    620: }
                    621: #endif /* MAC */
                    622: 
                    623: #ifndef NOCSETS
                    624: 
                    625: _PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
                    626: _PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
                    627: _PROTOTYP( CHAR zl1as, (CHAR) );       /* Latin-1 to ascii */
                    628: _PROTOTYP( CHAR xl1as, (CHAR) );       /* ditto */
                    629: 
                    630: /*  X L A T E  --  Translate a local file from one character set to another */
                    631: 
                    632: /*
                    633:   Translates input file (fin) from character set csin to character set csout
                    634:   and puts the result in the output file (fout).  The two character sets are
                    635:   file character sets from fcstab.
                    636: */
                    637: 
                    638: int
                    639: xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
                    640: 
                    641: #ifndef MAC
                    642:     SIGTYP (* oldsig)();               /* For saving old interrupt trap. */
                    643: #endif /* MAC */
                    644:     int filecode;                      /* Code for output file */
                    645: 
                    646:     int z = 1;                         /* Return code. */
                    647:     int c, tcs;                                /* Workers */
                    648: 
                    649:     if (zopeni(ZIFILE,fin) == 0) {     /* Open the file to be translated */
                    650:        printf("?Can't open input file %s\n",fin);
                    651:        return(0);
                    652:     }
                    653: #ifdef MAC
                    654: /*
                    655:   If user specified no output file, it goes to the screen.  For the Mac,
                    656:   this must be done a special way (result goes to a new window); the Mac
                    657:   doesn't have a "controlling terminal" device name.
                    658: */
                    659:     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
                    660: #else
                    661:     filecode = ZOFILE;
                    662: #endif /* MAC */
                    663: 
                    664:     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
                    665:        printf("?Can't open output file %s\n",fout);
                    666:        return(0);
                    667:     }
                    668: #ifndef AMIGA
                    669: #ifndef MAC
                    670:     oldsig = signal(SIGINT, trtrap);   /* Save current interrupt trap. */
                    671: #endif /* MAC */
                    672: #endif /* AMIGA */
                    673: 
                    674:     tr_int = 0;                                /* Have not been interrupted (yet). */
                    675:     z = 1;                             /* Return code presumed good. */
                    676: 
                    677: #ifdef KANJI
                    678: /* Kanji not supported yet */
                    679:     if (fcsinfo[csin].alphabet == AL_JAPAN)
                    680:       tcs = TC_TRANSP;
                    681:     else
                    682: #endif /* KANJI */
                    683: #ifdef CYRILLIC
                    684:     if (fcsinfo[csout].alphabet == AL_CYRIL)
                    685:        tcs = TC_CYRILL;
                    686:       else
                    687: #endif /* CYRILLIC */
                    688:        tcs = TC_1LATIN;
                    689: 
                    690:     printf("%s (%s) => %s (%s)\n",     /* Say what we're doing. */
                    691:           fin, fcsinfo[csin].name,
                    692:           fout,fcsinfo[csout].name
                    693:     );
                    694:     printf("via %s", tcsinfo[tcs].name);
                    695:     if (language)
                    696:       printf(", language: %s\n",langs[language].description);
                    697:     printf("\n\n");
                    698: 
                    699:     if (csin == csout) {               /* Input and output sets the same? */
                    700:        sxx = rxx = NULL;               /* If so, no translation. */
                    701:     } else {                           /* Otherwise, set up */
                    702:        sxx = xls[tcs][csin];           /* translation function */
                    703:        rxx = xlr[tcs][csout];          /* pointers. */
                    704:        if (rxx == zl1as) rxx = xl1as;
                    705:     }
                    706:     while ((c = zminchar()) != -1) {   /* Loop for all characters in file */
                    707:        if (tr_int) {                   /* Interrupted? */
                    708:            printf("^C...\n");          /* Print message */
                    709:            z = 0;
                    710:            break;
                    711:        }
                    712:        if (sxx) c = (*sxx)((CHAR)c);   /* From fcs1 to tcs */
                    713:        if (rxx) c = (*rxx)((CHAR)c);   /* from tcs to fcs2 */
                    714: 
                    715:        if (zchout(ZOFILE,(char)c) < 0) { /* Output the translated character */
                    716:            printf("File output error\n");
                    717:            z = 0;
                    718:            break;
                    719:        }
                    720:     }
                    721: #ifndef AMIGA
                    722: #ifndef MAC
                    723:     signal(SIGINT,oldsig);             /* put old signal action back. */
                    724: #endif /* MAC */
                    725: #endif /* AMIGA */
                    726: 
                    727:     tr_int = 0;
                    728:     zclose(ZIFILE);                    /* close files, */
                    729:     zclose(ZOFILE);
                    730:     return(z);                         /* and return successfully. */
                    731: }
                    732: #endif /* NOCSETS */
                    733: 
                    734: /*  D O L O G  --  Do the log command  */
                    735:  
                    736: int
                    737: dolog(x) int x; {
                    738:     int y, disp; char *s;
                    739:  
                    740:     switch (x) {
                    741:  
                    742: #ifdef DEBUG
                    743:        case LOGD:
                    744:            y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
                    745:            break;
                    746: #endif /* DEBUG */
                    747:  
                    748:        case LOGP:
                    749:            y = cmofi("Name of packet log file","packet.log",&s,xxstring);
                    750:            break;
                    751:  
                    752:        case LOGS:
                    753:            y = cmofi("Name of session log file","session.log",&s,xxstring);
                    754:            break;
                    755:  
                    756: #ifdef TLOG
                    757:        case LOGT:
                    758:            y = cmofi("Name of transaction log file","transact.log",&s,
                    759:                      xxstring);
                    760:            break;
                    761: #endif /* TLOG */
                    762:  
                    763:        default:
                    764:            printf("\n?Unknown log designator - %d\n",x);
                    765:            return(-2);
                    766:     }
                    767:     if (y < 0) return(y);
                    768:  
                    769:     strcpy(line,s);
                    770:     s = line;
                    771:     if ((y = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
                    772:       return(y);
                    773:     disp = y;
                    774:     if ((y = cmcfm()) < 0) return(y);
                    775:  
                    776:     switch (x) {
                    777:  
                    778: #ifdef DEBUG
                    779:        case LOGD:
                    780:            return(deblog = debopn(s,disp));
                    781: #endif /* DEBUG */
                    782:  
                    783:        case LOGP:
                    784:            return(pktlog = pktopn(s,disp));
                    785: 
                    786:        case LOGS:
                    787:            return(seslog = sesopn(s,disp));
                    788:  
                    789: #ifdef TLOG
                    790:        case LOGT:
                    791:            return(tralog = traopn(s,disp));
                    792: #endif /* TLOG */
                    793:  
                    794:        default:
                    795:            return(-2);
                    796:        }
                    797: }
                    798:  
                    799: int
                    800: pktopn(s,disp) char *s; int disp; {
                    801:     extern char pktfil[];
                    802:     static struct filinfo xx;
                    803:     int y;
                    804: 
                    805:     zclose(ZPFILE);
                    806:     if(s[0] == '\0') return(0);
                    807:     if (disp) {
                    808:        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
                    809:        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
                    810:        xx.lblopts = 0;
                    811:        y = zopeno(ZPFILE,s,NULL,&xx);
                    812:     } else y = zopeno(ZPFILE,s,NULL,NULL);
                    813:     if (y > 0) 
                    814:       strcpy(pktfil,s); 
                    815:     else 
                    816:       *pktfil = '\0';
                    817:     return(y);
                    818: }
                    819: 
                    820: int
                    821: traopn(s,disp) char *s; int disp; {
                    822: #ifdef TLOG
                    823:     extern char trafil[];
                    824:     static struct filinfo xx;
                    825:     int y;
                    826: 
                    827:     zclose(ZTFILE);
                    828:     if(s[0] == '\0') return(0);
                    829:     if (disp) {
                    830:        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
                    831:        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
                    832:        xx.lblopts = 0;
                    833:        y = zopeno(ZTFILE,s,NULL,&xx);
                    834:     } else y = zopeno(ZTFILE,s,NULL,NULL);
                    835:     if (y > 0) {
                    836:        strcpy(trafil,s);
                    837:        tlog(F110,"Transaction Log:",versio,0L);
                    838: #ifndef MAC
                    839:        tlog(F100,ckxsys,"",0L);
                    840: #endif /* MAC */
                    841:        ztime(&s);
                    842:        tlog(F100,s,"",0L);
                    843:     } else *trafil = '\0';
                    844:     return(y);
                    845: #else
                    846:     return(0);
                    847: #endif
                    848: }
                    849: 
                    850: int
                    851: sesopn(s,disp) char * s; int disp; {
                    852:     extern char sesfil[];
                    853:     static struct filinfo xx;
                    854:     int y;
                    855: 
                    856:     zclose(ZSFILE);
                    857:     if(s[0] == '\0') return(0);
                    858:     if (disp) {
                    859:        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
                    860:        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
                    861:        xx.lblopts = 0;
                    862:        y = zopeno(ZSFILE,s,NULL,&xx);
                    863:     } else y = zopeno(ZSFILE,s,NULL,NULL);
                    864:     if (y > 0)
                    865:       strcpy(sesfil,s);
                    866:     else
                    867:       *sesfil = '\0';
                    868:     return(y);
                    869: }
                    870:  
                    871: int
                    872: debopn(s,disp) char *s; int disp; {
                    873: #ifdef DEBUG
                    874:     char *tp;
                    875:     static struct filinfo xx;
                    876: 
                    877:     zclose(ZDFILE);
                    878: 
                    879:     if (disp) {
                    880:        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
                    881:        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
                    882:        xx.lblopts = 0;
                    883:        deblog = zopeno(ZDFILE,s,NULL,&xx);
                    884:     } else deblog = zopeno(ZDFILE,s,NULL,NULL);
                    885:     if (deblog > 0) {
                    886:        strcpy(debfil,s);
                    887:        debug(F110,"Debug Log ",versio,0);
                    888: #ifndef MAC
                    889:        debug(F100,ckxsys,"",0);
                    890: #endif /* MAC */
                    891:        ztime(&tp);
                    892:        debug(F100,tp,"",0);
                    893:     } else *debfil = '\0';
                    894:     return(deblog);
                    895: #else
                    896:     return(0);
                    897: #endif
                    898: }
                    899: 
                    900: char *
                    901: #ifdef CK_ANSIC
                    902: parnam(char c)
                    903: #else
                    904: parnam(c) char c; 
                    905: #endif /* CK_ANSIC */
                    906: /* parnam */ {
                    907:     switch (c) {
                    908:        case 'e': return("even");
                    909:        case 'o': return("odd");
                    910:        case 'm': return("mark");
                    911:        case 's': return("space");
                    912:        case 0:   return("none");
                    913:        default:  return("invalid");
                    914:     }
                    915: }
                    916: 
                    917: #ifndef NOSHOW
                    918: 
                    919: /*  S H O P A R  --  Show Parameters  */
                    920:  
                    921: #ifdef SUNX25
                    922: VOID
                    923: shox25() {
                    924:     if (nettype == NET_SX25) {
                    925:        printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
                    926:        if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
                    927:        printf("\n Reverse charge call %s",
                    928:               revcall ? "selected" : "not selected");
                    929:        printf (", Closed user group ");
                    930:        if (closgr > -1)
                    931:          printf ("%d",closgr);
                    932:        else
                    933:          printf ("not selected");
                    934:        printf (",");
                    935:        printf("\n Call user data %s.", cudata ? udata : "not selected");
                    936:     }
                    937: }
                    938: #endif /* SUNX25 */
                    939: 
                    940: VOID
                    941: shoparc() {
                    942:     int i; char *s;
                    943:     long zz;
                    944: 
                    945:     puts("Communications Parameters:");
                    946: 
                    947:     if (network) {
                    948:        printf(" Host: %s",ttname);
                    949:     } else {
                    950:        printf(" Line: %s, speed: ",ttname);
                    951:        if ((zz = ttgspd()) < 0) {
                    952:            printf("unknown");
                    953:         } else {
                    954:            if (speed == 8880) printf("75/1200"); else printf("%ld",zz);
                    955:        }
                    956:     }
                    957:     printf(", mode: ");
                    958:     if (local) printf("local"); else printf("remote");
                    959:     if (network == 0) {
                    960: #ifndef NODIAL
                    961:        for (i = 0; i < nmdm; i++) {
                    962:            if (mdmtab[i].kwval == mdmtyp) {
                    963:                printf(", modem: %s",mdmtab[i].kwd);
                    964:                break;
                    965:            }
                    966:        }
                    967: #endif /* NODIAL */
                    968:     } else {
                    969:        if (nettype == NET_TCPA) printf(", TCP/IP/streams");
                    970:        if (nettype == NET_TCPB) printf(", TCP/IP/sockets");
                    971:         if (nettype == NET_DEC) printf(", DECnet");
                    972: #ifdef SUNX25
                    973:        shox25();
                    974: #endif /* SUNX25 */
                    975:        if (ttnproto == NP_TELNET) printf(", telnet protocol");
                    976:     }
                    977:     if (local) {
                    978:        i = parity ? 7 : 8;
                    979:        if (i == 8) i = (cmask == 0177) ? 7 : 8;
                    980:        printf("\n Terminal bits: %d, p",i);
                    981:     } else printf("\n P");
                    982:     printf("arity: %s",parnam((char)parity));
                    983:     printf(", duplex: ");
                    984:     if (duplex) printf("half, "); else printf("full, ");
                    985:     printf("flow: ");
                    986:     if (flow == FLO_XONX) printf("xon/xoff");
                    987:        else if (flow == FLO_NONE) printf("none");
                    988: #ifdef UTEK
                    989:        else if (flow == FLO_HARD) printf("idtr/octs");
                    990: #else
                    991:        else if (flow == FLO_RTSC) printf("rts/cts");
                    992: #endif /* UTEK */
                    993:         else if (flow == FLO_DTRC) printf("dtr/cd");
                    994:        else printf("%d",flow);
                    995:     printf(", handshake: ");
                    996:     if (turn) printf("%d\n",turnch); else printf("none\n");
                    997:     if (local && !network) {           /* Lockfile & carrier stuff */
                    998:        if (carrier == CAR_OFF) s = "off";
                    999:        else if (carrier == CAR_ON) s = "on";
                   1000:        else if (carrier == CAR_AUT) s = "auto";
                   1001:        else s = "unknown";
                   1002:        printf(" Carrier: %s", s);
                   1003:        if (carrier == CAR_ON) {
                   1004:            if (cdtimo) printf(", timeout: %d sec", cdtimo);
                   1005:            else printf(", timeout: none");
                   1006:        }
                   1007: #ifdef UNIX
                   1008:        if (haslock && *flfnam) {       /* Lockfiles only apply to UNIX... */
                   1009:            printf(", lockfile: %s\n",flfnam);
                   1010:        }
                   1011: #else
                   1012:        printf("\n");
                   1013: #endif /* UNIX */
                   1014:        printf(" Escape character: %d (^%c)\n",escape,ctl(escape));
                   1015:     }
                   1016: }
                   1017: 
                   1018: VOID
                   1019: shonet() {
                   1020: #ifdef NETCONN
                   1021:     printf("Supported networks:\n");
                   1022: #ifdef VMS
                   1023: #ifdef MULTINET    
                   1024:     printf(" TGV MultiNet TCP/IP\n");
                   1025: #else
                   1026:     printf(" None\n");
                   1027: #endif /* MULTINET */
                   1028: 
                   1029: #else /* Not VMS */
                   1030: 
                   1031: #ifdef TCPSOCKET
                   1032:     printf(" TCP/IP (sockets library)\n");
                   1033: #endif /* TCPSOCKET */
                   1034: #ifdef TCPSTREAM
                   1035:     printf(" TCP/IP (streams)\n");
                   1036: #endif /* TCPSTREAM */
                   1037: #ifdef TNCODE
                   1038:     printf(" TELNET protocol\n");
                   1039: #endif /* TNCODE */
                   1040: #ifdef SUNX25
                   1041:     printf(" SunLink X.25\n");
                   1042: #endif /* SUNX25 */
                   1043: #endif /* VMS */
                   1044: 
                   1045:     printf("Active SET HOST connection:\n");
                   1046:     if (network) {
                   1047:        printf(" %s",ttname);
                   1048:        if (*ipaddr) printf(" [%s]",ipaddr);
                   1049:        printf("\n Via: ");
                   1050:        if (nettype == NET_TCPA) printf("TCP/IP (streams)\n");
                   1051:        else if (nettype == NET_TCPB) printf("TCP/IP (sockets)\n");
                   1052:        else if (nettype == NET_SX25) printf("SunLink X.25\n");
                   1053:        else if (nettype == NET_DEC) printf("DECnet\n");
                   1054: #ifdef SUNX25
                   1055:        if (nettype == NET_SX25) shox25();
                   1056: #endif /* SUNX25 */
                   1057: #ifdef TNCODE
                   1058:        if (ttnproto == NP_TELNET) printf(" TELNET protocol\n");
                   1059: #endif /* TNCODE */
                   1060:     } else printf(" None\n");
                   1061: #else /* Not NETCONN */
                   1062:     printf("No network support\n");
                   1063: #endif /* NETCONN */
                   1064: }
                   1065: 
                   1066: #ifndef NODIAL
                   1067: 
                   1068: VOID
                   1069: shodial() {
                   1070:     if (mdmtyp >= 0 || local != 0) doshodial();
                   1071: }
                   1072: 
                   1073: int
                   1074: doshodial() {
                   1075:     char c, *s;
                   1076:     printf(" Dial hangup: %s, dial timeout: ",
                   1077:           dialhng ? "on" : "off");
                   1078:     if (dialtmo > 0)
                   1079:       printf("%d sec", dialtmo);
                   1080:     else
                   1081:       printf("auto");
                   1082:     printf("\n Dial kermit-spoof: %s",dialksp ? "on" : "off");
                   1083:     printf(", dial display: %s\n",dialdpy ? "on" : "off");
                   1084:     printf(" Dial speed-matching: %s",mdmspd ? "off" : "on");
                   1085:     printf(", dial mnp-enable: %s\n",dialmnp ? "on" : "off");
                   1086:     printf(" Dial init-string: ");
                   1087:     s = getdws(mdmtyp);                        /* Ask dial module for it */
                   1088:     if (s == NULL || !(*s)) {          /* Empty? */
                   1089:        printf("none\n");
                   1090:     } else {                           /* Not empty. */
                   1091:        while (c = *s++)                     /* Can contain controls */
                   1092:          if (c > 31 && c < 127) { putchar(c); } /* so display them */
                   1093:          else printf("\\{%d}",c);           /* in backslash notation */
                   1094:        printf("\n");   
                   1095:     }
                   1096:     printf(" Redial number: %s\n",dialnum ? dialnum : "none");
                   1097:     return(0);
                   1098: }
                   1099: #endif /* NODIAL */
                   1100: 
                   1101: #ifdef SUNX25
                   1102: VOID
                   1103: shopad() {
                   1104:     int i;
                   1105:     printf("\nX.3 PAD Parameters:\n");
                   1106:     for (i = 0; i < npadx3; i++)
                   1107:       printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
                   1108:             padparms[padx3tab[i].kwval]);
                   1109: }
                   1110: #endif /* SUNX25 */
                   1111: 
                   1112: VOID
                   1113: shomdm() {
                   1114:     int y;
                   1115:     y = ttgmdm();
                   1116:     switch (y) {
                   1117:       case -3: printf("Modem signals unavailable in this version of Kermit\n");
                   1118:               break;
                   1119:       case -2: printf("No modem control for this device\n"); break;
                   1120:       case -1: printf("Modem signals unavailable\n"); break;
                   1121:       default: 
                   1122: #ifndef MAC
                   1123:        printf(" Carrier Detect      (CD):  %s\n",(y & BM_DCD) ? "On": "Off");
                   1124:        printf(" Dataset Ready       (DSR): %s\n",(y & BM_DSR) ? "On": "Off");
                   1125: #endif /* MAC */
                   1126:        printf(" Clear To Send       (CTS): %s\n",(y & BM_CTS) ? "On": "Off");
                   1127: #ifndef MAC
                   1128:         printf(" Ring Indicator      (RI):  %s\n",(y & BM_RNG) ? "On": "Off");
                   1129: #endif /* MAC */
                   1130:         printf(" Data Terminal Ready (DTR): %s\n",(y & BM_DTR) ? "On": "Off");
                   1131: #ifndef MAC
                   1132:         printf(" Request to Send     (RTS): %s\n",(y & BM_RTS) ? "On": "Off");
                   1133: #endif /* MAC */
                   1134:     }
                   1135: }
                   1136: 
                   1137: /*  Show File Parameters */
                   1138: 
                   1139: VOID
                   1140: shoparf() {
                   1141:     char *s; int i;
                   1142:     printf("\nFile parameters:       ");
                   1143: #ifdef COMMENT
                   1144:     printf("Blocksize:     %5d      ",fblksiz);
                   1145: #endif /* COMMENT */
                   1146:     printf(" Attributes:       ");
                   1147:     if (atcapr) printf("on"); else printf("off");
                   1148: #ifdef VMS
                   1149:     printf("  Record-Length: %5d",frecl);
                   1150: #endif /* VMS */
                   1151:     printf("\n Names:   ");
                   1152:     printf("%-12s",(fncnv) ? "converted" : "literal");
                   1153: #ifdef DEBUG
                   1154: #ifndef MAC
                   1155:     printf("  Debugging Log:    ");
                   1156:     if (deblog) printf("%s",debfil); else printf("none");
                   1157: #endif /* MAC */
                   1158: #endif /* DEBUG */
                   1159: 
                   1160:     printf("\n Type:    ");
                   1161:     switch (binary) {
                   1162:       case XYFT_T: s = "text";    break;
                   1163: #ifdef VMS
                   1164:       case XYFT_B: s = "binary fixed"; break;
                   1165:       case XYFT_I: s = "image";        break;
                   1166:       case XYFT_L: s = "labeled";      break;
                   1167:       case XYFT_U: s = "binary undef"; break;
                   1168: #else
                   1169:       case XYFT_B: s = "binary"; break;
                   1170: #endif /* VMS */
                   1171:       default: s = "?"; break;
                   1172:     }
                   1173:     printf("%-12s",s);
                   1174: #ifdef COMMENT
                   1175:     printf(" Organization:  ");
                   1176:     switch (forg) {
                   1177:       case XYFO_I: printf("%-10s","indexed"); break;
                   1178:       case XYFO_R: printf("%-10s","relative"); break;
                   1179:       case XYFO_S: printf("%-10s","sequential"); break;
                   1180:     }
                   1181: #endif /* COMMENT */
                   1182: #ifndef MAC
                   1183:     printf("  Packet Log:       ");
                   1184:     if (pktlog) printf(pktfil); else printf("none");
                   1185: #endif /* MAC */
                   1186: #ifdef UNIX
                   1187:     printf("  Longest filename: %d",maxnam);
                   1188: #endif /* UNIX */
                   1189:     printf("\n Collide: ");
                   1190:     for (i = 0; i < ncolx; i++)
                   1191:       if (colxtab[i].kwval == fncact) break;
                   1192:     printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
                   1193: 
                   1194: #ifdef COMMENT
                   1195:     printf(" Format:        ");
                   1196:     switch (frecfm) {
                   1197:       case XYFF_F:  printf("%-10s","fixed"); break;
                   1198:       case XYFF_VB: printf("%-10s","rcw"); break;
                   1199:       case XYFF_S:  printf("%-10s","stream"); break;
                   1200:       case XYFF_U:  printf("%-10s","undefined"); break;
                   1201:       case XYFF_V:  printf("%-10s","variable"); break;
                   1202:     }
                   1203: #endif /* COMMENT */
                   1204: #ifndef MAC
                   1205:     printf("  Session Log:      ");
                   1206:     if (seslog) printf(sesfil); else printf("none");
                   1207: #endif /* MAC */
                   1208: #ifdef UNIX
                   1209:     printf("  Longest pathname: %d",maxpath);
                   1210: #endif /* UNIX */
                   1211:     printf("\n Display: ");
                   1212:     if (quiet) printf("%-12s","off"); else printf("%-12s","on");
                   1213: #ifdef COMMENT
                   1214:     printf("Carriage-Control: ");
                   1215:     switch (fcctrl) {
                   1216:       case XYFP_F: printf("%-10s","fortran"); break;
                   1217:       case XYFP_N: printf("%-10s","newline"); break;
                   1218:       case XYFP_P: printf("%-10s","machine"); break;
                   1219:       case XYFP_X: printf("%-10s","none"); break;
                   1220:     }
                   1221: #endif /* COMMENT */
                   1222: #ifdef TLOG
                   1223: #ifndef MAC
                   1224:     printf("  Transaction Log:  ");
                   1225:     if (tralog) printf(trafil); else printf("none");
                   1226: #endif /* MAC */
                   1227: #endif /* TLOG */
                   1228: #ifndef NOCSETS
                   1229:     if (binary == XYFT_T) {
                   1230:        shocharset();
                   1231:     } else
                   1232: #endif /* NOCSETS */
                   1233:       printf("\n");
                   1234:     printf("\nFile Byte Size: %d",(fmask == 0177) ? 7 : 8);
                   1235:     printf(", Incomplete Files: ");
                   1236:     if (keep) printf("keep"); else printf("discard");
                   1237: #ifdef KERMRC    
                   1238:     printf(", Init file: %s",kermrc);
                   1239: #endif /* KERMRC */
                   1240:     printf("\n");
                   1241: }
                   1242: 
                   1243: VOID
                   1244: shoparp() {
                   1245:     printf("\nProtocol Parameters:   Send    Receive");
                   1246:     if (timef || spsizf) printf("    (* = override)");
                   1247:     printf("\n Timeout:      %11d%9d", rtimo,  pkttim);
                   1248:     if (timef) printf("*"); else printf(" ");
                   1249: #ifndef NOSERVER
                   1250:     printf("       Server timeout:%4d\n",srvtim);
                   1251: #endif /* NOSERVER */
                   1252:     printf(  " Padding:      %11d%9d", npad,   mypadn);
                   1253:     printf("        Block Check: %6d\n",bctr);
                   1254:     printf(  " Pad Character:%11d%9d", padch,  mypadc);
                   1255:     printf("        Delay:       %6d\n",delay);
                   1256:     printf(  " Packet Start: %11d%9d", mystch, stchr);
                   1257:     printf("        Max Retries: %6d\n",maxtry);
                   1258:     printf(  " Packet End:   %11d%9d", seol,   eol);
                   1259:     if (ebqflg)
                   1260:       printf("        8th-Bit Prefix: '%c'",ebq);
                   1261:     printf(  "\n Packet Length:%11d", spsizf ? spsizr : spsiz);
                   1262:     printf( spsizf ? "*" : " " ); printf("%8d",  urpsiz);
                   1263:     printf( (urpsiz > 94) ? " (94)" : "     ");
                   1264:     if (rptflg)
                   1265:       printf("   Repeat Prefix:  '%c'",rptq);
                   1266:     printf(  "\n Length Limit: %11d%9d", maxsps, maxrps);
                   1267:     printf("        Window:%12d set, %d used\n",wslotr,wslotn);
                   1268:     printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
                   1269:     printf("        Locking-Shift:    ");
                   1270:     if (lscapu == 2) {
                   1271:        printf("forced\n");
                   1272:     } else {
                   1273:        printf("%s", (lscapr ? "enabled" : "disabled"));
                   1274:        if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
                   1275:        printf("\n");
                   1276:     }
                   1277: }
                   1278: 
                   1279: #ifndef NOCSETS
                   1280: VOID
                   1281: shoparl() {
                   1282:     int i;
                   1283:     printf("\nAvailable Languages:\n");
                   1284:     for (i = 0; i < MAXLANG; i++) {
                   1285:        printf(" %s\n",langs[i].description);
                   1286:     }  
                   1287:     printf("\nCurrent Language: %s\n",langs[language].description);
                   1288:     shocharset();
                   1289:     printf("\n\n");
                   1290: }
                   1291: 
                   1292: VOID
                   1293: shocharset() {
                   1294:     printf("\nFile Character-Set: %s (",fcsinfo[fcharset].name);
                   1295:     if (fcsinfo[fcharset].size == 128) printf("7-bit)");
                   1296:     else printf("8-bit)");
                   1297:     printf("\nTransfer Character-Set");
                   1298:     if (tslevel == TS_L2)
                   1299:       printf(": (international)");
                   1300:     else if (tcharset == TC_TRANSP)
                   1301:       printf(": Transparent");
                   1302:     else
                   1303:       printf(": %s",tcsinfo[tcharset].name);
                   1304: }
                   1305: #endif /* NOCSETS */
                   1306: 
                   1307: VOID
                   1308: shopar() {
                   1309: #ifndef MAC
                   1310:     printf("\n%s,%s\n",versio,ckxsys); 
                   1311: #endif /* MAC */
                   1312:     shoparc();
                   1313:     shoparp();
                   1314:     shoparf();
                   1315: }
                   1316: #endif /* NOSHOW */
                   1317: 
                   1318: /*  D O S T A T  --  Display file transfer statistics.  */
                   1319: 
                   1320: int
                   1321: dostat() {
                   1322:     printf("\nMost recent transaction --\n");
                   1323:     printf(" parity: %s",parnam((char)parity));
                   1324:     if (autopar) printf(" (detected automatically)");
                   1325:     printf("\n files: %ld\n",filcnt);
                   1326:     printf(" characters last file   : %ld\n",ffc);
                   1327:     printf(" total file characters  : %ld\n",tfc);
                   1328:     printf(" communication line in  : %ld\n",tlci);
                   1329:     printf(" communication line out : %ld\n",tlco);
                   1330:     printf(" packets sent           : %d\n", spackets);
                   1331:     printf(" packets received       : %d\n", rpackets);
                   1332:     printf(" damaged packets rec'd  : %d\n", crunched);
                   1333:     printf(" timeouts               : %d\n", timeouts);
                   1334:     printf(" retransmissions        : %d\n", retrans);
                   1335:     printf(" window slots used      : %d\n", wmax);
                   1336:     printf(" elapsed time           : %d sec\n",tsecs);
                   1337:     if (speed <= 0L) speed = ttgspd();
                   1338:     if (speed > 0L) {
                   1339:        if (speed == 8880)
                   1340:          printf(" transmission rate      : 75/1200 bps\n");
                   1341:        else
                   1342:          printf(" transmission rate      : %ld bps\n",speed);
                   1343:     }
                   1344:     if (filcnt > 0) {
                   1345:        if (tsecs > 0) {
                   1346:            long lx;
                   1347:            lx = (tfc * 10L) / (long) tsecs;
                   1348:            printf(" effective data rate    : %ld cps\n",lx/10L);
                   1349:            if (speed > 0L && speed != 8880L && network == 0) {
                   1350:                lx = (lx * 100L) / speed;
                   1351:                printf(" efficiency (percent)   : %ld\n",lx);
                   1352:            }
                   1353:        }
                   1354:        printf(" packet length          : %d (send), %d (receive)\n",
                   1355:               spsizf ? spsizr : spsiz, urpsiz);
                   1356:        printf(" block check type used  : %d\n",bctu);
                   1357:        printf(" compression            : ");
                   1358:        if (rptflg) printf("yes [%c] (%d)\n",rptq,rptn); else printf("no\n");
                   1359:        printf(" 8th bit prefixing      : ");
                   1360:        if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
                   1361:        printf(" locking shifts         : %s\n\n", lscapu ? "yes" : "no");
                   1362:     } else printf("\n");
                   1363:     return(1);
                   1364: }
                   1365: 
                   1366: /*  D O C O N E C T  --  Do the connect command  */
                   1367:  
                   1368: /*  Note, we don't call this directly from dial, because we need to give */
                   1369: /*  the user a chance to change parameters (e.g. parity) after the */
                   1370: /*  connection is made. */
                   1371:  
                   1372: int
                   1373: doconect() {
                   1374:     int x;
                   1375:     conres();                          /* Put console back to normal */
                   1376:     x = conect();                      /* Connect */
                   1377:     concb((char)escape);               /* Put console into cbreak mode, */
                   1378:     return(x);                         /* for more command parsing. */
                   1379: }
                   1380: 
                   1381: #ifndef NOSPL
                   1382: /* The INPUT command */
                   1383: 
                   1384: #ifdef NETCONN
                   1385: extern int tn_init;
                   1386: #ifndef IAC
                   1387: #define IAC 255
                   1388: #endif /* IAC */
                   1389: #endif /* NETCONN */
                   1390: 
                   1391: int
                   1392: doinput(timo,s) int timo; char *s; {
                   1393:     int x, y, i, icn;
                   1394:     char *xp, *xq = (char *)0;
                   1395:     CHAR c;
                   1396: 
                   1397:     if (local) {                       /* Put line in "ttvt" mode */
                   1398:        y = ttvt(speed,flow);           /* if not already. */
                   1399:        if (y < 0) {
                   1400:            printf("?Can't condition line for INPUT\n");
                   1401:            return(0);                  /* Watch out for failure. */
                   1402:        }
                   1403:     }
                   1404:     y = (int)strlen(s);
                   1405:     debug(F111,"doinput",s,y);
                   1406:     if (timo <= 0) timo = 1;           /* Give at least 1 second timeout */
                   1407:     x = 0;                             /* Return code, assume failure */
                   1408:     i = 0;                             /* String pattern match position */
                   1409: 
                   1410:     if (!incase) {                     /* INPUT CASE = IGNORE?  */
                   1411:        xp = malloc(y+2);               /* Make a separate copy of the */
                   1412:        if (!xp) {                      /* input string for editing. */
                   1413:            printf("?malloc error 5\n");
                   1414:            return(x);
                   1415:        } else xq = xp;                 /* Save pointer to beginning */
                   1416: 
                   1417:        while (*s) {                    /* Convert to lowercase */
                   1418:            *xp = *s;
                   1419:            if (isupper(*xp)) *xp = tolower(*xp);
                   1420:            xp++; s++;
                   1421:        }
                   1422:        *xp = NUL;                      /* Terminate the search string. */
                   1423:        s = xq;                         /* Point back to beginning. */
                   1424:     }
                   1425:     inpbps = inpbp;                    /* Save current pointer. */
                   1426:     rtimer();                          /* Get current time. */
                   1427:     while (1) {                                /* Character-getting loop */
                   1428:        if (local) {                    /* One case for local */
                   1429:            y = ttinc(1);               /* Get character from comm line. */
                   1430:            debug(F101,"input ttinc(1) returns","",y);
                   1431:            if (icn = conchk()) {       /* Interrupted from keyboard? */
                   1432:                debug(F101,"input interrupted from keyboard","",icn);
                   1433:                while (icn--) coninc(0); /* Yes, read what was typed. */
                   1434:                break;                  /* And fail. */
                   1435:            }
                   1436:        } else {                        /* Another for remote */
                   1437:            y = coninc(1);
                   1438:            debug(F101,"input coninc(1) returns","",y);
                   1439:        }
                   1440:        if (y > -1) {                   /* A character arrived */
                   1441: #ifdef NETCONN
                   1442: /* Check for telnet protocol negotiation */
                   1443:            if (network && (ttnproto == NP_TELNET) && ((y & 0xff) == IAC)) {
                   1444:                switch (tn_doop((CHAR)(y & 0xff),duplex)) {
                   1445:                  case 2: duplex = 0; continue;
                   1446:                  case 1: duplex = 1;
                   1447:                  default: continue;
                   1448:                }
                   1449:            }
                   1450: #endif /* NETCONN */
                   1451: 
                   1452:            /* Real input character to be checked */
                   1453: 
                   1454:            c = cmask & (CHAR) y;       /* Mask off parity */
                   1455:            if (c) *inpbp++ = c;        /* Store result in circular buffer */
                   1456:            if (inpbp >= inpbuf + INPBUFSIZ) { /* Time to wrap around? */
                   1457:                inpbp = inpbuf;         /* Yes. */
                   1458:                *(inpbp+INPBUFSIZ) = NUL; /* Make sure it's null-terminated. */
                   1459:            }
                   1460: #ifdef MAC
                   1461:            {
                   1462:                extern char *ttermw;    /* fake pointer cast */
                   1463:                if (inecho) {
                   1464:                    outchar(ttermw, c); /* echo to terminal window */
                   1465:                    /* this might be too much overhead to do here ? */
                   1466:                    updatecommand(ttermw);
                   1467:                }
                   1468:            }
                   1469: #else /* Not MAC */ 
                   1470:            if (inecho) conoc(c);       /* Echo and log the input character */
                   1471: #endif /* MAC */
                   1472:            if (seslog) {
                   1473: #ifdef UNIX
                   1474:                if (sessft != 0 || c != '\r')
                   1475: #endif /* UNIX */
                   1476:                  if (zchout(ZSFILE,c) < 0) seslog = 0;
                   1477:            }
                   1478:            if (!incase) {              /* Ignore alphabetic case? */
                   1479:                if (isupper(c)) c = tolower(c); /* Yes */
                   1480:            }
                   1481:            debug(F000,"doinput char","",c);
                   1482:            debug(F000,"compare char","",s[i]);
                   1483:            if (c == s[i]) i++; else i = 0; /* Check for match */
                   1484:            if (s[i] == '\0') {         /* Matched all the way to end? */
                   1485:                x = 1;                  /* Yes, */
                   1486:                break;                  /* done. */
                   1487:            }
                   1488:        }
                   1489:        if (gtimer() > timo)            /* Did not match, timer exceeded? */
                   1490:          break;
                   1491:     }                                  /* Still have time left, continue. */
                   1492:     if (!incase) if (xq) free(xq);     /* Done, free dynamic memory. */
                   1493:     return(x);                         /* Return the return code. */
                   1494: }
                   1495: #endif /* NOSPL */
                   1496: 
                   1497: #ifndef NOSPL
                   1498: /* REINPUT Command */
                   1499: 
                   1500: /* Note, the timeout parameter is required, but ignored. */
                   1501: /* Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. */
                   1502: /* This function only looks at the characters already received */
                   1503: /* and does not read any new characters from the communication line. */
                   1504: 
                   1505: int
                   1506: doreinp(timo,s) int timo; char *s; {
                   1507:     int x, y, i;
                   1508:     char *xx, *xp, *xq = (char *)0;
                   1509:     CHAR c;
                   1510: 
                   1511:     y = (int)strlen(s);
                   1512:     debug(F111,"doreinput",s,y);
                   1513: 
                   1514:     x = 0;                             /* Return code, assume failure */
                   1515:     i = 0;                             /* String pattern match position */
                   1516: 
                   1517:     if (!incase) {                     /* INPUT CASE = IGNORE?  */
                   1518:        xp = malloc(y+2);               /* Make a separate copy of the */
                   1519:        if (!xp) {                      /* search string. */
                   1520:            printf("?malloc error 6\n");
                   1521:            return(x);
                   1522:        } else xq = xp;                 /* Keep pointer to beginning. */
                   1523:        while (*s) {                    /* Yes, convert to lowercase */
                   1524:            *xp = *s;
                   1525:            if (isupper(*xp)) *xp = tolower(*xp);
                   1526:            xp++; s++;
                   1527:        }
                   1528:        *xp = NUL;                      /* Terminate it! */
                   1529:        s = xq;                         /* Move search pointer to it. */
                   1530:     }
                   1531:     xx = inpbp;                                /* Current INPUT buffer pointer */
                   1532:     do {
                   1533:        c = *xx++;                      /* Get next character */
                   1534:        if (xx >= inpbuf + INPBUFSIZ) xx = inpbuf; /* Wrap around */
                   1535:        if (!incase) {                  /* Ignore alphabetic case? */
                   1536:            if (isupper(c)) c = tolower(c); /* Yes */
                   1537:        }
                   1538:        debug(F000,"doreinp char","",c);
                   1539:        debug(F000,"compare char","",s[i]);
                   1540:        if (c == s[i]) i++; else i = 0; /* Check for match */
                   1541:        if (s[i] == '\0') {             /* Matched all the way to end? */
                   1542:            x = 1;                      /* Yes, */
                   1543:            break;                      /* done. */
                   1544:        }
                   1545:     } while (xx != inpbp);             /* Until back where we started. */
                   1546: 
                   1547:     if (!incase) if (xq) free(xq);     /* Free this if it was malloc'd. */
                   1548:     return(x);                         /* Return search result. */
                   1549: }
                   1550: #ifndef NOSPL
                   1551: 
                   1552: #endif /* NOSPL */
                   1553: /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
                   1554: 
                   1555: /*
                   1556:  Copies result to new string.
                   1557:   strips enclosing braces or doublequotes.
                   1558:   interprets backslash escapes.
                   1559:   returns 0 on success, nonzero on failure.
                   1560:   tries to be compatible with MS-DOS Kermit.
                   1561: 
                   1562:  Syntax of input string:
                   1563:   string = chars | "chars" | {chars}
                   1564:   chars = (c*e*)*
                   1565:   where c = any printable character, ascii 32-126
                   1566:   and e = a backslash escape
                   1567:   and * means 0 or more repetitions of preceding quantity
                   1568:   backslash escape = \operand
                   1569:   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
                   1570:   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
                   1571:   radix code is oO (octal), hHxX (hex), dD or none (decimal).
                   1572: */
                   1573: 
                   1574: #ifndef NOFRILLS
                   1575: int
                   1576: yystring(s,s2) char *s; char **s2; {   /* Reverse a string */
                   1577:     int x;
                   1578:     static char *new;
                   1579:     new = *s2;
                   1580:     if (!s || !new) return(-1);                /* Watch out for null pointers. */
                   1581:     if ((x = (int)strlen(s)) == 0) {   /* Recursion done. */
                   1582:        *new = '\0';
                   1583:        return(0);
                   1584:     }
                   1585:     x--;                               /* Otherwise, call self */
                   1586:     *new++ = s[x];                     /* to reverse rest of string. */
                   1587:     s[x] = 0;
                   1588:     return(yystring(s,&new));
                   1589: }
                   1590: #endif /* NOFRILLS */
                   1591: 
                   1592: #define FNVALL 1000
                   1593: char fnval[FNVALL+2];                  /* Return value */
                   1594: 
                   1595: char *                                 /* Evaluate builtin function */
                   1596: fneval(fn,argp,argn) char *fn, *argp[]; int argn; {
                   1597:     int i, j, k, len1, len2, n, x, y;
                   1598:     char *bp[FNARGS];                  /* Pointers to malloc'd strings */
                   1599:     char *p, *s;
                   1600: 
                   1601:     if (!fn) fn = "";                  /* Paranoia */
                   1602:     debug(F111,"fneval",fn,argn);
                   1603:     debug(F110,"fneval",argp[0],0);
                   1604:     y = lookup(fnctab,fn,nfuncs,&x);
                   1605:     if (y < 0)                         /* bad function name */
                   1606:       return("");                      /* so value is null */
                   1607: 
                   1608: #ifdef DEBUG
                   1609:     if (deblog) {
                   1610:        int j;
                   1611:        for (j = 0; j < argn; j++)
                   1612:          debug(F111,"fneval function arg",argp[j],j);
                   1613:     }
                   1614: #endif
                   1615:     if (y == FN_LIT)                   /* literal(arg1) */
                   1616:       return(argp[0] ? argp[0] : "");  /* return a pointer to arg itself */
                   1617: 
                   1618:     if (y == FN_CON) {                 /* Contents of variable, unexpanded. */
                   1619:        char c;
                   1620:        if (!(p = argp[0]) || !*p) return("");
                   1621:        if (*p == CMDQ) p++;
                   1622:        if ((c = *p) == '%') {          /* Scalar variable. */
                   1623:            c = *++p;                   /* Get ID character. */
                   1624:            p = "";                     /* Assume definition is empty */
                   1625:            if (!c) return(p);          /* Double paranoia */
                   1626:            if (c >= '0' && c <= '9') { /* Digit for macro arg */
                   1627:                c -= '0';               /* convert character to integer */
                   1628:                if (maclvl < 0)         /* Digit variables are global */
                   1629:                  p = g_var[c];         /* if no macro is active */
                   1630:                else                    /* otherwise */
                   1631:                  p = m_arg[maclvl][c]; /* they're on the stack */
                   1632:            } else {
                   1633:                if (isupper(c)) c -= ('a'-'A');         
                   1634:                p = g_var[c];           /* Letter for global variable */
                   1635:            }
                   1636:            return(p ? p : "");
                   1637:        }
                   1638:        if (c == '&') {                 /* Array reference. */
                   1639:            int vbi, d;
                   1640:            if (arraynam(p,&vbi,&d) < 0) /* Get name and subscript */
                   1641:              return("");
                   1642:            if (chkarray(vbi,d) > 0) {  /* Array is declared? */
                   1643:                vbi -= 'a';             /* Convert name to index */
                   1644:                if (a_dim[vbi] >= d) {  /* If subscript in range */
                   1645:                    char **ap;
                   1646:                    ap = a_ptr[vbi];    /* get data pointer */
                   1647:                    if (ap) {           /* and if there is one */
                   1648:                        return(ap[d]);  /* return what it points to */
                   1649:                    }
                   1650:                }
                   1651:            }
                   1652:            return(p ? p : "");         /* Otherwise its enexpanded value. */
                   1653:        }
                   1654:     }
                   1655:     for (i = 0; i < argn; i++) {       /* Not literal, expand the args */
                   1656:        n = 1024;                       /* allow 1K per expanded arg, yow! */
                   1657:        bp[i] = s = malloc(n);          /* get the new space */
                   1658:        if (bp[i] == NULL) {            /* handle failure to get space */
                   1659:            for (k = 0; k < i; k++) if (bp[k]) free(bp[k]);
                   1660:            debug(F101,"fneval malloc failure, arg","",i);
                   1661:            return("");
                   1662:        }
                   1663:        p = argp[i] ? argp[i] : "";
                   1664:        if (xxstring(p,&s,&n) < 0) {    /* Expand arg into new space */
                   1665:            debug(F101,"fneval xxstring fails, arg","",i);
                   1666:            for (k = 0; k <= i; k++)    /* Free up previous space on error */
                   1667:              if (bp[k]) free(bp[k]);
                   1668:            return("");                 /* and return null string. */
                   1669:        }
                   1670:        debug(F101,"fneval xxstring n","",n);
                   1671:     }
                   1672: #ifdef DEBUG
                   1673:     if (deblog) {
                   1674:        int j;
                   1675:        for (j = 0; j < argn; j++) {
                   1676:            debug(F111,"fneval arg post eval",argp[j],j);
                   1677:            debug(F111,"fneval evaluated arg",bp[j],j);
                   1678:        }
                   1679:     }
                   1680: #endif /* DEBUG */
                   1681: 
                   1682:     switch (y) {                       /* Do function on expanded args */
                   1683: 
                   1684:       case FN_DEF:
                   1685:        k = mlook(mactab,bp[0],nmac);   /* def(arg1) - Return a macro def */
                   1686:        p = (k > -1) ? mactab[k].mval : "";
                   1687:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1688:        return(p ? p : "");
                   1689: 
                   1690:       case FN_EVA:                     /* eval(arg1) */
                   1691:        p = evala(bp[0]);
                   1692:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1693:        return(p ? p : "");
                   1694: 
                   1695:       case FN_EXE:                     /* execute(arg1) */
                   1696:        j = (int)strlen(s = bp[0]);     /* Length of macro invocation */
                   1697:        p = "";                         /* Initialize return value to null */
                   1698:        if (j) {                        /* If there is a macro to execute */
                   1699:            while (*s == SP) s++,j--;   /* strip leading spaces */
                   1700:            p = s;                      /* remember beginning of macro name */
                   1701:            for (i = 0; i < j; i++) {   /* find end of macro name */
                   1702:                if (*s == SP) break;
                   1703:                s++;
                   1704:            }
                   1705:            if (*s == SP) {             /* if there was a space after */
                   1706:                *s++ = NUL;             /* terminate the macro name */
                   1707:                while (*s == SP) s++;   /* skip past any extra spaces */
                   1708:            } else s = "";              /* maybe there are no arguments */
                   1709:            if (p && *p)
                   1710:              k = mlook(mactab,p,nmac); /* Look up the macro name */
                   1711:            else k = -1;
                   1712: 
                   1713:            p = "";                     /* Initialize return value */
                   1714:            if (k >= 0) {               /* If macro found in table */
                   1715:                if ((j = dodo(k,s)) > 0) { /* Go set it up (like DO cmd) */
                   1716:                    if (cmpush() > -1) { /* Push command parser state */
                   1717:                        extern int ifc;
                   1718:                        int ifcsav = ifc; /* Save IF condition (kludge) */
                   1719:                        k = parser(1);  /* Call parser to execute the macro */
                   1720:                        cmpop();        /* Pop command parser */
                   1721:                        ifc = ifcsav;   /* Restore IF condition */
                   1722:                        if (k == 0) {   /* No errors, ignore action cmds. */
                   1723:                            p = mrval[maclvl+1]; /* If OK, set return value. */
                   1724:                            if (p == NULL) p = "";
                   1725:                        }
                   1726:                    } else {            /* Can't push any more */
                   1727:                        debug(F100,"fexec pushed too deep","",0);
                   1728:                         printf("\n?\\fexec() too deeply nested\n");
                   1729:                        while (cmpop() > -1) ;
                   1730:                        p = "";
                   1731:                    }
                   1732:                } 
                   1733:            }
                   1734:        }
                   1735:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1736:        return(p ? p : "");
                   1737: 
                   1738:       case FN_FC:                      /* File count. */
                   1739:        p = fnval;
                   1740:        *p = NUL;
                   1741:        if (argn > 0) {
                   1742:            k = zxpand(bp[0]);
                   1743:            sprintf(fnval,"%d",k);
                   1744:            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1745:        }
                   1746:        return(p);
                   1747: 
                   1748:       case FN_FIL:                     /* Next file in list. */
                   1749:        p = fnval;                      /* (no args) */
                   1750:        *p = NUL;
                   1751:        znext(p);
                   1752:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1753:        return(p ? p : "");
                   1754: 
                   1755:       case FN_IND:                     /* index(arg1,arg2) */
                   1756:        if (argn > 1) {                 /* Only works if we have 2 args */
                   1757:            int start;
                   1758:            len1 = (int)strlen(bp[0]);  /* length of string to look for */
                   1759:            len2 = (int)strlen(s = bp[1]); /* length of string to look in */
                   1760:            if (len1 < 0) return("");   /* paranoia */
                   1761:            if (len2 < 0) return("");
                   1762:            j = len2 - len1;            /* length difference */
                   1763:            start = 0;                  /* starting position */
                   1764:            if (argn > 2) {
                   1765:                if (chknum(bp[2])) {
                   1766:                    start = atoi(bp[2]) - 1;
                   1767:                    if (start < 0) start = 0;
                   1768:                }
                   1769:            }
                   1770:            if (j < 0 || start > j) {   /* search string is longer */
                   1771:                p = "0";
                   1772:            } else {
                   1773:                if (!incase) {          /* input case ignore? */
                   1774:                    lower(bp[0]);
                   1775:                    lower(bp[1]);
                   1776:                }
                   1777:                s = bp[1] + start;      /* Point to beginning of target */
                   1778:                p = "0";
                   1779:                for (i = 0; i <= (j - start); i++) { /* Now compare */
                   1780:                    if (!strncmp(bp[0],s++,len1)) {
                   1781:                        sprintf(fnval,"%d",i+1+start);
                   1782:                        p = fnval;
                   1783:                        break;
                   1784:                    }
                   1785:                }
                   1786:            }
                   1787:        } else p = "0";
                   1788:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1789:        return(p);
                   1790: 
                   1791:       case FN_CHR:                     /* character(arg1) */
                   1792:        if (chknum(bp[0])) {
                   1793:            i = atoi(bp[0]) & 255;
                   1794:            p = fnval;
                   1795:            *p++ = i;
                   1796:            *p = NUL;
                   1797:            p = fnval;
                   1798:        } else p = "";
                   1799:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1800:        return(p);
                   1801: 
                   1802:       case FN_LEN:                     /* length(arg1) */
                   1803:        p = fnval;
                   1804:        sprintf(p,"%d",(int)strlen(bp[0]));
                   1805:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1806:        return(p);
                   1807: 
                   1808:       case FN_LOW:                     /* lower(arg1) */
                   1809:        s = bp[0];
                   1810:        p = fnval;
                   1811:     
                   1812:        while (*s) {
                   1813:            if (isupper(*s))
                   1814:              *p = tolower(*s);
                   1815:            else
                   1816:              *p = *s;
                   1817:            p++; s++;
                   1818:        }
                   1819:        *p = NUL;
                   1820:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1821:        p = fnval;
                   1822:        return(p);
                   1823: 
                   1824:       case FN_MAX:                     /* max(arg1,arg2) */
                   1825:       case FN_MIN:                     /* min(arg1,arg2) */
                   1826:       case FN_MOD:                     /* mod(arg1,arg2) */
                   1827:        if (chknum(bp[0]) && chknum(bp[1])) {
                   1828:            i = atoi(bp[0]);
                   1829:            j = atoi(bp[1]);
                   1830:            switch (y) {
                   1831:              case FN_MAX:
                   1832:                if (j < i) j = i;
                   1833:                break;
                   1834:              case FN_MIN:
                   1835:                if (j > i) j = i;
                   1836:                break;
                   1837:              case FN_MOD:
                   1838:                j = i % j;
                   1839:                break;
                   1840:            }
                   1841:            p = fnval;
                   1842:            sprintf(p,"%d",j);
                   1843:        } else p = "";
                   1844:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1845:        return(p);
                   1846: 
                   1847:       case FN_SUB:                     /* substr(arg1,arg2,arg3) */
                   1848:        if (((argn > 1) && (int)strlen(bp[1]) && !rdigits(bp[1])) ||
                   1849:            ((argn > 2) && (int)strlen(bp[2]) && !rdigits(bp[2]))) {
                   1850:            p = "";                               /* if either, return null */
                   1851:        } else {
                   1852:            p = fnval;                           /* pointer to result */
                   1853:            j = (argn > 1) ? atoi(bp[1]) : 1;    /* start position */
                   1854:            k = (argn > 2) ? atoi(bp[2]) : 1023; /* length */
                   1855:            if (k > 0 && j <= (int)strlen(bp[0])) { /* if start pos in range */
                   1856:                s = bp[0]+j-1;                   /* point to source string */
                   1857:                for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
                   1858:            }
                   1859:            *p = NUL;                   /* terminate the result */
                   1860:            p = fnval;                  /* and point to it. */
                   1861:        }
                   1862:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); /* Free temp mem */
                   1863:        return(p);
                   1864: 
                   1865:       case FN_UPP:                     /* upper(arg1) */
                   1866:        s = bp[0];
                   1867:        p = fnval;
                   1868:        while (*s) {
                   1869:            if (islower(*s))
                   1870:              *p = toupper(*s);
                   1871:            else
                   1872:              *p = *s;
                   1873:            p++; s++;
                   1874:        }
                   1875:        *p = NUL;
                   1876:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1877:        p = fnval;
                   1878:        return(p);
                   1879: 
                   1880:       case FN_REP:                     /* Repeat */
                   1881:        p = "";                         /* Return value */
                   1882:        if (chknum(bp[1])) {            /* Repeat count */
                   1883:            n = atoi(bp[1]);
                   1884:            if (n > 0) {                /* Make n copies */
                   1885:                p = fnval;
                   1886:                *p = '\0';
                   1887:                k = (int)strlen(bp[0]); /* Make sure string has some length */
                   1888:                if (k > 0) {
                   1889:                    for (i = 0; i < n; i++) {
                   1890:                        s = bp[0];
                   1891:                        for (j = 0; j < k; j++) {
                   1892:                            if ((p - fnval) >= FNVALL) { /* Protect against */
                   1893:                                p = "";              /* core dumps... */
                   1894:                                break;
                   1895:                            } else *p++ = *s++;
                   1896:                        }
                   1897:                    }
                   1898:                }
                   1899:            }
                   1900:        }
                   1901:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1902:        p = fnval;
                   1903:        return(p);
                   1904: 
                   1905: #ifndef NOFRILLS
                   1906:       case FN_REV:
                   1907:        p = fnval;
                   1908:        yystring(bp[0],&p);
                   1909:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1910:        return(p);
                   1911: #endif /* NOFRILLS */
                   1912:        
                   1913:       case FN_RPA:                     /* RPAD and LPAD */
                   1914:       case FN_LPA:
                   1915:        *fnval = NUL;                   /* Return value */
                   1916:        if (argn == 1) {                /* If a number wasn't given */
                   1917:            p = fnval;                  /* just return the original string */
                   1918:            strncpy(p,bp[0],FNVALL);
                   1919:        } else if (chknum(bp[1])) {     /* Repeat count */
                   1920:            char pc;
                   1921:            n = atoi(bp[1]);
                   1922:            if (n >= 0) {               /* Pad it out */
                   1923:                p = fnval;
                   1924:                k = (int)strlen(bp[0]); /* Length of string to be padded */
                   1925:                pc = (argn < 3) ? SP : *bp[2]; /* Padding character */
                   1926:                if (n > FNVALL) n = FNVALL-1; /* protect against overruns */
                   1927:                if (k > FNVALL) k = FNVALL-1; /* and silly args. */
                   1928:                 if (k > n) k = n;
                   1929:                if (y == FN_RPA) {      /* RPAD */
                   1930:                    strncpy(p,bp[0],k);
                   1931:                    p += k;
                   1932:                    for (i = k; i < n; i++)  
                   1933:                      *p++ = pc;
                   1934:                } else {                /* LPAD */
                   1935:                    n -= k;
                   1936:                    for (i = 0; i < n; i++)  
                   1937:                      *p++ = pc;
                   1938:                    strncpy(p,bp[0],k);
                   1939:                    p += k;
                   1940:                }
                   1941:                *p = NUL;
                   1942:            }
                   1943:        }
                   1944:        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
                   1945:        p = fnval;
                   1946:        return(p);
                   1947: 
                   1948:       default:
                   1949:        return("");
                   1950:     }
                   1951: }
                   1952: #endif /* NOSPL */
                   1953: 
                   1954: #ifndef NOSPL
                   1955: 
                   1956: char *                                 /* Evaluate builtin variable */
                   1957: nvlook(s) char *s; {
                   1958:     int x, y;
                   1959:     long z;
                   1960:     char *p;
                   1961: 
                   1962:     x = 30;
                   1963:     p = vvbuf;
                   1964:     if (xxstring(s,&p,&x) < 0) {
                   1965:        y = -1;
                   1966:     } else {
                   1967:        s = vvbuf;
                   1968:        if ((y = lookup(vartab,s,nvars,&x)) < 0) return(NULL);
                   1969:     }
                   1970:     switch (y) {
                   1971:       case VN_ARGC:                    /* ARGC */
                   1972:        sprintf(vvbuf,"%d",macargc[maclvl]);
                   1973:        return(vvbuf);
                   1974: 
                   1975:       case VN_ARGS:                    /* ARGS */
                   1976:        sprintf(vvbuf,"%d",xargs);
                   1977:        return(vvbuf);
                   1978: 
                   1979:       case VN_COUN:                    /* COUNT */
                   1980:        sprintf(vvbuf,"%d",count[cmdlvl]);
                   1981:        return(vvbuf);
                   1982: 
                   1983:       case VN_DATE:                    /* DATE */
                   1984:        ztime(&p);                      /* Get "asctime" string */
                   1985:        if (p == NULL || *p == NUL) return(NULL);
                   1986:        vvbuf[0] = p[8];                /* dd */
                   1987:        vvbuf[1] = p[9];
                   1988:        vvbuf[2] = SP;
                   1989:        vvbuf[3] = p[4];                /* mmm */
                   1990:        vvbuf[4] = p[5];
                   1991:        vvbuf[5] = p[6];
                   1992:        vvbuf[6] = SP;
                   1993:        for (x = 20; x < 24; x++)       /* yyyy */
                   1994:          vvbuf[x - 13] = p[x];
                   1995:        vvbuf[11] = NUL;
                   1996:        return(vvbuf);
                   1997: 
                   1998:       case VN_NDAT:                    /* Numeric date */
                   1999:        ztime(&p);                      /* Get "asctime" string */
                   2000:        if (p == NULL || *p == NUL) return(NULL);
                   2001:        for (x = 20; x < 24; x++)       /* yyyy */
                   2002:          vvbuf[x - 20] = p[x];
                   2003:         vvbuf[6] = (p[8] == ' ') ? '0' : p[8]; vvbuf[7] = p[9]; /* dd */
                   2004:        for (x = 0; x < 12; x++)          /* mm */
                   2005:          if (!strncmp(p+4,months[x],3)) break;
                   2006:        if (x == 12) {
                   2007:            vvbuf[4] = vvbuf[5] = '?';
                   2008:        } else {
                   2009:            x++;
                   2010:            vvbuf[4] = (x < 10) ? '0' : '1';
                   2011:            vvbuf[5] = (x % 10) + 48;
                   2012:        }
                   2013:        vvbuf[8] = NUL;
                   2014:         return(vvbuf);
                   2015: 
                   2016:       case VN_DIRE:                    /* DIRECTORY */
                   2017:        return(zgtdir());
                   2018: 
                   2019:       case VN_FILE:                    /* filespec */
                   2020:        return(fspec);
                   2021: 
                   2022:       case VN_HOST:                    /* host name */
                   2023:        if (*myhost) {                  /* If known */
                   2024:            return(myhost);             /* return it. */
                   2025:        } else {                        /* Otherwise */
                   2026:            strcpy(vvbuf,"unknown");    /* just say "unknown" */
                   2027:            return(vvbuf);
                   2028:        }
                   2029: 
                   2030:       case VN_SYST:                    /* System type */
                   2031: #ifdef UNIX    
                   2032:        strcpy(vvbuf,"UNIX");
                   2033: #else
                   2034: #ifdef VMS
                   2035:        strcpy(vvbuf,"VMS");
                   2036: #else
                   2037: #ifdef OSK
                   2038:        strcpy(vvbuf,"OS9/68K");
                   2039: #else
                   2040: #ifdef AMIGA
                   2041:        strcpy(vvbuf,"Amiga");
                   2042: #else
                   2043: #ifdef MAC
                   2044:        strcpy(vvbuf,"Macintosh");
                   2045: #else
                   2046: #ifdef OS2
                   2047:        strcpy(vvbuf,"OS/2");
                   2048: #else
                   2049:        strcpy(vvbuf,"unknown");
                   2050: #endif /* OS2 */
                   2051: #endif /* MAC */
                   2052: #endif /* AMIGA */
                   2053: #endif /* OSK */
                   2054: #endif /* VMS */
                   2055: #endif /* UNIX */
                   2056:        return(vvbuf);
                   2057: 
                   2058:       case VN_SYSV:                    /* System herald */
                   2059:        for (x = y = 0; x < VVBUFL; x++) {
                   2060:            if (ckxsys[x] == SP && y == 0) continue;
                   2061:            vvbuf[y++] = (ckxsys[x] == SP) ? '_' : ckxsys[x];
                   2062:        }
                   2063:        vvbuf[y] = NUL;
                   2064:        return(vvbuf);
                   2065: 
                   2066:       case VN_TIME:                    /* TIME. Assumes that ztime returns */
                   2067:        ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
                   2068:        if (p == NULL || *p == NUL)     /* like asctime()! */
                   2069:          return(NULL);
                   2070:        for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
                   2071:          vvbuf[x - 11] = p[x];         /* to vvbuf */
                   2072:        vvbuf[8] = NUL;                 /* terminate */
                   2073:        return(vvbuf);                  /* and return it */
                   2074: 
                   2075:       case VN_NTIM:                    /* Numeric time */
                   2076:        ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
                   2077:        if (p == NULL || *p == NUL)     /* like asctime()! */
                   2078:          return(NULL);
                   2079:        z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
                   2080:        sprintf(vvbuf,"%ld",z);
                   2081:        return(vvbuf);
                   2082: 
                   2083: #ifdef UNIX
                   2084:       case VN_TTYF:                    /* TTY file descriptor */
                   2085:        sprintf(vvbuf,"%d",ttyfd);
                   2086:        return(vvbuf);
                   2087: #endif /* UNIX */
                   2088: 
                   2089:       case VN_VERS:                    /* Numeric Kermit version number */
                   2090:        sprintf(vvbuf,"%ld",vernum);
                   2091:        return(vvbuf);
                   2092: 
                   2093:       case VN_HOME:                    /* Home directory */
                   2094: #ifdef UNIX
                   2095:         sprintf(vvbuf,"%s/",zhome());
                   2096:        return(vvbuf);
                   2097: #else
                   2098:        return(zhome());
                   2099: #endif /* UNIX */
                   2100: 
                   2101:       case VN_IBUF:                    /* INPUT buffer */
                   2102:        return(inpbuf);
                   2103: 
                   2104:       case VN_SPEE: {                  /* Transmission SPEED */
                   2105:          long t;
                   2106:          t = ttgspd();
                   2107:          if (t < 0L)
                   2108:            sprintf(vvbuf,"unknown");
                   2109:          else
                   2110:            sprintf(vvbuf,"%ld",t);
                   2111:          return(vvbuf);
                   2112:       }
                   2113:       case VN_SUCC:                    /* SUCCESS flag */
                   2114:        sprintf(vvbuf,"%d",(success == 0) ? 1 : 0);
                   2115:        return(vvbuf);
                   2116: 
                   2117:       case VN_LINE:                    /* LINE */
                   2118:        p = (char *) ttname;
                   2119:         return(p);
                   2120: 
                   2121:       case VN_PROG:                    /* Program name */
                   2122: #ifdef MAC
                   2123:        return("Mac-Kermit");
                   2124: #else
                   2125:        return("C-Kermit");
                   2126: #endif /* MAC */
                   2127: 
                   2128:       case VN_RET:                     /* Value of most recent RETURN */
                   2129:        p = mrval[maclvl+1];
                   2130:        if (p == NULL) p = "";
                   2131:        return(p);
                   2132: 
                   2133:       case VN_FFC:                     /* Size of most recent file */
                   2134:        sprintf(vvbuf, "%ld", ffc);
                   2135:        return(vvbuf);
                   2136: 
                   2137:       case VN_TFC:                     /* Size of most recent file group */
                   2138:        sprintf(vvbuf, "%ld", tfc);
                   2139:        return(vvbuf);
                   2140: 
                   2141:       case VN_CPU:                     /* CPU type */
                   2142: #ifdef CKCPU
                   2143:        return(CKCPU);
                   2144: #else
                   2145:        return("unknown");
                   2146: #endif /* CKCPU */
                   2147: 
                   2148:       default:
                   2149:        return(NULL);
                   2150:     }
                   2151: }
                   2152: #endif /* NOSPL */
                   2153: 
                   2154: /*
                   2155:   X X S T R I N G  --  Expand variables and backslash codes.
                   2156: 
                   2157:     int xxtstring(s,&s2,&n);
                   2158: 
                   2159:   Expands \ escapes via recursive descent.
                   2160:   Argument s is a pointer to string to expand (source).
                   2161:   Argument s2 is the address of where to put result (destination).
                   2162:   Argument n is the length of the destination string (to prevent overruns).
                   2163:   Returns -1 on failure, 0 on success,
                   2164:     with destination string null-terminated and s2 pointing to the
                   2165:     terminating null, so that subsequent characters can be added.
                   2166: */
                   2167: 
                   2168: #define XXDEPLIM 100                   /* Recursion depth limit */
                   2169: 
                   2170: int
                   2171: xxstring(s,s2,n) char *s; char **s2; int *n; {
                   2172:     int x,                             /* Current character */
                   2173:         y,                             /* Worker */
                   2174:         pp,                            /* Paren level */
                   2175:         argn,                          /* Function argument counter */
                   2176:         n2,                            /* Local copy of n */
                   2177:         d,                             /* Array dimension */
                   2178:         vbi,                           /* Variable id (integer form) */
                   2179:         argl;                          /* String argument length */
                   2180: 
                   2181:     char vb,                           /* Variable id (char form) */
                   2182:         *vp,                           /* Pointer to variable definition */
                   2183:         *new,                          /* Local pointer to target string */
                   2184:         *p,                            /* Worker */
                   2185:         *q;                            /* Worker */
                   2186:     char *r  = (char *)0;              /* For holding function args */
                   2187:     char *r2 = (char *)0;
                   2188: 
                   2189: #ifndef NOSPL
                   2190:     char vnambuf[VNAML];               /* Buffer for variable/function name */
                   2191:     char *argp[FNARGS];                        /* Pointers to function args */
                   2192: #endif /* NOSPL */
                   2193: 
                   2194:     static int depth = 0;              /* Call depth, avoid overflow */
                   2195: 
                   2196:     n2 = *n;                           /* Make local copies of args */
                   2197:     new = *s2;                         /* for one less level of indirection */
                   2198: 
                   2199:     depth++;                           /* Sink to a new depth */
                   2200:     if (depth > XXDEPLIM) {            /* Too deep? */
                   2201:        printf("?definition is circular or too deep\n");
                   2202:        depth = 0;
                   2203:        *new = NUL;
                   2204:        return(-1);
                   2205:     }
                   2206:     if (!s || !new) {                  /* Watch out for null pointers */
                   2207:        depth = 0;
                   2208:        *new = NUL;
                   2209:        return(-1);
                   2210:     }
                   2211:     argl = (int)strlen(s);             /* Get length of source string */
                   2212:     debug(F111,"xxstring",s,argl);
                   2213:     if (argl < 0) {                    /* Watch out for garbage */
                   2214:        depth = 0;
                   2215:        *new = NUL;
                   2216:        return(-1);
                   2217:     }
                   2218:     while ( x = *s ) {                 /* Loop for all characters */
                   2219:         if (x != CMDQ) {               /* Is it the command-quote char? */
                   2220:            *new++ = *s++;              /* No, normal char, just copy */
                   2221:            if (n2-- < 0) {             /* and count it, careful of overflow */
                   2222:                return(-1); 
                   2223:            }
                   2224:            continue;
                   2225:        }
                   2226: 
                   2227: /* We have the command-quote character. */
                   2228: 
                   2229:        x = *(s+1);                     /* Get the following character. */
                   2230:        switch (x) {                    /* Act according to variable type */
                   2231: #ifndef NOSPL
                   2232:          case '%':                     /* Variable */
                   2233:            s += 2;                     /* Get the letter or digit */
                   2234:            vb = *s++;                  /* and move source pointer past it */
                   2235:            vp = NULL;                  /* Assume definition is empty */
                   2236:            if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
                   2237:                if (maclvl < 0)         /* Digit variables are global */
                   2238:                  vp = g_var[vb];       /* if no macro is active */
                   2239:                else                    /* otherwise */
                   2240:                  vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
                   2241:            } else {
                   2242:                if (isupper(vb)) vb -= ('a'-'A');
                   2243:                vp = g_var[vb];         /* Letter for global variable */
                   2244:            }
                   2245:            if (vp) {                   /* If definition not empty */
                   2246:                if (xxstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
                   2247:                    return(-1);         /* Pass along failure */
                   2248:                }
                   2249:            }
                   2250:            break;
                   2251:          case '&':                     /* An array reference */
                   2252:            if (arraynam(s,&vbi,&d) < 0) { /* Get name and subscript */
                   2253:                return(-1);
                   2254:            }
                   2255:            pp = 0;                     /* Bracket counter */
                   2256:            while (*s) {                /* Advance source pointer */
                   2257:                if (*s == '[') pp++;
                   2258:                if (*s == ']' && --pp == 0) break;
                   2259:                s++;
                   2260:            }
                   2261:            if (*s == ']') s++;         /* past the closing bracket. */
                   2262:            if (chkarray(vbi,d) > 0) {  /* Array is declared? */
                   2263:                vbi -= 96;              /* Convert name to index */
                   2264:                if (a_dim[vbi] >= d) {  /* If subscript in range */
                   2265:                    char **ap;
                   2266:                    ap = a_ptr[vbi];    /* get data pointer */
                   2267:                    if (ap) {           /* and if there is one */
                   2268:                        if (ap[d]) {    /* If definition not empty */
                   2269:                            if (xxstring(ap[d],&new,&n2) < 0) { /* evaluate */
                   2270:                                return(-1); /* Pass along failure */
                   2271:                            }
                   2272:                        }
                   2273:                    }
                   2274:                }
                   2275:            }
                   2276:            break;
                   2277: 
                   2278:          case 'F':                     /* A builtin function */
                   2279:          case 'f':
                   2280:            q = vnambuf;                /* Copy the name */
                   2281:            y = 0;                      /* into a separate buffer */
                   2282:            s+=2;                       /* point past 'F' */
                   2283:            while (y++ < VNAML) {
                   2284:                if (*s == '(') { s++; break; } /* Look for open paren */
                   2285:                if ((*q = *s) == NUL) break;   /* or end of string */
                   2286:                s++; q++;
                   2287:            }
                   2288:            *q = NUL;                   /* Terminate function name */
                   2289:            if (y >= VNAML) {           /* Handle pathological case */
                   2290:                while (*s && (*s != '(')) /* of very long string entered */
                   2291:                  s++;                    /* as function name. */
                   2292:                if (*s == ')') s++;       /* Skip past it. */
                   2293:            }
                   2294:            r = r2 = malloc(argl+2);    /* And make a place to copy args */
                   2295:            debug(F101,"xxstring r2","",r2);
                   2296:            if (!r2) {                  /* Watch out for malloc failure */
                   2297:                depth = 0;
                   2298:                *new = NUL;
                   2299:                return(-1);
                   2300:            }
                   2301:            argn = 0;                   /* Argument counter */
                   2302:            argp[argn++] = r;           /* Point to first argument */
                   2303:            y = 0;                      /* Completion flag */
                   2304:            pp = 1;                     /* Paren level (already have one). */
                   2305:            while (*r = *s) {           /* Copy each argument, char by char. */
                   2306:                if (*r == '(') pp++;    /* Count an opening paren. */
                   2307:                if (*r == ')') {        /* Closing paren, count it. */
                   2308:                    if (--pp == 0) {    /* Final one? */
                   2309:                        *r = NUL;       /* Make it a terminating null */
                   2310:                        s++;
                   2311:                        y = 1;          /* Flag we've got all the args */
                   2312:                        break;
                   2313:                    }
                   2314:                }
                   2315:                if (*r == ',') {        /* Comma */
                   2316:                    if (pp == 1) {      /* If not within ()'s, */
                   2317:                        *r = NUL;           /* new arg, skip past it, */
                   2318:                        argp[argn++] = r+1; /* point to new arg. */
                   2319:                        if (argn == FNARGS) /* Too many args */
                   2320:                          break;
                   2321:                    }                   /* Otherwise just skip past  */
                   2322:                }
                   2323:                s++; r++;               /* Advance pointers */
                   2324:            }
                   2325:            debug(F110,"xxstring function name",vnambuf,0);
                   2326:            if (!y) {                   /* If we didn't find closing paren */
                   2327:                debug(F101,"xxstring r2 before free","",r2);
                   2328:                if (r2) free(r2);       /* free the temporary storage */
                   2329:                return(-1);             /* and return failure. */
                   2330:            }
                   2331: #ifdef DEBUG
                   2332:            if (deblog)
                   2333:              for (y = 0; y < argn; y++)
                   2334:                debug(F111,"xxstring function arg",argp[y],y);
                   2335: #endif /* DEBUG */
                   2336:            vp = fneval(vnambuf,argp,argn); /* Evaluate the function. */
                   2337:            if (vp) {                   /* If definition not empty */
                   2338:                while (*new++ = *vp++)  /* copy it to output string */
                   2339:                  if (n2-- < 0) return(-1); /* mindful of overflow */
                   2340:                new--;                  /* Back up over terminating null */
                   2341:                n2++;                   /* to allow for further deposits. */
                   2342:            }
                   2343:            if (r2) {
                   2344:                debug(F101,"xxstring freeing r2","",r2);
                   2345:                free(r2);               /* Now free the temporary storage */
                   2346:                r2 = NULL;
                   2347:            }
                   2348:            break;
                   2349:          case '$':                     /* An environment variable */
                   2350:          case 'V':                     /* Or a named builtin variable. */
                   2351:          case 'v':
                   2352:          case 'M':                     /* Or a macro = long variable */
                   2353:          case 'm':
                   2354:            p = s+2;                    /* $/V/M must be followed by (name) */
                   2355:            if (*p != '(') {            /* as in \$(HOME) or \V(count) */
                   2356:                *new++ = *s++;          /* If not, just copy it */
                   2357:                if (n2-- < 0) {
                   2358:                    return(-1);
                   2359:                }
                   2360:                break;
                   2361:            }
                   2362:            p++;                        /* Point to 1st char of name */
                   2363:            q = vnambuf;                /* Copy the name */
                   2364:            y = 0;                      /* into a separate buffer */
                   2365:            while (y++ < VNAML) {       /* Watch out for name too long */
                   2366:                if (*p == ')') {        /* Name properly terminated with ')' */
                   2367:                    p++;                /* Move source pointer past ')' */
                   2368:                    break;
                   2369:                }
                   2370:                if ((*q = *p) == NUL)   /* String ends before ')' */
                   2371:                  break;
                   2372:                p++; q++;               /* Advance pointers */
                   2373:            }
                   2374:            *q = NUL;                   /* Terminate the variable name */
                   2375:            if (y >= VNAML) {           /* Handle pathological case */
                   2376:                while (*p && (*p != ')')) /* of very long string entered */
                   2377:                  p++;                    /* as variable name. */
                   2378:                if (*p == ')') p++;       /* Skip ahead to the end of it. */
                   2379:            }
                   2380:            s = p;                      /* Adjust global source pointer */
                   2381:            debug(F110,"xxstring vname",vnambuf,0);
                   2382:            if (x == '$') {             /* Look up its value */
                   2383:                vp = getenv(vnambuf);   /* This way for environment variable */
                   2384:            } else if (x == 'm' || x == 'M') { /* or this way for macro */
                   2385:                y = mlook(mactab,vnambuf,nmac); /* contents (= long variable */
                   2386:                vp = (y > -1) ? mactab[y].mval : ""; /* name)... */
                   2387:            } else {                    /*  or */
                   2388:                vp = nvlook(vnambuf);   /* this way for builtin variable */
                   2389:            }
                   2390:            if (vp) {                   /* If definition not empty */
                   2391:                while (*new++ = *vp++)  /* copy it to output string. */
                   2392:                  if (n2-- < 0) {
                   2393:                    return(-1);
                   2394:                }
                   2395:                new--;                  /* Back up over terminating null */
                   2396:                n2++;                   /* to allow for further deposits. */
                   2397:            }
                   2398:            break;
                   2399: #endif /* NOSPL        */                      /* Handle \nnn even if NOSPL. */
                   2400:          default:                      /* Maybe it's a backslash code */
                   2401:            y = xxesc(&s);              /* Go interpret it */
                   2402:            if (y < 0) {                /* Upon failure */
                   2403:                *new++ = x;             /* Just quote the next character */
                   2404:                s += 2;                 /* Move past the pair */
                   2405:                n2 -= 2;
                   2406:                if (n2 < 0) {
                   2407:                    return(-1);
                   2408:                }
                   2409:                continue;               /* and go back for more */
                   2410:            } else {
                   2411:                *new++ = y;             /* else deposit interpreted value */
                   2412:                if (n2-- < 0) {
                   2413:                    return(-1);
                   2414:                }
                   2415:            }
                   2416:        }
                   2417:     }
                   2418:     *new = NUL;                                /* Terminate the new string */
                   2419:     depth--;                           /* Adjust stack depth gauge */
                   2420:     *s2 = new;                         /* Copy results back into */
                   2421:     *n = n2;                           /* the argument addresses */
                   2422:     return(0);                         /* and return. */
                   2423: }
                   2424: 
                   2425: /*  X X S T R C M P  --  Caseless string comparison  */
                   2426: 
                   2427: int
                   2428: xxstrcmp(s1,s2,n) char *s1, *s2; int n; { /* Caseless string comparison. */
                   2429:     char t1, t2;                       /*  1 if s1 > t1 */
                   2430:     int n1, n2;                                /*  0 if s1 = s2 */
                   2431:                                        /* -1 if s1 < t1 */
                   2432:     if (!s1) s1 = "";                  /* Get lengths and watch out */
                   2433:     n1 = (int)strlen(s1);              /* for null pointers. */
                   2434:     if (!s2) s2 = "";
                   2435:     n2 = (int)strlen(s2);
                   2436: 
                   2437:     if (n > n1) n = n1;
                   2438:     if (n > n2) n = n2;
                   2439: 
                   2440:     while (n--) {
                   2441:        t1 = *s1++;                     /* Get next character from each. */
                   2442:        if (isupper(t1)) t1 = tolower(t1);
                   2443:        t2 = *s2++;
                   2444:        if (isupper(t2)) t2 = tolower(t2);
                   2445:        if (t1 < t2) return(-1);        /* s1 < s2 */
                   2446:        if (t1 > t2) return(1);         /* s1 > s2 */
                   2447:     }
                   2448:     return(0);                         /* They're equal */
                   2449: }
                   2450: 
                   2451: #endif /* NOICP */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.