home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit5a188 / ckuus4.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  78KB  |  2,758 lines

  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, 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, *incase;
  148. #else
  149. extern int count[], incase[];
  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. #ifdef VMS
  762.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
  763. #else
  764.     filecode = ZOFILE;
  765. #endif /* VMS */
  766. #endif /* MAC */
  767.  
  768.     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
  769.     printf("?Can't open output file %s\n",fout);
  770.     return(0);
  771.     }
  772. #ifndef AMIGA
  773. #ifndef MAC
  774.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  775. #endif /* MAC */
  776. #endif /* AMIGA */
  777.  
  778.     tr_int = 0;                /* Have not been interrupted (yet). */
  779.     z = 1;                /* Return code presumed good. */
  780.  
  781.     tcs = gettcs(csin,csout);        /* Get intermediate set. */
  782.  
  783.     printf("%s (%s) => %s (%s)\n",    /* Say what we're doing. */
  784.        fin, fcsinfo[csin].name,
  785.        fout,fcsinfo[csout].name
  786.     );
  787.     printf("via %s", tcsinfo[tcs].name);
  788.     if (language)
  789.       printf(", language: %s\n",langs[language].description);
  790.     printf("\n\n");
  791.  
  792.     if (csin == csout) {        /* Input and output sets the same? */
  793.     sxx = rxx = NULL;        /* If so, no translation. */
  794.     } else {                /* Otherwise, set up */
  795.     sxx = xls[tcs][csin];        /* translation function */
  796.     rxx = xlr[tcs][csout];        /* pointers. */
  797.     if (rxx == zl1as) rxx = xl1as;
  798.     }
  799.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  800.     if (tr_int) {            /* Interrupted? */
  801.         printf("^C...\n");        /* Print message */
  802.         z = 0;
  803.         break;
  804.     }
  805.     if (sxx) c = (*sxx)((CHAR)c);    /* From fcs1 to tcs */
  806.     if (rxx) c = (*rxx)((CHAR)c);    /* from tcs to fcs2 */
  807.  
  808.     if (zchout(filecode,(char)c) < 0) { /* Output the xlated character */
  809.         printf("File output error\n");
  810.         z = 0;
  811.         break;
  812.     }
  813.     }
  814. #ifndef AMIGA
  815. #ifndef MAC
  816.     signal(SIGINT,oldsig);        /* put old signal action back. */
  817. #endif /* MAC */
  818. #endif /* AMIGA */
  819.  
  820.     tr_int = 0;
  821.     zclose(ZIFILE);            /* close files, */
  822.     zclose(filecode);
  823.     return(z);                /* and return successfully. */
  824. }
  825. #endif /* NOCSETS */
  826.  
  827. /*  D O L O G  --  Do the log command  */
  828.  
  829. int
  830. dolog(x) int x; {
  831.     int y, disp; char *s;
  832.  
  833.     switch (x) {
  834.  
  835. #ifdef DEBUG
  836.     case LOGD:
  837.         y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
  838.         break;
  839. #endif /* DEBUG */
  840.  
  841.     case LOGP:
  842.         y = cmofi("Name of packet log file","packet.log",&s,xxstring);
  843.         break;
  844.  
  845.     case LOGS:
  846.         y = cmofi("Name of session log file","session.log",&s,xxstring);
  847.         break;
  848.  
  849. #ifdef TLOG
  850.     case LOGT:
  851.         y = cmofi("Name of transaction log file","transact.log",&s,
  852.               xxstring);
  853.         break;
  854. #endif /* TLOG */
  855.  
  856.     default:
  857.         printf("\n?Unknown log designator - %d\n",x);
  858.         return(-2);
  859.     }
  860.     if (y < 0) return(y);
  861.  
  862.     strcpy(line,s);
  863.     s = line;
  864.     if ((y = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
  865.       return(y);
  866.     disp = y;
  867.     if ((y = cmcfm()) < 0) return(y);
  868.  
  869.     switch (x) {
  870.  
  871. #ifdef DEBUG
  872.     case LOGD:
  873.         return(deblog = debopn(s,disp));
  874. #endif /* DEBUG */
  875.  
  876.     case LOGP:
  877.         return(pktlog = pktopn(s,disp));
  878.  
  879.     case LOGS:
  880.         return(seslog = sesopn(s,disp));
  881.  
  882. #ifdef TLOG
  883.     case LOGT:
  884.         return(tralog = traopn(s,disp));
  885. #endif /* TLOG */
  886.  
  887.     default:
  888.         return(-2);
  889.     }
  890. }
  891.  
  892. int
  893. pktopn(s,disp) char *s; int disp; {
  894.     extern char pktfil[];
  895.     static struct filinfo xx;
  896.     int y;
  897.  
  898.     zclose(ZPFILE);
  899.     if(s[0] == '\0') return(0);
  900.     if (disp) {
  901.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  902.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  903.     xx.lblopts = 0;
  904.     y = zopeno(ZPFILE,s,NULL,&xx);
  905.     } else y = zopeno(ZPFILE,s,NULL,NULL);
  906.     if (y > 0)
  907.       strcpy(pktfil,s);
  908.     else
  909.       *pktfil = '\0';
  910.     return(y);
  911. }
  912.  
  913. int
  914. traopn(s,disp) char *s; int disp; {
  915. #ifdef TLOG
  916.     extern char trafil[];
  917.     static struct filinfo xx;
  918.     int y;
  919.  
  920.     zclose(ZTFILE);
  921.     if(s[0] == '\0') return(0);
  922.     if (disp) {
  923.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  924.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  925.     xx.lblopts = 0;
  926.     y = zopeno(ZTFILE,s,NULL,&xx);
  927.     } else y = zopeno(ZTFILE,s,NULL,NULL);
  928.     if (y > 0) {
  929.     strcpy(trafil,s);
  930.     tlog(F110,"Transaction Log:",versio,0L);
  931. #ifndef MAC
  932.     tlog(F100,ckxsys,"",0L);
  933. #endif /* MAC */
  934.     ztime(&s);
  935.     tlog(F100,s,"",0L);
  936.     } else *trafil = '\0';
  937.     return(y);
  938. #else
  939.     return(0);
  940. #endif
  941. }
  942.  
  943. int
  944. sesopn(s,disp) char * s; int disp; {
  945.     extern char sesfil[];
  946.     static struct filinfo xx;
  947.     int y;
  948.  
  949.     zclose(ZSFILE);
  950.     if(s[0] == '\0') return(0);
  951.     if (disp) {
  952.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  953.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  954.     xx.lblopts = 0;
  955.     y = zopeno(ZSFILE,s,NULL,&xx);
  956.     } else y = zopeno(ZSFILE,s,NULL,NULL);
  957.     if (y > 0)
  958.       strcpy(sesfil,s);
  959.     else
  960.       *sesfil = '\0';
  961.     return(y);
  962. }
  963.  
  964. int
  965. debopn(s,disp) char *s; int disp; {
  966. #ifdef DEBUG
  967.     char *tp;
  968.     static struct filinfo xx;
  969.  
  970.     zclose(ZDFILE);
  971.  
  972.     if (disp) {
  973.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  974.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  975.     xx.lblopts = 0;
  976.     deblog = zopeno(ZDFILE,s,NULL,&xx);
  977.     } else deblog = zopeno(ZDFILE,s,NULL,NULL);
  978.     if (deblog > 0) {
  979.     strcpy(debfil,s);
  980.     debug(F110,"Debug Log ",versio,0);
  981. #ifndef MAC
  982.     debug(F100,ckxsys,"",0);
  983. #endif /* MAC */
  984.     ztime(&tp);
  985.     debug(F100,tp,"",0);
  986.     } else *debfil = '\0';
  987.     return(deblog);
  988. #else
  989.     return(0);
  990. #endif
  991. }
  992.  
  993. #ifndef NOSHOW
  994.  
  995. /*  S H O P A R  --  Show Parameters  */
  996.  
  997. #ifdef SUNX25
  998. VOID
  999. shox25() {
  1000.     if (nettype == NET_SX25) {
  1001.     printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
  1002.     if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  1003.     printf("\n Reverse charge call %s",
  1004.            revcall ? "selected" : "not selected");
  1005.     printf (", Closed user group ");
  1006.     if (closgr > -1)
  1007.       printf ("%d",closgr);
  1008.     else
  1009.       printf ("not selected");
  1010.     printf (",");
  1011.     printf("\n Call user data %s.\n", cudata ? udata : "not selected");
  1012.     }
  1013. }
  1014. #endif /* SUNX25 */
  1015.  
  1016. VOID
  1017. shoparc() {
  1018.     int i; char *s;
  1019.     long zz;
  1020.  
  1021.     puts("Communications Parameters:");
  1022.  
  1023.     if (network) {
  1024.     printf(" Host: %s",ttname);
  1025.     } else {
  1026.     printf(" Line: %s, speed: ",ttname);
  1027.     if ((zz = ttgspd()) < 0) {
  1028.         printf("unknown");
  1029.         } else {
  1030.         if (speed == 8880) printf("75/1200"); else printf("%ld",zz);
  1031.     }
  1032.     }
  1033.     printf(", mode: ");
  1034.     if (local) printf("local"); else printf("remote");
  1035.     if (network == 0) {
  1036. #ifndef NODIAL
  1037.     for (i = 0; i < nmdm; i++) {
  1038.         if (mdmtab[i].kwval == mdmtyp) {
  1039.         printf(", modem: %s",mdmtab[i].kwd);
  1040.         break;
  1041.         }
  1042.     }
  1043. #endif /* NODIAL */
  1044.     } else {
  1045.     if (nettype == NET_TCPA) printf(", TCP/IP");
  1046.     if (nettype == NET_TCPB) printf(", TCP/IP");
  1047.         if (nettype == NET_DEC) {
  1048.           if ( ttnproto == NP_LAT ) printf(", DECnet LAT");
  1049.           else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
  1050.           else printf(", DECnet");
  1051.         }
  1052.         if (nettype == NET_PIPE) printf(", Named Pipe");
  1053. #ifdef SUNX25
  1054.     shox25();
  1055. #endif /* SUNX25 */
  1056.     if (ttnproto == NP_TELNET) printf(", telnet protocol");
  1057.     }
  1058.     if (local) {
  1059.     i = parity ? 7 : 8;
  1060.     if (i == 8) i = (cmask == 0177) ? 7 : 8;
  1061.     printf("\n Terminal bits: %d, p",i);
  1062.     } else printf("\n P");
  1063.     printf("arity: %s",parnam((char)parity));
  1064.     printf(", duplex: ");
  1065.     if (duplex) printf("half, "); else printf("full, ");
  1066.     printf("flow: ");
  1067.     if (flow == FLO_KEEP) printf("keep");
  1068.         else if (flow == FLO_XONX) printf("xon/xoff");
  1069.     else if (flow == FLO_NONE) printf("none");
  1070.     else if (flow == FLO_DTRT) printf("dtr/cts");
  1071.     else if (flow == FLO_RTSC) printf("rts/cts");
  1072.         else if (flow == FLO_DTRC) printf("dtr/cd");
  1073.     else printf("%d",flow);
  1074.     printf(", handshake: ");
  1075.     if (turn) printf("%d\n",turnch); else printf("none\n");
  1076.     if (local && !network) {        /* Lockfile & carrier stuff */
  1077.     if (carrier == CAR_OFF) s = "off";
  1078.     else if (carrier == CAR_ON) s = "on";
  1079.     else if (carrier == CAR_AUT) s = "auto";
  1080.     else s = "unknown";
  1081.     printf(" Carrier: %s", s);
  1082.     if (carrier == CAR_ON) {
  1083.         if (cdtimo) printf(", timeout: %d sec", cdtimo);
  1084.         else printf(", timeout: none");
  1085.     }
  1086. #ifdef UNIX
  1087.     if (haslock && *flfnam) {    /* Lockfiles only apply to UNIX... */
  1088.         printf(", lockfile: %s",flfnam);
  1089.     }
  1090. #endif /* UNIX */
  1091.     printf("\n Escape character: %d (^%c)\n",escape,ctl(escape));
  1092.     }
  1093. }
  1094.  
  1095. #ifdef TNCODE
  1096. static VOID
  1097. shotel() {
  1098.     printf("SET TELNET parameters:\n echo: %s\n newline-mode: %s\n",
  1099.        tn_duplex ? "local" : "remote", tn_nlm ? "on" : "off");
  1100.     printf(" terminal-type: ");
  1101.     if (tn_term) printf("%s\n",tn_term);
  1102.     else {
  1103.     char *p;
  1104.     p = getenv("TERM");
  1105.     if (p)
  1106.       printf("none (%s will be used)\n",p);
  1107.     else printf("none\n");
  1108.     }
  1109. }
  1110. #endif /* TNCODE */
  1111.  
  1112. VOID
  1113. shonet() {
  1114. #ifndef NETCONN
  1115.     printf("\nNo networks are supported in this version of C-Kermit\n");
  1116. #else
  1117.     printf("\nSupported networks:\n");
  1118.  
  1119. #ifdef VMS
  1120.  
  1121. #ifdef MULTINET
  1122.     printf(" TGV MultiNet TCP/IP");
  1123. #else
  1124. #ifdef WINTCP
  1125.     printf(" WOLLONGONG WIN/TCP");
  1126. #else
  1127. #ifdef DEC_TCPIP
  1128.     printf(" DEC TCP/IP Services for (Open)VMS");
  1129. #else
  1130.     printf(" None");
  1131. #endif /* DEC_TCPIP */
  1132. #endif /* WINTCP */
  1133. #endif /* MULTINET */
  1134. #ifdef TNCODE
  1135.     printf(", TELNET protocol\n\n");
  1136.     shotel();
  1137. #endif /* TNCODE */
  1138.     printf("\n");
  1139.  
  1140. #else /* Not VMS */
  1141.  
  1142. #ifdef SUNX25
  1143.     printf(" SunLink X.25\n");
  1144. #endif /* SUNX25 */
  1145. #ifdef DECNET
  1146.     printf(" DECnet\n");
  1147. #endif /* DECNET */
  1148. #ifdef NPIPE
  1149.     printf(" LAN Manager Named Pipe\n");
  1150. #endif /* DECNET */
  1151. #ifdef TCPSOCKET
  1152.     printf(" TCP/IP");
  1153. #ifdef TNCODE
  1154.     printf(", TELNET protocol\n\n");
  1155.     shotel();
  1156. #endif /* TNCODE */
  1157. #endif /* TCPSOCKET */
  1158.     printf("\n");
  1159.  
  1160. #endif /* VMS */
  1161.  
  1162.     printf("Current network type:\n");
  1163.     if (nettype == NET_TCPA || nettype == NET_TCPB)
  1164.       printf(" TCP/IP\n");
  1165. #ifdef SUNX25
  1166.     else if (nettype == NET_SX25) printf(" X.25\n");
  1167. #endif /* SUNX25 */
  1168. #ifdef DECNET
  1169.     else if (nettype == NET_DEC) printf(" DECnet\n");
  1170. #endif /* DECNET */
  1171.  
  1172.     printf("\nActive SET HOST connection:\n");
  1173.     if (network) {
  1174.     printf(" %s",ttname);
  1175.     if (*ipaddr) printf(" [%s]",ipaddr);
  1176.     printf("\n Via: ");
  1177.     if (nettype == NET_TCPA || nettype == NET_TCPB) printf("TCP/IP\n");
  1178.     else if (nettype == NET_SX25) printf("SunLink X.25\n");
  1179.     else if (nettype == NET_DEC) {
  1180.           if ( ttnproto == NP_LAT ) printf("DECnet LAT\n");
  1181.           else if ( ttnproto == NP_CTERM ) printf("DECnet CTERM\n");
  1182.           else printf("DECnet\n");
  1183.         }
  1184.     else if (nettype == NET_PIPE) printf("LAN Manager Named Pipe\n");
  1185. #ifdef SUNX25
  1186.     if (nettype == NET_SX25) shox25();
  1187. #endif /* SUNX25 */
  1188. #ifdef TNCODE
  1189.     if (ttnproto == NP_TELNET) {
  1190.         printf(" TELNET protocol\n");
  1191.         printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
  1192.     }
  1193. #endif /* TNCODE */
  1194.     } else printf(" None\n");
  1195.     printf("\n");
  1196. #endif /* NETCONN */
  1197. }
  1198.  
  1199. #ifndef NODIAL
  1200.  
  1201. VOID
  1202. shodial() {
  1203.     if (mdmtyp >= 0 || local != 0) doshodial();
  1204. }
  1205.  
  1206. static VOID
  1207. shods(s) char *s; {            /* Show a dial-related string */
  1208.     char c;
  1209.     if (s == NULL || !(*s)) {        /* Empty? */
  1210.     printf("(none)\n");
  1211.     } else {                /* Not empty. */
  1212.     while (c = *s++)             /* Can contain controls */
  1213.       if (c > 31 && c < 127) { putchar(c); } /* so display them */
  1214.       else printf("\\{%d}",c);         /* in backslash notation */
  1215.     printf("\n");
  1216.     }
  1217. }
  1218.  
  1219. int
  1220. doshodial() {
  1221.     printf(" Dial directory: %s\n",dialdir ? dialdir : "(none)");
  1222.     printf(" Dial hangup: %s, dial modem-hangup: %s\n",
  1223.        dialhng ? "on" : "off", dialmhu ? "on" : "off") ;
  1224.     printf(" Dial kermit-spoof: %s",dialksp ? "on" : "off");
  1225.     printf(", dial display: %s\n",dialdpy ? "on" : "off");
  1226.     printf(" Dial speed-matching: %s",mdmspd ? "on" : "off");
  1227.     printf(", dial mnp-enable: %s\n",dialmnp ? "on" : "off");
  1228.     printf(" Dial init-string: ");
  1229.     shods(getdws(mdmtyp));        /* Ask dial module for it */
  1230.     printf(" Dial dial-command: ");
  1231.     shods(getdcs(mdmtyp));        /* Ask dial module for it */
  1232.     printf(" Dial prefix: ");
  1233.     shods(dialnpr);
  1234.     printf(" Dial timeout: ");
  1235.     if (dialtmo > 0)
  1236.       printf("%d sec", dialtmo);
  1237.     else
  1238.       printf("0 (auto)");
  1239.     printf(", Redial number: %s\n",dialnum ? dialnum : "(none)");
  1240.     return(0);
  1241. }
  1242. #endif /* NODIAL */
  1243.  
  1244. #ifdef SUNX25
  1245. VOID
  1246. shopad() {
  1247.     int i;
  1248.     printf("\nX.3 PAD Parameters:\n");
  1249.     for (i = 0; i < npadx3; i++)
  1250.       printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
  1251.          padparms[padx3tab[i].kwval]);
  1252. }
  1253. #endif /* SUNX25 */
  1254.  
  1255. /*  Show File Parameters */
  1256.  
  1257. VOID
  1258. shoparf() {
  1259.     char *s; int i;
  1260.     printf("\nFile parameters:       ");
  1261. #ifdef COMMENT
  1262.     printf("Blocksize:     %5d      ",fblksiz);
  1263. #endif /* COMMENT */
  1264.     printf(" Attributes:       ");
  1265.     if (atcapr) printf("on"); else printf("off");
  1266. #ifdef VMS
  1267.     printf("  Record-Length: %5d",frecl);
  1268. #endif /* VMS */
  1269.     printf("\n Names:   ");
  1270.     printf("%-12s",(fncnv) ? "converted" : "literal");
  1271. #ifdef DEBUG
  1272. #ifndef MAC
  1273.     printf("  Debugging Log:    ");
  1274.     if (deblog) printf("%s",debfil); else printf("none");
  1275. #endif /* MAC */
  1276. #endif /* DEBUG */
  1277.  
  1278.     printf("\n Type:    ");
  1279.     switch (binary) {
  1280.       case XYFT_T: s = "text";    break;
  1281. #ifdef VMS
  1282.       case XYFT_B: s = "binary fixed"; break;
  1283.       case XYFT_I: s = "image";        break;
  1284.       case XYFT_L: s = "labeled";      break;
  1285.       case XYFT_U: s = "binary undef"; break;
  1286. #else
  1287.       case XYFT_B: s = "binary"; break;
  1288. #endif /* VMS */
  1289.       default: s = "?"; break;
  1290.     }
  1291.     printf("%-12s",s);
  1292. #ifdef COMMENT
  1293.     printf(" Organization:  ");
  1294.     switch (forg) {
  1295.       case XYFO_I: printf("%-10s","indexed"); break;
  1296.       case XYFO_R: printf("%-10s","relative"); break;
  1297.       case XYFO_S: printf("%-10s","sequential"); break;
  1298.     }
  1299. #endif /* COMMENT */
  1300. #ifndef MAC
  1301.     printf("  Packet Log:       ");
  1302.     if (pktlog) printf(pktfil); else printf("none");
  1303. #endif /* MAC */
  1304. #ifdef UNIX
  1305.     printf("  Longest filename: %d",maxnam);
  1306. #endif /* UNIX */
  1307.     printf("\n Collide: ");
  1308.     for (i = 0; i < ncolx; i++)
  1309.       if (colxtab[i].kwval == fncact) break;
  1310.     printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  1311.  
  1312. #ifdef COMMENT
  1313.     printf(" Format:        ");
  1314.     switch (frecfm) {
  1315.       case XYFF_F:  printf("%-10s","fixed"); break;
  1316.       case XYFF_VB: printf("%-10s","rcw"); break;
  1317.       case XYFF_S:  printf("%-10s","stream"); break;
  1318.       case XYFF_U:  printf("%-10s","undefined"); break;
  1319.       case XYFF_V:  printf("%-10s","variable"); break;
  1320.     }
  1321. #endif /* COMMENT */
  1322. #ifndef MAC
  1323.     printf("  Session Log:      ");
  1324.     if (seslog) printf(sesfil); else printf("none");
  1325. #endif /* MAC */
  1326. #ifdef UNIX
  1327.     printf("  Longest pathname: %d",maxpath);
  1328. #endif /* UNIX */
  1329.     printf("\n Display: ");
  1330.     switch (fdispla) {
  1331.       case XYFD_N: printf("%-12s","none"); break;
  1332.       case XYFD_R: printf("%-12s","serial"); break;
  1333.       case XYFD_C: printf("%-12s","fullscreen"); break;
  1334.       case XYFD_S: printf("%-12s","crt"); break;
  1335.     }
  1336. #ifdef COMMENT
  1337.     printf("Carriage-Control: ");
  1338.     switch (fcctrl) {
  1339.       case XYFP_F: printf("%-10s","fortran"); break;
  1340.       case XYFP_N: printf("%-10s","newline"); break;
  1341.       case XYFP_P: printf("%-10s","machine"); break;
  1342.       case XYFP_X: printf("%-10s","none"); break;
  1343.     }
  1344. #endif /* COMMENT */
  1345. #ifdef TLOG
  1346. #ifndef MAC
  1347.     printf("  Transaction Log:  ");
  1348.     if (tralog) printf(trafil); else printf("none");
  1349. #endif /* MAC */
  1350. #endif /* TLOG */
  1351. #ifndef NOCSETS
  1352.     if (binary == XYFT_T) {
  1353.     shocharset();
  1354.     } else
  1355. #endif /* NOCSETS */
  1356.       printf("\n");
  1357.     printf("\nFile Byte Size: %d",(fmask == 0177) ? 7 : 8);
  1358.     printf(", Incomplete Files: ");
  1359.     if (keep) printf("keep"); else printf("discard");
  1360. #ifdef KERMRC
  1361.     printf(", Init file: %s",kermrc);
  1362. #endif /* KERMRC */
  1363.     printf("\n");
  1364. }
  1365.  
  1366. VOID
  1367. shoparp() {
  1368.     printf("\nProtocol Parameters:   Send    Receive");
  1369.     if (timef)
  1370.       printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
  1371.     else
  1372.       printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
  1373. #ifndef NOSERVER
  1374.     printf("       Server Timeout:%4d\n",srvtim);
  1375. #endif /* NOSERVER */
  1376.     printf(  " Padding:      %11d%9d", npad,   mypadn);
  1377.     if (bctr == 4)
  1378.       printf("        Block Check: blank-free-2\n");
  1379.     else
  1380.       printf("        Block Check: %6d\n",bctr);
  1381.     printf(  " Pad Character:%11d%9d", padch,  mypadc);
  1382.     printf("        Delay:       %6d\n",delay);
  1383.     printf(  " Packet Start: %11d%9d", mystch, stchr);
  1384.     printf("        Max Retries: %6d\n",maxtry);
  1385.     printf(  " Packet End:   %11d%9d", seol,   eol);
  1386.     if (ebqflg)
  1387.       printf("        8th-Bit Prefix: '%c'",ebq);
  1388. #ifdef COMMENT
  1389. /*
  1390.   This is confusing.
  1391. */
  1392.     printf(  "\n Packet Length:%11d", spsizf ? spsizr : spsiz);
  1393.     printf( spsizf ? "*" : " " ); printf("%8d",  urpsiz);
  1394.     printf( (urpsiz > 94) ? " (94)" : "     ");
  1395. #else
  1396.     printf(  "\n Packet Length:%11d ", spmax);
  1397.     printf("%8d     ",  urpsiz);
  1398. #endif /* COMMENT */
  1399.     if (rptflg)
  1400.       printf("   Repeat Prefix:  '%c'",rptq);
  1401.     printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
  1402.     printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
  1403.     printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
  1404.     printf("        Locking-Shift:    ");
  1405.     if (lscapu == 2) {
  1406.     printf("forced\n");
  1407.     } else {
  1408.     printf("%s", (lscapr ? "enabled" : "disabled"));
  1409.     if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  1410.     printf("\n");
  1411.     }
  1412. }
  1413.  
  1414. #ifndef NOCSETS
  1415. VOID
  1416. shoparl() {
  1417. #ifdef COMMENT
  1418.     int i;
  1419. /* Misleading... */
  1420.     printf("\nAvailable Languages:\n");
  1421.     for (i = 0; i < MAXLANG; i++) {
  1422.     printf(" %s\n",langs[i].description);
  1423.     }
  1424. #else
  1425.     printf("\nLanguage-specific translation rules: %s\n",
  1426.        language == L_USASCII ? "none" : langs[language].description);
  1427.     shocharset();
  1428.     printf("\n\n");
  1429. #endif /* COMMENT */
  1430. }
  1431.  
  1432. VOID
  1433. shocharset() {
  1434.     int x;
  1435.     printf("\n File Character-Set: %s (",fcsinfo[fcharset].name);
  1436.     if ((x = fcsinfo[fcharset].size) == 128) printf("7-bit)");
  1437.     else if (x == 256) printf("8-bit)");
  1438.     else printf("(multibyte)");
  1439.     printf("\n Transfer Character-Set");
  1440. #ifdef COMMENT
  1441.     if (tslevel == TS_L2)
  1442.       printf(": (international)");
  1443.     else
  1444. #endif /* COMMENT */
  1445.     if (tcharset == TC_TRANSP)
  1446.       printf(": Transparent");
  1447.     else
  1448.       printf(": %s",tcsinfo[tcharset].name);
  1449. }
  1450. #endif /* NOCSETS */
  1451.  
  1452. VOID
  1453. shopar() {
  1454. #ifndef MAC
  1455.     printf("\n%s,%s\n",versio,ckxsys);
  1456. #endif /* MAC */
  1457.     shoparc();
  1458.     shoparp();
  1459.     shoparf();
  1460. }
  1461. #endif /* NOSHOW */
  1462.  
  1463. /*  D O S T A T  --  Display file transfer statistics.  */
  1464.  
  1465. int
  1466. dostat() {
  1467.     printf("\nMost recent transaction --\n");
  1468.     printf("\n files: %ld\n",filcnt);
  1469.     printf(" characters last file   : %ld\n",ffc);
  1470.     printf(" total file characters  : %ld\n",tfc);
  1471.     printf(" communication line in  : %ld\n",tlci);
  1472.     printf(" communication line out : %ld\n",tlco);
  1473.     printf(" packets sent           : %d\n", spackets);
  1474.     printf(" packets received       : %d\n", rpackets);
  1475.     printf(" damaged packets rec'd  : %d\n", crunched);
  1476.     printf(" timeouts               : %d\n", timeouts);
  1477.     printf(" retransmissions        : %d\n", retrans);
  1478.     if (filcnt > 0) {
  1479.     printf(" parity                 : %s",parnam((char)parity));
  1480.     if (autopar) printf(" (detected automatically)");
  1481.     printf("\n 8th bit prefixing      : ");
  1482.     if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
  1483.     printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
  1484.     printf(" window slots used      : %d of %d\n", wmax, wslotr);
  1485.     printf(" packet length          : %d (send), %d (receive)\n",
  1486.            spmax, urpsiz);
  1487.     printf(" compression            : ");
  1488.     if (rptflg)
  1489.       printf("yes [%c] (%ld)\n",(char) rptq,rptn);
  1490.     else
  1491.       printf("no\n");
  1492.     if (bctu == 4)
  1493.       printf(" block check type used  : blank-free-2\n");
  1494.     else
  1495.       printf(" block check type used  : %d\n",bctu);
  1496.     printf(" elapsed time           : %d sec\n",tsecs);
  1497.     if (speed <= 0L) speed = ttgspd();
  1498.     if (speed > 0L) {
  1499.         if (speed == 8880)
  1500.           printf(" transmission rate      : 75/1200 bps\n");
  1501.         else
  1502.           printf(" transmission rate      : %ld bps\n",speed);
  1503.     }
  1504.     if (tsecs > 0) {
  1505.         long lx;
  1506.         lx = (tfc * 10L) / (long) tsecs;
  1507.         printf(" effective data rate    : %ld cps\n",lx/10L);
  1508.         if (speed > 0L && speed != 8880L && network == 0) {
  1509.         lx = (lx * 100L) / speed;
  1510.         printf(" efficiency (percent)   : %ld\n",lx);
  1511.         }
  1512. #ifdef COMMENT
  1513.         lx = (tlci * 10L) / (long) tsecs;
  1514.         printf(" throughput (in)        : %ld cps\n",lx/10l);
  1515.         lx = (tlco * 10L) / (long) tsecs;
  1516.         printf(" throughput (out)       : %ld cps\n",lx/10l);
  1517. #endif /* COMMENT */
  1518.     }
  1519.     }
  1520.     return(1);
  1521. }
  1522.  
  1523. /*  D O C O N E C T  --  Do the connect command  */
  1524.  
  1525. /*  Note, we don't call this directly from dial, because we need to give */
  1526. /*  the user a chance to change parameters (e.g. parity) after the */
  1527. /*  connection is made. */
  1528.  
  1529. int
  1530. doconect() {
  1531.     int x;
  1532.     conres();                /* Put console back to normal */
  1533.     x = conect();            /* Connect */
  1534.     concb((char)escape);        /* Put console into cbreak mode, */
  1535.     return(x);                /* for more command parsing. */
  1536. }
  1537.  
  1538. #ifndef NOSPL
  1539. /* The INPUT command */
  1540.  
  1541. #ifdef NETCONN
  1542. extern int tn_init;
  1543. #ifndef IAC
  1544. #define IAC 255
  1545. #endif /* IAC */
  1546. #endif /* NETCONN */
  1547.  
  1548. int
  1549. doinput(timo,s) int timo; char *s; {
  1550.     int x, y, i, t, icn, anychar;
  1551.     int lastchar = 0;
  1552.     char *xp, *xq = (char *)0;
  1553.     CHAR c;
  1554.  
  1555.     if (local) {            /* Put line in "ttvt" mode */
  1556.     y = ttvt(speed,flow);        /* if not already. */
  1557.     if (y < 0) {
  1558.         printf("?Can't condition line for INPUT\n");
  1559.         return(0);            /* Watch out for failure. */
  1560.     }
  1561.     }
  1562.     if (!s) s = "";
  1563.     y = (int)strlen(s);            /* If search string is empty */
  1564.     anychar = (y < 1);            /* any input character will do. */
  1565.     debug(F111,"doinput",s,y);
  1566.     if (timo <= 0) timo = 1;        /* Give at least 1 second timeout */
  1567.  
  1568.     x = 0;                /* Return code, assume failure */
  1569.     i = 0;                /* String pattern match position */
  1570.  
  1571.     if (!incase[cmdlvl]) {        /* INPUT CASE = IGNORE?  */
  1572.     xp = malloc(y+2);        /* Make a separate copy of the */
  1573.     if (!xp) {            /* input string for editing. */
  1574.         printf("?malloc error 5\n");
  1575.         return(x);
  1576.     } else xq = xp;            /* Save pointer to beginning */
  1577.  
  1578.     while (*s) {            /* Convert to lowercase */
  1579.         *xp = *s;
  1580.         if (isupper(*xp)) *xp = tolower(*xp);
  1581.         xp++; s++;
  1582.     }
  1583.     *xp = NUL;            /* Terminate the search string. */
  1584.     s = xq;                /* Point back to beginning. */
  1585.     }
  1586.     inpbps = inpbp;            /* Save current pointer. */
  1587.     rtimer();                /* Reset timer. */
  1588.     t = 0;                /* Time is 0. */
  1589.     incount = 0;            /* Character counter */
  1590.     while (1) {                /* Character-getting loop */
  1591.     if (local) {            /* One case for local */
  1592.         y = ttinc(1);        /* Get character from comm line. */
  1593.         debug(F101,"input ttinc(1) returns","",y);
  1594.         if (icn = conchk()) {    /* Interrupted from keyboard? */
  1595.         debug(F101,"input interrupted from keyboard","",icn);
  1596.         while (icn--) coninc(0); /* Yes, read what was typed. */
  1597.         break;            /* And fail. */
  1598.         }
  1599.     } else {            /* Another for remote */
  1600.         y = coninc(1);
  1601.         debug(F101,"input coninc(1) returns","",y);
  1602.     }
  1603.     if (y > -1) {            /* A character arrived */
  1604. #ifdef TNCODE
  1605. /* Check for telnet protocol negotiation */
  1606.         if (network && (ttnproto == NP_TELNET) && ((y & 0xff) == IAC)) {
  1607.         switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
  1608.           case 2: duplex = 0; continue;
  1609.           case 1: duplex = 1;
  1610.           default: continue;
  1611.         }
  1612.         }
  1613. #endif /* TNCODE */
  1614.  
  1615.         /* Real input character to be checked */
  1616.  
  1617.         c = cmask & (CHAR) y;    /* Mask off parity */
  1618.  
  1619.         inchar[0] = c;        /* Remember character for \v(inchar) */
  1620.         lastchar = gtimer();    /* Remember when it came. */
  1621.  
  1622.         if (c == '\0') {        /* NUL, we can't use it */
  1623.         if (anychar) {        /* Any character will do? */
  1624.             x = 1;        /* Yes, done. */
  1625.             incount = 1;    /* This must be the first and only. */
  1626.             break;
  1627.         } else continue;    /* Otherwise continue INPUTting */
  1628.         }
  1629.  
  1630.         *inpbp++ = c;        /* Store char in circular buffer */
  1631.         incount++;            /* Count it for \v(incount) */
  1632.  
  1633.         if (inpbp >= inpbuf + INPBUFSIZ) { /* Time to wrap around? */
  1634.         inpbp = inpbuf;        /* Yes. */
  1635.         *(inpbp+INPBUFSIZ) = NUL; /* Make sure it's null-terminated. */
  1636.         }
  1637. #ifdef MAC
  1638.         {
  1639.         extern char *ttermw;    /* fake pointer cast */
  1640.         if (inecho) {
  1641.             outchar(ttermw, c);    /* echo to terminal window */
  1642.             /* this might be too much overhead to do here ? */
  1643.             updatecommand(ttermw);
  1644.         }
  1645.         }
  1646. #else /* Not MAC */
  1647.         if (inecho) conoc(c);    /* Echo and log the input character */
  1648. #endif /* MAC */
  1649.         if (seslog) {
  1650. #ifdef UNIX
  1651.         if (sessft != 0 || c != '\r')
  1652. #endif /* UNIX */
  1653.           if (zchout(ZSFILE,c) < 0) seslog = 0;
  1654.         }
  1655.         if (anychar) {        /* Any character will do? */
  1656.         x = 1;
  1657.         break;
  1658.         }
  1659.         if (!incase[cmdlvl]) {    /* Ignore alphabetic case? */
  1660.         if (isupper(c)) c = tolower(c); /* Yes */
  1661.         }
  1662.         debug(F000,"doinput char","",c);
  1663.         debug(F000,"compare char","",s[i]);
  1664.         if (c == s[i]) {        /* Check for match */
  1665.         i++;            /* Got one, go to next character */
  1666.         } else {            /* Don't have a match */
  1667.            int j, size;
  1668.            for (j = i; i-- > 0; ) { /* [jrs] search backwards */
  1669.                if (c == s[i]) {
  1670.                size = j - i;
  1671.                if (strncmp(s,&s[j-i],i-size)== 0)
  1672.               break;
  1673.                }
  1674.            }
  1675.            i++;            /* [jrs] count last char matched    */
  1676.            }                /* [jrs] or return to zero from -1  */
  1677.         if (s[i] == '\0') {        /* Matched all the way to end? */
  1678.         x = 1;            /* Yes, */
  1679.         break;            /* done. */
  1680.         }
  1681.     }
  1682.     if ((t = gtimer()) > timo)    /* Did not match, timer exceeded? */
  1683.       break;
  1684.     else if (insilence > 0 && (t - lastchar) > insilence)
  1685.       break;
  1686.     }                    /* Still have time left, continue. */
  1687.     if (!incase[cmdlvl]) if (xq) free(xq); /* Done, free dynamic memory. */
  1688.     return(x);                /* Return the return code. */
  1689. }
  1690. #endif /* NOSPL */
  1691.  
  1692. #ifndef NOSPL
  1693. /* REINPUT Command */
  1694.  
  1695. /* Note, the timeout parameter is required, but ignored. */
  1696. /* Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. */
  1697. /* This function only looks at the characters already received */
  1698. /* and does not read any new characters from the communication line. */
  1699.  
  1700. int
  1701. doreinp(timo,s) int timo; char *s; {
  1702.     int x, y, i;
  1703.     char *xx, *xp, *xq = (char *)0;
  1704.     CHAR c;
  1705.  
  1706.     y = (int)strlen(s);
  1707.     debug(F111,"doreinput",s,y);
  1708.  
  1709.     x = 0;                /* Return code, assume failure */
  1710.     i = 0;                /* String pattern match position */
  1711.  
  1712.     if (!incase[cmdlvl]) {        /* INPUT CASE = IGNORE?  */
  1713.     xp = malloc(y+2);        /* Make a separate copy of the */
  1714.     if (!xp) {            /* search string. */
  1715.         printf("?malloc error 6\n");
  1716.         return(x);
  1717.     } else xq = xp;            /* Keep pointer to beginning. */
  1718.     while (*s) {            /* Yes, convert to lowercase */
  1719.         *xp = *s;
  1720.         if (isupper(*xp)) *xp = tolower(*xp);
  1721.         xp++; s++;
  1722.     }
  1723.     *xp = NUL;            /* Terminate it! */
  1724.     s = xq;                /* Move search pointer to it. */
  1725.     }
  1726.     xx = inpbp;                /* Current INPUT buffer pointer */
  1727.     do {
  1728.     c = *xx++;            /* Get next character */
  1729.     if (xx >= inpbuf + INPBUFSIZ) xx = inpbuf; /* Wrap around */
  1730.     if (!incase[cmdlvl]) {        /* Ignore alphabetic case? */
  1731.         if (isupper(c)) c = tolower(c); /* Yes */
  1732.     }
  1733.     debug(F000,"doreinp char","",c);
  1734.     debug(F000,"compare char","",s[i]);
  1735.     if (c == s[i]) {        /* Check for match */
  1736.         i++;            /* Got one, go to next character */
  1737.     } else {            /* Don't have a match */
  1738.            int j, size;
  1739.            for (j = i; i-- > 0; ) { /* [jrs] search backwards for it  */
  1740.            if (c == s[i]) {
  1741.             size = j - i;
  1742.             if (strncmp(s,&s[j-i],i-size)== 0)
  1743.               break;
  1744.         }
  1745.            }
  1746.            i++;            /* [jrs] count last char matched */
  1747.        }                /* [jrs] or return to zero from -1 */
  1748.     if (s[i] == '\0') {        /* Matched all the way to end? */
  1749.         x = 1;            /* Yes, */
  1750.         break;            /* done. */
  1751.     }
  1752.     } while (xx != inpbp);        /* Until back where we started. */
  1753.  
  1754.     if (!incase[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
  1755.     return(x);                /* Return search result. */
  1756. }
  1757. #ifndef NOSPL
  1758.  
  1759. #endif /* NOSPL */
  1760. /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
  1761.  
  1762. /*
  1763.  Copies result to new string.
  1764.   strips enclosing braces or doublequotes.
  1765.   interprets backslash escapes.
  1766.   returns 0 on success, nonzero on failure.
  1767.   tries to be compatible with MS-DOS Kermit.
  1768.  
  1769.  Syntax of input string:
  1770.   string = chars | "chars" | {chars}
  1771.   chars = (c*e*)*
  1772.   where c = any printable character, ascii 32-126
  1773.   and e = a backslash escape
  1774.   and * means 0 or more repetitions of preceding quantity
  1775.   backslash escape = \operand
  1776.   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
  1777.   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
  1778.   radix code is oO (octal), hHxX (hex), dD or none (decimal).
  1779. */
  1780.  
  1781. #ifndef NOFRILLS
  1782. int
  1783. yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
  1784.     int x;
  1785.     static char *new;
  1786.     new = *s2;
  1787.     if (!s || !new) return(-1);        /* Watch out for null pointers. */
  1788.     if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
  1789.     *new = '\0';
  1790.     return(0);
  1791.     }
  1792.     x--;                /* Otherwise, call self */
  1793.     *new++ = s[x];            /* to reverse rest of string. */
  1794.     s[x] = 0;
  1795.     return(yystring(s,&new));
  1796. }
  1797. #endif /* NOFRILLS */
  1798.  
  1799. #define FNVALL 1000
  1800. char fnval[FNVALL+2];            /* Return value */
  1801.  
  1802. char *                    /* Evaluate builtin function */
  1803. fneval(fn,argp,argn) char *fn, *argp[]; int argn; {
  1804.     int i, j, k, len1, len2, n, x, y;
  1805.     char *bp[FNARGS];            /* Pointers to malloc'd strings */
  1806.     char *p, *s;
  1807.  
  1808.     if (!fn) fn = "";            /* Paranoia */
  1809.     debug(F111,"fneval",fn,argn);
  1810.     debug(F110,"fneval",argp[0],0);
  1811.     y = lookup(fnctab,fn,nfuncs,&x);
  1812.     if (y < 0)                /* bad function name */
  1813.       return("");            /* so value is null */
  1814.  
  1815. #ifdef DEBUG
  1816.     if (deblog) {
  1817.     int j;
  1818.     for (j = 0; j < argn; j++)
  1819.       debug(F111,"fneval function arg",argp[j],j);
  1820.     }
  1821. #endif /* DEBUG */
  1822.  
  1823.     if (y == FN_LIT)            /* literal(arg1) */
  1824.       return(argp[0] ? argp[0] : "");    /* return a pointer to arg itself */
  1825.  
  1826.     if (y == FN_CON) {            /* Contents of variable, unexpanded. */
  1827.     char c;
  1828.     if (!(p = argp[0]) || !*p) return("");
  1829.     if (*p == CMDQ) p++;
  1830.     if ((c = *p) == '%') {        /* Scalar variable. */
  1831.         c = *++p;            /* Get ID character. */
  1832.         p = "";            /* Assume definition is empty */
  1833.         if (!c) return(p);        /* Double paranoia */
  1834.         if (c >= '0' && c <= '9') { /* Digit for macro arg */
  1835.         c -= '0';        /* convert character to integer */
  1836.         if (maclvl < 0)        /* Digit variables are global */
  1837.           p = g_var[c];        /* if no macro is active */
  1838.         else            /* otherwise */
  1839.           p = m_arg[maclvl][c]; /* they're on the stack */
  1840.         } else {
  1841.         if (isupper(c)) c -= ('a'-'A');
  1842.         p = g_var[c];        /* Letter for global variable */
  1843.         }
  1844.         return(p ? p : "");
  1845.     }
  1846.     if (c == '&') {            /* Array reference. */
  1847.         int vbi, d;
  1848.         if (arraynam(p,&vbi,&d) < 0) /* Get name and subscript */
  1849.           return("");
  1850.         if (chkarray(vbi,d) > 0) {    /* Array is declared? */
  1851.         vbi -= 'a';        /* Convert name to index */
  1852.         if (a_dim[vbi] >= d) {    /* If subscript in range */
  1853.             char **ap;
  1854.             ap = a_ptr[vbi];    /* get data pointer */
  1855.             if (ap) {        /* and if there is one */
  1856.             return(ap[d]);    /* return what it points to */
  1857.             }
  1858.         }
  1859.         }
  1860.         return(p ? p : "");        /* Otherwise its enexpanded value. */
  1861.     }
  1862.     }
  1863.  
  1864.     for (i = 0; i < argn; i++) {    /* Not literal, expand the args */
  1865.     n = 1024;            /* allow 1K per expanded arg, yow! */
  1866.     bp[i] = s = malloc(n);        /* get the new space */
  1867.     if (bp[i] == NULL) {        /* handle failure to get space */
  1868.         for (k = 0; k < i; k++) if (bp[k]) free(bp[k]);
  1869.         debug(F101,"fneval malloc failure, arg","",i);
  1870.         return("");
  1871.     }
  1872.     p = argp[i] ? argp[i] : "";    /* Point to this argument */
  1873.  
  1874. /*
  1875.   Trim leading and trailing spaces from the original argument, before
  1876.   evaluation.  This code new to edit 184.
  1877. */
  1878.     if (y != FN_REP || i != 0) {    /* Don't trim 1st REPEAT argument */
  1879.         int j;            /* All others... */
  1880.         while (*p == SP || *p == HT) /* Point past leading whitespace */
  1881.           p++;
  1882.         j = (int) strlen(p) - 1;    /* Trim trailing whitespace */
  1883.         while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
  1884.           *(p + j--) = NUL;
  1885.     }
  1886.  
  1887. /* Now evaluate the argument */
  1888.  
  1889.     if (xxstring(p,&s,&n) < 0) {    /* Expand arg into new space */
  1890.         debug(F101,"fneval xxstring fails, arg","",i);
  1891.         for (k = 0; k <= i; k++)    /* Free up previous space on error */
  1892.           if (bp[k]) free(bp[k]);
  1893.         return("");            /* and return null string. */
  1894.     }
  1895.     debug(F111,"fneval arg",bp[i],i);
  1896.     }
  1897.  
  1898. #ifdef DEBUG
  1899.     if (deblog) {
  1900.     int j;
  1901.     for (j = 0; j < argn; j++) {
  1902.         debug(F111,"fneval arg post eval",argp[j],j);
  1903.         debug(F111,"fneval evaluated arg",bp[j],j);
  1904.     }
  1905.     }
  1906. #endif /* DEBUG */
  1907.  
  1908.     switch (y) {            /* Do function on expanded args */
  1909.  
  1910.       case FN_DEF:
  1911.     k = mlook(mactab,bp[0],nmac);    /* def(arg1) - Return a macro def */
  1912.     p = (k > -1) ? mactab[k].mval : "";
  1913.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  1914.     return(p ? p : "");
  1915.  
  1916.       case FN_EVA:            /* eval(arg1) */
  1917.     p = evala(bp[0]);
  1918.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  1919.     return(p ? p : "");
  1920.  
  1921.       case FN_EXE:            /* execute(arg1) */
  1922.     j = (int)strlen(s = bp[0]);    /* Length of macro invocation */
  1923.     p = "";                /* Initialize return value to null */
  1924.     if (j) {            /* If there is a macro to execute */
  1925.         while (*s == SP) s++,j--;    /* strip leading spaces */
  1926.         p = s;            /* remember beginning of macro name */
  1927.         for (i = 0; i < j; i++) {    /* find end of macro name */
  1928.         if (*s == SP) break;
  1929.         s++;
  1930.         }
  1931.         if (*s == SP) {        /* if there was a space after */
  1932.         *s++ = NUL;        /* terminate the macro name */
  1933.         while (*s == SP) s++;    /* skip past any extra spaces */
  1934.         } else s = "";        /* maybe there are no arguments */
  1935.         if (p && *p)
  1936.           k = mlook(mactab,p,nmac);    /* Look up the macro name */
  1937.         else k = -1;
  1938.  
  1939.         p = "";            /* Initialize return value */
  1940.         if (k >= 0) {        /* If macro found in table */
  1941.         if ((j = dodo(k,s)) > 0) { /* Go set it up (like DO cmd) */
  1942.             if (cmpush() > -1) { /* Push command parser state */
  1943.             extern int ifc;
  1944.             int ifcsav = ifc; /* Push IF condition on stack */
  1945.             k = parser(1);    /* Call parser to execute the macro */
  1946.             cmpop();    /* Pop command parser */
  1947.             ifc = ifcsav;    /* Restore IF condition */
  1948.             if (k == 0) {    /* No errors, ignore action cmds. */
  1949.                 p = mrval[maclvl+1]; /* If OK, set return value. */
  1950.                 if (p == NULL) p = "";
  1951.             }
  1952.             } else {        /* Can't push any more */
  1953.             debug(F100,"fexec pushed too deep","",0);
  1954.                         printf("\n?\\fexec() too deeply nested\n");
  1955.             while (cmpop() > -1) ;
  1956.             p = "";
  1957.             }
  1958.         }
  1959.         }
  1960.     }
  1961.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  1962.     return(p ? p : "");
  1963.  
  1964.       case FN_FC:            /* File count. */
  1965.     p = fnval;
  1966.     *p = NUL;
  1967.     if (argn > 0) {
  1968.         k = zxpand(bp[0]);
  1969.         sprintf(fnval,"%d",k);
  1970.         for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  1971.     }
  1972.     return(p);
  1973.  
  1974.       case FN_FIL:            /* Next file in list. */
  1975.     p = fnval;            /* (no args) */
  1976.     *p = NUL;
  1977.     znext(p);
  1978.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  1979.     return(p ? p : "");
  1980.  
  1981.       case FN_IND:            /* index(arg1,arg2) */
  1982.     if (argn > 1) {            /* Only works if we have 2 args */
  1983.         int start;
  1984.         len1 = (int)strlen(bp[0]);    /* length of string to look for */
  1985.         len2 = (int)strlen(s = bp[1]); /* length of string to look in */
  1986.         if (len1 < 0) return("");    /* paranoia */
  1987.         if (len2 < 0) return("");
  1988.         j = len2 - len1;        /* length difference */
  1989.         start = 0;            /* starting position */
  1990.         if (argn > 2) {
  1991.         if (chknum(bp[2])) {
  1992.             start = atoi(bp[2]) - 1;
  1993.             if (start < 0) start = 0;
  1994.         }
  1995.         }
  1996.         if (j < 0 || start > j) {    /* search string is longer */
  1997.         p = "0";
  1998.         } else {
  1999.         if (!incase[cmdlvl]) {    /* input case ignore? */
  2000.             lower(bp[0]);
  2001.             lower(bp[1]);
  2002.         }
  2003.         s = bp[1] + start;    /* Point to beginning of target */
  2004.         p = "0";
  2005.         for (i = 0; i <= (j - start); i++) { /* Now compare */
  2006.             if (!strncmp(bp[0],s++,len1)) {
  2007.             sprintf(fnval,"%d",i+1+start);
  2008.             p = fnval;
  2009.             break;
  2010.             }
  2011.         }
  2012.         }
  2013.     } else p = "0";
  2014.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2015.     return(p);
  2016.  
  2017.       case FN_CHR:            /* character(arg1) */
  2018.     if (chknum(bp[0])) {        /* Must be numeric */
  2019.         i = atoi(bp[0]);
  2020.         if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
  2021.         p = fnval;
  2022.         *p++ = i;
  2023.         *p = NUL;
  2024.         p = fnval;
  2025.         } else p = "";        /* Otherwise return null */
  2026.     } else p = "";            /* Otherwise return null */
  2027.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2028.     return(p);
  2029.  
  2030.       case FN_COD:            /* code(char) */
  2031.     p = "";
  2032.     if ((int)strlen(bp[0]) > 0) {
  2033.         p = fnval;
  2034.         i = *bp[0];
  2035.         sprintf(p,"%d",(i & 0xff));
  2036.     }
  2037.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2038.     return(p);
  2039.  
  2040.       case FN_LEN:            /* length(arg1) */
  2041.     p = fnval;
  2042.     sprintf(p,"%d",(int)strlen(bp[0]));
  2043.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2044.     return(p);
  2045.  
  2046.       case FN_LOW:            /* lower(arg1) */
  2047.     s = bp[0];
  2048.     p = fnval;
  2049.  
  2050.     while (*s) {
  2051.         if (isupper(*s))
  2052.           *p = tolower(*s);
  2053.         else
  2054.           *p = *s;
  2055.         p++; s++;
  2056.     }
  2057.     *p = NUL;
  2058.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2059.     p = fnval;
  2060.     return(p);
  2061.  
  2062.       case FN_MAX:            /* max(arg1,arg2) */
  2063.       case FN_MIN:            /* min(arg1,arg2) */
  2064.       case FN_MOD:            /* mod(arg1,arg2) */
  2065.     if (chknum(bp[0]) && chknum(bp[1])) {
  2066.         i = atoi(bp[0]);
  2067.         j = atoi(bp[1]);
  2068.         switch (y) {
  2069.           case FN_MAX:
  2070.         if (j < i) j = i;
  2071.         break;
  2072.           case FN_MIN:
  2073.         if (j > i) j = i;
  2074.         break;
  2075.           case FN_MOD:
  2076.         j = i % j;
  2077.         break;
  2078.         }
  2079.         p = fnval;
  2080.         sprintf(p,"%d",j);
  2081.     } else p = "";
  2082.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2083.     return(p);
  2084.  
  2085.       case FN_SUB:            /* substr(arg1,arg2,arg3) */
  2086.       case FN_RIG:            /* right(arg1,arg2) */
  2087.     if (((argn > 1) && (int)strlen(bp[1]) && !rdigits(bp[1])) ||
  2088.         ((y == FN_SUB) &&
  2089.         ((argn > 2) && (int)strlen(bp[2]) && !rdigits(bp[2])))) {
  2090.         p = "";            /* if either, return null */
  2091.     } else {
  2092.         int lx;
  2093.         p = fnval;                     /* pointer to result */
  2094.         lx = strlen(bp[0]);             /* length of arg1 */
  2095.         if (y == FN_SUB) {             /* substring */
  2096.         k = (argn > 2) ? atoi(bp[2]) : 1023; /* length */
  2097.         j = (argn > 1) ? atoi(bp[1]) : 1; /* start pos for substr */
  2098.         } else {                 /* right */
  2099.         k = (argn > 1) ? atoi(bp[1]) : lx; /* length */
  2100.         j = lx - k + 1;             /* start pos for right */
  2101.         if (j < 1) j = 1;
  2102.         }
  2103.         if (k > 0 && j <= lx) {          /* if start pos in range */
  2104.         s = bp[0]+j-1;             /* point to source string */
  2105.         for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
  2106.         }
  2107.         *p = NUL;            /* terminate the result */
  2108.         p = fnval;            /* and point to it. */
  2109.     }
  2110.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); /* Free temp mem */
  2111.     return(p);
  2112.  
  2113.       case FN_UPP:            /* upper(arg1) */
  2114.     s = bp[0];
  2115.     p = fnval;
  2116.     while (*s) {
  2117.         if (islower(*s))
  2118.           *p = toupper(*s);
  2119.         else
  2120.           *p = *s;
  2121.         p++; s++;
  2122.     }
  2123.     *p = NUL;
  2124.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2125.     p = fnval;
  2126.     return(p);
  2127.  
  2128.       case FN_REP:            /* Repeat */
  2129.     p = "";                /* Return value */
  2130.     if (chknum(bp[1])) {        /* Repeat count */
  2131.         n = atoi(bp[1]);
  2132.         if (n > 0) {        /* Make n copies */
  2133.         p = fnval;
  2134.         *p = '\0';
  2135.         k = (int)strlen(bp[0]);    /* Make sure string has some length */
  2136.         if (k > 0) {
  2137.             for (i = 0; i < n; i++) {
  2138.             s = bp[0];
  2139.             for (j = 0; j < k; j++) {
  2140.                 if ((p - fnval) >= FNVALL) { /* Protect against */
  2141.                 p = "";                 /* core dumps... */
  2142.                 break;
  2143.                 } else *p++ = *s++;
  2144.             }
  2145.             }
  2146.             *p = NUL;
  2147.         }
  2148.         }
  2149.     }
  2150.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2151.     p = fnval;
  2152.     return(p);
  2153.  
  2154. #ifndef NOFRILLS
  2155.       case FN_REV:
  2156.     p = fnval;
  2157.     yystring(bp[0],&p);
  2158.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2159.     return(p);
  2160. #endif /* NOFRILLS */
  2161.  
  2162.       case FN_RPA:            /* RPAD and LPAD */
  2163.       case FN_LPA:
  2164.     *fnval = NUL;            /* Return value */
  2165.     if (argn == 1) {        /* If a number wasn't given */
  2166.         p = fnval;            /* just return the original string */
  2167.         strncpy(p,bp[0],FNVALL);
  2168.     } else if (chknum(bp[1])) {    /* Repeat count */
  2169.         char pc;
  2170.         n = atoi(bp[1]);
  2171.         if (n >= 0) {        /* Pad it out */
  2172.         p = fnval;
  2173.         k = (int)strlen(bp[0]);    /* Length of string to be padded */
  2174.         pc = (argn < 3) ? SP : *bp[2]; /* Padding character */
  2175.         if (n > FNVALL) n = FNVALL-1; /* protect against overruns */
  2176.         if (k > FNVALL) k = FNVALL-1; /* and silly args. */
  2177.                 if (k > n) k = n;
  2178.         if (y == FN_RPA) {    /* RPAD */
  2179.             strncpy(p,bp[0],k);
  2180.             p += k;
  2181.             for (i = k; i < n; i++)
  2182.               *p++ = pc;
  2183.         } else {        /* LPAD */
  2184.             n -= k;
  2185.             for (i = 0; i < n; i++)
  2186.               *p++ = pc;
  2187.             strncpy(p,bp[0],k);
  2188.             p += k;
  2189.         }
  2190.         *p = NUL;
  2191.         }
  2192.     }
  2193.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2194.     p = fnval;
  2195.     return(p);
  2196.  
  2197.       default:
  2198.     return("");
  2199.     }
  2200. }
  2201. #endif /* NOSPL */
  2202.  
  2203. #ifndef NOSPL
  2204.  
  2205. char *                    /* Evaluate builtin variable */
  2206. nvlook(s) char *s; {
  2207.     int x, y;
  2208.     long z;
  2209.     char *p;
  2210.  
  2211.     x = 30;
  2212.     p = vvbuf;
  2213.     if (xxstring(s,&p,&x) < 0) {
  2214.     y = -1;
  2215.     } else {
  2216.     s = vvbuf;
  2217.     if ((y = lookup(vartab,s,nvars,&x)) < 0) return(NULL);
  2218.     }
  2219.     switch (y) {
  2220.       case VN_ARGC:            /* ARGC */
  2221.     sprintf(vvbuf,"%d",macargc[maclvl]);
  2222.     return(vvbuf);
  2223.  
  2224.       case VN_ARGS:            /* ARGS */
  2225.     sprintf(vvbuf,"%d",xargs);
  2226.     return(vvbuf);
  2227.  
  2228.       case VN_COUN:            /* COUNT */
  2229.     sprintf(vvbuf,"%d",count[cmdlvl]);
  2230.     return(vvbuf);
  2231.  
  2232.       case VN_DATE:            /* DATE */
  2233.     ztime(&p);            /* Get "asctime" string */
  2234.     if (p == NULL || *p == NUL) return(NULL);
  2235.     vvbuf[0] = p[8];        /* dd */
  2236.     vvbuf[1] = p[9];
  2237.     vvbuf[2] = SP;
  2238.     vvbuf[3] = p[4];        /* mmm */
  2239.     vvbuf[4] = p[5];
  2240.     vvbuf[5] = p[6];
  2241.     vvbuf[6] = SP;
  2242.     for (x = 20; x < 24; x++)    /* yyyy */
  2243.       vvbuf[x - 13] = p[x];
  2244.     vvbuf[11] = NUL;
  2245.     return(vvbuf);
  2246.  
  2247.       case VN_NDAT:            /* Numeric date */
  2248.     ztime(&p);            /* Get "asctime" string */
  2249.     if (p == NULL || *p == NUL) return(NULL);
  2250.     for (x = 20; x < 24; x++)    /* yyyy */
  2251.       vvbuf[x - 20] = p[x];
  2252.         vvbuf[6] = (p[8] == ' ') ? '0' : p[8]; vvbuf[7] = p[9]; /* dd */
  2253.     for (x = 0; x < 12; x++)      /* mm */
  2254.       if (!strncmp(p+4,months[x],3)) break;
  2255.     if (x == 12) {
  2256.         vvbuf[4] = vvbuf[5] = '?';
  2257.     } else {
  2258.         x++;
  2259.         vvbuf[4] = (x < 10) ? '0' : '1';
  2260.         vvbuf[5] = (x % 10) + 48;
  2261.     }
  2262.     vvbuf[8] = NUL;
  2263.         return(vvbuf);
  2264.  
  2265.       case VN_DIRE:            /* DIRECTORY */
  2266.     return(zgtdir());
  2267.  
  2268.       case VN_FILE:            /* filespec */
  2269.     return(fspec);
  2270.  
  2271.       case VN_HOST:            /* host name */
  2272.     if (*myhost) {            /* If known */
  2273.         return(myhost);        /* return it. */
  2274.     } else {            /* Otherwise */
  2275.         strcpy(vvbuf,"unknown");    /* just say "unknown" */
  2276.         return(vvbuf);
  2277.     }
  2278.  
  2279.       case VN_SYST:            /* System type */
  2280. #ifdef UNIX
  2281.     strcpy(vvbuf,"UNIX");
  2282. #else
  2283. #ifdef VMS
  2284.     strcpy(vvbuf,"VMS");
  2285. #else
  2286. #ifdef OSK
  2287.     strcpy(vvbuf,"OS9/68K");
  2288. #else
  2289. #ifdef AMIGA
  2290.     strcpy(vvbuf,"Amiga");
  2291. #else
  2292. #ifdef MAC
  2293.     strcpy(vvbuf,"Macintosh");
  2294. #else
  2295. #ifdef OS2
  2296.     strcpy(vvbuf,"OS/2");
  2297. #else
  2298. #ifdef datageneral
  2299.     strcpy(vvbuf,"AOS/VS");
  2300. #else
  2301. #ifdef GEMDOS
  2302.     strcpy(vvbuf,"Atari_ST");
  2303. #else
  2304.     strcpy(vvbuf,"unknown");
  2305. #endif /* GEMDOS */
  2306. #endif /* datageneral */
  2307. #endif /* OS2 */
  2308. #endif /* MAC */
  2309. #endif /* AMIGA */
  2310. #endif /* OSK */
  2311. #endif /* VMS */
  2312. #endif /* UNIX */
  2313.     return(vvbuf);
  2314.  
  2315.       case VN_SYSV:            /* System herald */
  2316.     for (x = y = 0; x < VVBUFL; x++) {
  2317.         if (ckxsys[x] == SP && y == 0) continue;
  2318.         vvbuf[y++] = (ckxsys[x] == SP) ? '_' : ckxsys[x];
  2319.     }
  2320.     vvbuf[y] = NUL;
  2321.     return(vvbuf);
  2322.  
  2323.       case VN_TIME:            /* TIME. Assumes that ztime returns */
  2324.     ztime(&p);            /* "Thu Feb  8 12:00:00 1990" */
  2325.     if (p == NULL || *p == NUL)    /* like asctime()! */
  2326.       return(NULL);
  2327.     for (x = 11; x < 19; x++)    /* copy hh:mm:ss */
  2328.       vvbuf[x - 11] = p[x];        /* to vvbuf */
  2329.     vvbuf[8] = NUL;            /* terminate */
  2330.     return(vvbuf);            /* and return it */
  2331.  
  2332.       case VN_NTIM:            /* Numeric time */
  2333.     ztime(&p);            /* "Thu Feb  8 12:00:00 1990" */
  2334.     if (p == NULL || *p == NUL)    /* like asctime()! */
  2335.       return(NULL);
  2336.     z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  2337.     sprintf(vvbuf,"%ld",z);
  2338.     return(vvbuf);
  2339.  
  2340. #ifdef UNIX
  2341.       case VN_TTYF:            /* TTY file descriptor */
  2342.     sprintf(vvbuf,"%d",ttyfd);
  2343.     return(vvbuf);
  2344. #else
  2345. #ifdef OS2
  2346.       case VN_TTYF:            /* TTY file descriptor */
  2347.     sprintf(vvbuf,"%d",ttyfd);
  2348.     return(vvbuf);
  2349. #endif /* OS2 */
  2350. #endif /* UNIX */
  2351.  
  2352.       case VN_VERS:            /* Numeric Kermit version number */
  2353.     sprintf(vvbuf,"%ld",vernum);
  2354.     return(vvbuf);
  2355.  
  2356.       case VN_HOME:            /* Home directory */
  2357. #ifdef UNIX
  2358.         sprintf(vvbuf,"%s/",zhome());
  2359.     return(vvbuf);
  2360. #else
  2361. #ifdef OSK
  2362.         sprintf(vvbuf,"%s/",zhome());
  2363.     return(vvbuf);
  2364. #else
  2365.     return(zhome());
  2366. #endif /* OSK */
  2367. #endif /* UNIX */
  2368.  
  2369.       case VN_IBUF:            /* INPUT buffer */
  2370.     return(inpbuf);
  2371.  
  2372.       case VN_ICHR:            /* INPUT character */
  2373.     inchar[1] = NUL;
  2374.     return((char *)inchar);
  2375.  
  2376.       case VN_ICNT:            /* INPUT character count */
  2377.         sprintf(vvbuf,"%d",incount);
  2378.     return(vvbuf);
  2379.  
  2380.       case VN_SPEE: {            /* Transmission SPEED */
  2381.       long t;
  2382.       t = ttgspd();
  2383.       if (t < 0L)
  2384.         sprintf(vvbuf,"unknown");
  2385.       else
  2386.         sprintf(vvbuf,"%ld",t);
  2387.       return(vvbuf);
  2388.       }
  2389.       case VN_SUCC:            /* SUCCESS flag */
  2390.     sprintf(vvbuf,"%d",(success == 0) ? 1 : 0);
  2391.     return(vvbuf);
  2392.  
  2393.       case VN_LINE:            /* LINE */
  2394.     p = (char *) ttname;
  2395.         return(p);
  2396.  
  2397.       case VN_PROG:            /* Program name */
  2398. #ifdef MAC
  2399.     return("Mac-Kermit");
  2400. #else
  2401.     return("C-Kermit");
  2402. #endif /* MAC */
  2403.  
  2404.       case VN_RET:            /* Value of most recent RETURN */
  2405.     p = mrval[maclvl+1];
  2406.     if (p == NULL) p = "";
  2407.     return(p);
  2408.  
  2409.       case VN_FFC:            /* Size of most recent file */
  2410.     sprintf(vvbuf, "%ld", ffc);
  2411.     return(vvbuf);
  2412.  
  2413.       case VN_TFC:            /* Size of most recent file group */
  2414.     sprintf(vvbuf, "%ld", tfc);
  2415.     return(vvbuf);
  2416.  
  2417.       case VN_CPU:            /* CPU type */
  2418. #ifdef CKCPU
  2419.     return(CKCPU);
  2420. #else
  2421.     return("unknown");
  2422. #endif /* CKCPU */
  2423.  
  2424.       case VN_CMDL:            /* Command level */
  2425.     sprintf(vvbuf, "%d", cmdlvl);
  2426.     return(vvbuf);
  2427.  
  2428.       case VN_DAY:            /* Day of week */
  2429.       case VN_NDAY:
  2430. /*
  2431.   Depends on ztime() returning ENGLISH asctime()-format string!
  2432.   asctime() format is: "Thu Feb  8 12:00:00 1990".
  2433.   Needs updating to accommodate non-English asctime() strings.
  2434. */
  2435.     ztime(&p);
  2436.     if (p != NULL && *p != NUL) {    /* ztime() succeeded. */
  2437.         if (y == VN_DAY) {        /* String day. */
  2438.         strncpy(vvbuf,p,3);
  2439.         } else {            /* Numeric day. */
  2440.         for (x = 0; x < 7; x++)      /* Look up day string in table */
  2441.           if (!strncmp(p,wkdays[x],3))
  2442.             break;
  2443.         if (x > 6) x = -1;    /* Not found */
  2444.         sprintf(vvbuf,"%d",x);    /* Return the number */
  2445.         }
  2446.     } else vvbuf[0] = NUL;        /* ztime() failed. */
  2447.     return(vvbuf);            /* Return what we got. */
  2448.  
  2449.       case VN_LCL:            /* Local (vs remote) mode */
  2450.     strcpy(vvbuf, local ? "1" : "0");
  2451.     return(vvbuf);
  2452.  
  2453.       case VN_CMDS:            /* Command source */
  2454.     if (cmdstk[cmdlvl].src == CMD_KB)
  2455.       strcpy(vvbuf,"prompt");
  2456.     else if (cmdstk[cmdlvl].src == CMD_MD)
  2457.       strcpy(vvbuf,"macro");
  2458.     else if (cmdstk[cmdlvl].src == CMD_TF)
  2459.       strcpy(vvbuf,"file");
  2460.     else strcpy(vvbuf,"unknown");
  2461.     return(vvbuf);
  2462.  
  2463.       case VN_CMDF:            /* Current command file name */
  2464.     return(tfnam[tlevel] ? tfnam[tlevel] : "");
  2465.  
  2466.       case VN_MAC:            /* Current macro name */
  2467.     return((maclvl > -1) ? m_arg[maclvl][0] : "");
  2468.  
  2469.       case VN_EXIT:
  2470.     sprintf(vvbuf,"%d",xitsta);
  2471.     return(vvbuf);
  2472.  
  2473.       default:
  2474.     return(NULL);
  2475.     }
  2476. }
  2477. #endif /* NOSPL */
  2478.  
  2479. /*
  2480.   X X S T R I N G  --  Expand variables and backslash codes.
  2481.  
  2482.     int xxtstring(s,&s2,&n);
  2483.  
  2484.   Expands \ escapes via recursive descent.
  2485.   Argument s is a pointer to string to expand (source).
  2486.   Argument s2 is the address of where to put result (destination).
  2487.   Argument n is the length of the destination string (to prevent overruns).
  2488.   Returns -1 on failure, 0 on success,
  2489.     with destination string null-terminated and s2 pointing to the
  2490.     terminating null, so that subsequent characters can be added.
  2491. */
  2492.  
  2493. #define XXDEPLIM 100            /* Recursion depth limit */
  2494.  
  2495. int
  2496. xxstring(s,s2,n) char *s; char **s2; int *n; {
  2497.     int x,                /* Current character */
  2498.         y,                /* Worker */
  2499.         pp,                /* Paren level */
  2500.         argn,                /* Function argument counter */
  2501.         n2,                /* Local copy of n */
  2502.         d,                /* Array dimension */
  2503.         vbi,                /* Variable id (integer form) */
  2504.         argl;                /* String argument length */
  2505.  
  2506.     char vb,                /* Variable id (char form) */
  2507.         *vp,                /* Pointer to variable definition */
  2508.         *new,                /* Local pointer to target string */
  2509.         *p,                /* Worker */
  2510.         *q;                /* Worker */
  2511.     char *r  = (char *)0;        /* For holding function args */
  2512.     char *r2 = (char *)0;
  2513.  
  2514. #ifndef NOSPL
  2515.     char vnambuf[VNAML];        /* Buffer for variable/function name */
  2516.     char *argp[FNARGS];            /* Pointers to function args */
  2517. #endif /* NOSPL */
  2518.  
  2519.     static int depth = 0;        /* Call depth, avoid overflow */
  2520.  
  2521.     n2 = *n;                /* Make local copies of args */
  2522.     new = *s2;                /* for one less level of indirection */
  2523.  
  2524.     depth++;                /* Sink to a new depth */
  2525.     if (depth > XXDEPLIM) {        /* Too deep? */
  2526.     printf("?definition is circular or too deep\n");
  2527.     depth = 0;
  2528.     *new = NUL;
  2529.     return(-1);
  2530.     }
  2531.     if (!s || !new) {            /* Watch out for null pointers */
  2532.     depth = 0;
  2533.     *new = NUL;
  2534.     return(-1);
  2535.     }
  2536.     argl = (int)strlen(s);        /* Get length of source string */
  2537.     debug(F111,"xxstring",s,argl);
  2538.     if (argl < 0) {            /* Watch out for garbage */
  2539.     depth = 0;
  2540.     *new = NUL;
  2541.     return(-1);
  2542.     }
  2543.     while ( x = *s ) {            /* Loop for all characters */
  2544.         if (x != CMDQ) {        /* Is it the command-quote char? */
  2545.         *new++ = *s++;        /* No, normal char, just copy */
  2546.         if (n2-- < 0) {        /* and count it, careful of overflow */
  2547.         return(-1);
  2548.         }
  2549.         continue;
  2550.     }
  2551.  
  2552. /* We have the command-quote character. */
  2553.  
  2554.     x = *(s+1);            /* Get the following character. */
  2555.     switch (x) {            /* Act according to variable type */
  2556. #ifndef NOSPL
  2557.       case '%':            /* Variable */
  2558.         s += 2;            /* Get the letter or digit */
  2559.         vb = *s++;            /* and move source pointer past it */
  2560.         vp = NULL;            /* Assume definition is empty */
  2561.         if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
  2562.         if (maclvl < 0)     /* Digit variables are global */
  2563.           vp = g_var[vb];    /* if no macro is active */
  2564.         else            /* otherwise */
  2565.           vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
  2566.         } else {
  2567.         if (isupper(vb)) vb -= ('a'-'A');
  2568.         vp = g_var[vb];        /* Letter for global variable */
  2569.         }
  2570.         if (vp) {            /* If definition not empty */
  2571.         if (xxstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
  2572.             return(-1);        /* Pass along failure */
  2573.         }
  2574.         }
  2575.         break;
  2576.       case '&':            /* An array reference */
  2577.         if (arraynam(s,&vbi,&d) < 0) { /* Get name and subscript */
  2578.         return(-1);
  2579.         }
  2580.         pp = 0;            /* Bracket counter */
  2581.         while (*s) {        /* Advance source pointer */
  2582.         if (*s == '[') pp++;
  2583.         if (*s == ']' && --pp == 0) break;
  2584.         s++;
  2585.         }
  2586.         if (*s == ']') s++;        /* past the closing bracket. */
  2587.         if (chkarray(vbi,d) > 0) {    /* Array is declared? */
  2588.         vbi -= 96;        /* Convert name to index */
  2589.         if (a_dim[vbi] >= d) {    /* If subscript in range */
  2590.             char **ap;
  2591.             ap = a_ptr[vbi];    /* get data pointer */
  2592.             if (ap) {        /* and if there is one */
  2593.             if (ap[d]) {    /* If definition not empty */
  2594.                 if (xxstring(ap[d],&new,&n2) < 0) { /* evaluate */
  2595.                 return(-1); /* Pass along failure */
  2596.                 }
  2597.             }
  2598.             }
  2599.         }
  2600.         }
  2601.         break;
  2602.  
  2603.       case 'F':            /* A builtin function */
  2604.       case 'f':
  2605.         q = vnambuf;        /* Copy the name */
  2606.         y = 0;            /* into a separate buffer */
  2607.         s+=2;            /* point past 'F' */
  2608.         while (y++ < VNAML) {
  2609.         if (*s == '(') { s++; break; } /* Look for open paren */
  2610.         if ((*q = *s) == NUL) break;   /* or end of string */
  2611.         s++; q++;
  2612.         }
  2613.         *q = NUL;            /* Terminate function name */
  2614.         if (y >= VNAML) {        /* Handle pathological case */
  2615.         while (*s && (*s != '(')) /* of very long string entered */
  2616.           s++;              /* as function name. */
  2617.         if (*s == ')') s++;      /* Skip past it. */
  2618.         }
  2619.         r = r2 = malloc(argl+2);    /* And make a place to copy args */
  2620.         debug(F101,"xxstring r2","",r2);
  2621.         if (!r2) {            /* Watch out for malloc failure */
  2622.         depth = 0;
  2623.         *new = NUL;
  2624.         return(-1);
  2625.         }
  2626.         argn = 0;            /* Argument counter */
  2627.         argp[argn++] = r;        /* Point to first argument */
  2628.         y = 0;            /* Completion flag */
  2629.         pp = 1;            /* Paren level (already have one). */
  2630.         while (*r = *s) {        /* Copy each argument, char by char. */
  2631.         if (*r == '(') pp++;    /* Count an opening paren. */
  2632.         if (*r == ')') {    /* Closing paren, count it. */
  2633.             if (--pp == 0) {    /* Final one? */
  2634.             *r = NUL;    /* Make it a terminating null */
  2635.             s++;
  2636.             y = 1;        /* Flag we've got all the args */
  2637.             break;
  2638.             }
  2639.         }
  2640.         if (*r == ',') {    /* Comma */
  2641.             if (pp == 1) {    /* If not within ()'s, */
  2642.             *r = NUL;        /* new arg, skip past it, */
  2643.             argp[argn++] = r+1; /* point to new arg. */
  2644.             if (argn == FNARGS) /* Too many args */
  2645.               break;
  2646.             }            /* Otherwise just skip past  */
  2647.         }
  2648.         s++; r++;        /* Advance pointers */
  2649.         }
  2650.         debug(F110,"xxstring function name",vnambuf,0);
  2651.         if (!y) {            /* If we didn't find closing paren */
  2652.         debug(F101,"xxstring r2 before free","",r2);
  2653.         if (r2) free(r2);    /* free the temporary storage */
  2654.         return(-1);        /* and return failure. */
  2655.         }
  2656. #ifdef DEBUG
  2657.         if (deblog)
  2658.           for (y = 0; y < argn; y++)
  2659.         debug(F111,"xxstring function arg",argp[y],y);
  2660. #endif /* DEBUG */
  2661.         vp = fneval(vnambuf,argp,argn); /* Evaluate the function. */
  2662.         if (vp) {            /* If definition not empty */
  2663.         while (*new++ = *vp++)    /* copy it to output string */
  2664.           if (n2-- < 0) return(-1); /* mindful of overflow */
  2665.         new--;            /* Back up over terminating null */
  2666.         n2++;            /* to allow for further deposits. */
  2667.         }
  2668.         if (r2) {
  2669.         debug(F101,"xxstring freeing r2","",r2);
  2670.         free(r2);        /* Now free the temporary storage */
  2671.         r2 = NULL;
  2672.         }
  2673.         break;
  2674.       case '$':            /* An environment variable */
  2675.       case 'V':            /* Or a named builtin variable. */
  2676.       case 'v':
  2677.       case 'M':            /* Or a macro = long variable */
  2678.       case 'm':
  2679.         p = s+2;            /* $/V/M must be followed by (name) */
  2680.         if (*p != '(') {        /* as in \$(HOME) or \V(count) */
  2681.         *new++ = *s++;        /* If not, just copy it */
  2682.         if (n2-- < 0) {
  2683.             return(-1);
  2684.         }
  2685.         break;
  2686.         }
  2687.         p++;            /* Point to 1st char of name */
  2688.         q = vnambuf;        /* Copy the name */
  2689.         y = 0;            /* into a separate buffer */
  2690.         while (y++ < VNAML) {    /* Watch out for name too long */
  2691.         if (*p == ')') {    /* Name properly terminated with ')' */
  2692.             p++;        /* Move source pointer past ')' */
  2693.             break;
  2694.         }
  2695.         if ((*q = *p) == NUL)    /* String ends before ')' */
  2696.           break;
  2697.          p++; q++;        /* Advance pointers */
  2698.         }
  2699.         *q = NUL;            /* Terminate the variable name */
  2700.         if (y >= VNAML) {        /* Handle pathological case */
  2701.         while (*p && (*p != ')')) /* of very long string entered */
  2702.           p++;              /* as variable name. */
  2703.         if (*p == ')') p++;      /* Skip ahead to the end of it. */
  2704.         }
  2705.         s = p;            /* Adjust global source pointer */
  2706.         p = malloc((int)strlen(vnambuf) + 1); /* Make temporary space */
  2707.         if (p) {            /* If we got the space */
  2708.         vp = vnambuf;        /* Point to original */
  2709.         strcpy(p,vp);        /* Make a copy of it */
  2710.         y = VNAML;        /* Length of name buffer */
  2711.         xxstring(p,&vp,&y);    /* Evaluate the copy */
  2712.         free(p);        /* Free the temporary space */
  2713.         }
  2714.         debug(F110,"xxstring vname",vnambuf,0);
  2715.         if (x == '$') {        /* Look up its value */
  2716.         vp = getenv(vnambuf);    /* This way for environment variable */
  2717.         } else if (x == 'm' || x == 'M') { /* or this way for macro */
  2718.         y = mlook(mactab,vnambuf,nmac);    /* contents (= long variable */
  2719.         vp = (y > -1) ? mactab[y].mval : ""; /* name)... */
  2720.         } else {             /*  or */
  2721.             vp = nvlook(vnambuf);    /* this way for builtin variable */
  2722.         }
  2723.         if (vp) {            /* If definition not empty */
  2724.         while (*new++ = *vp++)    /* copy it to output string. */
  2725.           if (n2-- < 0) {
  2726.             return(-1);
  2727.         }
  2728.         new--;            /* Back up over terminating null */
  2729.         n2++;            /* to allow for further deposits. */
  2730.         }
  2731.         break;
  2732. #endif /* NOSPL    */            /* Handle \nnn even if NOSPL. */
  2733.       default:            /* Maybe it's a backslash code */
  2734.         y = xxesc(&s);        /* Go interpret it */
  2735.         if (y < 0) {        /* Upon failure */
  2736.         *new++ = x;        /* Just quote the next character */
  2737.         s += 2;            /* Move past the pair */
  2738.         n2 -= 2;
  2739.         if (n2 < 0) {
  2740.             return(-1);
  2741.         }
  2742.         continue;        /* and go back for more */
  2743.         } else {
  2744.         *new++ = y;        /* else deposit interpreted value */
  2745.         if (n2-- < 0) {
  2746.             return(-1);
  2747.         }
  2748.         }
  2749.     }
  2750.     }
  2751.     *new = NUL;                /* Terminate the new string */
  2752.     depth--;                /* Adjust stack depth gauge */
  2753.     *s2 = new;                /* Copy results back into */
  2754.     *n = n2;                /* the argument addresses */
  2755.     return(0);                /* and return. */
  2756. }
  2757. #endif /* NOICP */
  2758.