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

  1. #include "ckcsym.h"
  2. #ifndef NOICP
  3.  
  4. /*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
  5.  
  6. /*
  7.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  8.   Columbia University Academic Information Systems, New York City.
  9.  
  10.   Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New
  11.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  12.   sold for profit as a software product itself, nor may it be included in or
  13.   distributed with commercial products or otherwise distributed by commercial
  14.   concerns to their clients or customers without written permission of the
  15.   Office of Kermit Development and Distribution, Columbia University.  This
  16.   copyright notice must not be removed, altered, or obscured.
  17. */
  18.  
  19. /*
  20.   File ckuus4.c -- Functions moved from other ckuus*.c modules to even
  21.   out their sizes.
  22. */
  23. #include "ckcdeb.h"
  24. #include "ckcasc.h"
  25. #include "ckcker.h"
  26. #include "ckuusr.h"
  27. #include "ckuver.h"
  28. #include "ckcnet.h"            /* Network symbols */
  29.  
  30. extern xx_strp xxstring;
  31.  
  32. #ifdef DEC_TCPIP
  33. #include <descrip>
  34. #include <dvidef>
  35. #include <dcdef>
  36. #endif /* DEC_TCPIP */
  37.  
  38. #ifndef NOCSETS                /* Character sets */
  39. #include "ckcxla.h"
  40. #endif /* NOCSETS */
  41.  
  42. #ifndef AMIGA
  43. #ifndef MAC
  44. #include <signal.h>
  45. /* #include <setjmp.h> */        /* (seems to be an artifact...) */
  46. #endif /* MAC */
  47. #endif /* AMIGA */
  48.  
  49. #ifdef STRATUS                /* Stratus Computer, Inc.  VOS */
  50. #ifdef putchar
  51. #undef putchar
  52. #endif /* putchar */
  53. #define putchar(x) conoc(x)
  54. #ifdef getchar
  55. #undef getchar
  56. #endif /* getchar */
  57. #define getchar(x) coninc(0)
  58. #endif /* STRATUS */
  59.  
  60. #ifdef ANYX25
  61. extern int revcall, closgr, cudata, npadx3;
  62. int x25ver;
  63. extern char udata[MAXCUDATA];
  64. extern CHAR padparms[MAXPADPARMS+1];
  65. extern struct keytab padx3tab[];
  66. #endif /* ANYX25 */
  67.  
  68. #ifdef NETCONN
  69. extern char ipaddr[];
  70. #ifdef TNCODE
  71. extern int tn_duplex, tn_nlm;
  72. extern char *tn_term;
  73. #endif /* TNCODE */
  74.  
  75. #ifdef CK_NETBIOS
  76. extern unsigned short netbiosAvail;
  77. extern unsigned long NetbeuiAPI ;
  78. extern unsigned char NetBiosName[] ;
  79. extern unsigned char NetBiosAdapter ;
  80. extern unsigned char NetBiosLSN ;
  81. #endif /* CK_NETBIOS */
  82. #endif /* NETCONN */
  83.  
  84. #ifndef NOSPL
  85. extern char evalbuf[];            /* EVALUATE result */
  86.  
  87. #ifdef CK_REXX
  88. extern char rexxbuf[];
  89. #endif /* CK_REXX */
  90.  
  91. /* This needs to be internationalized... */
  92. static
  93. char *months[] = {
  94.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  95.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  96. };
  97.  
  98. static
  99. char *wkdays[] = {
  100.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  101. };
  102. #endif /* NOSPL */
  103.  
  104. #ifdef CK_TTYFD
  105. extern int ttyfd;
  106. #endif /* CK_TTYFD */
  107. #ifdef OS2
  108. _PROTOTYP (int os2getcp, (void) );
  109. #ifdef TCPSOCKET
  110. extern char tcpname[];
  111. #endif /* TCPSOCKET */
  112. extern char startupdir[];
  113. extern int tcp_avail, dnet_avail;
  114. extern int tt_type, max_tt;
  115. extern struct tt_info_rec tt_info[];
  116. #endif /* OS2 */
  117.  
  118. #ifdef CK_NAWS
  119. extern int tt_rows, tt_cols;
  120. #endif /* CK_NAWS */
  121.  
  122. #ifndef NODIAL
  123. _PROTOTYP( static VOID shods, (char *) );
  124. #endif /* NODIAL */
  125.  
  126. extern struct keytab colxtab[];
  127.  
  128. extern CHAR
  129.   eol, mypadc, mystch, padch, seol, stchr;
  130.  
  131. extern char ttname[], *ckxsys, *versio, **xargv, *zinptr;
  132.  
  133. extern int remonly;
  134.  
  135. extern int
  136.   atcapr, autopar, bctr, bctu, bgset, bigrbsiz, bigsbsiz, binary, carrier,
  137.   cdtimo, cmask, crunched, delay, duplex, ebq, ebqflg, escape, flow, fmask,
  138.   fncact, fncnv, inecho, keep, local, lscapr, lscapu,
  139.   maxrps, maxsps, maxtry, mdmspd, mdmtyp, mypadn, ncolx,
  140.   nettype, network, nmac, noinit, npad, parity, pktlog, pkttim, rcflag,
  141.   retrans, rpackets, rptflg, rptq, rtimo, seslog, sessft, sosi, spackets,
  142.   spsiz, spsizf, spsizr, srvtim, stayflg, success, timeouts, tralog,
  143.   tsecs, ttnproto, turn, turnch, urpsiz, wmax, wslotn, wslotr, xargc, xargs,
  144.   zincnt, fdispla, tlevel, xitsta, spmax, insilence, cmdmsk, timint, timef,
  145.   fnrpath, fnspath, quiet;
  146.  
  147. #ifdef VMS
  148.   extern int frecl;
  149. #endif /* VMS */
  150.  
  151. extern long
  152.   ffc, filcnt, rptn, speed, tfc, tlci, tlco, vernum;
  153.  
  154. #ifndef NOSPL
  155. extern char fspec[], myhost[];
  156. #endif /* NOSPL */
  157.  
  158. extern char *tfnam[];            /* Command file names */
  159.  
  160. #ifdef DCMDBUF
  161. extern struct cmdptr *cmdstk;
  162. extern char *line, *kermrc;
  163. #else
  164. extern struct cmdptr cmdstk[];
  165. extern char line[], kermrcb[], *kermrc;
  166. #endif /* DCMDBUF */
  167.  
  168. extern char pktfil[],            /* Packet log file name */
  169. #ifdef DEBUG
  170.   debfil[],                /* Debug log file name */
  171. #endif /* DEBUG */
  172. #ifdef TLOG
  173.   trafil[],                /* Transaction log file name */
  174. #endif /* TLOG */
  175.   sesfil[];                /* Session log file name */
  176.  
  177. #ifndef NOXMIT                /* TRANSMIT command variables */
  178. extern char xmitbuf[];
  179. extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
  180. #endif /* NOXMIT */
  181.  
  182. #ifndef NOSPL
  183. /* Script programming language items */
  184. extern char **a_ptr[];            /* Arrays */
  185. extern int a_dim[];
  186. extern char inpbuf[], inchar[];        /* Buffers for INPUT and REINPUT */
  187. extern char *inpbp;            /* And pointer to same */
  188. static char *inpbps = inpbuf;        /* And another */
  189. extern int incount;            /* INPUT character count */
  190. extern int m_found;            /* MINPUT result */
  191. extern int maclvl;            /* Macro invocation level */
  192. extern struct mtab *mactab;        /* Macro table */
  193. extern char *mrval[];
  194. extern int macargc[], cmdlvl;
  195. extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
  196. extern char *g_var[GVARS];      /* for external 2-dimensional arrays. */
  197. #ifdef DCMDBUF
  198. extern int *count, *inpcas;
  199. #else
  200. extern int count[], inpcas[];
  201. #endif /* DCMDBUF */
  202. #endif /* NOSPL */
  203.  
  204. #ifdef UNIX
  205. extern int haslock;            /* For UUCP locks */
  206. extern char flfnam[];
  207. extern int maxnam, maxpath;        /* Longest name, path length */
  208. #endif /* UNIX */
  209.  
  210. #ifndef NODIAL
  211. /* DIAL-related variables */
  212. extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialmnp, dialmhu, dialsta;
  213. extern char *dialnum, *dialdir, *dialnpr;
  214. extern struct keytab mdmtab[];
  215. #endif /* NODIAL */
  216.  
  217. #ifndef NOCSETS
  218. /* Translation stuff */
  219. extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
  220. extern struct keytab lngtab[];
  221. extern struct csinfo fcsinfo[], tcsinfo[];
  222. extern struct langinfo langs[];
  223. #ifdef CK_ANSIC
  224. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  225. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  226. #else
  227. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  228. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  229. #endif /* CK_ANSIC */
  230. #endif /* NOCSETS */
  231.  
  232. #ifndef NOSPL
  233. /* Built-in variable names, maximum length VNAML (20 characters) */
  234.  
  235. struct keytab vartab[] = {
  236.     "argc",      VN_ARGC,  0,
  237.     "args",      VN_ARGS,  0,
  238. #ifndef NOCSETS
  239.     "charset",   VN_CSET,  0,
  240. #endif /* NOCSETS */
  241.     "cmdfile",   VN_CMDF,  0,
  242.     "cmdlevel",  VN_CMDL,  0,
  243.     "cmdsource", VN_CMDS,  0,
  244.     "cols",      VN_COLS,  0,        /* 190 */
  245.     "connection",VN_CONN,  0,        /* 190 */
  246.     "count",     VN_COUN,  0,
  247.     "cps",       VN_CPS,   0,        /* 190 */
  248.     "cpu",     VN_CPU,   0,
  249.     "date",      VN_DATE,  0,
  250.     "day",       VN_DAY,   0,
  251.     "directory", VN_DIRE,  0,
  252.     "dialstatus",VN_DIAL,  0,        /* 190 */
  253.     "evaluate",  VN_EVAL,  0,        /* 190 */
  254.     "exitstatus",VN_EXIT,  0,
  255.     "filespec",  VN_FILE,  0,
  256.     "fsize",     VN_FFC,   0,        /* 190 */
  257.     "ftype",     VN_MODE,  0,        /* 190 */
  258.     "home",      VN_HOME,  0,
  259.     "host",      VN_HOST,  0,
  260.     "input",     VN_IBUF,  0,
  261.     "inchar",    VN_ICHR,  0,
  262.     "incount",   VN_ICNT,  0,
  263. #ifdef OS2
  264.     "keyboard",  VN_KEYB,  0,
  265. #endif /* OS2 */
  266.     "line",      VN_LINE,  0,
  267.     "local",     VN_LCL,   0,
  268.     "macro",     VN_MAC,   0,
  269.     "minput",    VN_MINP,  0,
  270.     "modem",     VN_MDM,   0,
  271.     "ndate",     VN_NDAT,  0,
  272.     "nday",      VN_NDAY,  0,
  273.     "newline",   VN_NEWL,  0,
  274.     "ntime",     VN_NTIM,  0,
  275.     "parity",    VN_PRTY,  0,        /* 190 */
  276.     "platform",  VN_SYSV,  0,
  277.     "program",   VN_PROG,  0,
  278.     "query",     VN_QUE,   0,        /* 190 */
  279.     "return",    VN_RET,   0,
  280. #ifdef CK_REXX
  281.     "rexx",      VN_REXX,  0,        /* 190 */
  282. #endif /* CK_REXX */
  283.     "rows",      VN_ROWS,  0,        /* 190 */
  284.     "speed",     VN_SPEE,  0,
  285. #ifdef OS2
  286.     "space",     VN_SPA,   0,
  287.     "startup",   VN_STAR,  0,        /* 190 */
  288. #endif /* OS2 */
  289.     "status",    VN_SUCC,  0,
  290.     "sysid",     VN_SYSI,  0,
  291.     "system",    VN_SYST,  0,
  292.     "terminal",  VN_TTYP,  0,
  293.     "tfsize",    VN_TFC,   0,
  294.     "time",      VN_TIME,  0,
  295. #ifdef CK_TTYFD
  296.     "ttyfd",     VN_TTYF,  0,
  297. #endif /* CK_TTYFD */
  298.     "version",   VN_VERS,  0
  299. };
  300. int nvars = (sizeof(vartab) / sizeof(struct keytab));
  301. #endif /* NOSPL */
  302.  
  303. #ifndef NOSPL
  304. struct keytab fnctab[] = {        /* Function names */
  305.     "character",  FN_CHR, 0,        /* Character from code */
  306.     "code",       FN_COD, 0,        /* Code from character */
  307.     "contents",   FN_CON, 0,        /* Definition (contents) of variable */
  308. #ifdef ZFCDAT
  309.     "date",       FN_FD,  0,        /* File modification/creation date */
  310. #endif /* ZFCDAT */
  311.     "definition", FN_DEF, 0,        /* Return definition of given macro */
  312.     "evaluate",   FN_EVA, 0,        /* Evaluate given arith expression */
  313.     "execute",    FN_EXE, 0,        /* Execute given macro */
  314.     "files",      FN_FC,  0,        /* File count */
  315.     "index",      FN_IND, 0,        /* Index (string search) */
  316.     "length",     FN_LEN, 0,        /* Return length of argument */
  317.     "literal",    FN_LIT, 0,        /* Return argument literally */
  318.     "lower",      FN_LOW, 0,        /* Return lowercased argument */
  319.     "lpad",       FN_LPA, 0,        /* Return left-padded argument */
  320.     "maximum",    FN_MAX, 0,        /* Return maximum of two arguments */
  321.     "minimim",    FN_MIN, 0,        /* Return minimum of two arguments */
  322. #ifdef COMMENT
  323. /* not needed because \feval() has it */
  324.     "modulus",    FN_MOD, 0,        /* Return modulus of two arguments */
  325. #endif /* COMMENT */
  326.     "nextfile",   FN_FIL, 0,        /* Next file in list */
  327.     "rep",        FN_REP, CM_INV|CM_ABR,
  328.     "repeat",     FN_REP, 0,        /* Repeat argument given # of times */
  329.     "replace",    FN_RPL, 0,        /* Replace string1 with string2 */
  330. #ifndef NOFRILLS
  331.     "reverse",    FN_REV, 0,        /* Reverse the argument string */
  332. #endif /* NOFRILLS */
  333.     "right",      FN_RIG, 0,        /* Rightmost n characters */
  334.     "rpad",       FN_RPA, 0,        /* Right-pad the argument */
  335.     "size",       FN_FS,  0,        /* File size */
  336.     "substring",  FN_SUB, 0,        /* Extract substring from argument */
  337.     "upper",      FN_UPP, 0        /* Return uppercased argument */
  338. };
  339. int nfuncs = (sizeof(fnctab) / sizeof(struct keytab));
  340. #endif /* NOSPL */
  341.  
  342. #ifndef NOSPL                /* Buffer for expansion of */
  343. #define VVBUFL 65            /* built-in variables. */
  344. char vvbuf[VVBUFL];
  345. #endif /* NOSPL */
  346.  
  347. struct keytab disptb[] = {        /* Log file disposition */
  348.     "append",    1,  0,
  349.     "new",       0,  0
  350. };
  351.  
  352. /* 
  353.   P R E S C A N -- A quick look through the command-line options for 
  354.   items that must be handled before the initialization file is executed.
  355. */
  356. VOID
  357. prescan(y) int y; {
  358.     int yargc; char **yargv;
  359.     char x;
  360.     char *yp;
  361.  
  362.     yargc = xargc;
  363.     yargv = xargv;
  364.  
  365. #ifdef DCMDBUF
  366.     if (!kermrc)
  367.       if (!(kermrc = (char *) malloc(KERMRCL+1)))
  368.     fatal("cmdini: no memory for kermrc");
  369. #endif /* DCMDBUF */
  370.  
  371.     strcpy(kermrc,KERMRC);        /* Default init file name */
  372. #ifndef NOCMDL
  373.     while (--yargc > 0) {        /* Toodle through command-line args */
  374.     yargv++;
  375.     yp = *yargv+1;            /* Pointer for bundled args */
  376.     if (**yargv == '=') return;    /* Same rules as cmdlin()... */
  377. #ifdef VMS
  378.     else if (**yargv == '/') continue;
  379. #endif /* VMS */
  380.         else if (**yargv == '-') {    /* Got an option (begins with dash) */
  381.         x = *(*yargv+1);        /* Get option letter */
  382.         while (x) {            /* Allow for bundled options */
  383.         debug(F000,"prescan arg","",x);
  384.         switch (x) {
  385.           case 'R':        /* Remote-only advisory */
  386. #ifdef CK_IFRO
  387.             remonly = 1;
  388. #endif /* CK_IFRO */
  389.             break;
  390.           case 'S':        /* STAY */
  391.             stayflg = 1;
  392.             break;
  393.           case 'h':
  394.           case 'Y':        /* No init file */
  395.             noinit = 1;
  396.             break;
  397.           case 'd':        /* = SET DEBUG ON */
  398. #ifdef DEBUG
  399.             if (!deblog)
  400.               deblog = debopn("debug.log",0);
  401. #endif /* DEBUG */
  402.             break;
  403.           case 'y':        /* Alternative init file */
  404.             if (!y)
  405.               break;
  406.             yargv++, yargc--;
  407.             if (yargc < 1) fatal("missing name in -y");
  408.             strcpy(kermrc,*yargv); /* Replace init file name */
  409.             rcflag = 1;        /* Flag that this has been done */
  410.             break;
  411.           case 'z':        /* = SET BACKGROUND OFF */
  412.             bgset = 0;
  413.             break;
  414. #ifdef CK_NETBIOS
  415.           case 'N':
  416.             {
  417.             int n ;
  418.             yargv++, yargc--;
  419.             n = atoi(*yargv) ;
  420.             if ( strlen(*yargv) == 1 && n >= 0 && n <= 3 )
  421.               NetBiosAdapter = n ;
  422.             else NetBiosAdapter = 0 ;
  423.             } 
  424.             break;
  425. #endif /* CK_NETBIOS */
  426.           default:
  427.             break;
  428.         }
  429.         x = *++yp;        /* See if options are bundled */
  430.         }
  431.     }
  432.     }
  433. #endif /* NOCMDL */
  434. }
  435.  
  436. static int tr_int;            /* Flag if TRANSMIT interrupted */
  437.  
  438. #ifndef MAC
  439. SIGTYP
  440. trtrap(foo) int foo; {            /* TRANSMIT interrupt trap */
  441. #ifdef __EMX__
  442.     signal(SIGINT, SIG_ACK);
  443. #endif
  444.     tr_int = 1;                /* (Need arg for ANSI C) */
  445.     SIGRETURN;
  446. }
  447. #endif /* MAC */
  448. /*  G E T T C S  --  Get Transfer (Intermediate) Character Set  */
  449.  
  450. /*
  451.   Given two file character sets, this routine picks out the appropriate
  452.   "transfer" character set to use for translating between them.
  453.   The transfer character set number is returned.
  454.  
  455.   Translation between two file character sets is done, for example,
  456.   by the CONNECT, TRANSMIT, and TRANSLATE commands.
  457.  
  458.   Translation between Kanji character sets is not yet supported.
  459. */
  460. int
  461. gettcs(cs1,cs2) int cs1, cs2; {
  462. #ifdef NOCSETS                /* No character-set support */
  463.     return(0);                /* so no translation */
  464. #else
  465.     int tcs = TC_TRANSP;
  466. #ifdef KANJI
  467. /* Kanji not supported yet */
  468.     if (fcsinfo[cs1].alphabet == AL_JAPAN ||
  469.     fcsinfo[cs2].alphabet == AL_JAPAN )
  470.       tcs = TC_TRANSP;
  471.     else
  472. #endif /* KANJI */
  473. #ifdef CYRILLIC
  474. /*
  475.   I can't remember why we don't test both sets here, but I think there
  476.   must have been a reason...
  477. */
  478.       if (fcsinfo[cs2].alphabet == AL_CYRIL)
  479.     tcs = TC_CYRILL;
  480.       else
  481. #endif /* CYRILLIC */
  482. #ifdef LATIN2
  483.     if (cs1 == FC_2LATIN || cs2 == FC_2LATIN ||
  484.         cs1 == FC_CP852  || cs2 == FC_CP852 )
  485.       tcs = TC_2LATIN;
  486.     else
  487. #endif /* LATIN2 */
  488. #ifdef HEBREW
  489.       if (fcsinfo[cs1].alphabet == AL_HEBREW ||
  490.           fcsinfo[cs2].alphabet == AL_HEBREW )
  491.         tcs = TC_HEBREW;
  492.       else
  493. #endif /* HEBREW */
  494.         tcs = TC_1LATIN;
  495.     return(tcs);
  496. #endif /* NOCSETS */
  497. }
  498.  
  499. #ifdef COMMENT
  500. /*
  501.   It seemed that this was needed for OS/2, in which \v(cmdfile) and other
  502.   file-oriented variables or functions can return filenames containing
  503.   backslashes, which are subsequently interpreted as quotes rather than
  504.   directory separators (e.g. see commented section for VN_CMDF below).
  505.   But the problem can't be cured at this level.  Example:
  506.  
  507.     type \v(cmdfile)
  508.  
  509.   Without doubling, the filename is parsed correctly, but then when passed
  510.   to UNIX 'cat' through the shell, the backslash is removed, and then cat
  511.   can't open the file.  With doubling, the filename is not parsed correctly
  512.   and the TYPE command fails immediately with a "file not found" error.
  513. */
  514. /*
  515.   Utility routine to double all backslashes in a string.
  516.   s1 is pointer to source string, s2 is pointer to destination string,
  517.   n is length of destination string, both NUL-terminated.
  518.   Returns 0 if OK, -1 if not OK (destination string too short).
  519. */
  520. int
  521. dblbs(s1,s2,n) char *s1, *s2; int n; {
  522.     int i = 0;
  523.     while (*s1) {
  524.     if (*s1 == '\\') {
  525.         if (++i > n) return(-1);
  526.         *s2++ = '\\';
  527.     }
  528.     if (++i > n) return(-1);
  529.     *s2++ = *s1++;
  530.     }
  531.     *s2 = NUL;
  532.     return(0);
  533. }
  534. #endif /* COMMENT */
  535.  
  536. char * gmdmtyp() {            /* Get modem type */
  537. #ifndef NODIAL
  538.     int i;
  539.     if (mdmtyp < 1) {
  540.     return("none");
  541.     } else {
  542.     for (i = 0; i < nmdm; i++) {
  543.         if (mdmtab[i].kwval == mdmtyp && mdmtab[i].flgs == 0) {
  544.         return(mdmtab[i].kwd);
  545.         }
  546.     }
  547.     return("none");
  548.     }
  549. #else
  550.     return("none");
  551. #endif /* NODIAL */
  552. }
  553.  
  554. #ifndef NOXMIT
  555. #ifndef NOLOCAL
  556. /*  T R A N S M I T  --  Raw upload  */
  557.  
  558. /*  Obey current line, duplex, parity, flow, text/binary settings. */
  559. /*  Returns 0 upon apparent success, 1 on obvious failure.  */
  560.  
  561. /***
  562.  Things to add:
  563.  . Make both text and binary mode obey set file bytesize.
  564.  . Maybe allow user to specify terminators other than CR?
  565.  . Maybe allow user to specify prompts other than single characters?
  566. ***/
  567.  
  568. /*  T R A N S M I T  --  Raw upload  */
  569.  
  570. /*  s is the filename, t is the turnaround (prompt) character  */
  571.  
  572. /*
  573.   Maximum number of characters to buffer.
  574.   Must be less than LINBUFSIZ
  575. */
  576. #define XMBUFS 120
  577.  
  578. int
  579. #ifdef CK_ANSIC
  580. transmit(char * s, char t)
  581. #else
  582. transmit(s,t) char *s; char t;
  583. #endif /* CK_ANSIC */
  584. /* transmit */ {
  585. #ifdef MAC
  586.     extern char sstate;
  587.     int count = 100;
  588. #else
  589.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  590. #endif /* MAC */
  591.     long zz;
  592.     int z = 1;                /* Return code. 0=fail, 1=succeed. */
  593.     int x, c, i;            /* Workers... */
  594.     int myflow;
  595.     int mybinary;
  596.     CHAR csave;
  597.     char *p;
  598.  
  599. #ifndef NOCSETS
  600.     int tcs = TC_TRANSP;        /* Intermediate (xfer) char set */
  601.     int langsv = L_USASCII;        /* Save current language */
  602.  
  603.     _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
  604.     _PROTOTYP ( CHAR (*rxo), (CHAR) ) = NULL;
  605.     _PROTOTYP ( CHAR (*sxi), (CHAR) ) = NULL;
  606.     _PROTOTYP ( CHAR (*rxi), (CHAR) ) = NULL;
  607. #endif /* NOCSETS */
  608.  
  609. /*
  610.    If a system-specific binary mode is set (MacBinary, Image, Labeled, etc),
  611.    revert to "normal" binary mode for duration of TRANSMIT command.
  612. */
  613.     mybinary = binary;
  614.     if (binary) binary = XYFT_B;
  615.     if (zopeni(ZIFILE,s) == 0) {    /* Open the file to be transmitted */
  616.     printf("?Can't open file %s\n",s);
  617.     binary = mybinary;
  618.     return(0);
  619.     }
  620.     x = -1;                /* Open the communication line */
  621.     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {    /* (no harm if already open) */
  622.     printf("Can't open device %s\n",ttname);
  623.     binary = mybinary;
  624.     return(0);
  625.     }
  626.     zz = x ? speed : -1L;
  627.     if (binary) {            /* Binary file transmission */
  628.     myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
  629.     if (ttvt(zz,myflow) < 0) {    /* So no Xon/Xoff! */
  630.         printf("Can't condition line\n");
  631.         binary = mybinary;
  632.         return(0);
  633.     }
  634.     } else {
  635.     if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
  636.         printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
  637.         binary = mybinary;
  638.         return(0);
  639.     }
  640.     }
  641.  
  642. #ifndef NOCSETS
  643.     tcs = gettcs(tcsr,tcsl);        /* Get intermediate set. */
  644.  
  645. /* Set up character set translations */
  646.     if (binary == 0) {
  647.  
  648.     if (tcsr == tcsl || binary) {    /* Remote and local sets the same? */
  649.         sxo = rxo = NULL;        /* Or file type is not text? */
  650.         sxi = rxi = NULL;
  651.     } else {            /* Otherwise, set up */
  652.         sxo = xls[tcs][tcsl];    /* translation function */
  653.         rxo = xlr[tcs][tcsr];    /* pointers for output functions */
  654.         sxi = xls[tcs][tcsr];    /* and for input functions. */
  655.         rxi = xlr[tcs][tcsl];
  656.     }
  657. /*
  658.   This is to prevent use of zmstuff() and zdstuff() by translation functions.
  659.   They only work with disk i/o, not with communication i/o.  Luckily Russian
  660.   translation functions don't do any stuffing...
  661. */
  662.     langsv = language;
  663.     language = L_USASCII;
  664.     }
  665. #endif /* NOCSETS */
  666.  
  667.     i = 0;                /* Beginning of buffer. */
  668. #ifndef MAC
  669. #ifndef AMIGA
  670.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  671. #endif /* AMIGA */
  672. #endif /* MAC */
  673.     tr_int = 0;                /* Have not been interrupted (yet). */
  674.     z = 1;                /* Return code presumed good. */
  675. #ifdef VMS
  676.     conres();
  677. #endif /* VMS */
  678.  
  679.     c = 0;                /* Initial condition */
  680.     while (c > -1) {            /* Loop for all characters in file */
  681. #ifdef MAC
  682.     /*
  683.      * It is expensive to run the miniparser so don't do it for
  684.      * every character.
  685.      */
  686.     if (--count < 0) {
  687.         count = 100;
  688.         miniparser(1);
  689.         if (sstate == 'a') {
  690.         sstate = '\0';
  691.         z = 0;
  692.         break;
  693.         }
  694.     }
  695. #else /* Not MAC */
  696.     if (tr_int) {            /* Interrupted? */
  697.         printf("^C...\n");        /* Print message */
  698.         z = 0;
  699.         break;
  700.     }
  701. #endif /* MAC */
  702.     c = zminchar();            /* Get a file character */
  703.     debug(F101,"transmit char","",c);
  704.     if (c == -1)            /* Test for end-of-file */
  705.       break;
  706.     c &= fmask;            /* Apply SET FILE BYTESIZE mask */
  707.  
  708.     if (binary) {            /* If binary file, */
  709.         if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
  710.         printf("?Can't transmit character\n");
  711.         z = 0;
  712.         goto xmitexit;
  713.         }
  714.         if (xmitw) msleep(xmitw);    /* Pause if requested */
  715.         if (xmitx) {        /* SET TRANSMIT ECHO ON? */
  716.         if (duplex) {        /* Yes, for half duplex */
  717.             if (conoc((char)(c & cmdmsk)) < 0) { /* echo locally. */
  718.             z = 0;
  719.             goto xmitexit;
  720.             }
  721.         } else {        /* For full duplex, */
  722.             int i, n;        /* display whatever is there. */
  723.             n = ttchk();    /* How many chars are waiting? */
  724.             for (i = 0; i < n; i++) { /* Read and echo that many. */
  725.             x = ttinc(1);    /* Timed read just in case. */
  726.             if (x > -1) {    /* If no timeout */
  727.                 if (parity) x &= 0x7f; /* display the char, */
  728.                 if (conoc((char)(x & cmdmsk)) < 0) {
  729.                 z = 0;
  730.                 goto xmitexit;
  731.                 }
  732.             } else break;    /* otherwise stop reading. */
  733.             }
  734.         }
  735.         } else ttflui();        /* Not echoing, just flush input. */
  736.  
  737.     } else {            /* Text mode, line at a time. */
  738.  
  739.         if (c == '\n') {        /* Got a line */
  740.         if (i == 0) {        /* Blank line? */
  741.             if (xmitf)        /* Yes, insert fill if asked. */
  742.               line[i++] = dopar((char) xmitf);
  743.         }
  744.         if (i == 0 || line[i-1] != dopar(CR))
  745.           line[i++] = dopar(CR); /* Terminate it with CR */
  746.         if (
  747.             xmitl
  748. #ifdef TNCODE
  749.             || (network && ttnproto == NP_TELNET && tn_nlm)
  750. #endif /* TNCODE */
  751.             )
  752.           line[i++] = dopar(LF); /* Include LF if asked */
  753.  
  754.         } else if (c != -1) {    /* Not a newline, regular character */
  755.         csave = c;        /* Remember untranslated version */
  756. #ifndef NOCSETS
  757.         /* Translate character sets */
  758.         if (sxo) c = (*sxo)((CHAR)c); /* From local to intermediate */
  759.         if (rxo) c = (*rxo)((CHAR)c); /* From intermediate to remote */
  760. #endif /* NOCSETS */
  761.  
  762.         if (xmits && parity && (c & 0200)) { /* If shifting */
  763.             line[i++] = dopar(SO);          /* needs to be done, */
  764.             line[i++] = dopar((char)c);        /* do it here, */
  765.             line[i++] = dopar(SI);          /* crudely. */
  766.         } else {
  767.             line[i++] = dopar((char)c); /* else, just char itself */
  768.         }
  769.         }
  770.  
  771. /* Send characters if buffer full, or at end of line, or at end of file */
  772.  
  773.         if (i >= XMBUFS || c == '\n' || c == -1) {
  774.         p = line;
  775.         line[i] = '\0';
  776.         debug(F111,"transmit buf",p,i);
  777.         if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
  778.             printf("Can't send buffer\n");
  779.             z = 0;
  780.             break;
  781.         }
  782.         i = 0;            /* Reset buffer pointer. */
  783.  
  784. /* Worry about echoing here. "xmitx" is SET TRANSMIT ECHO flag. */
  785.  
  786.         if (duplex && xmitx) {    /* If local echo, echo it */
  787.             if (parity || cmdmsk == 0x7f) { /* Strip off high bits */
  788.             char *s = p;            /* if necessary */
  789.             while (*s) {
  790.                 *s &= 0x7f;
  791.                 s++;
  792.             }
  793.             if (conoll(p) < 0) {
  794.                 z = 0;
  795.                 goto xmitexit;
  796.             }
  797.             }
  798.         }
  799.         if (xmitw)        /* Give receiver time to digest. */
  800.           msleep(xmitw);
  801.         if (t != 0 && c == '\n') { /* Want a turnaround character */
  802.             x = 0;           /* Wait for it */
  803.             while (x != t) {
  804.             if ((x = ttinc(1)) < 0) { z = 0; goto xmitexit; }
  805.             if (xmitx && !duplex) {    /* Echo any echoes */
  806.                 if (parity) x &= 0x7f;
  807. #ifndef NOCSETS
  808.                 if (sxi) x = (*sxi)((CHAR)x); /* But translate */
  809.                 if (rxi) x = (*rxi)((CHAR)x); /* them first... */
  810. #endif /* NOCSETS */
  811.                 if (conoc((char) x) < 0) { z = 0; goto xmitexit; }
  812.             }
  813.             }
  814.         } else if (xmitx && !duplex) { /* Otherwise, */
  815.             while (ttchk() > 0) {      /* echo for as long as */
  816.             if ((x = ttinc(0)) < 0) break; /* anything is there. */
  817.             if (parity) x &= 0x7f;
  818. #ifndef NOCSETS
  819.             if (sxi) x = (*sxi)((CHAR)x); /* Translate first */
  820.             if (rxi) x = (*rxi)((CHAR)x);
  821. #endif /* NOCSETS */
  822.             if (conoc((char)x) < 0) { z = 0; goto xmitexit; }
  823.             }
  824.         } else ttflui();    /* Otherwise just flush input buffer */
  825.         }                /* End of buffer-dumping block */
  826.     }                /* End of text mode */
  827.     }                    /* End of character-reading loop */
  828.  
  829. xmitexit:
  830.  
  831.     if (z > 0) {
  832.     if (*xmitbuf) {            /* Anything to send at EOF? */
  833.         p = xmitbuf;        /* Yes, point to string. */
  834.         while (*p)            /* Send it. */
  835.           ttoc(dopar(*p++));    /* Don't worry about echo here. */
  836.     }
  837.     }
  838.  
  839. #ifndef AMIGA
  840. #ifndef MAC
  841.     signal(SIGINT,oldsig);        /* Put old signal action back. */
  842. #endif /* MAC */
  843. #endif /* AMIGA */
  844. #ifdef VMS
  845.     concb(escape);            /* Put terminal back, */
  846. #endif /* VMS */
  847.     zclose(ZIFILE);            /* Close file, */
  848. #ifndef NOCSETS
  849.     language = langsv;            /* restore language, */
  850. #endif /* NOCSETS */
  851.     binary = mybinary;            /* restore transfer mode, */
  852.     return(z);                /* and return successfully. */
  853. }
  854. #endif /* NOLOCAL */
  855. #endif /* NOXMIT */
  856.  
  857. #ifdef MAC
  858. /*
  859.   This code is not used any more, except on the Macintosh.  Instead we call
  860.   system to do the typing.  Revive this code if your system can't be called
  861.   to do this.
  862. */
  863.  
  864. /*  D O T Y P E  --  Type a file  */
  865.  
  866. int
  867. dotype(s) char *s; {
  868.  
  869. #ifdef MAC
  870.     extern char sstate;
  871.     int count = 100;
  872. #else
  873.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  874. #endif /* MAC */
  875.     int x, z;                /* Return code. */
  876.     int c;                /* Worker. */
  877.  
  878.     if (zopeni(ZIFILE,s) == 0) {    /* Open the file to be typed */
  879.     printf("?Can't open %s\n",s);
  880.     return(0);
  881.     }
  882. #ifndef AMIGA
  883. #ifndef MAC
  884.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  885. #endif /* MAC */
  886. #endif /* AMIGA */
  887.  
  888.     tr_int = 0;                /* Have not been interrupted (yet). */
  889.     z = 1;                /* Return code presumed good. */
  890.  
  891. #ifdef VMS
  892.     x = conoc(CR);            /* On VMS, display blank line first */
  893.     if (x > 0) {
  894.     conoc(LF);
  895.     conres();            /* So Ctrl-C/Y will work */
  896.     } else {
  897.     z = 0;
  898.     goto typexit;
  899.     }
  900. #endif /* VMS */
  901.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  902. #ifdef MAC
  903.     /*
  904.      * It is expensive to run the miniparser so don't do it for
  905.      * every character.
  906.      */
  907.     if (--count < 0) {
  908.         count = 100;
  909.         miniparser(1);
  910.         if (sstate == 'a') {
  911.         sstate = '\0';
  912.         z = 0;
  913.         break;
  914.         }
  915.     }
  916.     putchar(c);
  917. #else /* Not MAC */
  918.     if (tr_int) {            /* Interrupted? */
  919.         printf("^C...\n");        /* Print message */
  920.         z = 0;
  921.         break;
  922.     }
  923.     if (conoc(c) < 0) {        /* Echo character on screen */
  924.         z = 0;
  925.         break;
  926. #endif /* MAC */
  927.     }
  928.  
  929. typexit:
  930.  
  931. #ifndef AMIGA
  932. #ifndef MAC
  933.     signal(SIGINT,oldsig);        /* put old signal action back. */
  934. #endif /* MAC */
  935. #endif /* AMIGA */
  936.  
  937.     tr_int = 0;
  938. #ifdef VMS
  939.     concb(escape);            /* Get back in command-parsing mode, */
  940. #endif /* VMS */
  941.     zclose(ZIFILE);            /* close file, */
  942.     return(z);                /* and return successfully. */
  943. }
  944. #endif /* MAC */
  945.  
  946. #ifndef NOCSETS
  947.  
  948. _PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
  949. _PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
  950. _PROTOTYP( CHAR zl1as, (CHAR) );    /* Latin-1 to ascii */
  951. _PROTOTYP( CHAR xl1as, (CHAR) );    /* ditto */
  952.  
  953. /*  X L A T E  --  Translate a local file from one character set to another */
  954.  
  955. /*
  956.   Translates input file (fin) from character set csin to character set csout
  957.   and puts the result in the output file (fout).  The two character sets are
  958.   file character sets from fcstab.
  959. */
  960.  
  961. int
  962. xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
  963.  
  964. #ifndef MAC
  965.     SIGTYP (* oldsig)();        /* For saving old interrupt trap. */
  966. #endif /* MAC */
  967.     int filecode;            /* Code for output file */
  968.  
  969.     int z = 1;                /* Return code. */
  970.     int c, tcs;                /* Workers */
  971.  
  972.     if (zopeni(ZIFILE,fin) == 0) {    /* Open the file to be translated */
  973.     printf("?Can't open input file %s\n",fin);
  974.     return(0);
  975.     }
  976. #ifdef MAC
  977. /*
  978.   If user specified no output file, it goes to the screen.  For the Mac,
  979.   this must be done a special way (result goes to a new window); the Mac
  980.   doesn't have a "controlling terminal" device name.
  981. */
  982.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
  983. #else
  984. #ifdef VMS
  985.     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
  986. #else
  987.     filecode = ZOFILE;
  988. #endif /* VMS */
  989. #endif /* MAC */
  990.  
  991.     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
  992.     printf("?Can't open output file %s\n",fout);
  993.     return(0);
  994.     }
  995. #ifndef AMIGA
  996. #ifndef MAC
  997.     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
  998. #endif /* MAC */
  999. #endif /* AMIGA */
  1000.  
  1001.     tr_int = 0;                /* Have not been interrupted (yet). */
  1002.     z = 1;                /* Return code presumed good. */
  1003.  
  1004.     tcs = gettcs(csin,csout);        /* Get intermediate set. */
  1005.  
  1006.     printf("%s (%s) => %s (%s)\n",    /* Say what we're doing. */
  1007.        fin, fcsinfo[csin].name,
  1008.        fout,fcsinfo[csout].name
  1009.     );
  1010.     printf("via %s", tcsinfo[tcs].name);
  1011.     if (language)
  1012.       printf(", language: %s\n",langs[language].description);
  1013.     printf("\n\n");
  1014.  
  1015.     if (csin == csout) {        /* Input and output sets the same? */
  1016.     sxx = rxx = NULL;        /* If so, no translation. */
  1017.     } else {                /* Otherwise, set up */
  1018.     sxx = xls[tcs][csin];        /* translation function */
  1019.     rxx = xlr[tcs][csout];        /* pointers. */
  1020.     if (rxx == zl1as) rxx = xl1as;
  1021.     }
  1022.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  1023.     if (tr_int) {            /* Interrupted? */
  1024.         printf("^C...\n");        /* Print message */
  1025.         z = 0;
  1026.         break;
  1027.     }
  1028.     if (sxx) c = (*sxx)((CHAR)c);    /* From fcs1 to tcs */
  1029.     if (rxx) c = (*rxx)((CHAR)c);    /* from tcs to fcs2 */
  1030.  
  1031.     if (zchout(filecode,(char)c) < 0) { /* Output the xlated character */
  1032.         printf("File output error\n");
  1033.         z = 0;
  1034.         break;
  1035.     }
  1036.     }
  1037. #ifndef AMIGA
  1038. #ifndef MAC
  1039.     signal(SIGINT,oldsig);        /* put old signal action back. */
  1040. #endif /* MAC */
  1041. #endif /* AMIGA */
  1042.  
  1043.     tr_int = 0;
  1044.     zclose(ZIFILE);            /* close files, */
  1045.     zclose(filecode);
  1046.     return(z);                /* and return successfully. */
  1047. }
  1048. #endif /* NOCSETS */
  1049.  
  1050. /*  D O L O G  --  Do the log command  */
  1051.  
  1052. int
  1053. dolog(x) int x; {
  1054.     int y, disp; char *s;
  1055.  
  1056.     switch (x) {
  1057.  
  1058. #ifdef DEBUG
  1059.     case LOGD:
  1060.         y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
  1061.         break;
  1062. #endif /* DEBUG */
  1063.  
  1064.     case LOGP:
  1065.         y = cmofi("Name of packet log file","packet.log",&s,xxstring);
  1066.         break;
  1067.  
  1068. #ifndef NOLOCAL
  1069.     case LOGS:
  1070.         y = cmofi("Name of session log file","session.log",&s,xxstring);
  1071.         break;
  1072. #endif /* NOLOCAL */
  1073.  
  1074. #ifdef TLOG
  1075.     case LOGT:
  1076.         y = cmofi("Name of transaction log file","transact.log",&s,
  1077.               xxstring);
  1078.         break;
  1079. #endif /* TLOG */
  1080.  
  1081.     default:
  1082.         printf("\n?Unknown log designator - %d\n",x);
  1083.         return(-2);
  1084.     }
  1085.     if (y < 0) return(y);
  1086.     if (y == 2) {
  1087.     printf("?Sorry, %s is a directory name\n",s);
  1088.     return(-9);
  1089.     }
  1090.     strcpy(line,s);
  1091.     s = line;
  1092. #ifdef MAC
  1093.     y = 0;
  1094. #else
  1095.     if ((y = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
  1096.       return(y);
  1097. #endif /* MAC */
  1098.     disp = y;    
  1099.     if ((y = cmcfm()) < 0) return(y);
  1100.  
  1101.     switch (x) {
  1102.  
  1103. #ifdef DEBUG
  1104.     case LOGD:
  1105.         return(deblog = debopn(s,disp));
  1106. #endif /* DEBUG */
  1107.  
  1108.     case LOGP:
  1109.         return(pktlog = pktopn(s,disp));
  1110.  
  1111. #ifndef NOLOCAL
  1112.     case LOGS:
  1113.         return(seslog = sesopn(s,disp));
  1114. #endif /* NOLOCAL */
  1115.  
  1116. #ifdef TLOG
  1117.     case LOGT:
  1118.         return(tralog = traopn(s,disp));
  1119. #endif /* TLOG */
  1120.  
  1121.     default:
  1122.         return(-2);
  1123.     }
  1124. }
  1125.  
  1126. int
  1127. pktopn(s,disp) char *s; int disp; {
  1128.     extern char pktfil[];
  1129.     static struct filinfo xx;
  1130.     int y;
  1131.  
  1132.     zclose(ZPFILE);
  1133.     if(s[0] == '\0') return(0);
  1134.     if (disp) {
  1135.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  1136.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  1137.     xx.lblopts = 0;
  1138.     y = zopeno(ZPFILE,s,NULL,&xx);
  1139.     } else y = zopeno(ZPFILE,s,NULL,NULL);
  1140.     if (y > 0)
  1141.       strcpy(pktfil,s);
  1142.     else
  1143.       *pktfil = '\0';
  1144.     return(y);
  1145. }
  1146.  
  1147. int
  1148. traopn(s,disp) char *s; int disp; {
  1149. #ifdef TLOG
  1150.     extern char trafil[];
  1151.     static struct filinfo xx;
  1152.     int y;
  1153.  
  1154.     zclose(ZTFILE);
  1155.     if(s[0] == '\0') return(0);
  1156.     if (disp) {
  1157.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  1158.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  1159.     xx.lblopts = 0;
  1160.     y = zopeno(ZTFILE,s,NULL,&xx);
  1161.     } else y = zopeno(ZTFILE,s,NULL,NULL);
  1162.     if (y > 0) {
  1163.     strcpy(trafil,s);
  1164.     tlog(F110,"Transaction Log:",versio,0L);
  1165. #ifndef MAC
  1166.     tlog(F100,ckxsys,"",0L);
  1167. #endif /* MAC */
  1168.     ztime(&s);
  1169.     tlog(F100,s,"",0L);
  1170.     } else *trafil = '\0';
  1171.     return(y);
  1172. #else
  1173.     return(0);
  1174. #endif
  1175. }
  1176.  
  1177. #ifndef NOLOCAL
  1178. int
  1179. sesopn(s,disp) char * s; int disp; {
  1180.     extern char sesfil[];
  1181.     static struct filinfo xx;
  1182.     int y;
  1183.  
  1184.     zclose(ZSFILE);
  1185.     if(s[0] == '\0') return(0);
  1186.     if (disp) {
  1187.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  1188.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  1189.     xx.lblopts = 0;
  1190.     y = zopeno(ZSFILE,s,NULL,&xx);
  1191.     } else y = zopeno(ZSFILE,s,NULL,NULL);
  1192.     if (y > 0)
  1193.       strcpy(sesfil,s);
  1194.     else
  1195.       *sesfil = '\0';
  1196.     return(y);
  1197. }
  1198. #endif /* NOLOCAL */
  1199.  
  1200. int
  1201. debopn(s,disp) char *s; int disp; {
  1202. #ifdef DEBUG
  1203.     char *tp;
  1204.     static struct filinfo xx;
  1205.  
  1206.     zclose(ZDFILE);
  1207.  
  1208.     if (disp) {
  1209.     xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  1210.     xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
  1211.     xx.lblopts = 0;
  1212.     deblog = zopeno(ZDFILE,s,NULL,&xx);
  1213.     } else deblog = zopeno(ZDFILE,s,NULL,NULL);
  1214.     if (deblog > 0) {
  1215.     strcpy(debfil,s);
  1216.     debug(F110,"Debug Log ",versio,0);
  1217. #ifndef MAC
  1218.     debug(F100,ckxsys,"",0);
  1219. #endif /* MAC */
  1220.     ztime(&tp);
  1221.     debug(F100,tp,"",0);
  1222.     } else *debfil = '\0';
  1223.     return(deblog);
  1224. #else
  1225.     return(0);
  1226. #endif
  1227. }
  1228.  
  1229. #ifndef NOSHOW
  1230.  
  1231. /*  S H O P A R  --  Show Parameters  */
  1232.  
  1233. #ifdef ANYX25
  1234. VOID
  1235. shox25() {
  1236.     if (nettype == NET_SX25) {
  1237.     printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
  1238.     if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  1239.     printf("\n Reverse charge call %s",
  1240.            revcall ? "selected" : "not selected");
  1241.     printf (", Closed user group ");
  1242.     if (closgr > -1)
  1243.       printf ("%d",closgr);
  1244.     else
  1245.       printf ("not selected");
  1246.     printf (",");
  1247.     printf("\n Call user data %s.\n", cudata ? udata : "not selected");
  1248.     } else if (nettype == NET_VX25) {
  1249.     if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
  1250.     printf("\n Reverse charge call %s",
  1251.            revcall ? "selected" : "not selected");
  1252.     printf (", Closed user group [unsupported]");
  1253.     if (closgr > -1)
  1254.       printf ("%d",closgr);
  1255.     else
  1256.       printf ("not selected");
  1257.     printf (",");
  1258.     printf("\n Call user data %s.\n", cudata ? udata : "not selected");
  1259.     }
  1260. }
  1261. #endif /* ANYX25 */
  1262.  
  1263. VOID
  1264. shoparc() {
  1265.     int i; char *s;
  1266.     long zz;
  1267.  
  1268.     printf("Communications Parameters:\n");
  1269.  
  1270.     if (network) {
  1271.     printf(" Host: %s",ttname);
  1272.     } else {
  1273.     printf(" Line: %s, speed: ",ttname);
  1274.     if ((zz = ttgspd()) < 0) {
  1275.         printf("unknown");
  1276.         } else {
  1277.         if (speed == 8880) printf("75/1200"); else printf("%ld",zz);
  1278.     }
  1279.     }
  1280.     printf(", mode: ");
  1281.     if (local) printf("local"); else printf("remote");
  1282.     if (network == 0) {
  1283.     printf(", modem: %s",gmdmtyp());
  1284.     } else {
  1285.     if (nettype == NET_TCPA) printf(", TCP/IP");
  1286.     if (nettype == NET_TCPB) printf(", TCP/IP");
  1287.         if (nettype == NET_DEC) {
  1288.           if ( ttnproto == NP_LAT ) printf(", DECnet LAT");
  1289.           else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
  1290.           else printf(", DECnet");
  1291.         }
  1292.         if (nettype == NET_PIPE) printf(", Named Pipes");
  1293. #ifdef ANYX25
  1294.     shox25();
  1295. #endif /* ANYX25 */
  1296.     if (ttnproto == NP_TELNET) printf(", telnet protocol");
  1297.     }
  1298.     if (local) {
  1299.     i = parity ? 7 : 8;
  1300.     if (i == 8) i = (cmask == 0177) ? 7 : 8;
  1301.     printf("\n Terminal bits: %d, p",i);
  1302.     } else printf("\n P");
  1303.     printf("arity: %s",parnam((char)parity));
  1304.     printf(", duplex: ");
  1305.     if (duplex) printf("half, "); else printf("full, ");
  1306.     printf("flow: ");
  1307.     if (flow == FLO_KEEP) printf("keep");
  1308.         else if (flow == FLO_XONX) printf("xon/xoff");
  1309.     else if (flow == FLO_NONE) printf("none");
  1310.     else if (flow == FLO_RTSC) printf(network ? "none" : "rts/cts");
  1311.     else if (flow == FLO_DTRT) printf(network ? "none" : "dtr/cts");
  1312.         else if (flow == FLO_DTRC) printf(network ? "none" : "dtr/cd");
  1313.     else printf("%d",flow);
  1314.     printf(", handshake: ");
  1315.     if (turn) printf("%d\n",turnch); else printf("none\n");
  1316.     if (local && !network) {        /* Lockfile & carrier stuff */
  1317.     if (carrier == CAR_OFF) s = "off";
  1318.     else if (carrier == CAR_ON) s = "on";
  1319.     else if (carrier == CAR_AUT) s = "auto";
  1320.     else s = "unknown";
  1321.     printf(" Carrier: %s", s);
  1322.     if (carrier == CAR_ON) {
  1323.         if (cdtimo) printf(", timeout: %d sec", cdtimo);
  1324.         else printf(", timeout: none");
  1325.     }
  1326. #ifdef UNIX
  1327.     if (haslock && *flfnam) {    /* Lockfiles only apply to UNIX... */
  1328.         printf(", lockfile: %s",flfnam);
  1329.     }
  1330. #endif /* UNIX */
  1331.     printf("\n Escape character: %d (^%c)\n",escape,ctl(escape));
  1332.     }
  1333. }
  1334.  
  1335. #ifdef TNCODE
  1336. static VOID
  1337. shotel() {
  1338.     printf("SET TELNET parameters:\n echo: %s\n newline-mode: ",
  1339.        tn_duplex ? "local" : "remote");
  1340.     switch (tn_nlm) {
  1341.       case TNL_CRNUL: printf("%s\n","off"); break;
  1342.       case TNL_CRLF:  printf("%s\n","on"); break;
  1343.       case TNL_CR:    printf("%s\n","raw"); break;
  1344.     }
  1345.     printf(" terminal-type: ");
  1346.     if (tn_term) {
  1347.     printf("%s\n",tn_term);
  1348.     } else {
  1349.     char *p;
  1350. #ifdef OS2
  1351.     p = (tt_type >= 0 && tt_type <= max_tt) ?
  1352.       tt_info[tt_type].x_name :
  1353.         "UNKNOWN";
  1354. #else
  1355.     p = getenv("TERM");
  1356. #endif /* OS2 */
  1357.     if (p)
  1358.       printf("none (%s will be used)\n",p);
  1359.     else printf("none\n");
  1360.     }
  1361. }
  1362. #endif /* TNCODE */
  1363.  
  1364. #ifdef CK_NETBIOS 
  1365. static VOID
  1366. shonb() {
  1367.    printf("NETBIOS parameters:\n");
  1368.    printf(" API       : %s\n",
  1369.       NetbeuiAPI ? "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
  1370.       : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
  1371.    printf(" Local Name: [%s]\n", NetBiosName ) ;
  1372.    printf(" Adapter   : %d\n", NetBiosAdapter ) ;
  1373.    if ( NetBiosLSN > -1 )
  1374.       printf(" Session   : %d\n", NetBiosLSN ) ;
  1375.    else
  1376.       printf(" Session   : none active\n") ;
  1377. }
  1378. #endif /* CK_NETBIOS */
  1379.  
  1380. VOID
  1381. shonet() {
  1382. #ifndef NETCONN
  1383.     printf("\nNo networks are supported in this version of C-Kermit\n");
  1384. #else
  1385. #ifdef OS2
  1386.     printf("\nAvailable networks:\n");
  1387. #else
  1388.     printf("\nSupported networks:\n");
  1389. #endif /* OS2 */
  1390.  
  1391. #ifdef VMS
  1392.  
  1393. #ifdef MULTINET
  1394.     printf(" TGV MultiNet TCP/IP");
  1395. #else
  1396. #ifdef WINTCP
  1397.     printf(" WOLLONGONG WIN/TCP");
  1398. #else
  1399. #ifdef DEC_TCPIP
  1400.     {
  1401.     static    $DESCRIPTOR(tcp_desc,"_TCP0:");
  1402.         int    status;
  1403.     long    devclass;
  1404.     static    int    itmcod = DVI$_DEVCLASS;
  1405.  
  1406.     status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
  1407.     if ((status & 1) && (devclass == DC$_SCOM))
  1408.         printf(" Process Software Corporation TCPware for OpenVMS");
  1409.     else
  1410.         printf(" DEC TCP/IP Services for (Open)VMS");
  1411.     }
  1412. #else
  1413. #ifdef CMU_TCPIP
  1414.     printf(" CMU-OpenVMS/IP");
  1415. #else
  1416.     printf(" None");
  1417. #endif /* CMU_TCPIP */
  1418. #endif /* DEC_TCPIP */
  1419. #endif /* WINTCP */
  1420. #endif /* MULTINET */
  1421. #ifdef TNCODE
  1422.     printf(", TELNET protocol\n\n");
  1423.     shotel();
  1424. #endif /* TNCODE */
  1425.     printf("\n");
  1426.  
  1427. #else /* Not VMS */
  1428.  
  1429. #ifdef SUNX25
  1430.     printf(" SunLink X.25\n");
  1431. #endif /* SUNX25 */
  1432. #ifdef STRATUSX25
  1433.     printf(" Stratus VOS X.25\n");
  1434. #endif /* STRATUSX25 */
  1435. #ifdef DECNET
  1436. #ifdef OS2
  1437.     if (dnet_avail) printf(" DECnet, LAT protocol\n");
  1438. #else
  1439.     printf(" DECnet\n");
  1440. #endif /* OS2 */
  1441. #endif /* DECNET */
  1442. #ifdef NPIPE
  1443.     printf(" Named Pipe\n");
  1444. #endif /* NPIPE */
  1445. #ifdef CK_NETBIOS
  1446.     if (netbiosAvail)
  1447.       printf(" NetBIOS\n");
  1448. #endif /* CK_NETBIOS */
  1449. #ifdef TCPSOCKET
  1450.     if (
  1451. #ifdef OS2
  1452.     tcp_avail
  1453. #else
  1454.     1
  1455. #endif /* OS2 */
  1456.     ) {
  1457. #ifdef OS2
  1458.     printf(" TCP/IP via %s\n", tcpname);
  1459. #else
  1460.     printf(" TCP/IP\n");
  1461. #endif /* OS2 */
  1462. #ifdef TNCODE
  1463.     if (nettype == NET_TCPB) {
  1464.         printf("\n");
  1465.         shotel();
  1466.     }
  1467. #endif /* TNCODE */
  1468.     }
  1469. #ifdef OS2
  1470.     else if (tcpname[0]) printf(" %s\n",tcpname);
  1471. #endif /* OS2 */
  1472. #endif /* TCPSOCKET */
  1473.  
  1474. #ifdef CK_NETBIOS 
  1475.     if (netbiosAvail && nettype == NET_BIOS) {
  1476.        printf("\n") ;
  1477.        shonb();
  1478.     } else printf("\n");
  1479. #endif /* CK_NETBIOS */
  1480.  
  1481. #endif /* VMS */
  1482.  
  1483. #ifdef COMMENT
  1484.     printf("\nCurrent network type:\n");
  1485.     if (nettype == NET_TCPA || nettype == NET_TCPB)
  1486.       printf(" TCP/IP\n");
  1487. #ifdef SUNX25
  1488.     else if (nettype == NET_SX25) printf(" X.25\n");
  1489. #endif /* SUNX25 */
  1490.  
  1491. #ifdef STRATUSX25
  1492.     else if (nettype == NET_VX25) printf(" X.25\n");
  1493. #endif /* STRATUSX25 */
  1494.  
  1495. #ifdef DECNET
  1496.     else if (nettype == NET_DEC) printf(" DECnet\n");
  1497. #endif /* DECNET */
  1498.  
  1499. #ifdef NPIPE
  1500.     else if (nettype == NET_PIPE) printf(" Named Pipes\n");
  1501. #endif /* NPIPE */
  1502.  
  1503. #ifdef CK_NETBIOS
  1504.     else if (nettype == NET_BIOS) printf(" NetBIOS\n");
  1505. #endif /* CK_NETBIOS */
  1506. #endif /* COMMENT */
  1507.     printf("\nActive network connection:\n");
  1508.  
  1509.     if (network) {
  1510.     printf(" Host: %s",ttname);
  1511.     if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
  1512.       printf(" [%s]",ipaddr);
  1513.     } else printf(" Host: none");
  1514.     printf(" via: ");
  1515.     if (nettype == NET_TCPA || nettype == NET_TCPB) printf("tcp/ip\n");
  1516.     else if (nettype == NET_SX25) printf("SunLink X.25\n");
  1517.     else if (nettype == NET_VX25) printf("Stratus VOS X.25\n");
  1518.     else if (nettype == NET_DEC) {
  1519.         if ( ttnproto == NP_LAT ) printf("DECnet LAT\n");
  1520.         else if ( ttnproto == NP_CTERM ) printf("DECnet CTERM\n");
  1521.         else printf("DECnet\n");
  1522.         } else if (nettype == NET_PIPE) printf("Named Pipes\n");
  1523.     else if (nettype == NET_BIOS) printf("NetBIOS\n");
  1524. #ifdef ANYX25
  1525.     if (nettype == NET_SX25 || nettype == NET_VX25) shox25();
  1526. #endif /* ANYX25 */
  1527. #ifdef TNCODE
  1528.     if (ttnproto == NP_TELNET) {
  1529.         printf(" TELNET protocol\n");
  1530.         printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
  1531.     }
  1532. #endif /* TNCODE */
  1533.     printf("\n");
  1534. #endif /* NETCONN */
  1535. }
  1536.  
  1537. #ifndef NODIAL
  1538.  
  1539. VOID
  1540. shodial() {
  1541.     if (mdmtyp >= 0 || local != 0) doshodial();
  1542. }
  1543.  
  1544. static VOID
  1545. shods(s) char *s; {            /* Show a dial-related string */
  1546.     char c;
  1547.     if (s == NULL || !(*s)) {        /* Empty? */
  1548.     printf("(none)\n");
  1549.     } else {                /* Not empty. */
  1550.     while (c = *s++)             /* Can contain controls */
  1551.       if (c > 31 && c < 127) { putchar(c); } /* so display them */
  1552.       else printf("\\{%d}",c);         /* in backslash notation */
  1553.     printf("\n");
  1554.     }
  1555. }
  1556.  
  1557. int
  1558. doshodial() {
  1559.     printf(" Dial directory: %s\n",dialdir ? dialdir : "(none)");
  1560.     printf(" Dial hangup: %s, dial modem-hangup: %s\n",
  1561.        dialhng ? "on" : "off", dialmhu ? "on" : "off") ;
  1562.     printf(" Dial kermit-spoof: %s",dialksp ? "on" : "off");
  1563.     printf(", dial display: %s\n",dialdpy ? "on" : "off");
  1564.     printf(" Dial speed-matching: %s",mdmspd ? "on" : "off");
  1565.     printf(", dial mnp-enable: %s\n",dialmnp ? "on" : "off");
  1566.     printf(" Dial init-string: ");
  1567.     shods(getdws(mdmtyp));        /* Ask dial module for it */
  1568.     printf(" Dial dial-command: ");
  1569.     shods(getdcs(mdmtyp));        /* Ask dial module for it */
  1570.     printf(" Dial prefix: ");
  1571.     shods(dialnpr);
  1572.     printf(" Dial timeout: ");
  1573.     if (dialtmo > 0)
  1574.       printf("%d sec", dialtmo);
  1575.     else
  1576.       printf("0 (auto)");
  1577.     printf(", Redial number: %s\n",dialnum ? dialnum : "(none)");
  1578.     return(0);
  1579. }
  1580. #endif /* NODIAL */
  1581.  
  1582. #ifdef ANYX25
  1583. VOID
  1584. shopad() {
  1585.     int i;
  1586.     printf("\nX.3 PAD Parameters:\n");
  1587.     for (i = 0; i < npadx3; i++)
  1588.       printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
  1589.          padparms[padx3tab[i].kwval]);
  1590. }
  1591. #endif /* ANYX25 */
  1592.  
  1593. /*  Show File Parameters */
  1594.  
  1595. VOID
  1596. shoparf() {
  1597.     char *s; int i;
  1598.     printf("\nFile parameters:       ");
  1599. #ifdef COMMENT
  1600.     printf("Blocksize:     %5d      ",fblksiz);
  1601. #endif /* COMMENT */
  1602.     printf(" Attributes:       ");
  1603.     if (atcapr) printf("on"); else printf("off");
  1604. #ifdef VMS
  1605.     printf("  Record-Length: %5d",frecl);
  1606. #endif /* VMS */
  1607.     printf("\n Names:   ");
  1608.     printf("%-12s",(fncnv) ? "converted" : "literal");
  1609. #ifdef DEBUG
  1610. #ifndef MAC
  1611.     printf("  Debugging Log:    ");
  1612.     if (deblog) printf("%s",debfil); else printf("none");
  1613. #endif /* MAC */
  1614. #endif /* DEBUG */
  1615.  
  1616.     printf("\n Type:    ");
  1617.     switch (binary) {
  1618.       case XYFT_T: s = "text";           break;
  1619. #ifdef VMS
  1620.       case XYFT_B: s = "binary fixed"; break;
  1621.       case XYFT_I: s = "image";        break;
  1622.       case XYFT_L: s = "labeled";      break;
  1623.       case XYFT_U: s = "binary undef"; break;
  1624. #else
  1625. #ifdef MAC
  1626.       case XYFT_B: s = "binary";       break;
  1627.       case XYFT_M: s = "macbinary";    break;
  1628. #else
  1629.       case XYFT_B: s = "binary";       break;
  1630. #ifdef CK_LABELED
  1631.       case XYFT_L: s = "labeled";      break;
  1632. #endif /* CK_LABELED */
  1633. #endif /* MAC */
  1634. #endif /* VMS */
  1635.       default: s = "?"; break;
  1636.     }
  1637.     printf("%-12s",s);
  1638. #ifdef COMMENT
  1639.     printf(" Organization:  ");
  1640.     switch (forg) {
  1641.       case XYFO_I: printf("%-10s","indexed"); break;
  1642.       case XYFO_R: printf("%-10s","relative"); break;
  1643.       case XYFO_S: printf("%-10s","sequential"); break;
  1644.     }
  1645. #endif /* COMMENT */
  1646. #ifndef MAC
  1647.     printf("  Packet Log:       ");
  1648.     if (pktlog) printf(pktfil); else printf("none");
  1649. #endif /* MAC */
  1650. #ifdef UNIX
  1651.     printf("  Longest filename: %d",maxnam);
  1652. #endif /* UNIX */
  1653.     printf("\n Collide: ");
  1654.     for (i = 0; i < ncolx; i++)
  1655.       if (colxtab[i].kwval == fncact) break;
  1656.     printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
  1657.  
  1658. #ifdef COMMENT
  1659.     printf(" Format:        ");
  1660.     switch (frecfm) {
  1661.       case XYFF_F:  printf("%-10s","fixed"); break;
  1662.       case XYFF_VB: printf("%-10s","rcw"); break;
  1663.       case XYFF_S:  printf("%-10s","stream"); break;
  1664.       case XYFF_U:  printf("%-10s","undefined"); break;
  1665.       case XYFF_V:  printf("%-10s","variable"); break;
  1666.     }
  1667. #endif /* COMMENT */
  1668. #ifndef MAC
  1669.     printf("  Session Log:      ");
  1670.     if (seslog) printf(sesfil); else printf("none");
  1671. #endif /* MAC */
  1672. #ifdef UNIX
  1673.     printf("  Longest pathname: %d",maxpath);
  1674. #endif /* UNIX */
  1675.     printf("\n Send Pathnames: %s", fnspath ? "off" : " on");
  1676.     printf("    Receive Pathnames: %s\n", fnrpath ? "off" : "on");
  1677.     printf(" Display: ");
  1678.     switch (fdispla) {
  1679.       case XYFD_N: printf("%-12s","none"); break;
  1680.       case XYFD_R: printf("%-12s","serial"); break;
  1681.       case XYFD_C: printf("%-12s","fullscreen"); break;
  1682.       case XYFD_S: printf("%-12s","crt"); break;
  1683.     }
  1684. #ifdef COMMENT
  1685.     printf("Carriage-Control: ");
  1686.     switch (fcctrl) {
  1687.       case XYFP_F: printf("%-10s","fortran"); break;
  1688.       case XYFP_N: printf("%-10s","newline"); break;
  1689.       case XYFP_P: printf("%-10s","machine"); break;
  1690.       case XYFP_X: printf("%-10s","none"); break;
  1691.     }
  1692. #endif /* COMMENT */
  1693. #ifdef TLOG
  1694. #ifndef MAC
  1695.     printf("  Transaction Log:  ");
  1696.     if (tralog) printf(trafil); else printf("none");
  1697. #endif /* MAC */
  1698. #endif /* TLOG */
  1699. #ifndef NOCSETS
  1700.     if (binary == XYFT_T) {
  1701.     shocharset();
  1702.     } else
  1703. #endif /* NOCSETS */
  1704.       printf("\n");
  1705.     printf("\nByte Size: %d",(fmask == 0177) ? 7 : 8);
  1706.     printf(", Incomplete: ");
  1707.     if (keep) printf("keep"); else printf("discard");
  1708. #ifdef KERMRC
  1709.     printf(", Init file: %s",
  1710. #ifdef CK_SYSINI
  1711.        CK_SYSINI
  1712. #else
  1713.        kermrc
  1714. #endif /* CK_SYSINI */
  1715.        );
  1716. #endif /* KERMRC */
  1717.     printf("\n");
  1718. }
  1719.  
  1720. VOID
  1721. shoparp() {
  1722.     printf("\nProtocol Parameters:   Send    Receive");
  1723.     if (timef)
  1724.       printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
  1725.     else
  1726.       printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
  1727. #ifndef NOSERVER
  1728.     printf("       Server Timeout:%4d",srvtim);
  1729. #endif /* NOSERVER */
  1730.     printf("\n Padding:      %11d%9d", npad,   mypadn);
  1731.     if (bctr == 4)
  1732.       printf("        Block Check: blank-free-2\n");
  1733.     else
  1734.       printf("        Block Check: %6d\n",bctr);
  1735.     printf(  " Pad Character:%11d%9d", padch,  mypadc);
  1736.     printf("        Delay:       %6d\n",delay);
  1737.     printf(  " Packet Start: %11d%9d", mystch, stchr);
  1738.     printf("        Max Retries: %6d\n",maxtry);
  1739.     printf(  " Packet End:   %11d%9d", seol,   eol);
  1740.     if (ebqflg)
  1741.       printf("        8th-Bit Prefix: '%c'",ebq);
  1742. #ifdef COMMENT
  1743. /*
  1744.   This is confusing.
  1745. */
  1746.     printf(  "\n Packet Length:%11d", spsizf ? spsizr : spsiz);
  1747.     printf( spsizf ? "*" : " " ); printf("%8d",  urpsiz);
  1748.     printf( (urpsiz > 94) ? " (94)" : "     ");
  1749. #else
  1750.     printf(  "\n Packet Length:%11d ", spmax);
  1751.     printf("%8d     ",  urpsiz);
  1752. #endif /* COMMENT */
  1753.     if (rptflg)
  1754.       printf("   Repeat Prefix:  '%c'",rptq);
  1755.     printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
  1756.     printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
  1757.     printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
  1758.     printf("        Locking-Shift:    ");
  1759.     if (lscapu == 2) {
  1760.     printf("forced\n");
  1761.     } else {
  1762.     printf("%s", (lscapr ? "enabled" : "disabled"));
  1763.     if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
  1764.     printf("\n");
  1765.     }
  1766. }
  1767.  
  1768. #ifndef NOCSETS
  1769. VOID
  1770. shoparl() {
  1771. #ifdef COMMENT
  1772.     int i;
  1773. /* Misleading... */
  1774.     printf("\nAvailable Languages:\n");
  1775.     for (i = 0; i < MAXLANG; i++) {
  1776.     printf(" %s\n",langs[i].description);
  1777.     }
  1778. #else
  1779.     printf("\nLanguage-specific translation rules: %s\n",
  1780.        language == L_USASCII ? "none" : langs[language].description);
  1781.     shocharset();
  1782.     printf("\n\n");
  1783. #endif /* COMMENT */
  1784. }
  1785.  
  1786. VOID
  1787. shocharset() {
  1788.     int x;
  1789.     printf("\n File Character-Set: %s (",fcsinfo[fcharset].name);
  1790.     if ((x = fcsinfo[fcharset].size) == 128) printf("7-bit)");
  1791.     else if (x == 256) printf("8-bit)");
  1792.     else printf("(multibyte)");
  1793.     printf("\n Transfer Character-Set");
  1794. #ifdef COMMENT
  1795.     if (tslevel == TS_L2)
  1796.       printf(": (international)");
  1797.     else
  1798. #endif /* COMMENT */
  1799.     if (tcharset == TC_TRANSP)
  1800.       printf(": Transparent");
  1801.     else
  1802.       printf(": %s",tcsinfo[tcharset].name);
  1803. }
  1804. #endif /* NOCSETS */
  1805.  
  1806. VOID
  1807. shopar() {
  1808. #ifndef MAC
  1809.     printf("\n%s,%s\n",versio,ckxsys);
  1810. #endif /* MAC */
  1811.     shoparc();
  1812.     shoparp();
  1813.     shoparf();
  1814. }
  1815. #endif /* NOSHOW */
  1816.  
  1817. /*  D O S T A T  --  Display file transfer statistics.  */
  1818.  
  1819. int
  1820. dostat() {
  1821.     extern long filrej;
  1822.     printf("\nMost recent transaction --\n\n");
  1823.     printf(" files transferred      : %ld\n",filcnt - filrej);
  1824.     printf(" files not transferred  : %ld\n",filrej);
  1825.     printf(" characters last file   : %ld\n",ffc);
  1826.     printf(" total file characters  : %ld\n",tfc);
  1827.     printf(" communication line in  : %ld\n",tlci);
  1828.     printf(" communication line out : %ld\n",tlco);
  1829.     printf(" packets sent           : %d\n", spackets);
  1830.     printf(" packets received       : %d\n", rpackets);
  1831.     printf(" damaged packets rec'd  : %d\n", crunched);
  1832.     printf(" timeouts               : %d\n", timeouts);
  1833.     printf(" retransmissions        : %d\n", retrans);
  1834.     if (filcnt > 0) {
  1835.     printf(" parity                 : %s",parnam((char)parity));
  1836.     if (autopar) printf(" (detected automatically)");
  1837.     printf("\n 8th bit prefixing      : ");
  1838.     if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
  1839.     printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
  1840.     printf(" window slots used      : %d of %d\n", wmax, wslotr);
  1841.     printf(" packet length          : %d (send), %d (receive)\n",
  1842.            spmax, urpsiz);
  1843.     printf(" compression            : ");
  1844.     if (rptflg)
  1845.       printf("yes [%c] (%ld)\n",(char) rptq,rptn);
  1846.     else
  1847.       printf("no\n");
  1848.     if (bctu == 4)
  1849.       printf(" block check type used  : blank-free-2\n");
  1850.     else
  1851.       printf(" block check type used  : %d\n",bctu);
  1852.     printf(" elapsed time           : %d sec\n",tsecs);
  1853.     if (speed <= 0L) speed = ttgspd();
  1854.     if (speed > 0L) {
  1855.         if (speed == 8880)
  1856.           printf(" transmission rate      : 75/1200 bps\n");
  1857.         else
  1858.           printf(" transmission rate      : %ld bps\n",speed);
  1859.     }
  1860.     if (tsecs > 0) {
  1861.         long ecps;            /* Effective data rate, cps */
  1862.         int eff;            /* Percent efficiency */
  1863.         ecps = tfc / (long) tsecs;
  1864.         printf(" effective data rate    : %ld cps\n", ecps);
  1865.         if (speed > 99L && speed != 8880L && network == 0) {
  1866.         eff = (((ecps * 100L) / (speed / 100L)) + 5L) / 10L;
  1867.         printf(" efficiency (percent)   : %d\n", eff);
  1868.         }
  1869.     }
  1870.     }
  1871.     return(1);
  1872. }
  1873.  
  1874. #ifndef NOLOCAL
  1875. /*  D O C O N E C T  --  Do the connect command  */
  1876. /*
  1877.   q = 0 means issue normal informational message about how to get back, etc.
  1878.   q != 0 means to skip the message.
  1879. */
  1880. int
  1881. doconect(q) int q; {
  1882.     int x;                /* Return code */
  1883.     extern int what;
  1884. #ifdef CK_APC
  1885.     extern int apcactive;        /* Nonzero = APC command was rec'd */
  1886.     extern int apcstatus;        /* ON, OFF, UNCHECKED */
  1887. #ifdef DCMDBUF
  1888.     extern char *apcbuf;        /* APC command buffer */
  1889. #else
  1890.     extern char apcbuf[];
  1891. #endif /* DCMDBUF */
  1892. #endif /* CK_APC */
  1893. #ifndef NOKVERBS            /* Keyboard macro material */
  1894.     extern int keymac, keymacx;
  1895. #endif /* NOKVERBS */
  1896.     int qsave;                /* For remembering "quiet" value */
  1897.  
  1898.     qsave = quiet;            /* Save it */
  1899.     if (!quiet)
  1900.       quiet = q;            /* Use argument temporarily */
  1901.     conres();                /* Put console back to normal */
  1902.     x = conect();            /* Connect the first time */
  1903.     concb((char)escape);        /* Restore console for commands */
  1904.  
  1905. #ifdef CK_APC
  1906. /*
  1907.   If an APC command was received during CONNECT mode, we define it now
  1908.   as a macro, execute the macro, and then return to CONNECT mode.
  1909.   We do this in a WHILE loop in case additional APCs come during subsequent
  1910.   CONNECT sessions.
  1911. */
  1912.     while (apcactive && apcstatus != APC_OFF) {
  1913.     domac("apc_commands",apcbuf);
  1914.     x = conect();            /* Re-CONNECT. */
  1915.     concb((char)escape);        /* Restore console. */
  1916.     }                    /* Loop back for more. */
  1917. #endif /* CK_APC */
  1918.  
  1919.     quiet = qsave;            /* Restore "quiet" value. */
  1920.  
  1921. #ifndef NOKVERBS
  1922.     if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
  1923.     keymac = 0;            /* Yes, unset the flag */
  1924.     return(dodo(keymacx,NULL));    /* Set up the macro and return */
  1925.     }
  1926. #endif /* NOKVERBS */
  1927.     what = W_COMMAND;            /* Back in command mode. */
  1928.     return(x);                /* Done. */
  1929. }
  1930. #endif /* NOLOCAL */
  1931.  
  1932. #ifndef NOSPL
  1933.  
  1934. /* The INPUT command */
  1935.  
  1936. #ifdef NETCONN
  1937. #ifndef IAC
  1938. #define IAC 255
  1939. #endif /* IAC */
  1940. #endif /* NETCONN */
  1941.  
  1942. /* Output buffering for "doinput" */
  1943.  
  1944. #ifdef pdp11
  1945. #define    MAXBURST 16        /* Maximum size of input burst */
  1946. #else
  1947. #define    MAXBURST 1024
  1948. #endif /* pdp11 */
  1949. static CHAR conbuf[MAXBURST];    /* Buffer to hold output for console */
  1950. static int concnt = 0;        /* Number of characters buffered */
  1951. static CHAR sesbuf[MAXBURST];    /* Buffer to hold output for session log */
  1952. static int sescnt = 0;        /* Number of characters buffered */
  1953.  
  1954. static VOID                /* Flush INPUT echoing */
  1955. myflsh() {                /* and session log output. */
  1956.     if (concnt > 0) {
  1957.     conxo(concnt, (char *) conbuf);
  1958.     concnt = 0;
  1959.     }
  1960.     if (sescnt > 0) {
  1961.     if (zsoutx(ZSFILE, (char *) sesbuf, sescnt) < 0)
  1962.       seslog = 0;
  1963.     sescnt = 0;
  1964.     }
  1965. }
  1966.  
  1967. /* Execute the INPUT and MINPUT commands */
  1968.  
  1969. int
  1970. doinput(timo,ms) int timo; char *ms[]; {
  1971.     int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
  1972.     int lastchar = 0;
  1973.     char *xp, *s;
  1974.     CHAR c;
  1975. #define CK_BURST
  1976. /*
  1977.   This enables the INPUT speedup code, which depends on ttchk() returning
  1978.   accurate information.  If INPUT fails with this code enabled, change the
  1979.   above "#define" to "#undef".
  1980. */
  1981. #ifdef CK_BURST
  1982.     int burst = 0;            /* Chars remaining in input burst */
  1983. #endif /* CK_BURST */
  1984.  
  1985. #ifndef NOLOCAL
  1986.     if (local) {            /* Put line in "ttvt" mode */
  1987.     y = ttvt(speed,flow);        /* if not already. */
  1988.     if (y < 0) {
  1989.         printf("?Can't condition line for INPUT\n");
  1990.         return(0);            /* Watch out for failure. */
  1991.     }
  1992.     }
  1993. #endif /* NOLOCAL */
  1994.  
  1995.     if (!ms[0]) {            /* If we were passed a NULL pointer */
  1996.     anychar = 1;            /*  ... */
  1997.     } else {
  1998.         y = (int)strlen(ms[0]);        /* Or if search string is empty */
  1999.         anychar = (y < 1);        /* any input character will do. */
  2000.     }
  2001. #ifndef NODEBUG
  2002.     debug(F101,"doinput","",anychar);
  2003.     y = -1;
  2004.     while (ms[++y]) debug(F111,"  ",ms[y],strlen(ms[y]));
  2005.     debug(F101,"doinput timo","",timo);
  2006.     debug(F101,"doinput echo","",inecho);
  2007. #endif /* NODEBUG */
  2008.     if (timo <= 0) timo = 1;        /* Give at least 1 second timeout */
  2009.     
  2010.     x = 0;                /* Return code, assume failure */
  2011.  
  2012.     for (y = 0; y < MINPMAX; y++)
  2013.       mi[y] = 0;            /* String pattern match position */
  2014.  
  2015.     if (!inpcas[cmdlvl]) {        /* INPUT CASE = IGNORE?  */
  2016.     y = -1;
  2017.  
  2018.     while(xp = ms[++y]) {
  2019.         while (*xp) {               /* Convert to lowercase */
  2020.         if (isupper(*xp)) *xp = tolower(*xp);
  2021.         xp++;
  2022.         }
  2023.         }
  2024.     }
  2025.     inpbps = inpbp;            /* Save current pointer. */
  2026.     rtimer();                /* Reset timer. */
  2027.     t = 0;                /* Time now is 0. */
  2028.     m_found = 0;            /* Default to timed-out */
  2029.     incount = 0;            /* Character counter */
  2030.  
  2031.     while (1) {                /* Character-getting loop */
  2032.     rt = (timo > t) ? timo - t : 1;    /* Read timer */
  2033.     debug(F101,"input rt","",rt);
  2034.     if (local) {            /* One case for local */
  2035.         y = ttinc(rt);        /* Get character from comm device */
  2036.         debug(F101,"input ttinc(rt) returns","",y);
  2037. #ifndef CK_BURST
  2038.         if (icn = conchk()) {    /* Interrupted from keyboard? */
  2039.         debug(F101,"input interrupted from keyboard","",icn);
  2040.         while (icn--) coninc(0); /* Yes, absorb what was typed. */
  2041.         break;            /* And fail. */
  2042.         }
  2043. #endif /* CK_BURST */
  2044.     } else {            /* Another for remote */
  2045.         y = coninc(rt);
  2046.         debug(F101,"input coninc(rt) returns","",y);
  2047.     }
  2048.     if (y > -1) {            /* A character arrived */
  2049. #ifdef TNCODE
  2050. /* Check for telnet protocol negotiation */
  2051.         if (network && (ttnproto == NP_TELNET) && ((y & 0xff) == IAC)) {
  2052.         myflsh();    /* Break from input burst for tn_doop() */
  2053. #ifdef CK_BURST
  2054.         burst = 0;
  2055. #endif /* CK_BURST */
  2056.         switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
  2057.           case 2: duplex = 0; continue;
  2058.           case 1: duplex = 1;
  2059.           default: continue;
  2060.         }
  2061.         }
  2062. #endif /* TNCODE */
  2063.  
  2064.         /* Real input character to be checked */
  2065.  
  2066. #ifdef CK_BURST
  2067.         burst--;            /* One less character waiting */
  2068. #endif /* CK_BURST */
  2069.         c = cmask & (CHAR) y;    /* Mask off parity */
  2070.  
  2071.         inchar[0] = c;        /* Remember character for \v(inchar) */
  2072. #ifdef CK_BURST
  2073.         /* Update "lastchar" time only once during input burst */
  2074.         if (burst <= 0)
  2075. #endif /* CK_BURST */
  2076.           lastchar = gtimer();    /* Remember when it came */
  2077.  
  2078.         if (c == '\0') {        /* NUL, we can't use it */
  2079.         if (anychar) {        /* Except if any character will do? */
  2080.             x = 1;        /* Yes, done. */
  2081.             incount = 1;    /* This must be the first and only. */
  2082.             break;
  2083.         } else continue;    /* Otherwise continue INPUTting */
  2084.         }
  2085.         *inpbp++ = c;        /* Store char in circular buffer */
  2086.         incount++;            /* Count it for \v(incount) */
  2087.  
  2088.         if (inpbp >= inpbuf + INPBUFSIZ) { /* Time to wrap around? */
  2089.         inpbp = inpbuf;        /* Yes. */
  2090.         *(inpbp+INPBUFSIZ-1) = NUL; /* Make it null-terminated. */
  2091.         }
  2092. #ifdef MAC
  2093.         {
  2094.         extern char *ttermw;    /* fake pointer cast */
  2095.         if (inecho) {
  2096.             outchar(ttermw, c);    /* echo to terminal window */
  2097.             /* this might be too much overhead to do here ? */
  2098.             updatecommand(ttermw);
  2099.         }
  2100.         }
  2101. #else /* Not MAC */
  2102.         if (inecho) conbuf[concnt++] = c; /* Buffer console output */
  2103. #endif /* MAC */
  2104.         if (seslog) {
  2105. #ifdef UNIX
  2106.         if (sessft != 0 || c != '\r')
  2107. #endif /* UNIX */
  2108.           sesbuf[sescnt++] = c;    /* Buffer session log output */
  2109.         }
  2110.         if (anychar) {        /* Any character will do? */
  2111.         x = 1;
  2112.         break;
  2113.         }
  2114.         if (!inpcas[cmdlvl]) {    /* Ignore alphabetic case? */
  2115.         if (isupper(c))        /* Yes, convert input char to lower */
  2116.           c = tolower(c);
  2117.         }
  2118.         debug(F000,"doinput char","",c);
  2119.         y = -1;            /* Loop thru search strings */
  2120.         while (s = ms[++y]) {    /* ...as many as we have. */
  2121.         i = mi[y];        /* Match-position in this one. */
  2122.         debug(F000,"compare char","",(CHAR)s[i]);
  2123.         if (c == (CHAR) s[i]) { /* Check for match */
  2124.             i++;        /* Got one, go to next character */
  2125.         } else {        /* Don't have a match */
  2126.             int j;
  2127.             for (j = i; i > 0; ) { /* Back up in search string */
  2128.             i--; /* (Do this here to prevent compiler foulup) */
  2129.             /* j is the length of the substring that matched */
  2130.             if (c == (CHAR) s[i]) {
  2131.                 if (!strncmp(s,&s[j-i],i)) {
  2132.                 i++;          /* c actually matches -- cfk */
  2133.                 break;
  2134.                 }
  2135.             }
  2136.             }
  2137.         }
  2138.         if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
  2139.             x = 1;        /* Yes, */
  2140.             break;        /* done. */
  2141.         }
  2142.         mi[y] = i;        /* No, remember match-position */
  2143.             }
  2144.         if (x == 1) {        /* Set \v(minput) result */
  2145.         m_found = y + 1;
  2146.         break;
  2147.         }
  2148.         }
  2149. #ifdef CK_BURST
  2150.     if (burst <= 0) {
  2151.         myflsh();            /* Flush buffered output */
  2152.         if (local) {        /* Get size of next input burst */
  2153.         burst = ttchk();
  2154.         if (icn = conchk()) {    /* Interrupted from keyboard? */
  2155.             debug(F101,"input interrupted from keyboard","",icn);
  2156.             while (icn--) coninc(0); /* Yes, absorb what was typed. */
  2157.             break;        /* And fail. */
  2158.         }
  2159.         } else {
  2160.         burst = conchk();
  2161.         }
  2162.         /* Prevent overflow of "conbuf" and "sesbuf" */
  2163.         if (burst > MAXBURST)
  2164.           burst = MAXBURST;
  2165.  
  2166.         if ((t = gtimer()) > timo)    /* Did not match, timer exceeded? */
  2167.           break;
  2168.         else if (insilence > 0 && (t - lastchar) > insilence)
  2169.           break;
  2170.     }
  2171. #else
  2172.     myflsh();            /* Flush buffered output */
  2173.     if ((t = gtimer()) > timo)    /* Did not match, timer exceeded? */
  2174.       break;
  2175.     else if (insilence > 0 && (t - lastchar) > insilence)
  2176.       break;
  2177. #endif /* CK_BURST */
  2178.     }                    /* Still have time left, continue. */
  2179.     myflsh();                /* Flush buffered output. */
  2180.     return(x);                /* Return the return code. */
  2181. }
  2182. #endif /* NOSPL */
  2183.  
  2184. #ifndef NOSPL
  2185. /* REINPUT Command */
  2186.  
  2187. /* Note, the timeout parameter is required, but ignored. */
  2188. /* Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. */
  2189. /* This function only looks at the characters already received */
  2190. /* and does not read any new characters from the communication line. */
  2191.  
  2192. int
  2193. doreinp(timo,s) int timo; char *s; {
  2194.     int x, y, i;
  2195.     char *xx, *xp, *xq = (char *)0;
  2196.     CHAR c;
  2197.  
  2198.     y = (int)strlen(s);
  2199.     debug(F111,"doreinput",s,y);
  2200.  
  2201.     x = 0;                /* Return code, assume failure */
  2202.     i = 0;                /* String pattern match position */
  2203.  
  2204.     if (!inpcas[cmdlvl]) {        /* INPUT CASE = IGNORE?  */
  2205.     xp = malloc(y+2);        /* Make a separate copy of the */
  2206.     if (!xp) {            /* search string. */
  2207.         printf("?malloc error 6\n");
  2208.         return(x);
  2209.     } else xq = xp;            /* Keep pointer to beginning. */
  2210.     while (*s) {            /* Yes, convert to lowercase */
  2211.         *xp = *s;
  2212.         if (isupper(*xp)) *xp = tolower(*xp);
  2213.         xp++; s++;
  2214.     }
  2215.     *xp = NUL;            /* Terminate it! */
  2216.     s = xq;                /* Move search pointer to it. */
  2217.     }
  2218.     xx = inpbp;                /* Current INPUT buffer pointer */
  2219.     do {
  2220.     c = *xx++;            /* Get next character */
  2221.     if (xx >= inpbuf + INPBUFSIZ) xx = inpbuf; /* Wrap around */
  2222.     if (!inpcas[cmdlvl]) {        /* Ignore alphabetic case? */
  2223.         if (isupper(c)) c = tolower(c); /* Yes */
  2224.     }
  2225.     debug(F000,"doreinp char","",c);
  2226.     debug(F000,"compare char","",(CHAR) s[i]);
  2227.     if (c == s[i]) {        /* Check for match */
  2228.         i++;            /* Got one, go to next character */
  2229.     } else {            /* Don't have a match */
  2230.            int j;
  2231.            for (j = i; i > 0; ) {    /* [jrs] search backwards for it  */
  2232.         i--;
  2233.            if (c == s[i]) {
  2234.             if (!strncmp(s,&s[j-i],i)) {
  2235.             i++;
  2236.             break;
  2237.             }
  2238.         }
  2239.            }
  2240.        }                /* [jrs] or return to zero from -1 */
  2241.     if (s[i] == '\0') {        /* Matched all the way to end? */
  2242.         x = 1;            /* Yes, */
  2243.         break;            /* done. */
  2244.     }
  2245.     } while (xx != inpbp);        /* Until back where we started. */
  2246.  
  2247.     if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
  2248.     return(x);                /* Return search result. */
  2249. }
  2250. #ifndef NOSPL
  2251.  
  2252. #endif /* NOSPL */
  2253. /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
  2254. /*  Z Z S T R I N G  --  (new name...)  */
  2255. /*
  2256.  Copies result to new string.
  2257.   strips enclosing braces or doublequotes.
  2258.   interprets backslash escapes.
  2259.   returns 0 on success, nonzero on failure.
  2260.   tries to be compatible with MS-DOS Kermit.
  2261.  
  2262.  Syntax of input string:
  2263.   string = chars | "chars" | {chars}
  2264.   chars = (c*e*)*
  2265.   where c = any printable character, ascii 32-126
  2266.   and e = a backslash escape
  2267.   and * means 0 or more repetitions of preceding quantity
  2268.   backslash escape = \operand
  2269.   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
  2270.   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
  2271.   radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
  2272. */
  2273.  
  2274. #ifndef NOFRILLS
  2275. int
  2276. yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
  2277.     int x;
  2278.     static char *new;
  2279.     new = *s2;
  2280.     if (!s || !new) return(-1);        /* Watch out for null pointers. */
  2281.     if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
  2282.     *new = '\0';
  2283.     return(0);
  2284.     }
  2285.     x--;                /* Otherwise, call self */
  2286.     *new++ = s[x];            /* to reverse rest of string. */
  2287.     s[x] = 0;
  2288.     return(yystring(s,&new));
  2289. }
  2290. #endif /* NOFRILLS */
  2291.  
  2292. #define FNVALL 1000
  2293. char fnval[FNVALL+2];            /* Return value */
  2294.  
  2295. char *                    /* Evaluate builtin function */
  2296. fneval(fn,argp,argn) char *fn, *argp[]; int argn; {
  2297.     int i, j, k, len1, len2, len3, n, x, y;
  2298.     char *bp[FNARGS];            /* Pointers to malloc'd strings */
  2299.     char *p, *s;
  2300.  
  2301.     if (!fn) fn = "";            /* Paranoia */
  2302.     debug(F111,"fneval",fn,argn);
  2303.     debug(F110,"fneval",argp[0],0);
  2304.     y = lookup(fnctab,fn,nfuncs,&x);
  2305.     if (y < 0)                /* bad function name */
  2306.       return("");            /* so value is null */
  2307.  
  2308. #ifdef DEBUG
  2309.     if (deblog) {
  2310.     int j;
  2311.     for (j = 0; j < argn; j++)
  2312.       debug(F111,"fneval function arg",argp[j],j);
  2313.     }
  2314. #endif /* DEBUG */
  2315.  
  2316.     if (y == FN_LIT)            /* literal(arg1) */
  2317.       return(argp[0] ? argp[0] : "");    /* return a pointer to arg itself */
  2318.  
  2319.     if (y == FN_CON) {            /* Contents of variable, unexpanded. */
  2320.     char c;
  2321.     if (!(p = argp[0]) || !*p) return("");
  2322.     if (*p == CMDQ) p++;
  2323.     if ((c = *p) == '%') {        /* Scalar variable. */
  2324.         c = *++p;            /* Get ID character. */
  2325.         p = "";            /* Assume definition is empty */
  2326.         if (!c) return(p);        /* Double paranoia */
  2327.         if (c >= '0' && c <= '9') { /* Digit for macro arg */
  2328.         c -= '0';        /* convert character to integer */
  2329.         if (maclvl < 0)        /* Digit variables are global */
  2330.           p = g_var[c];        /* if no macro is active */
  2331.         else            /* otherwise */
  2332.           p = m_arg[maclvl][c]; /* they're on the stack */
  2333.         } else {
  2334.         if (isupper(c)) c -= ('a'-'A');
  2335.         p = g_var[c];        /* Letter for global variable */
  2336.         }
  2337.         return(p ? p : "");
  2338.     }
  2339.     if (c == '&') {            /* Array reference. */
  2340.         int vbi, d;
  2341.         if (arraynam(p,&vbi,&d) < 0) /* Get name and subscript */
  2342.           return("");
  2343.         if (chkarray(vbi,d) > 0) {    /* Array is declared? */
  2344.         vbi -= 'a';        /* Convert name to index */
  2345.         if (a_dim[vbi] >= d) {    /* If subscript in range */
  2346.             char **ap;
  2347.             ap = a_ptr[vbi];    /* get data pointer */
  2348.             if (ap) {        /* and if there is one */
  2349.             return(ap[d]);    /* return what it points to */
  2350.             }
  2351.         }
  2352.         }
  2353.         return(p ? p : "");        /* Otherwise its enexpanded value. */
  2354.     }
  2355.     }
  2356.  
  2357.     for (i = 0; i < argn; i++) {    /* Not literal, expand the args */
  2358.     n = 1024;            /* allow 1K per expanded arg, yow! */
  2359.     bp[i] = s = malloc(n);        /* get the new space */
  2360.     if (bp[i] == NULL) {        /* handle failure to get space */
  2361.         for (k = 0; k < i; k++) if (bp[k]) free(bp[k]);
  2362.         debug(F101,"fneval malloc failure, arg","",i);
  2363.         return("");
  2364.     }
  2365.     p = argp[i] ? argp[i] : "";    /* Point to this argument */
  2366.  
  2367. /*
  2368.   Trim leading and trailing spaces from the original argument, before
  2369.   evaluation.  This code new to edit 184.
  2370. */
  2371.     if (y != FN_REP || i != 0) {    /* Don't trim 1st REPEAT argument */
  2372.         int j;            /* All others... */
  2373.         while (*p == SP || *p == HT) /* Point past leading whitespace */
  2374.           p++;
  2375.         j = (int) strlen(p) - 1;    /* Trim trailing whitespace */
  2376.         while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
  2377.           *(p + j--) = NUL;
  2378.     }
  2379.  
  2380. /* Now evaluate the argument */
  2381.  
  2382.     if (zzstring(p,&s,&n) < 0) {    /* Expand arg into new space */
  2383.         debug(F101,"fneval xxstring fails, arg","",i);
  2384.         for (k = 0; k <= i; k++)    /* Free up previous space on error */
  2385.           if (bp[k]) free(bp[k]);
  2386.         return("");            /* and return null string. */
  2387.     }
  2388.     debug(F111,"fneval arg",bp[i],i);
  2389.     }
  2390.  
  2391. #ifdef DEBUG
  2392.     if (deblog) {
  2393.     int j;
  2394.     for (j = 0; j < argn; j++) {
  2395.         debug(F111,"fneval arg post eval",argp[j],j);
  2396.         debug(F111,"fneval evaluated arg",bp[j],j);
  2397.     }
  2398.     }
  2399. #endif /* DEBUG */
  2400.  
  2401.     switch (y) {            /* Do function on expanded args */
  2402.  
  2403.       case FN_DEF:
  2404.     k = mlook(mactab,bp[0],nmac);    /* def(arg1) - Return a macro def */
  2405.     p = (k > -1) ? mactab[k].mval : "";
  2406.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2407.     return(p ? p : "");
  2408.  
  2409.       case FN_EVA:            /* eval(arg1) */
  2410.     p = evala(bp[0]);
  2411.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2412.     return(p ? p : "");
  2413.  
  2414.       case FN_EXE:            /* execute(arg1) */
  2415.     j = (int)strlen(s = bp[0]);    /* Length of macro invocation */
  2416.     p = "";                /* Initialize return value to null */
  2417.     if (j) {            /* If there is a macro to execute */
  2418.         while (*s == SP) s++,j--;    /* strip leading spaces */
  2419.         p = s;            /* remember beginning of macro name */
  2420.         for (i = 0; i < j; i++) {    /* find end of macro name */
  2421.         if (*s == SP) break;
  2422.         s++;
  2423.         }
  2424.         if (*s == SP) {        /* if there was a space after */
  2425.         *s++ = NUL;        /* terminate the macro name */
  2426.         while (*s == SP) s++;    /* skip past any extra spaces */
  2427.         } else s = "";        /* maybe there are no arguments */
  2428.         if (p && *p)
  2429.           k = mlook(mactab,p,nmac);    /* Look up the macro name */
  2430.         else k = -1;
  2431.  
  2432.         p = "";            /* Initialize return value */
  2433.         if (k >= 0) {        /* If macro found in table */
  2434.         if ((j = dodo(k,s)) > 0) { /* Go set it up (like DO cmd) */
  2435.             if (cmpush() > -1) { /* Push command parser state */
  2436.             extern int ifc;
  2437.             int ifcsav = ifc; /* Push IF condition on stack */
  2438.             k = parser(1);    /* Call parser to execute the macro */
  2439.             cmpop();    /* Pop command parser */
  2440.             ifc = ifcsav;    /* Restore IF condition */
  2441.             if (k == 0) {    /* No errors, ignore action cmds. */
  2442.                 p = mrval[maclvl+1]; /* If OK, set return value. */
  2443.                 if (p == NULL) p = "";
  2444.             }
  2445.             } else {        /* Can't push any more */
  2446.             debug(F100,"fexec pushed too deep","",0);
  2447.                         printf("\n?\\fexec() too deeply nested\n");
  2448.             while (cmpop() > -1) ;
  2449.             p = "";
  2450.             }
  2451.         }
  2452.         }
  2453.     }
  2454.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2455.     return(p ? p : "");
  2456.  
  2457.       case FN_FC:            /* File count. */
  2458.     p = fnval;
  2459.     *p = NUL;
  2460.     if (argn > 0) {
  2461.         k = zxpand(bp[0]);
  2462.         sprintf(fnval,"%d",k);
  2463.         for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2464.     }
  2465.     return(p);
  2466.  
  2467.       case FN_FIL:            /* Next file in list. */
  2468.     p = fnval;            /* (no args) */
  2469.     *p = NUL;
  2470.     znext(p);
  2471.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2472.     return(p ? p : "");
  2473.  
  2474.       case FN_IND:            /* index(arg1,arg2) */
  2475.     if (argn > 1) {            /* Only works if we have 2 args */
  2476.         int start;
  2477.         len1 = (int)strlen(bp[0]);    /* length of string to look for */
  2478.         len2 = (int)strlen(s = bp[1]); /* length of string to look in */
  2479.         if (len1 < 0) return("");    /* paranoia */
  2480.         if (len2 < 0) return("");
  2481.         j = len2 - len1;        /* length difference */
  2482.         start = 0;            /* starting position */
  2483.         if (argn > 2) {
  2484.         if (chknum(bp[2])) {
  2485.             start = atoi(bp[2]) - 1;
  2486.             if (start < 0) start = 0;
  2487.         }
  2488.         }
  2489.         if (j < 0 || start > j) {    /* search string is longer */
  2490.         p = "0";
  2491.         } else {
  2492.         if (!inpcas[cmdlvl]) {    /* input case ignore? */
  2493.             lower(bp[0]);
  2494.             lower(bp[1]);
  2495.         }
  2496.         s = bp[1] + start;    /* Point to beginning of target */
  2497.         p = "0";
  2498.         for (i = 0; i <= (j - start); i++) { /* Now compare */
  2499.             if (!strncmp(bp[0],s++,len1)) {
  2500.             sprintf(fnval,"%d",i+1+start);
  2501.             p = fnval;
  2502.             break;
  2503.             }
  2504.         }
  2505.         }
  2506.     } else p = "0";
  2507.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2508.     return(p);
  2509.  
  2510.       case FN_RPL:            /* replace(s1,s2,s3) */
  2511.     p = fnval;
  2512.     if (argn < 2) {            /* Only works if we have 2 or 3 args */
  2513.         strcpy(p,bp[0]);
  2514.     } else  {            
  2515.         len1 = (int)strlen(bp[0]);    /* length of string to look in */
  2516.         len2 = (int)strlen(bp[1]);    /* length of string to look for */
  2517.         len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
  2518.         j = len1 - len2 + 1;
  2519.         if (j < 1 || len1 == 0 || len2 == 0) { /* Args out of whack */
  2520.         strcpy(p,bp[0]);    /* so just return original string */
  2521.         } else {
  2522.         s = bp[0];        /* Point to beginning of string */
  2523.         while (j--) {        /* For each character */
  2524.             if (inpcas[cmdlvl] ?
  2525.             !strncmp(bp[1],s,len2) :
  2526.             !xxstrcmp(bp[1],s,len2) ) { /* To be replaced? */
  2527.             if (len3) {            /* Yes, */
  2528.                 strncpy(p,bp[2],len3);  /* replace it */
  2529.                 p += len3;
  2530.             }
  2531.             s += len2;                /* and skip past it. */
  2532.             } else {        /* No, */
  2533.             *p++ = *s++;    /* just copy this character */
  2534.             }
  2535.         }
  2536.         *p = NUL;
  2537.         }
  2538.     }
  2539.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2540.     return(p = fnval);
  2541.  
  2542.       case FN_CHR:            /* character(arg1) */
  2543.     if (chknum(bp[0])) {        /* Must be numeric */
  2544.         i = atoi(bp[0]);
  2545.         if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
  2546.         p = fnval;
  2547.         *p++ = i;
  2548.         *p = NUL;
  2549.         p = fnval;
  2550.         } else p = "";        /* Otherwise return null */
  2551.     } else p = "";            /* Otherwise return null */
  2552.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2553.     return(p);
  2554.  
  2555.       case FN_COD:            /* code(char) */
  2556.     p = "";
  2557.     if ((int)strlen(bp[0]) > 0) {
  2558.         p = fnval;
  2559.         i = *bp[0];
  2560.         sprintf(p,"%d",(i & 0xff));
  2561.     }
  2562.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2563.     return(p);
  2564.  
  2565.       case FN_LEN:            /* length(arg1) */
  2566.     p = fnval;
  2567.     sprintf(p,"%d",(int)strlen(bp[0]));
  2568.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2569.     return(p);
  2570.  
  2571.       case FN_LOW:            /* lower(arg1) */
  2572.     s = bp[0];
  2573.     p = fnval;
  2574.  
  2575.     while (*s) {
  2576.         if (isupper(*s))
  2577.           *p = tolower(*s);
  2578.         else
  2579.           *p = *s;
  2580.         p++; s++;
  2581.     }
  2582.     *p = NUL;
  2583.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2584.     p = fnval;
  2585.     return(p);
  2586.  
  2587.       case FN_MAX:            /* max(arg1,arg2) */
  2588.       case FN_MIN:            /* min(arg1,arg2) */
  2589.       case FN_MOD:            /* mod(arg1,arg2) */
  2590.     if (chknum(bp[0]) && chknum(bp[1])) {
  2591.         i = atoi(bp[0]);
  2592.         j = atoi(bp[1]);
  2593.         switch (y) {
  2594.           case FN_MAX:
  2595.         if (j < i) j = i;
  2596.         break;
  2597.           case FN_MIN:
  2598.         if (j > i) j = i;
  2599.         break;
  2600.           case FN_MOD:
  2601.         j = i % j;
  2602.         break;
  2603.         }
  2604.         p = fnval;
  2605.         sprintf(p,"%d",j);
  2606.     } else p = "";
  2607.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2608.     return(p);
  2609.  
  2610.       case FN_SUB:            /* substr(arg1,arg2,arg3) */
  2611.       case FN_RIG:            /* right(arg1,arg2) */
  2612.     if (((argn > 1) && (int)strlen(bp[1]) && !rdigits(bp[1])) ||
  2613.         ((y == FN_SUB) &&
  2614.         ((argn > 2) && (int)strlen(bp[2]) && !rdigits(bp[2])))) {
  2615.         p = "";            /* if either, return null */
  2616.     } else {
  2617.         int lx;
  2618.         p = fnval;                     /* pointer to result */
  2619.         lx = strlen(bp[0]);             /* length of arg1 */
  2620.         if (y == FN_SUB) {             /* substring */
  2621.         k = (argn > 2) ? atoi(bp[2]) : 1023; /* length */
  2622.         j = (argn > 1) ? atoi(bp[1]) : 1; /* start pos for substr */
  2623.         } else {                 /* right */
  2624.         k = (argn > 1) ? atoi(bp[1]) : lx; /* length */
  2625.         j = lx - k + 1;             /* start pos for right */
  2626.         if (j < 1) j = 1;
  2627.         }
  2628.         if (k > 0 && j <= lx) {          /* if start pos in range */
  2629.         s = bp[0]+j-1;             /* point to source string */
  2630.         for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
  2631.         }
  2632.         *p = NUL;            /* terminate the result */
  2633.         p = fnval;            /* and point to it. */
  2634.     }
  2635.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); /* Free temp mem */
  2636.     return(p);
  2637.  
  2638.       case FN_UPP:            /* upper(arg1) */
  2639.     s = bp[0];
  2640.     p = fnval;
  2641.     while (*s) {
  2642.         if (islower(*s))
  2643.           *p = toupper(*s);
  2644.         else
  2645.           *p = *s;
  2646.         p++; s++;
  2647.     }
  2648.     *p = NUL;
  2649.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2650.     p = fnval;
  2651.     return(p);
  2652.  
  2653.       case FN_REP:            /* Repeat */
  2654.     p = "";                /* Return value */
  2655.     if (chknum(bp[1])) {        /* Repeat count */
  2656.         n = atoi(bp[1]);
  2657.         if (n > 0) {        /* Make n copies */
  2658.         p = fnval;
  2659.         *p = '\0';
  2660.         k = (int)strlen(bp[0]);    /* Make sure string has some length */
  2661.         if (k > 0) {
  2662.             for (i = 0; i < n; i++) {
  2663.             s = bp[0];
  2664.             for (j = 0; j < k; j++) {
  2665.                 if ((p - fnval) >= FNVALL) { /* Protect against */
  2666.                 p = "";                 /* core dumps... */
  2667.                 break;
  2668.                 } else *p++ = *s++;
  2669.             }
  2670.             }
  2671.             *p = NUL;
  2672.         }
  2673.         }
  2674.     }
  2675.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2676.     p = fnval;
  2677.     return(p);
  2678.  
  2679. #ifndef NOFRILLS
  2680.       case FN_REV:
  2681.     p = fnval;
  2682.     yystring(bp[0],&p);
  2683.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2684.     return(p);
  2685. #endif /* NOFRILLS */
  2686.  
  2687.       case FN_RPA:            /* RPAD and LPAD */
  2688.       case FN_LPA:
  2689.     *fnval = NUL;            /* Return value */
  2690.     if (argn == 1) {        /* If a number wasn't given */
  2691.         p = fnval;            /* just return the original string */
  2692.         strncpy(p,bp[0],FNVALL);
  2693.     } else if (chknum(bp[1])) {    /* Repeat count */
  2694.         char pc;
  2695.         n = atoi(bp[1]);
  2696.         if (n >= 0) {        /* Pad it out */
  2697.         p = fnval;
  2698.         k = (int)strlen(bp[0]);    /* Length of string to be padded */
  2699.         pc = (argn < 3) ? SP : *bp[2]; /* Padding character */
  2700.         if (n > FNVALL) n = FNVALL-1; /* protect against overruns */
  2701.         if (k > FNVALL) k = FNVALL-1; /* and silly args. */
  2702.                 if (k > n) k = n;
  2703.         if (y == FN_RPA) {    /* RPAD */
  2704.             strncpy(p,bp[0],k);
  2705.             p += k;
  2706.             for (i = k; i < n; i++)
  2707.               *p++ = pc;
  2708.         } else {        /* LPAD */
  2709.             n -= k;
  2710.             for (i = 0; i < n; i++)
  2711.               *p++ = pc;
  2712.             strncpy(p,bp[0],k);
  2713.             p += k;
  2714.         }
  2715.         *p = NUL;
  2716.         }
  2717.     }
  2718.     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2719.     p = fnval;
  2720.     return(p);
  2721.  
  2722. #ifdef ZFCDAT
  2723.       case FN_FD:            /* \fdate(filename) */
  2724.     p = fnval;
  2725.     *p = NUL;
  2726.     if (argn > 0) {
  2727.         sprintf(fnval,"%s",zfcdat(bp[0]));
  2728.         for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2729.     }
  2730.     return(p);
  2731. #endif /* ZFCDAT */
  2732.  
  2733.       case FN_FS:            /* \fsize(filename) */
  2734.     p = fnval;
  2735.     *p = NUL;
  2736.     if (argn > 0) {
  2737.         sprintf(fnval,"%ld",zchki(bp[0]));
  2738.         for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
  2739.     }
  2740.     return(p);
  2741.  
  2742.       default:
  2743.     return("");
  2744.     }
  2745. }
  2746. #endif /* NOSPL */
  2747.  
  2748. #ifndef NOSPL
  2749.  
  2750. char *                    /* Evaluate builtin variable */
  2751. nvlook(s) char *s; {
  2752.     int x, y;
  2753.     long z;
  2754.     char *p;
  2755.  
  2756.     x = 30;
  2757.     p = vvbuf;
  2758.     if (zzstring(s,&p,&x) < 0) {
  2759.     y = -1;
  2760.     } else {
  2761.     s = vvbuf;
  2762.     if ((y = lookup(vartab,s,nvars,&x)) < 0) return(NULL);
  2763.     }
  2764.     switch (y) {
  2765.       case VN_ARGC:            /* ARGC */
  2766.     sprintf(vvbuf,"%d",macargc[maclvl]);
  2767.     return(vvbuf);
  2768.  
  2769.       case VN_ARGS:            /* ARGS */
  2770.     sprintf(vvbuf,"%d",xargs);
  2771.     return(vvbuf);
  2772.  
  2773.       case VN_COUN:            /* COUNT */
  2774.     sprintf(vvbuf,"%d",count[cmdlvl]);
  2775.     return(vvbuf);
  2776.  
  2777.       case VN_DATE:            /* DATE */
  2778.     ztime(&p);            /* Get "asctime" string */
  2779.     if (p == NULL || *p == NUL) return(NULL);
  2780.     vvbuf[0] = p[8];        /* dd */
  2781.     vvbuf[1] = p[9];
  2782.     vvbuf[2] = SP;
  2783.     vvbuf[3] = p[4];        /* mmm */
  2784.     vvbuf[4] = p[5];
  2785.     vvbuf[5] = p[6];
  2786.     vvbuf[6] = SP;
  2787.     for (x = 20; x < 24; x++)    /* yyyy */
  2788.       vvbuf[x - 13] = p[x];
  2789.     vvbuf[11] = NUL;
  2790.     return(vvbuf);
  2791.  
  2792.       case VN_NDAT:            /* Numeric date */
  2793.     ztime(&p);            /* Get "asctime" string */
  2794.     if (p == NULL || *p == NUL) return(NULL);
  2795.     for (x = 20; x < 24; x++)    /* yyyy */
  2796.       vvbuf[x - 20] = p[x];
  2797.         vvbuf[6] = (p[8] == ' ') ? '0' : p[8]; vvbuf[7] = p[9]; /* dd */
  2798.     for (x = 0; x < 12; x++)      /* mm */
  2799.       if (!strncmp(p+4,months[x],3)) break;
  2800.     if (x == 12) {
  2801.         vvbuf[4] = vvbuf[5] = '?';
  2802.     } else {
  2803.         x++;
  2804.         vvbuf[4] = (x < 10) ? '0' : '1';
  2805.         vvbuf[5] = (x % 10) + 48;
  2806.     }
  2807.     vvbuf[8] = NUL;
  2808.         return(vvbuf);
  2809.  
  2810.       case VN_DIRE:            /* DIRECTORY */
  2811.     return(zgtdir());
  2812.  
  2813.       case VN_FILE:            /* filespec */
  2814.     return(fspec);
  2815.  
  2816.       case VN_HOST:            /* host name */
  2817.     if (*myhost) {            /* If known */
  2818.         return(myhost);        /* return it. */
  2819.     } else {            /* Otherwise */
  2820.         strcpy(vvbuf,"unknown");    /* just say "unknown" */
  2821.         return(vvbuf);
  2822.     }
  2823.  
  2824.       case VN_SYST:            /* System type */
  2825. #ifdef UNIX
  2826.     strcpy(vvbuf,"UNIX");
  2827. #else
  2828. #ifdef VMS
  2829.     strcpy(vvbuf,"VMS");
  2830. #else
  2831. #ifdef OSK
  2832.     strcpy(vvbuf,"OS9/68K");
  2833. #else
  2834. #ifdef AMIGA
  2835.     strcpy(vvbuf,"Amiga");
  2836. #else
  2837. #ifdef MAC
  2838.     strcpy(vvbuf,"Macintosh");
  2839. #else
  2840. #ifdef OS2
  2841.     strcpy(vvbuf,"OS/2");
  2842. #else
  2843. #ifdef datageneral
  2844.     strcpy(vvbuf,"AOS/VS");
  2845. #else
  2846. #ifdef GEMDOS
  2847.     strcpy(vvbuf,"Atari_ST");
  2848. #else
  2849. #ifdef STRATUS
  2850.     strcpy(vvbuf,"Stratus_VOS");
  2851. #else
  2852.     strcpy(vvbuf,"unknown");
  2853. #endif /* STRATUS */
  2854. #endif /* GEMDOS */
  2855. #endif /* datageneral */
  2856. #endif /* OS2 */
  2857. #endif /* MAC */
  2858. #endif /* AMIGA */
  2859. #endif /* OSK */
  2860. #endif /* VMS */
  2861. #endif /* UNIX */
  2862.     return(vvbuf);
  2863.  
  2864.       case VN_SYSV:            /* System herald */
  2865.     for (x = y = 0; x < VVBUFL; x++) {
  2866.         if (ckxsys[x] == SP && y == 0) continue;
  2867.         vvbuf[y++] = (ckxsys[x] == SP) ? '_' : ckxsys[x];
  2868.     }
  2869.     vvbuf[y] = NUL;
  2870.     return(vvbuf);
  2871.  
  2872.       case VN_TIME:            /* TIME. Assumes that ztime returns */
  2873.     ztime(&p);            /* "Thu Feb  8 12:00:00 1990" */
  2874.     if (p == NULL || *p == NUL)    /* like asctime()! */
  2875.       return(NULL);
  2876.     for (x = 11; x < 19; x++)    /* copy hh:mm:ss */
  2877.       vvbuf[x - 11] = p[x];        /* to vvbuf */
  2878.     vvbuf[8] = NUL;            /* terminate */
  2879.     return(vvbuf);            /* and return it */
  2880.  
  2881.       case VN_NTIM:            /* Numeric time */
  2882.     ztime(&p);            /* "Thu Feb  8 12:00:00 1990" */
  2883.     if (p == NULL || *p == NUL)    /* like asctime()! */
  2884.       return(NULL);
  2885.     z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  2886.     sprintf(vvbuf,"%ld",z);
  2887.     return(vvbuf);
  2888.  
  2889. #ifdef CK_TTYFD
  2890.       case VN_TTYF:            /* TTY file descriptor */
  2891.     sprintf(vvbuf,"%d",ttyfd);
  2892.     return(vvbuf);
  2893. #endif /* CK_TTYFD */
  2894.  
  2895.       case VN_VERS:            /* Numeric Kermit version number */
  2896.     sprintf(vvbuf,"%ld",vernum);
  2897.     return(vvbuf);
  2898.  
  2899.       case VN_HOME:            /* Home directory */
  2900. #ifdef UNIX
  2901.         sprintf(vvbuf,"%s/",zhome());
  2902.     return(vvbuf);
  2903. #else
  2904. #ifdef OSK
  2905.         sprintf(vvbuf,"%s/",zhome());
  2906.     return(vvbuf);
  2907. #else
  2908. #ifdef STRATUS
  2909.     sprintf(vvbuf,"%s>",zhome());
  2910.     return(vvbuf);
  2911. #else
  2912.     return(zhome());
  2913. #endif /* STRATUS */
  2914. #endif /* OSK */
  2915. #endif /* UNIX */
  2916.  
  2917.       case VN_IBUF:            /* INPUT buffer */
  2918.     return(inpbuf);
  2919.  
  2920.       case VN_ICHR:            /* INPUT character */
  2921.     inchar[1] = NUL;
  2922.     return((char *)inchar);
  2923.  
  2924.       case VN_ICNT:            /* INPUT character count */
  2925.         sprintf(vvbuf,"%d",incount);
  2926.     return(vvbuf);
  2927.  
  2928.       case VN_SPEE: {            /* Transmission SPEED */
  2929.       long t;
  2930.       t = ttgspd();
  2931.       if (t < 0L)
  2932.         sprintf(vvbuf,"unknown");
  2933.       else
  2934.         sprintf(vvbuf,"%ld",t);
  2935.       return(vvbuf);
  2936.       }
  2937.       case VN_SUCC:            /* SUCCESS flag */
  2938.     sprintf(vvbuf,"%d",(success == 0) ? 1 : 0);
  2939.     return(vvbuf);
  2940.  
  2941.       case VN_LINE:            /* LINE */
  2942.     p = (char *) ttname;
  2943.         return(p);
  2944.  
  2945.       case VN_PROG:            /* Program name */
  2946.     return("C-Kermit");
  2947.  
  2948.       case VN_RET:            /* Value of most recent RETURN */
  2949.     p = mrval[maclvl+1];
  2950.     if (p == NULL) p = "";
  2951.     return(p);
  2952.  
  2953.       case VN_FFC:            /* Size of most recent file */
  2954.     sprintf(vvbuf, "%ld", ffc);
  2955.     return(vvbuf);
  2956.  
  2957.       case VN_TFC:            /* Size of most recent file group */
  2958.     sprintf(vvbuf, "%ld", tfc);
  2959.     return(vvbuf);
  2960.  
  2961.       case VN_CPU:            /* CPU type */
  2962. #ifdef CKCPU
  2963.     return(CKCPU);
  2964. #else
  2965.     return("unknown");
  2966. #endif /* CKCPU */
  2967.  
  2968.       case VN_CMDL:            /* Command level */
  2969.     sprintf(vvbuf, "%d", cmdlvl);
  2970.     return(vvbuf);
  2971.  
  2972.       case VN_DAY:            /* Day of week */
  2973.       case VN_NDAY:
  2974. /*
  2975.   Depends on ztime() returning ENGLISH asctime()-format string!
  2976.   asctime() format is: "Thu Feb  8 12:00:00 1990".
  2977.   Needs updating to accommodate non-English asctime() strings.
  2978. */
  2979.     ztime(&p);
  2980.     if (p != NULL && *p != NUL) {    /* ztime() succeeded. */
  2981.         if (y == VN_DAY) {        /* String day. */
  2982.         strncpy(vvbuf,p,3);
  2983.         } else {            /* Numeric day. */
  2984.         for (x = 0; x < 7; x++)      /* Look up day string in table */
  2985.           if (!strncmp(p,wkdays[x],3))
  2986.             break;
  2987.         if (x > 6) x = -1;    /* Not found */
  2988.         sprintf(vvbuf,"%d",x);    /* Return the number */
  2989.         }
  2990.     } else vvbuf[0] = NUL;        /* ztime() failed. */
  2991.     return(vvbuf);            /* Return what we got. */
  2992.  
  2993.       case VN_LCL:            /* Local (vs remote) mode */
  2994.     strcpy(vvbuf, local ? "1" : "0");
  2995.     return(vvbuf);
  2996.  
  2997.       case VN_CMDS:            /* Command source */
  2998.     if (cmdstk[cmdlvl].src == CMD_KB)
  2999.       strcpy(vvbuf,"prompt");
  3000.     else if (cmdstk[cmdlvl].src == CMD_MD)
  3001.       strcpy(vvbuf,"macro");
  3002.     else if (cmdstk[cmdlvl].src == CMD_TF)
  3003.       strcpy(vvbuf,"file");
  3004.     else strcpy(vvbuf,"unknown");
  3005.     return(vvbuf);
  3006.  
  3007.       case VN_CMDF:            /* Current command file name */
  3008. #ifdef COMMENT                /* (see comments above) */
  3009.     if (tfnam[tlevel]) {        /* (near dblbs declaration) */
  3010.         dblbs(tfnam[tlevel],vvbuf,VVBUFL);
  3011.         return(vvbuf);
  3012.     } else return("");
  3013. #else
  3014.     if (tlevel < 0)
  3015.       return("");
  3016.     else
  3017.       return(tfnam[tlevel] ? tfnam[tlevel] : "");
  3018. #endif /* COMMENT */
  3019.  
  3020.       case VN_MAC:            /* Current macro name */
  3021.     return((maclvl > -1) ? m_arg[maclvl][0] : "");
  3022.  
  3023.       case VN_EXIT:
  3024.     sprintf(vvbuf,"%d",xitsta);
  3025.     return(vvbuf);
  3026.  
  3027.       case VN_PRTY: {            /* Parity */
  3028.       char *s;
  3029.       switch (parity) {
  3030.         case 0:   s = "none";  break;
  3031.         case 'e': s = "even";  break;
  3032.         case 'm': s = "mark";  break;
  3033.         case 'o': s = "odd";   break;
  3034.         case 's': s = "space"; break;
  3035.         default:  s = "unknown"; break;
  3036.       }
  3037.       strcpy(vvbuf,s);
  3038.       return(vvbuf);
  3039.       }
  3040.  
  3041.       case VN_DIAL:
  3042.     sprintf(vvbuf,"%d",
  3043. #ifndef NODIAL
  3044.         dialsta
  3045. #else
  3046.         -1
  3047. #endif /* NODIAL */
  3048.         );
  3049.     return(vvbuf);
  3050.  
  3051. #ifdef OS2
  3052.       case VN_KEYB:
  3053.     strcpy(vvbuf,conkbg());
  3054.     return(vvbuf);
  3055. #endif /* OS2 */
  3056.  
  3057.       case VN_CPS:
  3058.     if (tsecs > 0)
  3059.       sprintf(vvbuf, "%ld", tfc / (long) tsecs);
  3060.     else strcpy(vvbuf,"0");
  3061.     return(vvbuf);
  3062.  
  3063.       case VN_MODE:            /* File transfer mode */
  3064.     switch (binary) {
  3065.       case XYFT_T: strcpy(vvbuf,"text"); break;
  3066.       case XYFT_B:
  3067.       case XYFT_U: strcpy(vvbuf,"binary"); break;
  3068.       case XYFT_I: strcpy(vvbuf,"image"); break;
  3069.       case XYFT_L: strcpy(vvbuf,"labeled"); break;
  3070.       case XYFT_M: strcpy(vvbuf,"macbinary"); break;
  3071.       default:     strcpy(vvbuf,"unknown");
  3072.     }
  3073.     return(vvbuf);
  3074.  
  3075. #ifdef CK_REXX
  3076.       case VN_REXX:
  3077.     return(rexxbuf);
  3078. #endif /* CK_REXX */
  3079.  
  3080.       case VN_NEWL:            /* System newline char or sequence */
  3081. #ifdef UNIX
  3082.     strcpy(vvbuf,"\n");
  3083. #else
  3084. #ifdef datageneral
  3085.     strcpy(vvbuf,"\n");
  3086. #else
  3087. #ifdef OSK
  3088.     strcpy(vvbuf,"\15");        /* Remember, these are octal... */
  3089. #else
  3090. #ifdef MAC
  3091.     strcpy(vvbuf,"\15");
  3092. #else
  3093. #ifdef OS2
  3094.     strcpy(vvbuf,"\15\12");
  3095. #else
  3096. #ifdef STRATUS
  3097.     strcpy(vvbuf,"\n");
  3098. #else
  3099. #ifdef VMS
  3100.     strcpy(vvbuf,"\15\12");
  3101. #else
  3102. #ifdef AMIGA
  3103.     strcpy(vvbuf,"\n");
  3104. #else
  3105. #ifdef GEMDOS
  3106.     strcpy(vvbuf,"\n");
  3107. #else
  3108.     strcpy(vvbuf,"\n");
  3109. #endif /* GEMDOS */
  3110. #endif /* AMIGA */
  3111. #endif /* VMS */
  3112. #endif /* STRATUS */
  3113. #endif /* OS2 */
  3114. #endif /* MAC */
  3115. #endif /* OSK */
  3116. #endif /* datageneral */
  3117. #endif /* UNIX */
  3118.     return(vvbuf);
  3119.  
  3120.       case VN_ROWS:            /* ROWS */
  3121.       case VN_COLS:            /* COLS */
  3122.         strcpy(vvbuf,(y == VN_ROWS) ? "24" : "80"); /* Default */
  3123. #ifdef CK_NAWS    
  3124.     if (ttgwsiz() > 0)        /* Get window size */
  3125.       if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
  3126.         sprintf(vvbuf,"%d",(y == VN_ROWS) ? tt_rows : tt_cols);
  3127. #endif /* CK_NAWS */
  3128.     return(vvbuf);
  3129.  
  3130.       case VN_TTYP:
  3131. #ifdef OS2
  3132.     sprintf(vvbuf, "%s",
  3133.            (tt_type >= 0 && tt_type <= max_tt) ?
  3134.            tt_info[tt_type].x_name :
  3135.            "unknown"
  3136.            );
  3137. #else
  3138. #ifdef MAC
  3139.     strcpy(vvbuf,"vt320");
  3140. #else
  3141.     p = getenv("TERM");
  3142.     sprintf(vvbuf,"%s", p ? p : "unknown");
  3143. #endif /* MAC */
  3144. #endif /* OS2 */
  3145.     return(vvbuf);
  3146.  
  3147.       case VN_MINP:            /* MINPUT */
  3148.     sprintf(vvbuf, "%d", m_found);
  3149.     return(vvbuf);
  3150.  
  3151.       case VN_CONN:            /* CONNECTION */
  3152.     if (!local) {
  3153.       strcpy(vvbuf,"remote");
  3154.     } else {
  3155.         if (!network)
  3156.           strcpy(vvbuf,"serial");
  3157. #ifdef TCPSOCKET
  3158.         else if (nettype == NET_TCPB || nettype == NET_TCPA) {
  3159.         if (ttnproto == NP_TELNET)
  3160.           strcpy(vvbuf,"tcp/ip_telnet");
  3161.         else
  3162.           strcpy(vvbuf,"tcp/ip");
  3163.         }
  3164. #endif /* TCPSOCKET */
  3165. #ifdef ANYX25
  3166.         else if (nettype == NET_SX25 || nettype == NET_VX25)
  3167.           strcpy(vvbuf,"x.25");
  3168. #endif /* ANYX25 */
  3169. #ifdef DECNET
  3170.         else if (nettype == NET_DEC) {
  3171.         if ( ttnproto == NP_LAT ) strcpy(vvbuf,"decnet_lat");
  3172.         else if ( ttnproto == NP_CTERM ) sprintf(vvbuf,"decnet_cterm");
  3173.         else strcpy(vvbuf,"decnet");
  3174.         }
  3175. #endif /* DECNET */
  3176. #ifdef NPIPE
  3177.         else if (nettype == NET_PIPE)
  3178.           strcpy(vvbuf,"named_pipe");
  3179. #endif /* NPIPE */
  3180. #ifdef CK_NETBIOS
  3181.         else if (nettype == NET_BIOS)
  3182.           strcpy(vvbuf,"netbios");
  3183. #endif /* CK_NETBIOS */
  3184.         else
  3185.           strcpy(vvbuf,"unknown");
  3186.     }
  3187.     return(vvbuf);
  3188.  
  3189.       case VN_SYSI:            /* System ID, Kermit code */
  3190.                     /* (see pp.275-278 of Kermit book) */
  3191.     /* This could also be done by calling zsattr(), but that */
  3192.     /* might mess up other things.  There should be an atomic */
  3193.         /* low-level routine that returns the system ID. */
  3194. #ifdef UNIX
  3195.     strcpy(vvbuf,"U1");
  3196. #else
  3197. #ifdef VMS
  3198.     strcpy(vvbuf,"D7");
  3199. #else
  3200. #ifdef OSK
  3201.     strcpy(vvbuf,"UD");
  3202. #else
  3203. #ifdef AMIGA
  3204.     strcpy(vvbuf,"L3");
  3205. #else
  3206. #ifdef MAC
  3207.     strcpy(vvbuf,"A3");
  3208. #else
  3209. #ifdef OS2
  3210.     strcpy(vvbuf,"UO");
  3211. #else
  3212. #ifdef datageneral
  3213.     strcpy(vvbuf,"F3");
  3214. #else
  3215. #ifdef GEMDOS
  3216.     strcpy(vvbuf,"K2");
  3217. #else
  3218. #ifdef STRATUS
  3219.     strcpy(vvbuf,"MV");
  3220. #else
  3221.     strcpy(vvbuf,"");
  3222. #endif /* STRATUS */
  3223. #endif /* GEMDOS */
  3224. #endif /* datageneral */
  3225. #endif /* OS2 */
  3226. #endif /* MAC */
  3227. #endif /* AMIGA */
  3228. #endif /* OSK */
  3229. #endif /* VMS */
  3230. #endif /* UNIX */
  3231.     return(vvbuf);
  3232.  
  3233. #ifdef OS2
  3234.       case VN_SPA: {
  3235.       extern long zdskspace(int);
  3236.       sprintf(vvbuf,"%ld",zdskspace(0));
  3237.       return(vvbuf);
  3238.       }
  3239. #endif /* OS2 */
  3240.  
  3241.       case VN_QUE: {
  3242.       extern char querybuf[];
  3243.       return(querybuf);
  3244.       }
  3245. #ifndef NOCSETS
  3246.       case VN_CSET:
  3247. #ifdef OS2
  3248.     sprintf(vvbuf,"cp%d",os2getcp());
  3249. #else
  3250.     sprintf(vvbuf,"%s",fcsinfo[fcharset].keyword);
  3251. #endif /* OS2 */
  3252.     return(vvbuf);
  3253. #endif /* NOCSETS */
  3254.  
  3255. #ifdef OS2
  3256.       case VN_STAR:
  3257.     return(startupdir);
  3258. #endif /* OS2 */
  3259.  
  3260.       case VN_MDM:
  3261.     return(gmdmtyp());
  3262.  
  3263.       case VN_EVAL:
  3264.     return(evalbuf);
  3265.  
  3266.       default:
  3267.     return(NULL);
  3268.     }
  3269. }
  3270. #endif /* NOSPL */
  3271.  
  3272. /*
  3273.   X X S T R I N G  --  Expand variables and backslash codes.
  3274.  
  3275.     int xxtstring(s,&s2,&n);
  3276.  
  3277.   Expands \ escapes via recursive descent.
  3278.   Argument s is a pointer to string to expand (source).
  3279.   Argument s2 is the address of where to put result (destination).
  3280.   Argument n is the length of the destination string (to prevent overruns).
  3281.   Returns -1 on failure, 0 on success,
  3282.     with destination string null-terminated and s2 pointing to the
  3283.     terminating null, so that subsequent characters can be added.
  3284. */
  3285.  
  3286. #define XXDEPLIM 100            /* Recursion depth limit */
  3287.  
  3288. int
  3289. zzstring(s,s2,n) char *s; char **s2; int *n; {
  3290.     int x,                /* Current character */
  3291.         y,                /* Worker */
  3292.         pp,                /* Paren level */
  3293.         argn,                /* Function argument counter */
  3294.         n2,                /* Local copy of n */
  3295.         d,                /* Array dimension */
  3296.         vbi,                /* Variable id (integer form) */
  3297.         argl;                /* String argument length */
  3298.  
  3299.     char vb,                /* Variable id (char form) */
  3300.         *vp,                /* Pointer to variable definition */
  3301.         *new,                /* Local pointer to target string */
  3302.         *p,                /* Worker */
  3303.         *q;                /* Worker */
  3304.     char *r  = (char *)0;        /* For holding function args */
  3305.     char *r2 = (char *)0;
  3306.  
  3307. #ifndef NOSPL
  3308.     char vnambuf[VNAML];        /* Buffer for variable/function name */
  3309.     char *argp[FNARGS];            /* Pointers to function args */
  3310. #endif /* NOSPL */
  3311.  
  3312.     static int depth = 0;        /* Call depth, avoid overflow */
  3313.  
  3314.     n2 = *n;                /* Make local copies of args */
  3315.     new = *s2;                /* for one less level of indirection */
  3316.  
  3317.     depth++;                /* Sink to a new depth */
  3318.     if (depth > XXDEPLIM) {        /* Too deep? */
  3319.     printf("?definition is circular or too deep\n");
  3320.     depth = 0;
  3321.     *new = NUL;
  3322.     return(-1);
  3323.     }
  3324.     if (!s || !new) {            /* Watch out for null pointers */
  3325.     depth = 0;
  3326.     *new = NUL;
  3327.     return(-1);
  3328.     }
  3329.     argl = (int)strlen(s);        /* Get length of source string */
  3330.     debug(F111,"xxstring",s,argl);
  3331.     if (argl < 0) {            /* Watch out for garbage */
  3332.     depth = 0;
  3333.     *new = NUL;
  3334.     return(-1);
  3335.     }
  3336.     while ( x = *s ) {            /* Loop for all characters */
  3337.         if (x != CMDQ) {        /* Is it the command-quote char? */
  3338.         *new++ = *s++;        /* No, normal char, just copy */
  3339.         if (n2-- < 0) {        /* and count it, careful of overflow */
  3340.         return(-1);
  3341.         }
  3342.         continue;
  3343.     }
  3344.  
  3345. /* We have the command-quote character. */
  3346.  
  3347.     x = *(s+1);            /* Get the following character. */
  3348.     switch (x) {            /* Act according to variable type */
  3349. #ifndef NOSPL
  3350.       case 0:            /* It's a lone backslash */
  3351.         *new++ = *s++;
  3352.         if (n2-- < 0)
  3353.           return(-1);
  3354.         break;
  3355.       case '%':            /* Variable */
  3356.         s += 2;            /* Get the letter or digit */
  3357.         vb = *s++;            /* and move source pointer past it */
  3358.         vp = NULL;            /* Assume definition is empty */
  3359.         if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
  3360.         if (maclvl < 0)     /* Digit variables are global */
  3361.           vp = g_var[vb];    /* if no macro is active */
  3362.         else            /* otherwise */
  3363.           vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
  3364.         } else {
  3365.         if (isupper(vb)) vb += ('a'-'A');
  3366.         vp = g_var[vb];        /* Letter for global variable */
  3367.         }
  3368.         if (vp) {            /* If definition not empty */
  3369.         if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
  3370.             return(-1);        /* Pass along failure */
  3371.         }
  3372.         }
  3373.         break;
  3374.       case '&':            /* An array reference */
  3375.         if (arraynam(s,&vbi,&d) < 0) { /* Get name and subscript */
  3376.         return(-1);
  3377.         }
  3378.         pp = 0;            /* Bracket counter */
  3379.         while (*s) {        /* Advance source pointer */
  3380.         if (*s == '[') pp++;
  3381.         if (*s == ']' && --pp == 0) break;
  3382.         s++;
  3383.         }
  3384.         if (*s == ']') s++;        /* past the closing bracket. */
  3385.         if (chkarray(vbi,d) > 0) {    /* Array is declared? */
  3386.         vbi -= 96;        /* Convert name to index */
  3387.         if (a_dim[vbi] >= d) {    /* If subscript in range */
  3388.             char **ap;
  3389.             ap = a_ptr[vbi];    /* get data pointer */
  3390.             if (ap) {        /* and if there is one */
  3391.             if (ap[d]) {    /* If definition not empty */
  3392.                 if (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
  3393.                 return(-1); /* Pass along failure */
  3394.                 }
  3395.             }
  3396.             }
  3397.         }
  3398.         }
  3399.         break;
  3400.  
  3401.       case 'F':            /* A builtin function */
  3402.       case 'f':
  3403.         q = vnambuf;        /* Copy the name */
  3404.         y = 0;            /* into a separate buffer */
  3405.         s+=2;            /* point past 'F' */
  3406.         while (y++ < VNAML) {
  3407.         if (*s == '(') { s++; break; } /* Look for open paren */
  3408.         if ((*q = *s) == NUL) break;   /* or end of string */
  3409.         s++; q++;
  3410.         }
  3411.         *q = NUL;            /* Terminate function name */
  3412.         if (y >= VNAML) {        /* Handle pathological case */
  3413.         while (*s && (*s != '(')) /* of very long string entered */
  3414.           s++;              /* as function name. */
  3415.         if (*s == ')') s++;      /* Skip past it. */
  3416.         }
  3417.         r = r2 = malloc(argl+2);    /* And make a place to copy args */
  3418.         debug(F101,"xxstring r2","",r2);
  3419.         if (!r2) {            /* Watch out for malloc failure */
  3420.         depth = 0;
  3421.         *new = NUL;
  3422.         return(-1);
  3423.         }
  3424.         argn = 0;            /* Argument counter */
  3425.         argp[argn++] = r;        /* Point to first argument */
  3426.         y = 0;            /* Completion flag */
  3427.         pp = 1;            /* Paren level (already have one). */
  3428.         while (*r = *s) {        /* Copy each argument, char by char. */
  3429.         if (*r == '(') pp++;    /* Count an opening paren. */
  3430.         if (*r == ')') {    /* Closing paren, count it. */
  3431.             if (--pp == 0) {    /* Final one? */
  3432.             *r = NUL;    /* Make it a terminating null */
  3433.             s++;
  3434.             y = 1;        /* Flag we've got all the args */
  3435.             break;
  3436.             }
  3437.         }
  3438.         if (*r == ',') {    /* Comma */
  3439.             if (pp == 1) {    /* If not within ()'s, */
  3440.             *r = NUL;        /* new arg, skip past it, */
  3441.             argp[argn++] = r+1; /* point to new arg. */
  3442.             if (argn == FNARGS) /* Too many args */
  3443.               break;
  3444.             }            /* Otherwise just skip past  */
  3445.         }
  3446.         s++; r++;        /* Advance pointers */
  3447.         }
  3448.         debug(F110,"xxstring function name",vnambuf,0);
  3449.         if (!y) {            /* If we didn't find closing paren */
  3450.         debug(F101,"xxstring r2 before free","",r2);
  3451.         if (r2) free(r2);    /* free the temporary storage */
  3452.         return(-1);        /* and return failure. */
  3453.         }
  3454. #ifdef DEBUG
  3455.         if (deblog)
  3456.           for (y = 0; y < argn; y++)
  3457.         debug(F111,"xxstring function arg",argp[y],y);
  3458. #endif /* DEBUG */
  3459.         vp = fneval(vnambuf,argp,argn); /* Evaluate the function. */
  3460.         if (vp) {            /* If definition not empty */
  3461.         while (*new++ = *vp++)    /* copy it to output string */
  3462.           if (n2-- < 0) return(-1); /* mindful of overflow */
  3463.         new--;            /* Back up over terminating null */
  3464.         n2++;            /* to allow for further deposits. */
  3465.         }
  3466.         if (r2) {
  3467.         debug(F101,"xxstring freeing r2","",r2);
  3468.         free(r2);        /* Now free the temporary storage */
  3469.         r2 = NULL;
  3470.         }
  3471.         break;
  3472.       case '$':            /* An environment variable */
  3473.       case 'V':            /* Or a named builtin variable. */
  3474.       case 'v':
  3475.       case 'M':            /* Or a macro = long variable */
  3476.       case 'm':
  3477.         p = s+2;            /* $/V/M must be followed by (name) */
  3478.         if (*p != '(') {        /* as in \$(HOME) or \V(count) */
  3479.         *new++ = *s++;        /* If not, just copy it */
  3480.         if (n2-- < 0) {
  3481.             return(-1);
  3482.         }
  3483.         break;
  3484.         }
  3485.         p++;            /* Point to 1st char of name */
  3486.         q = vnambuf;        /* Copy the name */
  3487.         y = 0;            /* into a separate buffer */
  3488.         while (y++ < VNAML) {    /* Watch out for name too long */
  3489.         if (*p == ')') {    /* Name properly terminated with ')' */
  3490.             p++;        /* Move source pointer past ')' */
  3491.             break;
  3492.         }
  3493.         if ((*q = *p) == NUL)    /* String ends before ')' */
  3494.           break;
  3495.          p++; q++;        /* Advance pointers */
  3496.         }
  3497.         *q = NUL;            /* Terminate the variable name */
  3498.         if (y >= VNAML) {        /* Handle pathological case */
  3499.         while (*p && (*p != ')')) /* of very long string entered */
  3500.           p++;              /* as variable name. */
  3501.         if (*p == ')') p++;      /* Skip ahead to the end of it. */
  3502.         }
  3503.         s = p;            /* Adjust global source pointer */
  3504.         p = malloc((int)strlen(vnambuf) + 1); /* Make temporary space */
  3505.         if (p) {            /* If we got the space */
  3506.         vp = vnambuf;        /* Point to original */
  3507.         strcpy(p,vp);        /* Make a copy of it */
  3508.         y = VNAML;        /* Length of name buffer */
  3509.         zzstring(p,&vp,&y);    /* Evaluate the copy */
  3510.         free(p);        /* Free the temporary space */
  3511.         }
  3512.         debug(F110,"xxstring vname",vnambuf,0);
  3513.         q = NULL;
  3514.         if (x == '$') {        /* Look up its value */
  3515.         vp = getenv(vnambuf);    /* This way for environment variable */
  3516.         } else if (x == 'm' || x == 'M') { /* or this way for macro */
  3517.         y = mlook(mactab,vnambuf,nmac);    /* get definition */
  3518.         if (y > -1) {        /* Got definition */
  3519.             vp = mactab[y].mval;
  3520. #ifdef COMMENT
  3521. /*
  3522.   This works, but it breaks too many things, like CKERMIT.INI!
  3523.   We need a new \_() function for this, which fully evaluates the name
  3524.   of the macro before retrieving its definition.
  3525. */
  3526.             q = p = malloc(1024); /* Now evaluate it */
  3527.             if (p) {
  3528.             y = 1023;
  3529.             zzstring(vp,&p,&y);
  3530.             }
  3531.             vp = q;        /* Point to evaluated definition */
  3532. #endif /* COMMENT */
  3533.         } else vp = NULL;
  3534.         } else {             /*  or */
  3535.             vp = nvlook(vnambuf);    /* this way for builtin variable */
  3536.         }
  3537.         if (vp) {            /* If definition not empty */
  3538.         while (*new++ = *vp++)    /* copy it to output string. */
  3539.           if (n2-- < 0) {
  3540.               if (q) free(q);
  3541.               return(-1);
  3542.           }
  3543.         new--;            /* Back up over terminating null */
  3544.         n2++;            /* to allow for further deposits. */
  3545.         }
  3546.         if (q) free(q);
  3547.         break;
  3548. #endif /* NOSPL    */            /* Handle \nnn even if NOSPL. */
  3549.       default:            /* Maybe it's a backslash code */
  3550.         y = xxesc(&s);        /* Go interpret it */
  3551.         if (y < 0) {        /* Upon failure */
  3552.         *new++ = x;        /* Just quote the next character */
  3553.         s += 2;            /* Move past the pair */
  3554.         n2 -= 2;
  3555.         if (n2 < 0) {
  3556.             return(-1);
  3557.         }
  3558.         continue;        /* and go back for more */
  3559.         } else {
  3560.         *new++ = y;        /* else deposit interpreted value */
  3561.         if (n2-- < 0) {
  3562.             return(-1);
  3563.         }
  3564.         }
  3565.     }
  3566.     }
  3567.     *new = NUL;                /* Terminate the new string */
  3568.     depth--;                /* Adjust stack depth gauge */
  3569.     *s2 = new;                /* Copy results back into */
  3570.     *n = n2;                /* the argument addresses */
  3571.     return(0);                /* and return. */
  3572. }
  3573. #endif /* NOICP */
  3574.