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

Defined functions

debopn defined in line 960; used 3 times
doconect defined in line 1522; used 2 times
doinput defined in line 1541; used 1 times
dolog defined in line 825; used 1 times
doreinp defined in line 1693; used 1 times
doshodial defined in line 1215; used 2 times
dostat defined in line 1461; used 1 times
dotype defined in line 653; used 1 times
fneval defined in line 1795; used 1 times
gettcs defined in line 335; used 6 times
nvlook defined in line 2198; used 3 times
pktopn defined in line 888; used 1 times
prescan defined in line 274; used 1 times
sesopn defined in line 939; used 1 times
shocharset defined in line 1428; used 3 times
shodial defined in line 1197; used 1 times
shods defined in line 1202; used 4 times
shonet defined in line 1108; used 1 times
shopad defined in line 1241; used 1 times
shopar defined in line 1448; used 1 times
shoparc defined in line 1012; used 2 times
shoparf defined in line 1253; used 2 times
shoparl defined in line 1411; used 1 times
shoparp defined in line 1362; used 2 times
shotel defined in line 1092; used 2 times
shox25 defined in line 994; used 2 times
transmit defined in line 391; used 1 times
traopn defined in line 909; used 1 times
trtrap defined in line 314; used 3 times
xlate defined in line 738; used 1 times
yystring defined in line 1775; used 2 times

Defined variables

VOID defined in line 1448; never used
disptb defined in line 266; used 1 times
fnctab defined in line 229; used 3 times
fnval defined in line 1793; used 24 times
inpbps defined in line 138; used 1 times
months defined in line 57; used 1 times
nfuncs defined in line 258; used 2 times
nvars defined in line 225; used 2 times
tr_int defined in line 311; used 9 times
vartab defined in line 184; used 4 times
vvbuf defined in line 263; used 81 times
wkdays defined in line 63; used 1 times
x25ver defined in line 40; used 2 times
  • in line 997(2)

Defined macros

FNVALL defined in line 1792; used 7 times
IAC defined in line 1537; used 2 times
VVBUFL defined in line 262; used 2 times
XMBUFS defined in line 389; used 1 times
XXDEPLIM defined in line 2481; used 1 times
Last modified: 1992-11-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5433
Valid CSS Valid XHTML 1.0 Strict