source: trunk/third/kermit/ckuus4.c @ 10780

Revision 10780, 138.1 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
Line 
1#include "ckcsym.h"
2
3/*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
4
5/*
6  Author: Frank da Cruz <fdc@columbia.edu>,
7  Columbia University Academic Information Systems, New York City.
8
9  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
10  York.  The C-Kermit software may not be, in whole or in part, licensed or
11  sold for profit as a software product itself, nor may it be included in or
12  distributed with commercial products or otherwise distributed by commercial
13  concerns to their clients or customers without written permission of the
14  Office of Kermit Development and Distribution, Columbia University.  This
15  copyright notice must not be removed, altered, or obscured.
16*/
17
18/*
19  File ckuus4.c -- Functions moved from other ckuus*.c modules to even
20  out their sizes.
21*/
22#include "ckcdeb.h"
23#include "ckcasc.h"
24#include "ckcker.h"
25#include "ckuusr.h"
26#include "ckuver.h"
27#include "ckcnet.h"                     /* Network symbols */
28
29#ifdef VMS
30#include <errno.h>                      /* For \v(errno) */
31#ifndef OLD_VMS
32#include <lib$routines.h>               /* Not for VAX C 2.4 */
33#else
34#include <libdef.h>
35#endif /* OLD_VMS */
36_PROTOTYP(int vmsttyfd, (void) );
37#endif /* VMS */
38
39#ifdef OS2
40#ifndef NT
41#define INCL_NOPM
42#define INCL_VIO                        /* Needed for ckocon.h */
43#include <os2.h>
44#else
45#include <windows.h>
46#define APIRET ULONG
47#endif /* NT */
48#include "ckocon.h"
49#include "ckoetc.h"
50int StartedFromDialer = 0;
51HWND hwndDialer = 0;
52LONG KermitDialerID = 0;
53#ifdef putchar
54#undef putchar
55#endif /* putchar */
56#define putchar(x) conoc(x)
57#endif /* OS2 */
58
59extern xx_strp xxstring;
60
61#ifdef DEC_TCPIP
62#include <descrip>
63#include <dvidef>
64#include <dcdef>
65#endif /* DEC_TCPIP */
66
67#include "ckcxla.h"                     /* Character sets */
68#ifdef CKOUNI
69#include "ckouni.h"
70#endif /* CKOUNI */
71
72extern int quiet, network, xitsta, escape;
73#ifndef MAC
74#ifndef AMIGA
75extern int ttyfd;
76#endif /* MAC */
77#endif /* AMIGA */
78
79#ifdef NETCONN
80extern int tn_exit;
81#endif /* NETCONN */
82
83#ifndef NOICP                           /* Most of this file... */
84
85#ifndef AMIGA
86#ifndef MAC
87#include <signal.h>
88#endif /* MAC */
89#endif /* AMIGA */
90
91#ifdef STRATUS                          /* Stratus Computer, Inc.  VOS */
92#ifdef putchar
93#undef putchar
94#endif /* putchar */
95#define putchar(x) conoc(x)
96#ifdef getchar
97#undef getchar
98#endif /* getchar */
99#define getchar(x) coninc(0)
100#endif /* STRATUS */
101
102#ifdef ANYX25
103extern int revcall, closgr, cudata, npadx3;
104int x25ver;
105extern char udata[];
106extern CHAR padparms[];
107extern struct keytab padx3tab[];
108#endif /* ANYX25 */
109
110#ifdef NETCONN
111#ifndef NODIAL
112extern int nnetdir;
113extern char *netdir[];
114#endif /* NODIAL */
115extern char ipaddr[];
116#ifdef TNCODE
117_PROTOTYP (static VOID shotel, (void) );
118extern int tn_duplex, tn_nlm, tn_binary, tn_b_nlm, u_binary, me_binary;
119extern int tn_b_meu, tn_b_ume;
120extern char *tn_term;
121#endif /* TNCODE */
122
123#ifdef CK_NETBIOS
124extern unsigned short netbiosAvail;
125extern unsigned long NetbeuiAPI;
126extern unsigned char NetBiosName[];
127extern unsigned char NetBiosAdapter;
128extern unsigned char NetBiosLSN;
129#endif /* CK_NETBIOS */
130
131#ifdef TCPSOCKET
132extern char myipaddr[];
133#ifdef SOL_SOCKET
134#ifdef SO_LINGER
135extern int tcp_linger;
136extern int tcp_linger_tmo;
137#endif /* SO_LINGER */
138#ifdef TCP_NODELAY
139extern int tcp_nodelay;
140#endif /* TCP_NODELAY */
141#ifdef SO_SNDBUF
142extern int tcp_sendbuf;
143#endif /* SO_SNDBUF */
144#ifdef SO_RCVBUF
145extern int tcp_recvbuf;
146#endif /* SO_RCVBUF */
147#ifdef SO_KEEPALIVE
148extern int tcp_keepalive;
149#endif /* SO_KEEPALIVE */
150#endif /* SOL_SOCKET */
151#endif /* TCPSOCKET */
152#endif /* NETCONN */
153
154extern int cfilef;
155extern char cmdfil[];
156
157#ifndef NOSPL
158#ifdef CK_APC
159extern int apcactive;                   /* Nonzero = APC command was rec'd */
160extern int apcstatus;                   /* Are APC commands being processed? */
161#ifdef DCMDBUF
162extern char *apcbuf;                    /* APC command buffer */
163#else
164extern char apcbuf[];
165#endif /* DCMDBUF */
166#endif /* CK_APC */
167
168extern char evalbuf[];                  /* EVALUATE result */
169extern char uidbuf[], pwbuf[], prmbuf[];
170_PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
171_PROTOTYP( static VOID myflsh, (void) );
172_PROTOTYP( static char * getip, (char *) );
173
174static char hexdigits[16] = {
175    '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
176};
177extern char * tempdir;
178
179#ifdef CK_REXX
180extern char rexxbuf[];
181#endif /* CK_REXX */
182
183extern int tfline[];
184
185/* These need to be internationalized... */
186
187static
188char *wkdays[] = {
189    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
190};
191#endif /* NOSPL */
192
193static
194char *months[] = {
195    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
196    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
197};
198
199#ifdef OS2
200_PROTOTYP (int os2getcp, (void) );
201#ifdef TCPSOCKET
202extern char tcpname[];
203#endif /* TCPSOCKET */
204extern char startupdir[],exedir[];
205extern int tcp_avail;
206#ifdef DECNET
207extern int dnet_avail;
208#endif /* DECNET */
209#ifdef SUPERLAT
210extern int slat_avail;
211#endif /* SUPERLAT */
212
213extern int tt_type, max_tt;
214extern struct tt_info_rec tt_info[];
215extern int tt_rows[], tt_cols[];
216#else /* OS2 */
217extern int tt_rows, tt_cols;
218#endif /* OS2 */
219
220extern struct keytab colxtab[];
221
222extern CHAR
223  eol, feol, mypadc, mystch, padch, seol, stchr;
224
225extern char ttname[], *ckxsys, *versio, **xargv, *zinptr;
226extern char inidir[], *cksysid;
227
228extern int activecmd, remonly, cmd_rows;
229
230extern struct ck_p ptab[];
231extern int protocol, prefixing;
232
233extern int
234  atcapr, autopar, bctr, bctu, bgset, bigrbsiz, bigsbsiz, binary, carrier,
235  cdtimo, cmask, crunched, delay, duplex, ebq, ebqflg, flow, fmask,
236  fncact, fncnv, inecho, keep, local, lscapr, lscapu, xfermode,
237  maxrps, maxsps, maxtry, mypadn, ncolx, dest, slostart,
238  nettype, nmac, noinit, npad, parity, pktlog, pkttim, rcflag,
239  retrans, rpackets, rptflg, rptq, rtimo, seslog, sessft, sosi, spackets,
240  spsiz, spsizf, spsizr, srvtim, stayflg, success, timeouts, tralog,
241  tsecs, ttnproto, turn, turnch, urpsiz, wmax, wslotn, wslotr, xargc, xargs,
242  zincnt, fdispla, tlevel, spmax, insilence, cmdmsk, timint, timef,
243  fnrpath, fnspath, inbufsize;
244
245#ifdef VMS
246  extern int frecl;
247#endif /* VMS */
248
249extern long
250  ffc, filcnt, rptn, speed, tfc, tlci, tlco, ccu, ccp, vernum, xvernum, crc16;
251
252#ifndef NOSPL
253extern char fspec[], myhost[];
254#endif /* NOSPL */
255
256extern char *tfnam[];                   /* Command file names */
257#ifdef CK_TMPDIR
258extern char *dldir;
259#endif /* CK_TMPDIR */
260
261#ifdef DCMDBUF
262extern struct cmdptr *cmdstk;
263extern char *line, *tmpbuf, *kermrc;
264#else
265extern struct cmdptr cmdstk[];
266extern char line[], tmpbuf[], kermrcb[], *kermrc;
267#endif /* DCMDBUF */
268
269extern char pktfil[],                   /* Packet log file name */
270#ifdef DEBUG
271  debfil[],                             /* Debug log file name */
272#endif /* DEBUG */
273#ifdef TLOG
274  trafil[],                             /* Transaction log file name */
275#endif /* TLOG */
276  sesfil[];                             /* Session log file name */
277
278#ifndef NOXMIT                          /* TRANSMIT command variables */
279extern char xmitbuf[];
280extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
281#endif /* NOXMIT */
282
283#ifndef NOSPL
284/* Script programming language items */
285extern char **a_ptr[];                  /* Arrays */
286extern int a_dim[];
287extern char * inpbuf, inchar[];         /* Buffers for INPUT and REINPUT */
288extern char *inpbp;                     /* And pointer to same */
289#ifdef COMMENT
290static char *inpbps = inpbuf;           /* And another */
291#endif /* COMMENT */
292static char *r3 = (char *)0;
293extern int incount;                     /* INPUT character count */
294extern int m_found;                     /* MINPUT result */
295extern int maclvl;                      /* Macro invocation level */
296extern struct mtab *mactab;             /* Macro table */
297extern char *mrval[];
298extern int macargc[], cmdlvl;
299extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
300extern char *g_var[GVARS];        /* for external 2-dimensional arrays. */
301#ifdef DCMDBUF
302extern int *count, *inpcas;
303#else
304extern int count[], inpcas[];
305#endif /* DCMDBUF */
306#endif /* NOSPL */
307
308#ifdef UNIX
309extern int haslock;                     /* For UUCP locks */
310extern char flfnam[];
311#endif /* UNIX */
312
313#ifdef OS2ORUNIX
314extern int maxnam, maxpath;             /* Longest name, path length */
315#endif /* OS2ORUNIX */
316
317extern int mdmtyp, mdmsav;
318
319#ifndef NODIAL
320/* DIAL-related variables */
321extern char modemmsg[];
322extern MDMINF *modemp[];                /* Pointers to modem info structs */
323extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialmhu, dialsta;
324extern int dialrtr, dialint, dialrstr, dialcon, dialcq;
325extern int mdmspd, dialec, dialdc, dialfc, dialmth, dialesc;
326extern char *dialnum,   *dialini,  *dialdir[], *dialcmd,  *dialnpr,
327 *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
328 *dialhwfc, *dialswfc,  *dialnofc, *dialpulse, *dialtone,
329 *dialaaon, *dialaaoff;
330extern char *diallcc,   *dialixp,  *dialixs,   *dialldp,  *diallds,
331 *dialpxx,  *dialpxi,   *dialpxo,  *dialsfx,   *dialtfp;
332extern int ntollfree;
333extern char *dialtfc[];
334extern int ndialdir, dialcnf, dialcvt;
335extern long dialmax, dialcapas;
336
337extern struct keytab mdmtab[];
338
339#ifdef BIGBUFOK
340extern char * dialmsg[];
341#endif /* BIGBUFOK */
342
343#endif /* NODIAL */
344
345#ifndef NOCSETS
346/* Translation stuff */
347extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
348extern struct keytab lngtab[];
349extern struct csinfo fcsinfo[], tcsinfo[];
350extern struct langinfo langs[];
351#ifdef CK_ANSIC
352extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
353extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
354#else
355extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
356extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
357#endif /* CK_ANSIC */
358#endif /* NOCSETS */
359
360#ifndef NOSPL
361/* Built-in variable names, maximum length VNAML (20 characters) */
362
363struct keytab vartab[] = {
364    "_line",     VN_TFLN,  CM_INV,      /* 192 */
365    "apcactive", VN_APC,   CM_INV,      /* 192 */
366    "argc",      VN_ARGC,  0,
367    "args",      VN_ARGS,  0,
368#ifndef NOCSETS
369    "charset",   VN_CSET,  0,           /* 192 */
370#endif /* NOCSETS */
371    "cmdfile",   VN_CMDF,  0,
372    "cmdlevel",  VN_CMDL,  0,
373    "cmdsource", VN_CMDS,  0,
374    "cols",      VN_COLS,  0,           /* 190 */
375    "connection",VN_CONN,  0,           /* 190 */
376    "count",     VN_COUN,  0,
377    "cps",       VN_CPS,   0,           /* 190 */
378    "cpu",       VN_CPU,   0,
379    "crc16",     VN_CRC16, 0,           /* 192 */
380#ifndef NODIAL
381    "d$ac",      VN_D_AC,  0,           /* 192 */
382    "d$cc",      VN_D_CC,  0,           /* 192 */
383    "d$ip",      VN_D_IP,  0,           /* 192 */
384    "d$lp",      VN_D_LP,  0,           /* 192 */
385#endif /* NODIAL */
386    "date",      VN_DATE,  0,
387    "day",       VN_DAY,   0,
388    "dialnumber",VN_DNUM,  0,           /* 192 */
389    "dialresult",VN_MDMSG, 0,           /* 192 */
390    "dialstatus",VN_DIAL,  0,           /* 190 */
391    "directory", VN_DIRE,  0,
392    "download",  VN_DLDIR, 0,           /* 192 */
393    "errno",     VN_ERRNO, 0,           /* 192 */
394    "errstring", VN_ERSTR, 0,           /* 192 */
395    "evaluate",  VN_EVAL,  0,           /* 190 */
396#ifdef OS2
397     "exedir",   VN_EXEDIR,0,           /* 192 */
398#endif /* OS2 */
399    "exitstatus",VN_EXIT,  0,
400    "filespec",  VN_FILE,  0,
401    "fsize",     VN_FFC,   0,           /* 190 */
402    "ftype",     VN_MODE,  0,           /* 190 */
403    "home",      VN_HOME,  0,
404    "host",      VN_HOST,  0,
405    "input",     VN_IBUF,  0,
406    "inchar",    VN_ICHR,  0,
407    "incount",   VN_ICNT,  0,
408    "inidir",    VN_INI,   0,           /* 192 */
409    "instatus",  VN_ISTAT, 0,           /* 192 */
410    "ipaddress", VN_IPADDR,0,           /* 192 */
411#ifdef OS2
412    "keyboard",  VN_KEYB,  0,
413#endif /* OS2 */
414    "line",      VN_LINE,  0,
415    "local",     VN_LCL,   0,
416    "macro",     VN_MAC,   0,
417    "minput",    VN_MINP,  0,           /* 192 */
418    "modem",     VN_MDM,   0,
419#ifndef NODIAL
420    "m_aa_off",  VN_M_ECX, 0,           /* all 192... */
421    "m_aa_on",   VN_M_AAO, 0,
422    "m_dc_off",  VN_M_DCX, 0,
423    "m_dc_on",   VN_M_DCO, 0,
424    "m_dial",    VN_M_DCM, 0,
425    "m_ec_off",  VN_M_ECX, 0,
426    "m_ec_on",   VN_M_ECO, 0,
427    "m_fc_hw",   VN_M_HWF, 0,
428    "m_fc_no",   VN_M_NFC, 0,
429    "m_fc_sw",   VN_M_SWF, 0,
430    "m_hup",     VN_M_HUP, 0,
431    "m_init",    VN_M_INI, 0,
432    "m_pulse",   VN_M_PDM, 0,
433    "m_tone",    VN_M_TDM, 0,
434#endif /* NODIAL */
435    "ndate",     VN_NDAT,  0,
436    "nday",      VN_NDAY,  0,
437    "newline",   VN_NEWL,  0,
438    "ntime",     VN_NTIM,  0,
439    "packetlen", VN_RPSIZ, 0,           /* 192 */
440    "parity",    VN_PRTY,  0,           /* 190 */
441    "password",  VN_PWD,   CM_INV,      /* 192 */
442    "platform",  VN_SYSV,  0,
443    "program",   VN_PROG,  0,
444    "query",     VN_QUE,   0,           /* 190 */
445    "prompt",    VN_PRM,   CM_INV,      /* 192 */
446    "protocol",  VN_PROTO, 0,           /* 192 */
447    "return",    VN_RET,   0,
448#ifdef CK_REXX
449    "rexx",      VN_REXX,  0,           /* 190 */
450#endif /* CK_REXX */
451    "rows",      VN_ROWS,  0,           /* 190 */
452#ifdef OS2
453    "select",    VN_SELCT, 0,           /* 192 */
454#endif /* OS2 */
455    "speed",     VN_SPEE,  0,
456#ifdef OS2
457    "space",     VN_SPA,   0,
458    "startup",   VN_STAR,  0,           /* 190 */
459#endif /* OS2 */
460    "status",    VN_SUCC,  0,
461    "sysid",     VN_SYSI,  0,
462    "system",    VN_SYST,  0,
463    "terminal",  VN_TTYP,  0,
464#ifdef OS2
465    "termkey",   VN_TRMK,  CM_INV,      /* 192 */
466#endif /* OS2 */
467    "tfsize",    VN_TFC,   0,
468    "time",      VN_TIME,  0,
469    "tmpdir",    VN_TEMP,  0,           /* 192 */
470#ifdef CK_TTYFD
471    "ttyfd",     VN_TTYF,  0,
472#endif /* CK_TTYFD */
473    "userid",    VN_UID,   0,           /* 192 */
474    "version",   VN_VERS,  0,
475    "window",    VN_WINDO, 0,           /* 192 */
476    "xversion",  VN_XVNUM, 0            /* 192 */
477};
478int nvars = (sizeof(vartab) / sizeof(struct keytab));
479#endif /* NOSPL */
480
481#ifndef NOSPL
482struct keytab fnctab[] = {              /* Function names */
483#ifdef OS2
484    ".oox",       FN_OOX, CM_INV,       /* ... */
485#endif /* OS2 */
486    "basename",   FN_BSN, 0,            /* Basename */
487    "break",      FN_BRK, 0,            /* Break (as in Snobol) */
488    "capitalize", FN_CAP, 0,            /* First Letter -> uppercase */
489    "caps",       FN_CAP, CM_INV,       /* ditto */
490    "character",  FN_CHR, 0,            /* Character from code */
491    "checksum",   FN_CHK, 0,            /* Checksum */
492    "code",       FN_COD, 0,            /* Code from character */
493    "contents",   FN_CON, 0,            /* Definition (contents) of variable */
494    "crc16",      FN_CRC, 0,            /* CRC-16 */
495#ifdef OS2
496    "crypt",      FN_CRY, CM_INV,
497#endif /* OS2 */
498#ifdef ZFCDAT
499    "date",       FN_FD,  0,            /* File modification/creation date */
500#endif /* ZFCDAT */
501    "definition", FN_DEF, 0,            /* Return definition of given macro */
502    "evaluate",   FN_EVA, 0,            /* Evaluate given arith expression */
503    "execute",    FN_EXE, 0,            /* Execute given macro */
504    "files",      FN_FC,  0,            /* File count */
505    "hexify",     FN_HEX, 0,            /* Hexify */
506    "index",      FN_IND, 0,            /* Index (string search) */
507    "ipaddress",  FN_IPA, 0,            /* Find and return IP address */
508    "length",     FN_LEN, 0,            /* Return length of argument */
509    "literal",    FN_LIT, 0,            /* Return argument literally */
510    "lower",      FN_LOW, 0,            /* Return lowercased argument */
511    "lpad",       FN_LPA, 0,            /* Return left-padded argument */
512    "ltrim",      FN_LTR, 0,            /* Left-Trim */
513    "maximum",    FN_MAX, 0,            /* Return maximum of two arguments */
514    "minimim",    FN_MIN, 0,            /* Return minimum of two arguments */
515    "modulus",    FN_MOD, CM_INV,       /* Return modulus of two arguments */
516    "nextfile",   FN_FIL, 0,            /* Next file in list */
517    "pathname",   FN_FFN, 0,            /* Full file name */
518    "rep",        FN_REP, CM_INV|CM_ABR,
519    "repeat",     FN_REP, 0,            /* Repeat argument given # of times */
520    "replace",    FN_RPL, 0,            /* Replace characters in string */
521    "reverse",    FN_REV, 0,            /* Reverse the argument string */
522    "right",      FN_RIG, 0,            /* Rightmost n characters of string */
523    "rindex",     FN_RIX, 0,            /* Right index */
524    "rpad",       FN_RPA, 0,            /* Right-pad the argument */
525    "size",       FN_FS,  0,            /* File size */
526    "span",       FN_SPN, 0,            /* Span - like Snobol */
527    "substring",  FN_SUB, 0,            /* Extract substring from argument */
528    "tod2secs",   FN_TOD, 0,            /* Time-of-day-to-secs-since-midnite */
529    "trim",       FN_TRM, 0,            /* Trim */
530    "unhexify",   FN_UNH, 0,            /* Unhexify */
531    "upper",      FN_UPP, 0,            /* Return uppercased argument */
532    "verify",     FN_VER, 0             /* Verify */
533};
534int nfuncs = (sizeof(fnctab) / sizeof(struct keytab));
535#endif /* NOSPL */
536
537#ifndef NOSPL                           /* Buffer for expansion of */
538#define VVBUFL 256                      /* built-in variables. */
539char vvbuf[VVBUFL+1];
540#endif /* NOSPL */
541
542struct keytab disptb[] = {              /* Log file disposition */
543    "append",    1,  0,
544    "new",       0,  0
545};
546
547/*
548  P R E S C A N -- A quick look through the command-line options for
549  items that must be handled before the initialization file is executed.
550*/
551#ifdef NT
552extern int StartedFromDialer;
553#endif /* NT */
554
555VOID
556prescan(y) int y; {
557    int yargc; char **yargv;
558    char x;
559    char *yp;
560
561    yargc = xargc;
562    yargv = xargv;
563
564#ifdef DCMDBUF
565    if (!kermrc)
566      if (!(kermrc = (char *) malloc(KERMRCL+1)))
567        fatal("prescan: no memory for kermrc");
568#endif /* DCMDBUF */
569
570    strcpy(kermrc,KERMRC);              /* Default init file name */
571
572#ifndef NOCMDL
573#ifndef NOICP
574    if (yargc > 1 && *yargv[1] != '-') { /* Filename as 1st argument */
575#ifdef OS2
576        extern char startupdir[], exedir[], inidir[];
577        char * scriptenv, * keymapenv;
578#endif /* OS2 */
579#ifdef DCMDBUF
580        extern char * cmdbuf;
581#else
582        extern char cmdbuf[];
583#endif /* DCMDBUF */
584        char takepath[1024];
585        char *s;
586        int x, y;
587
588        if (!isabsolute(yargv[1])) {    /* If not absolute */
589            /* Set up search path... */
590#ifdef OS2   
591#ifdef NT
592            scriptenv = getenv("K95SCRIPTS");
593            keymapenv = getenv("K95KEYMAPS");
594#else /* NT */
595            scriptenv = getenv("K2SCRIPTS");
596            keymapenv = getenv("K2KEYMAPS");
597#endif /* NT */
598            if (!scriptenv)
599              scriptenv = getenv("CK_SCRIPTS");
600            if (!keymapenv)
601              keymapenv = getenv("CK_KEYMAPS");
602
603            sprintf(takepath,
604                    /* semicolon-separated path list */
605                    "%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s;%s;%s%s;%s%s",
606                    scriptenv?scriptenv:"",
607                    (scriptenv && scriptenv[strlen(scriptenv)-1]==';')?"":";",
608                    keymapenv?keymapenv:"",
609                    (keymapenv && keymapenv[strlen(keymapenv)-1]==';')?"":";",
610                    startupdir,
611                    startupdir, "SCRIPTS/",   
612                    startupdir, "KEYMAPS/",
613                    inidir,
614                    inidir, "SCRIPTS/",
615                    inidir, "KEYMAPS/",
616                    exedir,
617                    exedir, "SCRIPTS/",
618                    exedir, "KEYMAPS/"
619                );
620#else /* not OS2 */
621#ifndef NOSPL
622            y = 1024;                   /* Look in home directory */
623            s = takepath;
624            zzstring("\\v(home)",&s,&y);
625#else
626            takepath[0] = '\0';
627#endif /* NOSPL */
628#endif /* OS2 */
629/*
630  All the logic for searching the take path is in the command parser.
631  So even though we aren't parsing commands, we initialize and call the
632  parser from here, with the purported filename stuffed into the command
633  buffer, followed by some carriage returns to make the parser return.
634  If the file is not found, or otherwise not accessible, the parser prints
635  an appropriate message, and then we just exit.
636*/
637            cmdini();                   /* Allocate command buffers etc */
638            cmini(0);                   /* Initialize them */
639            strcpy(cmdbuf,yargv[1]);    /* Stuff filename into command buf */
640            strcat(cmdbuf,"\r\r");      /* And some carriage returns */
641            if ((y = cmifip("","",&s,&x,0,takepath,xxstring)) < 0)
642              doexit(BAD_EXIT,xitsta);
643            cmres();
644        } else
645          s = yargv[1];
646        /* cfilef = 1; */       /* Command file */
647#ifdef ZFNQFP
648        zfnqfp(s,CKMAXPATH,cmdfil); /* In case of CD in file */
649#else
650        strncpy(cmdfil,CKMAXPATH,s);
651#endif /* ZFNQFP */
652        yargc -= 1;                     /* Skip past the filename */
653        yargv += 1;                     /* Otherwise we'll get an error */
654    }
655#endif /* NOICP */
656    while (--yargc > 0) {               /* Go through command-line args */
657        yargv++;
658        yp = *yargv+1;                  /* Pointer for bundled args */
659        if (**yargv == '=') return;     /* Same rules as cmdlin()... */
660#ifdef VMS
661        else if (**yargv == '/')
662          continue;
663#endif /* VMS */
664        else if (**yargv == '-') {      /* Got an option (begins with dash) */
665            x = *(*yargv+1);            /* Get option letter */
666            while (x) {                 /* Allow for bundled options */
667                debug(F000,"prescan arg","",x);
668                switch (x) {
669#ifdef OS2
670                  case 'W':
671                    if (*(yp+1))
672                      fatal("invalid argument bundling after -W");
673                    yargv++, yargc--;
674                    if (yargc < 1)
675                      fatal("Window handle missing");
676                    if (y) {
677                        yargv++, yargc--;
678                        break;
679                    } else {   
680                        hwndDialer = (HWND) atol(*yargv);
681                        StartedFromDialer = 1;
682                        yargv++, yargc--;
683                        KermitDialerID = atol(*yargv) ;
684                    }
685                    break;
686#endif /* OS2 */
687
688#ifndef NOSPL
689                case 'M':                               /* My User Name */
690                      if (*(yp+1)) {
691                          fatal("invalid argument bundling");
692                      }
693                      yargv++, yargc--;
694                      if ((yargc < 1) || (**yargv == '-')) {
695                          fatal("missing username");
696                      }
697                      if ((int)strlen(*yargv) > 63) {
698                          fatal("username too long");
699                      }
700                      strcpy(uidbuf,*yargv);
701                      break;
702#endif /* NOSPL */
703                  case 'R':             /* Remote-only advisory */
704#ifdef CK_IFRO
705                    remonly = 1;
706#endif /* CK_IFRO */
707                    break;
708                  case 'S':             /* STAY */
709                    stayflg = 1;
710                    break;
711                  case 'h':
712                  case 'Y':             /* No init file */
713                    noinit = 1;
714                    break;
715                  case 'd':             /* = SET DEBUG ON */
716#ifdef DEBUG
717                    if (!deblog)
718                      deblog = debopn("debug.log",0);
719#endif /* DEBUG */
720                    break;
721                  case 'y':             /* Alternative init file */
722                    yargv++, yargc--;
723                    if (yargc < 1) fatal("missing name in -y");
724                    if (!y)
725                      break;
726                    strcpy(kermrc,*yargv); /* Replace init file name */
727                    rcflag = 1;         /* Flag that this has been done */
728                    break;
729                  case 'z':             /* = SET BACKGROUND OFF */
730                    bgset = 0;
731                    break;
732#ifdef CK_NETBIOS
733                  case 'N':
734                    {
735                        int n ;
736                        yargv++, yargc--;
737                        if (y)
738                          break;
739                        if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
740                            NetBiosAdapter = -1;
741                        } else {
742                            n = atoi(*yargv);
743                            if (n >= 0 && n <= 9)
744                              NetBiosAdapter = n;
745                            else
746                              NetBiosAdapter = -1;
747                        }
748                    }
749                    break;
750#endif /* CK_NETBIOS */
751                  default:
752                    break;
753                }
754                x = *++yp;              /* See if options are bundled */
755            }
756        }
757    }
758#endif /* NOCMDL */
759}
760
761static int tr_int;                      /* Flag if TRANSMIT interrupted */
762
763#ifndef MAC
764SIGTYP
765#ifdef CK_ANSIC
766trtrap(int foo)                         /* TRANSMIT interrupt trap */
767#else
768trtrap(foo) int foo;                    /* TRANSMIT interrupt trap */
769#endif /* CK_ANSIC */
770/* trtrap */ {
771#ifdef __EMX__
772    signal(SIGINT, SIG_ACK);
773#endif
774    tr_int = 1;                         /* (Need arg for ANSI C) */
775    SIGRETURN;
776}
777#endif /* MAC */
778#endif /* NOICP */
779
780/*  G E T T C S  --  Get Transfer (Intermediate) Character Set  */
781
782/*
783  Given two file character sets, this routine picks out the appropriate
784  "transfer" character set to use for translating between them.
785  The transfer character set number is returned.
786
787  Translation between two file character sets is done, for example,
788  by the CONNECT, TRANSMIT, and TRANSLATE commands.
789
790  Translation between Kanji character sets is not yet supported.
791*/
792int
793gettcs(cs1,cs2) int cs1, cs2; {
794#ifdef NOCSETS                          /* No character-set support */
795    return(0);                          /* so no translation */
796#else
797    int tcs = TC_TRANSP;
798#ifdef KANJI
799/* Kanji not supported yet */
800    if (fcsinfo[cs1].alphabet == AL_JAPAN ||
801        fcsinfo[cs2].alphabet == AL_JAPAN )
802      tcs = TC_TRANSP;
803    else
804#endif /* KANJI */
805#ifdef CYRILLIC
806/*
807  I can't remember why we don't test both sets here, but I think there
808  must have been a reason...
809*/
810      if (fcsinfo[cs2].alphabet == AL_CYRIL)
811        tcs = TC_CYRILL;
812      else
813#endif /* CYRILLIC */
814#ifdef LATIN2
815        if (cs1 == FC_2LATIN || cs2 == FC_2LATIN ||
816            cs1 == FC_CP852  || cs2 == FC_CP852 )
817          tcs = TC_2LATIN;
818        else
819#endif /* LATIN2 */
820#ifdef HEBREW
821          if (fcsinfo[cs1].alphabet == AL_HEBREW ||
822              fcsinfo[cs2].alphabet == AL_HEBREW )
823            tcs = TC_HEBREW;
824          else
825#endif /* HEBREW */
826            tcs = TC_1LATIN;
827    return(tcs);
828#endif /* NOCSETS */
829}
830
831#ifndef NOLOCAL
832/*  D O C O N E C T  --  Do the connect command  */
833/*
834  q = 0 means issue normal informational message about how to get back, etc.
835  q != 0 means to skip the message.
836*/
837
838int
839doconect(q) int q; {
840    int x;                              /* Return code */
841    extern int what;
842#ifndef NOKVERBS                        /* Keyboard macro material */
843    extern int keymac, keymacx;
844#endif /* NOKVERBS */
845    extern int justone;
846    int qsave;                          /* For remembering "quiet" value */
847/*
848  Saving, changing, and restoring the global "quiet" variable around calls
849  to conect() to control whether the verbose CONNECT message is printed is
850  obviously less elegant than passing a parameter to conect(), but we do it
851  this way to avoid the need to change all of the ck?con.c modules.  NOTE:
852  it is important to restore the value immediately upon return in case there
853  is an autodownload or APC.
854*/
855    qsave = quiet;                      /* Save it */
856    if (!quiet && q > -1)
857      quiet = q;                        /* Use argument temporarily */
858    conres();                           /* Put console back to normal */
859    debug(F101,"doconect justone 1","",justone);
860    x = conect();                       /* Connect the first time */
861    quiet = qsave;                      /* Restore "quiet" value */
862
863    debug(F101,"doconect justone 2","",justone);
864#ifdef NETCONN
865    if (network && tn_exit && ttyfd == -1)
866      doexit(GOOD_EXIT,xitsta);         /* Exit with good status */     
867#endif /* NETCONN */
868
869    concb((char)escape);                /* Restore console for commands */
870
871#ifdef CK_APC
872/*
873  If an APC command was received during CONNECT mode, we define it now
874  as a macro, execute the macro, and then return to CONNECT mode.
875  We do this in a WHILE loop in case additional APCs come during subsequent
876  CONNECT sessions.
877*/
878    while (apcactive == APC_LOCAL ||
879           apcactive == APC_REMOTE && apcstatus != APC_OFF) {
880        debug(F101,"doconect justone 3","",justone);
881        domac("apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
882        if (!apcactive)                 /* In case CLEAR APC was in APC */
883          break;
884#ifdef OS2
885        msleep(250);
886#endif /* OS2 */
887        debug(F101,"doconect justone 4","",justone);
888        qsave = quiet;                  /* Do this again... */
889        if (!quiet && q > -1)
890          quiet = q;
891        x = conect();                   /* Re-CONNECT. */
892        quiet = qsave;
893        debug(F101,"doconect justone 5","",justone);
894#ifdef NETCONN
895        if (network && tn_exit && ttyfd == -1)
896          doexit(GOOD_EXIT,xitsta);     /* Exit with good status */     
897#endif /* NETCONN */
898        concb((char)escape);            /* Restore console. */
899        if (ttyfd == -1)
900          break;
901    }                                   /* Loop back for more. */
902#endif /* CK_APC */
903
904#ifndef NOKVERBS
905    if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
906        /* Set up the macro and return */
907        /* Do not clear the keymac flag */
908        return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
909    }
910#endif /* NOKVERBS */
911    what = W_COMMAND;                   /* Back in command mode. */
912    return(x);                          /* Done. */
913}
914#endif /* NOLOCAL */
915
916#ifndef NOICP
917#ifdef COMMENT
918/*
919  It seemed that this was needed for OS/2, in which \v(cmdfile) and other
920  file-oriented variables or functions can return filenames containing
921  backslashes, which are subsequently interpreted as quotes rather than
922  directory separators (e.g. see commented section for VN_CMDF below).
923  But the problem can't be cured at this level.  Example:
924
925    type \v(cmdfile)
926
927  Without doubling, the filename is parsed correctly, but then when passed
928  to UNIX 'cat' through the shell, the backslash is removed, and then cat
929  can't open the file.  With doubling, the filename is not parsed correctly
930  and the TYPE command fails immediately with a "file not found" error.
931*/
932/*
933  Utility routine to double all backslashes in a string.
934  s1 is pointer to source string, s2 is pointer to destination string,
935  n is length of destination string, both NUL-terminated.
936  Returns 0 if OK, -1 if not OK (destination string too short).
937*/
938int
939dblbs(s1,s2,n) char *s1, *s2; int n; {
940    int i = 0;
941    while (*s1) {
942        if (*s1 == '\\') {
943            if (++i > n) return(-1);
944            *s2++ = '\\';
945        }
946        if (++i > n) return(-1);
947        *s2++ = *s1++;
948    }
949    *s2 = NUL;
950    return(0);
951}
952#endif /* COMMENT */
953
954char *
955gmdmtyp() {                             /* Get modem type */
956#ifndef NODIAL
957    int i, x;
958    x = mdmtyp;
959    if (x < 0)                          /* In case of network dialing */
960      x = mdmsav;
961    if (x < 1)   
962      return("none");
963    else
964      for (i = 0; i < nmdm; i++)
965        if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
966          return(mdmtab[i].kwd);
967#endif /* NODIAL */
968    return("none");
969}
970
971#ifndef NOXMIT
972#ifndef NOLOCAL
973/*  T R A N S M I T  --  Raw upload  */
974
975/*  Obey current line, duplex, parity, flow, text/binary settings. */
976/*  Returns 0 upon apparent success, 1 on obvious failure.  */
977
978/***
979 Things to add:
980 . Make both text and binary mode obey set file bytesize.
981 . Maybe allow user to specify terminators other than CR?
982 . Maybe allow user to specify prompts other than single characters?
983***/
984
985/*  T R A N S M I T  --  Raw upload  */
986
987/*  s is the filename, t is the turnaround (prompt) character  */
988
989/*
990  Maximum number of characters to buffer.
991  Must be less than LINBUFSIZ
992*/
993#define XMBUFS 120
994
995#ifdef NETCONN
996#ifndef IAC
997#define IAC 255
998#endif /* IAC */
999#endif /* NETCONN */
1000
1001int
1002#ifdef CK_ANSIC
1003transmit(char * s, char t)
1004#else
1005transmit(s,t) char *s; char t;
1006#endif /* CK_ANSIC */
1007/* transmit */ {
1008#ifdef MAC
1009    extern char sstate;
1010    int count = 100;
1011#else
1012#ifdef OS2
1013#ifdef NT
1014SIGTYP (* oldsig)(int);                 /* For saving old interrupt trap. */
1015#else /* NT */
1016SIGTYP (* volatile oldsig)(int);        /* For saving old interrupt trap. */
1017#endif /* NT */
1018
1019#else /* OS2 */
1020    SIGTYP (* oldsig)();
1021#endif /* OS2 */
1022#endif /* MAC */
1023    long zz;
1024    int z = 1;                          /* Return code. 0=fail, 1=succeed. */
1025    int x, c, i;                        /* Workers... */
1026    int myflow;
1027    int mybinary;
1028#ifdef COMMENT
1029    CHAR csave;
1030#endif /* COMMENT */
1031    char *p;
1032
1033#ifndef NOCSETS
1034    int tcs = TC_TRANSP;                /* Intermediate (xfer) char set */
1035    int langsv = L_USASCII;             /* Save current language */
1036
1037#ifdef CKOUNI
1038    _PROTOTYP ( USHORT (*sxo), (CHAR) ) = NULL; /* Translation functions */
1039    _PROTOTYP ( int (*rxo), (USHORT) ) = NULL;
1040    _PROTOTYP ( USHORT (*sxi), (CHAR) ) = NULL;
1041    _PROTOTYP ( int (*rxi), (USHORT) ) = NULL;
1042#else /* CKOUNI */
1043    _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
1044    _PROTOTYP ( CHAR (*rxo), (CHAR) ) = NULL;
1045    _PROTOTYP ( CHAR (*sxi), (CHAR) ) = NULL;
1046    _PROTOTYP ( CHAR (*rxi), (CHAR) ) = NULL;
1047#endif /* CKOUNI */
1048#endif /* NOCSETS */
1049
1050/*
1051   If a system-specific binary mode is set (MacBinary, Image, Labeled, etc),
1052   revert to "normal" binary mode for duration of TRANSMIT command.
1053*/
1054    mybinary = binary;
1055    if (binary) binary = XYFT_B;
1056    if (zopeni(ZIFILE,s) == 0) {        /* Open the file to be transmitted */
1057        printf("?Can't open file %s\n",s);
1058        binary = mybinary;
1059        return(0);
1060    }
1061    x = -1;                             /* Open the communication line */
1062    if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {  /* (no harm if already open) */
1063        printf("Can't open device %s\n",ttname);
1064        binary = mybinary;
1065        return(0);
1066    }
1067    zz = x ? speed : -1L;
1068    if (binary) {                       /* Binary file transmission */
1069        myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
1070        if (ttvt(zz,myflow) < 0) {      /* So no Xon/Xoff! */
1071            printf("Can't condition line\n");
1072            binary = mybinary;
1073            return(0);
1074        }
1075    } else {
1076        if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
1077            printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
1078            binary = mybinary;
1079            return(0);
1080        }
1081    }
1082
1083#ifndef NOCSETS
1084#ifdef CKOUNI
1085/* Set up character set translations */
1086    if (binary == 0) {
1087        if (tcsr == tcsl || binary) {   /* Remote and local sets the same? */
1088            sxo = NULL;                 /* Or file type is not text? */
1089            rxo = NULL;         
1090            sxi = NULL;
1091            rxi = NULL;
1092        } else { 
1093            sxo = xl_u[tcsl];
1094            rxo = xl_tx[tcsr];
1095            rxi = xl_tx[tcsl];
1096            sxi = xl_u[tcsr];
1097        }
1098/*
1099   This is to prevent use of zmstuff() and zdstuff() by translation functions.
1100   They only work with disk i/o, not with communication i/o.  Luckily Russian
1101   translation functions don't do any stuffing...
1102*/
1103        langsv = language;
1104        language = L_USASCII;
1105    }
1106#else /* CKOUNI */
1107    tcs = gettcs(tcsr,tcsl);            /* Get intermediate set. */
1108
1109/* Set up character set translations */
1110    if (binary == 0) {
1111
1112        if (tcsr == tcsl || binary) {   /* Remote and local sets the same? */
1113            sxo = rxo = NULL;           /* Or file type is not text? */
1114            sxi = rxi = NULL;
1115        } else {                        /* Otherwise, set up */
1116            sxo = xls[tcs][tcsl];       /* translation function */
1117            rxo = xlr[tcs][tcsr];       /* pointers for output functions */
1118            sxi = xls[tcs][tcsr];       /* and for input functions. */
1119            rxi = xlr[tcs][tcsl];
1120        }
1121/*
1122  This is to prevent use of zmstuff() and zdstuff() by translation functions.
1123  They only work with disk i/o, not with communication i/o.  Luckily Russian
1124  translation functions don't do any stuffing...
1125*/
1126        langsv = language;
1127        language = L_USASCII;
1128    }
1129#endif /* CKOUNI */
1130#endif /* NOCSETS */
1131
1132    i = 0;                              /* Beginning of buffer. */
1133#ifndef MAC
1134#ifndef AMIGA
1135    oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
1136#endif /* AMIGA */
1137#endif /* MAC */
1138    tr_int = 0;                         /* Have not been interrupted (yet). */
1139    z = 1;                              /* Return code presumed good. */
1140#ifdef VMS
1141    conres();
1142#endif /* VMS */
1143
1144    c = 0;                              /* Initial condition */
1145    while (c > -1) {                    /* Loop for all characters in file */
1146#ifdef MAC
1147        /*
1148         * It is expensive to run the miniparser so don't do it for
1149         * every character.
1150         */
1151        if (--count < 0) {
1152            count = 100;
1153            miniparser(1);
1154            if (sstate == 'a') {
1155                sstate = '\0';
1156                z = 0;
1157                break;
1158            }
1159        }
1160#else /* Not MAC */
1161        if (tr_int) {                   /* Interrupted? */
1162            printf("^C...\n");          /* Print message */
1163            z = 0;
1164            break;
1165        }
1166#endif /* MAC */
1167        c = zminchar();                 /* Get a file character */
1168        debug(F101,"transmit char","",c);
1169        if (c == -1)                    /* Test for end-of-file */
1170          break;
1171        if (c < 0) {
1172            z = 0;
1173            goto xmitexit;         
1174        }
1175        c &= fmask;                     /* Apply SET FILE BYTESIZE mask */
1176
1177        if (binary) {                   /* If binary file, */
1178            if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
1179                printf("?Can't transmit character\n");
1180                z = 0;
1181                goto xmitexit;
1182            }
1183#ifdef TNCODE
1184            if (c == IAC && network && ttnproto == NP_TELNET)
1185              ttoc((char)IAC);
1186#endif /* TNCODE */
1187            if (xmitw) msleep(xmitw);   /* Pause if requested */
1188            if (xmitx) {                /* SET TRANSMIT ECHO ON? */
1189                if (duplex) {           /* Yes, for half duplex */
1190                    if (conoc((char)(c & cmdmsk)) < 0) { /* echo locally. */
1191                        z = 0;
1192                        goto xmitexit;
1193                    }
1194                } else {                /* For full duplex, */
1195                    int i, n;           /* display whatever is there. */
1196                    n = ttchk();        /* See how many chars are waiting */
1197                    if (n < 0) {        /* Connection dropped? */
1198                        z = 0;
1199                        goto xmitexit;
1200                    }
1201                    for (i = 0; i < n; i++) { /* Read and echo that many. */
1202                        x = ttinc(1);   /* Timed read just in case. */
1203                        if (x > -1) {   /* If no timeout */
1204                            if (parity) x &= 0x7f; /* display the char, */
1205                            if (conoc((char)(x & cmdmsk)) < 0) {
1206                                z = 0;
1207                                goto xmitexit;
1208                            }
1209                        } else break;   /* otherwise stop reading. */
1210                    }
1211                }
1212            } else ttflui();            /* Not echoing, just flush input. */
1213
1214        } else {                        /* Text mode, line at a time. */
1215
1216            if (c == '\n') {            /* Got a line */
1217                int stuff = -1;
1218                if (i == 0) {           /* Blank line? */
1219                    if (xmitf)          /* Yes, insert fill if asked. */
1220                      line[i++] = dopar((char) xmitf);
1221                }
1222                if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
1223                  line[i++] = dopar(CR); /* Terminate it with CR */
1224                if (xmitl) {
1225                    stuff = LF;
1226#ifdef TNCODE
1227                } else if (network &&   /* TELNET NEWLINE ON/OFF/RAW */
1228                           (ttnproto == NP_TELNET) &&
1229                           (tn_nlm != TNL_CR)) {
1230                    stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
1231#endif /* TNCODE */
1232                }
1233                if (stuff > -1)
1234                  line[i++] = dopar((char)stuff);
1235
1236            } else if (c != -1) {       /* Not a newline, regular character */
1237#ifdef COMMENT
1238                csave = c;              /* Remember untranslated version */
1239#endif /* COMMENT */
1240#ifndef NOCSETS
1241                /* Translate character sets */
1242#ifdef CKOUNI
1243                if (cs_is_nrc(tcsl) || c > 127)
1244                  if (sxo) c = (*sxo)(c); /* From local to intermediate */
1245                if (c >= 32)
1246                  if (rxo) c = (*rxo)(c); /* From intermediate to remote */
1247#else /* CKOUNI */
1248                if (sxo) c = (*sxo)((CHAR)c); /* From local to intermediate */
1249                if (rxo) c = (*rxo)((CHAR)c); /* From intermediate to remote */
1250#endif /* CKOUNI */
1251#endif /* NOCSETS */
1252
1253                if (xmits && parity && (c & 0200)) { /* If shifting */
1254                    line[i++] = dopar(SO);          /* needs to be done, */
1255                    line[i++] = dopar((char)c);     /* do it here, */
1256                    line[i++] = dopar(SI);          /* crudely. */
1257                } else {
1258                    line[i++] = dopar((char)c); /* else, just char itself */
1259#ifdef TNCODE
1260                    if (c == IAC && network && ttnproto == NP_TELNET)
1261                      line[i++] = IAC;
1262#endif /* TNCODE */
1263                }
1264            }
1265
1266/* Send characters if buffer full, or at end of line, or at end of file */
1267
1268            if (i >= XMBUFS || c == '\n' || c == -1) {
1269                p = line;
1270                line[i] = '\0';
1271                debug(F111,"transmit buf",p,i);
1272                if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
1273                    printf("Can't send buffer\n");
1274                    z = 0;
1275                    break;
1276                }
1277                i = 0;                  /* Reset buffer pointer. */
1278
1279/* Worry about echoing here. "xmitx" is SET TRANSMIT ECHO flag. */
1280
1281                if (duplex && xmitx) {  /* If local echo, echo it */
1282                    if (parity || cmdmsk == 0x7f) { /* Strip off high bits */
1283                        char *s = p;                /* if necessary */
1284                        while (*s) {
1285                            *s &= 0x7f;
1286                            s++;
1287                        }
1288                        if (conoll(p) < 0) {
1289                            z = 0;
1290                            goto xmitexit;
1291                        }
1292                    }
1293                }
1294                if (xmitw)              /* Give receiver time to digest. */
1295                  msleep(xmitw);
1296                if (t != 0 && c == '\n') { /* Want a turnaround character */
1297                    x = 0;                 /* Wait for it */
1298                    while (x != t) {
1299                        if ((x = ttinc(1)) < 0) { z = 0; goto xmitexit; }
1300                        if (xmitx && !duplex) { /* Echo any echoes */
1301                            if (parity) x &= 0x7f;
1302#ifndef NOCSETS
1303#ifdef CKOUNI
1304                            if (cs_is_nrc(tcsr) || x > 127)
1305                              if (sxi) x = (*sxi)(x);
1306                            if (x >= 32)
1307                              if (rxi) x = (*rxi)(x);
1308#else /* CKOUNI */
1309                            if (sxi) x = (*sxi)((CHAR)x); /* But translate */
1310                            if (rxi) x = (*rxi)((CHAR)x); /* them first... */
1311#endif /* CKOUNI */
1312#endif /* NOCSETS */
1313                            if (conoc((char) x) < 0) { z = 0; goto xmitexit; }
1314                        }
1315                    }
1316                } else if (xmitx && !duplex) { /* Otherwise, */
1317                    int n;
1318                    while ((n = ttchk()) > 0) { /* echo for as long as */
1319                        if ((x = ttinc(0)) < 0) break; /* anything is there. */
1320                        if (parity) x &= 0x7f;
1321#ifndef NOCSETS
1322#ifdef CKOUNI
1323                        if (cs_is_nrc(tcsr) || x > 127)
1324                          if (sxi) x = (*sxi)(x);
1325                        if (x >= 32)
1326                          if (rxi) x = (*rxi)(x);
1327#else /* CKOUNI */
1328                        if (sxi) x = (*sxi)((CHAR)x); /* Translate first */
1329                        if (rxi) x = (*rxi)((CHAR)x);
1330#endif /* CKOUNI */
1331#endif /* NOCSETS */
1332                        if (conoc((char)x) < 0) { z = 0; goto xmitexit; }
1333                    }
1334                    if (n < 0) {        /* Connection dropped? */
1335                        z = 0;
1336                        goto xmitexit;
1337                    }
1338                } else ttflui();        /* Otherwise just flush input buffer */
1339            }                           /* End of buffer-dumping block */
1340        }                               /* End of text mode */
1341    }                                   /* End of character-reading loop */
1342
1343xmitexit:
1344
1345    if (z > 0) {
1346        if (*xmitbuf) {                 /* Anything to send at EOF? */
1347            p = xmitbuf;                /* Yes, point to string. */
1348            while (*p)                  /* Send it. */
1349              ttoc(dopar(*p++));        /* Don't worry about echo here. */
1350        }
1351    }
1352
1353#ifndef AMIGA
1354#ifndef MAC
1355    signal(SIGINT,oldsig);              /* Put old signal action back. */
1356#endif /* MAC */
1357#endif /* AMIGA */
1358#ifdef VMS
1359    concb(escape);                      /* Put terminal back, */
1360#endif /* VMS */
1361    zclose(ZIFILE);                     /* Close file, */
1362#ifndef NOCSETS
1363    language = langsv;                  /* restore language, */
1364#endif /* NOCSETS */
1365    binary = mybinary;                  /* restore transfer mode, */
1366    ttres();                            /* and terminal modes, */
1367    return(z);                          /* and return successfully. */
1368}
1369#endif /* NOLOCAL */
1370#endif /* NOXMIT */
1371
1372#ifndef NOCSETS
1373
1374_PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
1375_PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
1376_PROTOTYP( CHAR zl1as, (CHAR) );        /* Latin-1 to ascii */
1377_PROTOTYP( CHAR xl1as, (CHAR) );        /* ditto */
1378
1379/*  X L A T E  --  Translate a local file from one character set to another */
1380
1381/*
1382  Translates input file (fin) from character set csin to character set csout
1383  and puts the result in the output file (fout).  The two character sets are
1384  file character sets from fcstab.
1385*/
1386
1387int
1388xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
1389
1390#ifndef MAC
1391#ifdef OS2
1392#ifdef NT
1393    SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
1394#else /* NT */
1395    SIGTYP (* volatile oldsig)(int);    /* For saving old interrupt trap. */
1396#endif /* NT */
1397#else /* OS2 */   
1398    SIGTYP (* oldsig)();                /* For saving old interrupt trap. */
1399#endif /* OS2 */
1400#endif /* MAC */
1401    int filecode;                       /* Code for output file */
1402
1403    int z = 1;                          /* Return code. */
1404    int c, tcs;                         /* Workers */
1405
1406    if (zopeni(ZIFILE,fin) == 0) {      /* Open the file to be translated */
1407        printf("?Can't open input file %s\n",fin);
1408        return(0);
1409    }
1410#ifdef MAC
1411/*
1412  If user specified no output file, it goes to the screen.  For the Mac,
1413  this must be done a special way (result goes to a new window); the Mac
1414  doesn't have a "controlling terminal" device name.
1415*/
1416    filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
1417#else
1418#ifdef VMS
1419    filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
1420#else
1421    filecode = ZOFILE;
1422#endif /* VMS */
1423#endif /* MAC */
1424
1425    if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
1426        printf("?Can't open output file %s\n",fout);
1427        return(0);
1428    }
1429#ifndef AMIGA
1430#ifndef MAC
1431    oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
1432#endif /* MAC */
1433#endif /* AMIGA */
1434
1435    tr_int = 0;                         /* Have not been interrupted (yet). */
1436    z = 1;                              /* Return code presumed good. */
1437
1438    tcs = gettcs(csin,csout);           /* Get intermediate set. */
1439
1440    printf("%s (%s) => %s (%s)\n",      /* Say what we're doing. */
1441           fin, fcsinfo[csin].name,
1442           fout,fcsinfo[csout].name
1443    );
1444    printf("via %s", tcsinfo[tcs].name);
1445    if (language)
1446      printf(", language: %s\n",langs[language].description);
1447    printf("\n\n");
1448
1449    if (csin == csout) {                /* Input and output sets the same? */
1450        sxx = rxx = NULL;               /* If so, no translation. */
1451    } else {                            /* Otherwise, set up */
1452        sxx = xls[tcs][csin];           /* translation function */
1453        rxx = xlr[tcs][csout];          /* pointers. */
1454        if (rxx == zl1as) rxx = xl1as;
1455    }
1456    while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
1457        if (tr_int) {                   /* Interrupted? */
1458            printf("^C...\n");          /* Print message */
1459            z = 0;
1460            break;
1461        }
1462        if (sxx) c = (*sxx)((CHAR)c);   /* From fcs1 to tcs */
1463        if (rxx) c = (*rxx)((CHAR)c);   /* from tcs to fcs2 */
1464
1465        if (zchout(filecode,(char)c) < 0) { /* Output the xlated character */
1466            printf("File output error\n");
1467            z = 0;
1468            break;
1469        }
1470    }
1471#ifndef AMIGA
1472#ifndef MAC
1473    signal(SIGINT,oldsig);              /* put old signal action back. */
1474#endif /* MAC */
1475#endif /* AMIGA */
1476
1477    tr_int = 0;
1478    zclose(ZIFILE);                     /* close files, */
1479    zclose(filecode);
1480    return(z);                          /* and return successfully. */
1481}
1482#endif /* NOCSETS */
1483
1484/*  D O L O G  --  Do the log command  */
1485
1486int
1487dolog(x) int x; {
1488    int y, disp; char *s = NULL;
1489#ifdef ZFNQFP
1490    struct zfnfp * fnp;
1491#endif /* ZFNQFP */
1492
1493    switch (x) {                        /* Which log... */
1494
1495#ifdef DEBUG
1496      case LOGD:
1497        y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
1498        break;
1499#endif /* DEBUG */
1500
1501      case LOGP:
1502        y = cmofi("Name of packet log file","packet.log",&s,xxstring);
1503        break;
1504
1505#ifndef NOLOCAL
1506      case LOGS:
1507        y = cmofi("Name of session log file","session.log",&s,xxstring);
1508        break;
1509#endif /* NOLOCAL */
1510
1511#ifdef TLOG
1512      case LOGT:
1513        y = cmofi("Name of transaction log file","transact.log",&s,
1514                  xxstring);
1515        break;
1516#endif /* TLOG */
1517
1518      default:
1519        printf("\n?Unknown log designator - %d\n",x);
1520        return(-2);
1521    }
1522    if (y < 0) return(y);
1523    if (y == 2) {
1524        printf("?Sorry, %s is a directory name\n",s);
1525        return(-9);
1526    }
1527#ifdef ZFNQFP
1528    if (fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf)) {
1529        if (fnp->fpath)
1530          if ((int) strlen(fnp->fpath) > 0)
1531            s = fnp->fpath;
1532    }
1533#endif /* ZFNQFP */
1534
1535    strcpy(line,s);
1536    s = line;
1537#ifdef MAC
1538    y = 0;
1539#else
1540    if ((y = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
1541      return(y);
1542#endif /* MAC */
1543    disp = y;   
1544    if ((y = cmcfm()) < 0) return(y);
1545
1546    switch (x) {
1547
1548#ifdef DEBUG
1549      case LOGD:
1550        return(deblog = debopn(s,disp));
1551#endif /* DEBUG */
1552
1553      case LOGP:
1554        return(pktlog = pktopn(s,disp));
1555
1556#ifndef NOLOCAL
1557      case LOGS:
1558        return(seslog = sesopn(s,disp));
1559#endif /* NOLOCAL */
1560
1561#ifdef TLOG
1562      case LOGT:
1563        return(tralog = traopn(s,disp));
1564#endif /* TLOG */
1565
1566      default:
1567        return(-2);
1568    }
1569}
1570
1571int
1572pktopn(s,disp) char *s; int disp; {
1573    extern char pktfil[];
1574    static struct filinfo xx;
1575    int y;
1576
1577    zclose(ZPFILE);
1578    if(s[0] == '\0') return(0);
1579    if (disp) {
1580        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
1581        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
1582        xx.lblopts = 0;
1583        pktlog = zopeno(ZPFILE,s,NULL,&xx);
1584    } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
1585    if (pktlog > 0)
1586      strcpy(pktfil,s);
1587    else
1588      *pktfil = '\0';
1589    return(pktlog);
1590}
1591
1592int
1593traopn(s,disp) char *s; int disp; {
1594#ifdef TLOG
1595    extern char trafil[];
1596    static struct filinfo xx;
1597    int y;
1598
1599    zclose(ZTFILE);
1600    if(s[0] == '\0') return(0);
1601    if (disp) {
1602        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
1603        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
1604        xx.lblopts = 0;
1605        tralog = zopeno(ZTFILE,s,NULL,&xx);
1606    } else tralog = zopeno(ZTFILE,s,NULL,NULL);
1607    if (tralog > 0) {
1608        strcpy(trafil,s);
1609        tlog(F110,"Transaction Log:",versio,0L);
1610#ifndef MAC
1611        tlog(F100,ckxsys,"",0L);
1612#endif /* MAC */
1613        ztime(&s);
1614        tlog(F100,s,"",0L);
1615    } else *trafil = '\0';
1616    return(tralog);
1617#else
1618    return(0);
1619#endif /* TLOG */
1620}
1621
1622#ifndef NOLOCAL
1623int
1624sesopn(s,disp) char * s; int disp; {
1625    extern char sesfil[];
1626    static struct filinfo xx;
1627    int y;
1628
1629    zclose(ZSFILE);
1630    if(s[0] == '\0') return(0);
1631    if (disp) {
1632        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
1633        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
1634        xx.lblopts = 0;
1635        seslog = zopeno(ZSFILE,s,NULL,&xx);
1636    } else seslog = zopeno(ZSFILE,s,NULL,NULL);
1637    if (seslog > 0)
1638      strcpy(sesfil,s);
1639    else
1640      *sesfil = '\0';
1641    return(seslog);
1642}
1643#endif /* NOLOCAL */
1644
1645int
1646debopn(s,disp) char *s; int disp; {
1647#ifdef DEBUG
1648    char *tp;
1649    static struct filinfo xx;
1650
1651    zclose(ZDFILE);
1652
1653    if (disp) {
1654        xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
1655        xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
1656        xx.lblopts = 0;
1657        deblog = zopeno(ZDFILE,s,NULL,&xx);
1658    } else deblog = zopeno(ZDFILE,s,NULL,NULL);
1659    if (deblog > 0) {
1660        strcpy(debfil,s);
1661        debug(F110,"Debug Log ",versio,0);
1662#ifndef MAC
1663        debug(F100,ckxsys,"",0);
1664#endif /* MAC */
1665        ztime(&tp);
1666        debug(F100,tp,"",0);
1667    } else *debfil = '\0';
1668    return(deblog);
1669#else
1670    return(0);
1671#endif /* MAC */
1672}
1673
1674/*  G F M O D E  --  Get File (transfer) Mode  */
1675
1676char *
1677gfmode(binary) int binary; {
1678    char * s;
1679    switch (binary) {
1680      case XYFT_T: s = "text";         break;
1681#ifdef VMS
1682      case XYFT_B: s = "binary fixed"; break;
1683      case XYFT_I: s = "image";        break;
1684      case XYFT_L: s = "labeled";      break;
1685      case XYFT_U: s = "binary undef"; break;
1686#else
1687#ifdef MAC
1688      case XYFT_B: s = "binary";       break;
1689      case XYFT_M: s = "macbinary";    break;
1690#else
1691      case XYFT_B: s = "binary";       break;
1692#ifdef CK_LABELED
1693      case XYFT_L: s = "labeled";      break;
1694#endif /* CK_LABELED */
1695#endif /* MAC */
1696#endif /* VMS */
1697      default: s = ""; break;
1698    }
1699    return(s);
1700}
1701
1702#ifndef NOSHOW
1703
1704/*  S H O P A R  --  Show Parameters  */
1705
1706#ifdef ANYX25
1707VOID
1708shox25() {
1709    if (nettype == NET_SX25) {
1710        printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
1711        if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
1712        printf("\n Reverse charge call %s",
1713               revcall ? "selected" : "not selected");
1714        printf (", Closed user group ");
1715        if (closgr > -1)
1716          printf ("%d",closgr);
1717        else
1718          printf ("not selected");
1719        printf (",");
1720        printf("\n Call user data %s.\n", cudata ? udata : "not selected");
1721    } else if (nettype == NET_VX25) {
1722        if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
1723        printf("\n Reverse charge call %s",
1724               revcall ? "selected" : "not selected");
1725        printf (", Closed user group [unsupported]");
1726        if (closgr > -1)
1727          printf ("%d",closgr);
1728        else
1729          printf ("not selected");
1730        printf (",");
1731        printf("\n Call user data %s.\n", cudata ? udata : "not selected");
1732    }
1733}
1734#endif /* ANYX25 */
1735
1736VOID
1737shoparc() {
1738    int i; char *s;
1739    long zz;
1740
1741    printf("Communications Parameters:\n");
1742
1743    if (network) {
1744        printf(" Host: %s",ttname);
1745    } else {
1746#ifdef OS2
1747        printf(" Port: %s, speed: ",ttname);
1748#else
1749        printf(" Line: %s, speed: ",ttname);
1750#endif /* OS2 */
1751        if ((zz = ttgspd()) < 0) {
1752            printf("unknown");
1753        } else {
1754            if (speed == 8880) printf("75/1200"); else printf("%ld",zz);
1755        }
1756    }
1757    printf(", mode: ");
1758    if (local) printf("local"); else printf("remote");
1759    if (network == 0) {
1760        printf(", modem: %s",gmdmtyp());
1761    } else {
1762       if (nettype == NET_TCPA) printf(", TCP/IP");
1763       if (nettype == NET_TCPB) printf(", TCP/IP");
1764       if (nettype == NET_DEC) {
1765          if ( ttnproto == NP_LAT ) printf(", DECnet LAT");
1766          else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
1767          else printf(", DECnet");
1768        }
1769       if ( nettype == NET_SLAT ) printf(", Meridian Technologies' SuperLAT") ;
1770#ifdef NETFILE
1771       if ( nettype == NET_FILE ) printf(", local file") ;
1772#endif /* NETFILE */
1773       if (nettype == NET_PIPE) printf(", Named Pipes");
1774#ifdef ANYX25
1775        shox25();
1776#endif /* ANYX25 */
1777        if (ttnproto == NP_TELNET) printf(", telnet protocol");
1778    }
1779    if (local) {
1780        i = parity ? 7 : 8;
1781        if (i == 8) i = (cmask == 0177) ? 7 : 8;
1782        printf("\n Terminal bits: %d, p",i);
1783    } else printf("\n P");
1784    printf("arity: %s",parnam((char)parity));
1785    printf(", duplex: ");
1786    if (duplex) printf("half, "); else printf("full, ");
1787    printf("flow: ");
1788    if (flow == FLO_KEEP) printf("keep");
1789        else if (flow == FLO_AUTO) printf("auto");
1790        else if (flow == FLO_XONX) printf("xon/xoff");
1791        else if (flow == FLO_NONE) printf("none");
1792        else if (flow == FLO_RTSC) printf(network ? "none" : "rts/cts");
1793        else if (flow == FLO_DTRT) printf(network ? "none" : "dtr/cts");
1794        else if (flow == FLO_DTRC) printf(network ? "none" : "dtr/cd");
1795        else printf("%d",flow);
1796    printf(", handshake: ");
1797    if (turn) printf("%d\n",turnch); else printf("none\n");
1798    if (local && !network) {            /* Lockfile & carrier stuff */
1799        if (carrier == CAR_OFF) s = "off";
1800        else if (carrier == CAR_ON) s = "on";
1801        else if (carrier == CAR_AUT) s = "auto";
1802        else s = "unknown";
1803        printf(" Carrier: %s", s);
1804        if (carrier == CAR_ON) {
1805            if (cdtimo) printf(", timeout: %d sec", cdtimo);
1806            else printf(", timeout: none");
1807        }
1808#ifdef UNIX
1809        if (haslock && *flfnam) {       /* Lockfiles only apply to UNIX... */
1810            printf(", lockfile: %s",flfnam);
1811        }
1812#endif /* UNIX */
1813        printf("\n Escape character: %d (^%c)\n",escape,ctl(escape));
1814    }
1815}
1816
1817#ifdef TNCODE
1818static VOID
1819shotel() {
1820    printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
1821           tn_duplex ? "local" : "remote");
1822    switch (tn_nlm) {
1823      case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
1824      case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
1825      case TNL_CR:    printf("%s\n","raw (cr)"); break;
1826      case TNL_LF:    printf("%s\n","(lf)"); break;
1827    }
1828    printf(" BINARY newline-mode: ");
1829    switch (tn_b_nlm) {
1830      case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
1831      case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
1832      case TNL_CR:    printf("%s\n","raw (cr)"); break;
1833      case TNL_LF:    printf("%s\n","(lf)"); break;
1834    }
1835    printf(" binary-mode: ");
1836    switch ( tn_binary ) {
1837        case TN_BM_AC: printf( "accepted, " ); break ;
1838        case TN_BM_RF: printf( "refused, " ); break;
1839        case TN_BM_RQ: printf( "requested, "); break;
1840        };
1841    printf("host=%s, c-kermit=%s\n", u_binary ? "BINARY" : "NVT",
1842        me_binary ? "BINARY" : "NVT" ) ;
1843    printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
1844    printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
1845    printf(" terminal-type: ");
1846    if (tn_term) {
1847        printf("%s\n",tn_term);
1848    } else {
1849        char *p;
1850#ifdef OS2
1851        p = (tt_type >= 0 && tt_type <= max_tt) ?
1852          tt_info[tt_type].x_name :
1853            "UNKNOWN";
1854#else
1855        p = getenv("TERM");
1856#endif /* OS2 */
1857        if (p)
1858          printf("none (%s will be used)\n",p);
1859        else printf("none\n");
1860    }
1861}
1862#endif /* TNCODE */
1863
1864#ifdef CK_NETBIOS
1865static VOID
1866shonb() {
1867   printf("NETBIOS parameters:\n");
1868   printf(" API       : %s\n",
1869      NetbeuiAPI ?
1870          "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
1871          : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
1872   printf(" Local Name: [%s]\n", NetBiosName ) ;
1873   printf(" Adapter   : %d\n", NetBiosAdapter ) ;
1874   if ( NetBiosLSN > 0xFF )
1875     printf(" Session   : %d\n", NetBiosLSN ) ;
1876   else
1877     printf(" Session   : none active\n") ;
1878}
1879#endif /* CK_NETBIOS */
1880
1881VOID
1882shonet() {
1883#ifndef NETCONN
1884    printf("\nNo networks are supported in this version of C-Kermit\n");
1885
1886#else /* rest of this routine */
1887
1888    int i;
1889
1890#ifndef NODIAL
1891    if (nnetdir <= 1) {
1892        printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
1893    } else {
1894        int i;
1895        printf("\nNetwork directories:\n");
1896        for (i = 0; i < nnetdir; i++)
1897          printf("%2d. %s\n",i,netdir[i]);
1898    }
1899#endif /* NODIAL */
1900
1901#ifdef OS2
1902    printf("\nNetwork availability:\n");
1903#else
1904    printf("\nSupported networks:\n");
1905#endif /* OS2 */
1906
1907#ifdef VMS
1908
1909#ifdef MULTINET
1910    printf(" TGV MultiNet TCP/IP");
1911#else
1912#ifdef WINTCP
1913    printf(" WOLLONGONG WIN/TCP");
1914#else
1915#ifdef DEC_TCPIP
1916    {
1917        static $DESCRIPTOR(tcp_desc,"_TCP0:");
1918        int status;
1919        long devclass;
1920        static int itmcod = DVI$_DEVCLASS;
1921
1922#ifdef COMMENT
1923        status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
1924#else
1925        /* Martin Zinser 9/96 */
1926        status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
1927#endif /* COMMENT */
1928        if ((status & 1) && (devclass == DC$_SCOM))
1929          printf(" Process Software Corporation TCPware for OpenVMS");
1930        else
1931          printf(" DEC TCP/IP Services for (Open)VMS");
1932    }
1933#else
1934#ifdef CMU_TCPIP
1935    printf(" CMU-OpenVMS/IP");
1936#else
1937    printf(" None");
1938#endif /* CMU_TCPIP */
1939#endif /* DEC_TCPIP */
1940#endif /* WINTCP */
1941#endif /* MULTINET */
1942#ifdef TNCODE
1943    printf(", TELNET protocol\n\n");
1944    shotel();
1945#endif /* TNCODE */
1946    printf("\n");
1947
1948#else /* Not VMS */
1949
1950#ifdef SUNX25
1951    printf(" SunLink X.25\n");
1952#endif /* SUNX25 */
1953
1954#ifdef STRATUSX25
1955    printf(" Stratus VOS X.25\n");
1956#endif /* STRATUSX25 */
1957
1958#ifdef DECNET
1959#ifdef OS2
1960    if (dnet_avail)
1961      printf(" DECnet, LAT protocol\n");
1962    else
1963      printf(" DECnet, LAT protocol - not available\n");
1964#else
1965    printf(" DECnet\n");
1966#endif /* OS2 */
1967#endif /* DECNET */
1968
1969#ifdef NPIPE
1970    printf(" Named Pipes\n");
1971#endif /* NPIPE */
1972
1973#ifdef CK_NETBIOS
1974    if (netbiosAvail)
1975      printf(" NETBIOS\n");
1976    else
1977      printf(" NETBIOS - not available\n");
1978#endif /* CK_NETBIOS */
1979
1980#ifdef SUPERLAT
1981    if (slat_avail)
1982      printf(" SuperLAT\n");
1983    else
1984      printf(" SuperLAT - not available\n") ;
1985#endif /* SUPERLAT */
1986
1987#ifdef TCPSOCKET
1988    if (
1989#ifdef OS2
1990        tcp_avail
1991#else
1992        1
1993#endif /* OS2 */
1994        ) {
1995        if ( myipaddr[0] )
1996#ifdef OS2ONLY
1997          printf(" TCP/IP [%s] via %s\n", myipaddr, tcpname);
1998#else
1999          printf(" TCP/IP [%s]\n",myipaddr);
2000#endif /* OS2ONLY */
2001        else
2002#ifdef OS2ONLY
2003          printf(" TCP/IP via %s\n", tcpname);
2004#else
2005          printf(" TCP/IP\n");
2006#endif /* OS2ONLY */
2007
2008#ifdef TNCODE
2009        if (nettype == NET_TCPB) {
2010            printf("\n");
2011            shotel();
2012        }
2013#endif /* TNCODE */
2014#ifdef OS2
2015    } else {
2016        printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
2017#endif /* OS2 */
2018    }
2019#endif /* TCPSOCKET */
2020
2021#ifdef CK_NETBIOS
2022    if (netbiosAvail && nettype == NET_BIOS) {
2023       printf("\n") ;
2024       shonb();
2025    }
2026#endif /* CK_NETBIOS */
2027
2028#endif /* VMS */
2029
2030    printf("\nActive network connection:\n");
2031
2032    if (network) {
2033        printf(" Host: %s",ttname);
2034        if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
2035          printf(" [%s]",ipaddr);
2036    } else
2037      printf(" Host: none");
2038    printf(" via: ");
2039    if (nettype == NET_TCPA || nettype == NET_TCPB)
2040      printf("tcp/ip\n");
2041    else if (nettype == NET_SX25)
2042      printf("SunLink X.25\n");
2043    else if (nettype == NET_VX25)
2044      printf("Stratus VOS X.25\n");
2045    else if (nettype == NET_DEC) {
2046        if ( ttnproto == NP_LAT )
2047          printf("DECnet LAT\n");
2048        else if ( ttnproto == NP_CTERM )
2049          printf("DECnet CTERM\n");
2050        else
2051          printf("DECnet\n");
2052    } else if (nettype == NET_PIPE)
2053      printf("Named Pipes\n");
2054    else if (nettype == NET_BIOS)
2055      printf("NetBIOS\n");
2056    else if (nettype == NET_SLAT)
2057      printf("SuperLAT\n");
2058
2059#ifdef NETFILE
2060    else if ( nettype == NET_FILE )
2061      printf("local file\n");
2062#endif /* NETFILE */
2063
2064#ifdef ANYX25
2065    if (nettype == NET_SX25 || nettype == NET_VX25)
2066      shox25();
2067#endif /* ANYX25 */
2068
2069#ifdef TCPSOCKET
2070    if (nettype == NET_TCPA || nettype == NET_TCPB) {
2071#ifdef SOL_SOCKET
2072#ifdef SO_KEEPALIVE
2073        printf(" Keepalive is %s\n", tcp_keepalive ? "on" : "off" );
2074#endif /* SO_KEEPALIVE */
2075
2076#ifdef SO_LINGER
2077        printf(" Linger is %s", tcp_linger ? "on, " : "off\n" );
2078        if (tcp_linger) {
2079            if (tcp_linger_tmo)
2080              printf("%d x 10 milliseconds\n",tcp_linger_tmo);
2081            else
2082              printf("no timeout\n");
2083        }
2084#endif /* SO_LINGER */
2085
2086#ifdef TCP_NODELAY
2087        printf(" Nodelay is %s\n", tcp_nodelay ? "on" : "off");
2088#endif /* TCP_NODELAY */
2089
2090#ifdef SO_SNDBUF
2091        if (tcp_sendbuf <= 0)
2092          printf(" Send buffer is default size\n");
2093        else
2094          printf(" Send buffer is %d bytes\n", tcp_sendbuf);
2095#endif /* SO_SNDBUF */
2096#ifdef SO_RCVBUF
2097        if (tcp_recvbuf <= 0)
2098          printf(" Receive buffer is default size\n");
2099        else
2100          printf(" Receive buffer is %d bytes\n", tcp_recvbuf);
2101#endif /* SO_RCVBUF */
2102#endif /* SOL_SOCKET */
2103    }
2104
2105#ifdef RLOGCODE
2106    if (ttnproto == NP_RLOGIN)
2107      printf(" LOGIN protocol\n");
2108#endif /* RLOGCODE */
2109
2110#ifdef TNCODE
2111    if (ttnproto == NP_TELNET) {
2112        printf(" TELNET protocol\n");
2113        printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
2114    }
2115#endif /* TNCODE */
2116#endif /* TCPSOCKET */
2117
2118    printf("\n");
2119#endif /* NETCONN */
2120}
2121
2122#ifndef NODIAL
2123
2124VOID
2125shodial() {
2126    if (mdmtyp >= 0 || local != 0) doshodial();
2127}
2128
2129VOID
2130shods(s) char *s; {                     /* Show a dial-related string */
2131    char c;
2132    if (s == NULL || !(*s)) {           /* Empty? */
2133        printf("(none)\n");
2134    } else {                            /* Not empty. */
2135        while (c = *s++)                /* Can contain controls */
2136          if (c > 31 && c < 127) { putchar(c); } /* so display them */
2137          else printf("\\{%d}",c);      /* in backslash notation */
2138        printf("\n");
2139    }
2140}
2141
2142int
2143doshodial() {
2144
2145    int i, n;
2146
2147    printf(" Dial status:  %d", dialsta);
2148
2149#ifdef BIGBUFOK
2150    if (dialsta > 90)
2151      printf(" = Unknown error");
2152    else if (dialsta < 0)
2153      printf(" = (none)");
2154    else if (dialsta < 30 && dialmsg[dialsta])
2155      printf(" = %s", dialmsg[dialsta]);
2156#endif /* BIGBUFOK */
2157
2158    if (ndialdir <= 1) {
2159        printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
2160    } else {
2161        int i;
2162        printf("\n Dial directories:\n");
2163        for (i = 0; i < ndialdir; i++)
2164          printf("%2d. %s\n",i+1,dialdir[i]);
2165    }
2166    printf(" Dial method:  ");
2167    if      (dialmth == XYDM_D) printf("default");
2168    else if (dialmth == XYDM_P) printf("pulse  ");
2169    else if (dialmth == XYDM_T) printf("tone   ");
2170    printf("         Dial sort: %s\n",dialsrt ? "on" : "off") ;
2171    printf(" Dial hangup:  %s             Dial display: %s\n",
2172           dialhng ? "on " : "off", dialdpy ? "on" : "off") ;
2173    printf(" Dial retries: %-6d          Dial interval: %d\n",
2174           dialrtr, dialint);
2175    printf(" Dial timeout: ");
2176    if (dialtmo > 0)
2177      printf("%4d sec", dialtmo);
2178    else
2179      printf("0 (auto)");
2180    printf("        Redial number: %s\n",dialnum ? dialnum : "(none)");
2181    printf(" Dial confirmation: %s        Dial convert-directory: %s\n",
2182           dialcnf ? "on " : "off",
2183           dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
2184    printf(
2185" Dial prefix:                  %s\n", dialnpr ? dialnpr : "(none)");
2186    printf(
2187" Dial suffix:                  %s\n", dialsfx ? dialsfx : "(none)");
2188    printf(
2189" Dial country-code:            %-12s", diallcc ? diallcc : "(none)");
2190    printf("Dial connect:  %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
2191           : "off");
2192    if (dialcon != CAR_OFF)
2193      printf(" %s", dialcq ? "quiet" : "verbose");
2194    printf(
2195"\n Dial area-code:               %-12s", diallac ? diallac : "(none)");
2196    printf("Dial restrict: ");
2197    if (dialrstr == 5) printf("international\n");
2198    else if (dialrstr == 4) printf("long-distance\n");
2199    else if (dialrstr == 2) printf("local\n");
2200    else if (dialrstr == 6) printf("none\n");
2201    else printf("?\n");
2202    printf(
2203" Dial ld-prefix:               %s\n", dialldp ? dialldp : "(none)");
2204    printf(
2205" Dial ld-suffix:               %s\n", diallds ? diallds : "(none)");
2206    printf(
2207" Dial intl-prefix:             %s\n", dialixp ? dialixp : "(none)");
2208    printf(
2209" Dial intl-suffix:             %s\n", dialixs ? dialixs : "(none)");
2210    printf(
2211" Dial toll-free-area-code:     ");
2212    if (ntollfree == 0)
2213      printf("(none)");
2214    else
2215      for (i = 0; i < ntollfree; i++)
2216        printf("%s ", dialtfc[i]);
2217    printf(
2218"\n Dial toll-free-prefix:        %s\n",
2219           dialtfp ? dialtfp :
2220          (dialldp ? dialldp : "(none)")
2221          );
2222    printf(
2223" Dial pbx-exchange:            %s\n", dialpxx ? dialpxx : "(none)");
2224    printf(
2225" Dial pbx-internal-prefix:     %s\n", dialpxi ? dialpxi : "(none)");
2226    printf(
2227" Dial pbx-outside-prefix:      %s\n", dialpxo ? dialpxo : "(none)");
2228    return(0);
2229}
2230#endif /* NODIAL */
2231
2232#ifdef ANYX25
2233VOID
2234shopad() {
2235    int i;
2236    printf("\nX.3 PAD Parameters:\n");
2237    for (i = 0; i < npadx3; i++)
2238      printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
2239             padparms[padx3tab[i].kwval]);
2240}
2241#endif /* ANYX25 */
2242
2243/*  Show File Parameters */
2244
2245VOID
2246shoparf() {
2247    char *s; int i;
2248#ifdef COMMENT
2249    printf("\nFile parameters:       ");
2250#ifdef COMMENT
2251    printf("Blocksize:     %5d      ",fblksiz);
2252#endif /* COMMENT */
2253    printf(" Attributes:       ");
2254    if (atcapr) printf("on"); else printf("off");
2255#ifdef VMS
2256    printf("  Record-Length: %5d",frecl);
2257#endif /* VMS */
2258    printf("\n Names:   ");
2259    if (fncnv == XYFN_L)
2260      s = "literal";
2261    else if (fncnv == XYFN_C)
2262      s = "converted";
2263    else s = "(unknown)"
2264    printf("%-12s",s);
2265#ifdef DEBUG
2266#ifndef MAC
2267    printf("  Debugging Log:    ");
2268    if (deblog) printf("%s",debfil); else printf("none");
2269#endif /* MAC */
2270#endif /* DEBUG */
2271
2272    printf("\n Type:    ");
2273    s = gfmode(binary);
2274    printf("%-12s",s);
2275#ifdef COMMENT
2276    printf(" Organization:  ");
2277    switch (forg) {
2278      case XYFO_I: printf("%-10s","indexed"); break;
2279      case XYFO_R: printf("%-10s","relative"); break;
2280      case XYFO_S: printf("%-10s","sequential"); break;
2281    }
2282#endif /* COMMENT */
2283#ifndef MAC
2284    printf("  Packet Log:       ");
2285    if (pktlog) printf(pktfil); else printf("none");
2286#endif /* MAC */
2287#ifdef UNIX
2288    printf("  Longest filename: %d",maxnam);
2289#endif /* UNIX */
2290    printf("\n Collide: ");
2291    for (i = 0; i < ncolx; i++)
2292      if (colxtab[i].kwval == fncact) break;
2293    printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
2294
2295#ifdef COMMENT
2296    printf(" Format:        ");
2297    switch (frecfm) {
2298      case XYFF_F:  printf("%-10s","fixed"); break;
2299      case XYFF_VB: printf("%-10s","rcw"); break;
2300      case XYFF_S:  printf("%-10s","stream"); break;
2301      case XYFF_U:  printf("%-10s","undefined"); break;
2302      case XYFF_V:  printf("%-10s","variable"); break;
2303    }
2304#endif /* COMMENT */
2305#ifndef MAC
2306    printf("  Session Log:      ");
2307    if (seslog) printf(sesfil); else printf("none");
2308#endif /* MAC */
2309#ifdef UNIX
2310    printf("  Longest pathname: %d",maxpath);
2311#endif /* UNIX */
2312    printf("\n Send Pathnames: %s", fnspath ? "off" : " on");
2313    printf("    Receive Pathnames: %s\n", fnrpath ? "off" : "on");
2314    printf(" Display: ");
2315    switch (fdispla) {
2316      case XYFD_N: printf("%-12s","none"); break;
2317      case XYFD_R: printf("%-12s","serial"); break;
2318      case XYFD_C: printf("%-12s","fullscreen"); break;
2319      case XYFD_S: printf("%-12s","crt"); break;
2320    }
2321#ifdef COMMENT
2322    printf("Carriage-Control: ");
2323    switch (fcctrl) {
2324      case XYFP_F: printf("%-10s","fortran"); break;
2325      case XYFP_N: printf("%-10s","newline"); break;
2326      case XYFP_P: printf("%-10s","machine"); break;
2327      case XYFP_X: printf("%-10s","none"); break;
2328    }
2329#endif /* COMMENT */
2330#ifdef TLOG
2331#ifndef MAC
2332    printf("  Transaction Log:  ");
2333    if (tralog) printf(trafil); else printf("none");
2334#endif /* MAC */
2335#endif /* TLOG */
2336#ifndef NOCSETS
2337    if (binary == XYFT_T) {
2338        shocharset();
2339    } else
2340#endif /* NOCSETS */
2341      printf("\n");
2342    printf("\nByte Size: %d",(fmask == 0177) ? 7 : 8);
2343    printf(", Incomplete: ");
2344    if (keep) printf("keep"); else printf("discard");
2345#ifdef KERMRC
2346    printf(", Init file: %s",
2347#ifdef CK_SYSINI
2348           CK_SYSINI
2349#else
2350           kermrc
2351#endif /* CK_SYSINI */
2352           );
2353#endif /* KERMRC */
2354    printf("\n");
2355
2356#else /* not COMMENT -- new format */
2357
2358#ifdef VMS
2359    printf(" File record-Length: %5d\n",frecl);
2360#endif /* VMS */
2361
2362    printf(" Transfer mode:      %s\n",
2363           xfermode == XMODE_A ?
2364           "automatic" :
2365           "manual"
2366           );
2367
2368    printf(" File type:          ");
2369    switch (binary) {
2370      case XYFT_T: s = "text";         break;
2371#ifdef VMS
2372      case XYFT_B: s = "binary fixed"; break;
2373      case XYFT_I: s = "image";        break;
2374      case XYFT_L: s = "labeled";      break;
2375      case XYFT_U: s = "binary undef"; break;
2376#else
2377#ifdef MAC
2378      case XYFT_B: s = "binary";       break;
2379      case XYFT_M: s = "macbinary";    break;
2380#else
2381      case XYFT_B: s = "binary";       break;
2382#ifdef CK_LABELED
2383      case XYFT_L: s = "labeled";      break;
2384#endif /* CK_LABELED */
2385#endif /* MAC */
2386#endif /* VMS */
2387      default: s = "?"; break;
2388    }
2389    printf("%s\n",s);
2390    if (fncnv == XYFN_L)
2391      s = "literal";
2392    else if (fncnv == XYFN_C)
2393      s = "converted";
2394    else
2395      s = "(unknown)";
2396    printf(" File names:         %s\n",s);
2397    printf(" Send pathnames:     %s\n", fnspath ? "off" : "on");
2398    printf(" Receive pathnames:  %s\n", fnrpath ? "off" : "on");
2399
2400    printf(" File collision:     ");
2401    for (i = 0; i < ncolx; i++)
2402      if (colxtab[i].kwval == fncact) break;
2403    printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
2404    printf(" File destination:   %s\n",
2405           (dest == DEST_D) ? "disk" :
2406           ((dest == DEST_S) ? "screen" : "printer")
2407           );
2408    printf(" File incomplete:    %s\n", keep ? "keep" : "discard");
2409    printf(" File bytesize:      %d\n",(fmask == 0177) ? 7 : 8);
2410#ifndef NOCSETS
2411    printf(" File character-set: %s\n",fcsinfo[fcharset].keyword);
2412#endif /* NOCSETS */
2413
2414    printf(" File end-of-line:   ");
2415    switch (feol) {
2416      case XYFA_C: printf("%s\n","cr"); break;
2417      case XYFA_L: printf("%s\n","lf"); break;
2418      case XYFA_2: printf("%s\n","crlf"); break;
2419    }
2420    printf(" File display:       ");
2421    switch (fdispla) {
2422      case XYFD_N: printf("%s\n","none"); break;
2423      case XYFD_R: printf("%s\n","serial"); break;
2424      case XYFD_C: printf("%s\n","fullscreen"); break;
2425      case XYFD_S: printf("%s\n","crt"); break;
2426    }
2427#ifndef MAC
2428#ifdef DEBUG
2429    printf(" Debug log:          %s\n", deblog ? debfil : "(none)");
2430#endif /* DEBUG */
2431    printf(" Packet log:         %s\n", pktlog ? pktfil : "(none)");
2432    printf(" Session log:        %s\n", seslog ? sesfil : "(none)");
2433#ifdef TLOG
2434    printf(" Transaction log:    %s\n", tralog ? trafil : "(none)");
2435#endif /* TLOG */
2436#endif /* MAC */
2437
2438#ifdef KERMRC
2439    printf("\n Initialization file:     %s\n", noinit ? "(none)" :
2440#ifdef CK_SYSINI
2441           CK_SYSINI
2442#else
2443           kermrc
2444#endif /* CK_SYSINI */
2445           );
2446#endif /* KERMRC */
2447#ifdef CK_TMPDIR
2448    printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
2449    i = 256;
2450    s = line;
2451    zzstring("\\v(tmpdir)",&s,&i);
2452    printf(" Temporary directory:     %s\n", line);
2453#endif /* CK_TMPDIR */
2454
2455#ifdef OS2ORUNIX
2456    printf(" Longest filename:        %d\n", maxnam);
2457    printf(" Longest pathname:        %d\n", maxpath);
2458#endif /* OS2ORUNIX */
2459
2460#endif /* COMMENT */
2461}
2462
2463VOID
2464shoparp() {
2465    char *s;
2466
2467#ifdef CK_TIMERS
2468    extern int rttflg;
2469#endif /* CK_TIMERS */
2470
2471    printf("\nProtocol: %s\n",ptab[protocol].p_name);
2472
2473    if (protocol == PROTO_K) {
2474        printf("\nProtocol Parameters:   Send    Receive");
2475        if (timef)
2476          printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
2477        else
2478          printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
2479#ifndef NOSERVER
2480        printf("       Server Timeout:%4d",srvtim);
2481#endif /* NOSERVER */
2482        printf("\n Padding:      %11d%9d", npad,   mypadn);
2483        if (bctr == 4)
2484          printf("        Block Check: blank-free-2\n");
2485        else
2486          printf("        Block Check: %6d\n",bctr);
2487        printf(  " Pad Character:%11d%9d", padch,  mypadc);
2488        printf("        Delay:       %6d\n",delay);
2489        printf(  " Packet Start: %11d%9d", mystch, stchr);
2490        printf("        Max Retries: %6d\n",maxtry);
2491        printf(  " Packet End:   %11d%9d", seol,   eol);
2492        if (ebqflg)
2493          printf("        8th-Bit Prefix: '%c'",ebq);
2494        printf(  "\n Packet Length:%11d ", spmax);
2495        printf("%8d     ",  urpsiz);
2496        if (rptflg)
2497          printf("   Repeat Prefix:  '%c'",rptq);
2498        printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
2499        printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
2500        printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
2501        printf("        Locking-Shift:    ");
2502        if (lscapu == 2) {
2503            printf("forced");
2504        } else {
2505            printf("%s", (lscapr ? "enabled" : "disabled"));
2506            if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
2507        }
2508        printf("\n\n");
2509#ifdef CK_TIMERS
2510        if (rttflg) {
2511            extern int mintime, maxtime;
2512            printf(" Packet timeouts: dynamic %d:%d\n", mintime, maxtime);
2513        } else {
2514            printf(" Packet timeouts: fixed\n");
2515        }
2516#endif /* CK_TIMERS */
2517        if (!(s = ptab[protocol].h_b_init))
2518          s = "";
2519        printf(" Auto-upload command (binary):  %s\n",
2520               *s ? s : "(none)");
2521        if (!(s = ptab[protocol].h_t_init))
2522          s = "";
2523        printf(" Auto-upload command (text):    %s\n",
2524               *s ? s : "(none)");
2525
2526#ifndef NOCSETS
2527        printf(" Transfer character-set: ");
2528        if (tcharset == TC_TRANSP)
2529          printf("transparent");
2530        else
2531          printf("%s\n", tcsinfo[tcharset].keyword );
2532#endif /* NOCSETS */
2533        printf("\n Transfer mode: %s\n", xfermode == XMODE_A ?
2534               "automatic" :
2535               "manual"
2536               );
2537        printf(" Transfer slow-start: %s\n",showoff(slostart));
2538        printf(" Attributes: %s\n",showoff(atcapr));
2539    }
2540
2541#ifdef CK_XYZ
2542
2543#ifdef XYZ_INTERNAL
2544   
2545    if (protocol != PROTO_K) {
2546        int i;
2547        int x;
2548        printf(" Transfer mode: %s\n", binary ? "binary" : "text");
2549        if (protocol == PROTO_Z) {              /* Zmodem */
2550            printf(" Window size:   ");
2551            if (ptab[protocol].winsize < 1)
2552              printf("none\n");
2553            else
2554              printf("%d\n",wslotr);
2555#ifdef COMMENT
2556            printf(" Packet (frame) length: ");
2557            if (ptab[protocol].spktlen < 0)
2558              printf("none\n");
2559            else
2560              printf("%d\n",spmax);
2561#endif /* COMMENT */
2562        } else {
2563            if (ptab[protocol].spktlen >= 1000)
2564              printf(" 1K packets\n");
2565            else
2566              printf(" 128-byte packets\n");
2567        }
2568        printf(" Pathname stripping when sending:   %s\n",
2569               showoff(ptab[protocol].fnsp)
2570               );
2571        printf(" Pathname stripping when receiving: %s\n",
2572               showoff(ptab[protocol].fnrp)
2573               );
2574        printf(" Filename collision action:         ");
2575        for (i = 0; i < ncolx; i++)
2576          if (colxtab[i].kwval == fncact) break;
2577        printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
2578
2579        printf("\n Escape control characters:          ");
2580        x = ptab[protocol].prefix;
2581        if (x == PX_ALL)
2582          printf("all\n");
2583        else if (x == PX_CAU || x==PX_WIL)
2584          printf("minimal\n");
2585        else
2586          printf("none\n");
2587        if (!(s = ptab[protocol].h_b_init))
2588          s = "";
2589        printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
2590        if (!(s = ptab[protocol].h_t_init))
2591          s = "";
2592        printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
2593    }
2594#else
2595    if (protocol != PROTO_K) {
2596        printf("\nExecuted by external commands:\n\n");
2597        s = ptab[protocol].p_b_scmd;
2598        if (!s) s = "";
2599        printf(" SEND command (binary):        %s\n", *s ? s : "(none)");
2600        s = ptab[protocol].p_t_scmd;
2601        if (!s) s = "";
2602        printf(" SEND command (text):          %s\n", *s ? s : "(none)");
2603        s = ptab[protocol].p_b_rcmd;
2604        if (!s) s = "";
2605        printf(" RECEIVE command (binary):     %s\n", *s ? s : "(none)");
2606        s = ptab[protocol].p_t_rcmd;
2607        if (!s) s = "";
2608        printf(" RECEIVE command (text):       %s\n", *s ? s : "(none)");
2609        s = ptab[protocol].h_b_init;
2610        if (!s) s = "";
2611        printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
2612        s = ptab[protocol].h_t_init;
2613        if (!s) s = "";
2614        printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
2615    }
2616#endif /* XYZ_INTERNAL */
2617#endif /* CK_XYZ */
2618}
2619
2620
2621#ifndef NOCSETS
2622VOID
2623shoparl() {
2624#ifdef COMMENT
2625    int i;
2626/* Misleading... */
2627    printf("\nAvailable Languages:\n");
2628    for (i = 0; i < MAXLANG; i++) {
2629        printf(" %s\n",langs[i].description);
2630    }
2631#else
2632    printf("\nLanguage-specific translation rules: %s\n",
2633           language == L_USASCII ? "none" : langs[language].description);
2634    shocharset();
2635    printf("\n\n");
2636#endif /* COMMENT */
2637}
2638
2639VOID
2640shocharset() {
2641    int x;
2642    printf("\n File Character-Set: %s (%s), ",
2643           fcsinfo[fcharset].keyword,
2644           fcsinfo[fcharset].name
2645           );
2646    if ((x = fcsinfo[fcharset].size) == 128) printf("7-bit");
2647    else if (x == 256) printf("8-bit");
2648    else printf("multibyte");
2649    printf("\n Transfer Character-Set");
2650#ifdef COMMENT
2651    if (tslevel == TS_L2)
2652      printf(": (international)");
2653    else
2654#endif /* COMMENT */
2655    if (tcharset == TC_TRANSP)
2656      printf(": Transparent");
2657    else
2658      printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
2659}
2660#endif /* NOCSETS */
2661
2662VOID
2663shopar() {
2664    printf("SHOW what?\n");
2665}
2666#endif /* NOSHOW */
2667
2668/*  D O S T A T  --  Display file transfer statistics.  */
2669
2670int
2671dostat() {
2672    extern long filrej;
2673    extern char whoareu[];
2674    printf("\nMost recent transaction --\n");
2675    if (whoareu[0])
2676      printf(" remote system type     : %s\n", getsysid((char *)whoareu));
2677    printf(" files transferred      : %ld\n",filcnt - filrej);
2678    printf(" files not transferred  : %ld\n",filrej);
2679    printf(" characters last file   : %ld\n",ffc);
2680    printf(" total file characters  : %ld\n",tfc);
2681    printf(" communication line in  : %ld\n",tlci);
2682    printf(" communication line out : %ld\n",tlco);
2683    printf(" packets sent           : %d\n", spackets);
2684    printf(" packets received       : %d\n", rpackets);
2685    printf(" damaged packets rec'd  : %d\n", crunched);
2686    printf(" timeouts               : %d\n", timeouts);
2687    printf(" retransmissions        : %d\n", retrans);
2688    if (filcnt > 0) {
2689        printf(" parity                 : %s",parnam((char)parity));
2690        if (autopar) printf(" (detected automatically)");
2691        printf("\n control characters     : %ld prefixed, %ld unprefixed\n",
2692               ccp, ccu);
2693        printf(" 8th bit prefixing      : ");
2694        if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
2695        printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
2696        printf(" window slots used      : %d of %d\n", wmax, wslotr);
2697        printf(" packet length          : %d (send), %d (receive)\n",
2698               spmax, urpsiz);
2699        printf(" compression            : ");
2700        if (rptflg)
2701          printf("yes [%c] (%ld)\n",(char) rptq,rptn);
2702        else
2703          printf("no\n");
2704        if (bctu == 4)
2705          printf(" block check type used  : blank-free-2\n");
2706        else
2707          printf(" block check type used  : %d\n",bctu);
2708        printf(" elapsed time           : %d sec\n",tsecs);
2709        if (speed <= 0L) speed = ttgspd();
2710        if (speed > 0L) {
2711            if (speed == 8880)
2712              printf(" transmission rate      : 75/1200 bps\n");
2713            else
2714              printf(" transmission rate      : %ld bps\n",speed);
2715        }
2716        if (tsecs > 0) {                /* No dividing by zero...   */
2717            long ecps;                  /* Effective data rate, cps */
2718            int eff;                    /* Percent efficiency */
2719            ecps = tfc / (long) tsecs;
2720            if (local && !network &&    /* Only makes sense for */
2721                mdmtyp == 0 &&          /* direct serial connections */
2722                speed > 99L &&          /* when we really know the speed */
2723                speed != 8880L
2724                ) {
2725                eff = (((ecps * 100L) / (speed / 100L)) + 5L) / 10L;
2726                printf(" effective data rate    : %ld cps (%d%%)\n",ecps,eff);
2727            } else
2728                printf(" effective data rate    : %ld cps\n", ecps);
2729        }
2730    }
2731    return(1);
2732}
2733
2734#ifndef NOSPL
2735
2736/* The INPUT command */
2737
2738/* Output buffering for "doinput" */
2739
2740#ifdef pdp11
2741#define MAXBURST 16             /* Maximum size of input burst */
2742#else
2743#define MAXBURST 1024
2744#endif /* pdp11 */
2745#ifdef OSK
2746static CHAR *conbuf;            /* Buffer to hold output for console */
2747#else
2748static CHAR conbuf[MAXBURST];   /* Buffer to hold output for console */
2749#endif /* OSK */
2750static int concnt = 0;          /* Number of characters buffered */
2751#ifdef OSK
2752static CHAR *sesbuf;            /* Buffer to hold output for session log */
2753#else
2754static CHAR sesbuf[MAXBURST];   /* Buffer to hold output for session log */
2755#endif /* OSK */
2756static int sescnt = 0;          /* Number of characters buffered */
2757
2758static VOID                             /* Flush INPUT echoing */
2759myflsh() {                              /* and session log output. */
2760    if (concnt > 0) {
2761        conxo(concnt, (char *) conbuf);
2762        concnt = 0;
2763    }
2764    if (sescnt > 0) {
2765        if (zsoutx(ZSFILE, (char *) sesbuf, sescnt) < 0)
2766          seslog = 0;
2767        sescnt = 0;
2768    }
2769}
2770
2771/* Execute the INPUT and MINPUT commands */
2772
2773int instatus = -1;
2774
2775int
2776doinput(timo,ms) int timo; char *ms[]; {
2777    int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
2778    int lastchar = 0;
2779    char *xp, *s;
2780    CHAR c;
2781#define CK_BURST
2782/*
2783  This enables the INPUT speedup code, which depends on ttchk() returning
2784  accurate information.  If INPUT fails with this code enabled, change the
2785  above "#define" to "#undef".
2786*/
2787#ifdef CK_BURST
2788    int burst = 0;                      /* Chars remaining in input burst */
2789#endif /* CK_BURST */
2790
2791    instatus = INP_IE;                  /* 3 = internal error */
2792
2793#ifdef OSK
2794    if (conbuf == NULL) {
2795        if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
2796            return(0);
2797        }
2798        sesbuf = conbuf + MAXBURST;
2799    }
2800#endif /* OSK */
2801
2802#ifndef NOLOCAL
2803    if (local) {                        /* Put line in "ttvt" mode */
2804        y = ttvt(speed,flow);           /* if not already. */
2805        if (y < 0) {
2806            printf("?Can't condition line for INPUT\n");
2807            return(0);                  /* Watch out for failure. */
2808        }
2809    }
2810#endif /* NOLOCAL */
2811
2812    if (!ms[0]) {                       /* If we were passed a NULL pointer */
2813        anychar = 1;                    /*  ... */
2814    } else {
2815        y = (int)strlen(ms[0]);         /* Or if search string is empty */
2816        anychar = (y < 1);              /* any input character will do. */
2817    }
2818#ifndef NODEBUG
2819    debug(F101,"doinput","",anychar);
2820    y = -1;
2821    while (ms[++y]) debug(F111,"  ",ms[y],strlen(ms[y]));
2822    debug(F101,"doinput timo","",timo);
2823    debug(F101,"doinput echo","",inecho);
2824#endif /* NODEBUG */
2825
2826    x = 0;                              /* Return code, assume failure */
2827    instatus = INP_TO;                  /* Status, assume timeout */
2828
2829    for (y = 0; y < MINPMAX; y++)
2830      mi[y] = 0;                        /* String pattern match position */
2831
2832    if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
2833        y = -1;
2834
2835        while(xp = ms[++y]) {
2836            while (*xp) {               /* Convert to lowercase */
2837                if (isupper(*xp)) *xp = (char) tolower(*xp);
2838                xp++;
2839            }
2840        }
2841    }
2842#ifdef COMMENT
2843    inpbps = inpbp;                     /* Save current pointer. */
2844#endif /* COMMENT */
2845    rtimer();                           /* Reset timer. */
2846    t = 0;                              /* Time now is 0. */
2847    m_found = 0;                        /* Default to timed-out */
2848    incount = 0;                        /* Character counter */
2849
2850    rt = 1;                             /* One-second intervals */
2851    while (1) {                         /* Character-getting loop */
2852#ifdef SCRIPTTERM
2853#ifdef CK_APC
2854        if (apcactive == APC_LOCAL ||
2855            (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
2856            domac("apc_commands",apcbuf,CF_APC);
2857            apcactive = APC_INACTIVE ;
2858        }
2859#endif /* CK_APC */
2860#endif /* SCRIPTTERM */
2861        if (local) {                    /* One case for local */
2862            y = ttinc(rt);              /* Get character from comm device */
2863            debug(F101,"input ttinc(rt) returns","",y);
2864            if (y < -1) {               /* Connection failed. */
2865                instatus = INP_IO;      /* Status = i/o error */
2866                return(0);
2867            }           
2868            if (icn = conchk()) {       /* Interrupted from keyboard? */
2869                debug(F101,"input interrupted from keyboard","",icn);
2870                while (icn--) coninc(0); /* Yes, absorb what was typed. */
2871                instatus = INP_UI;      /* Fail and remember why. */
2872                break;
2873            }
2874        } else {                        /* Another for remote */
2875            y = coninc(rt);
2876            debug(F101,"input coninc(rt) returns","",y);
2877        }
2878        if (y > -1) {                   /* A character arrived */
2879#ifndef SCRIPTTERM
2880#ifdef TNCODE
2881/* Check for telnet protocol negotiation */
2882            if (network && (ttnproto == NP_TELNET) && ((y & 0xff) == IAC)) {
2883                myflsh();       /* Break from input burst for tn_doop() */
2884#ifdef CK_BURST
2885                burst = 0;
2886#endif /* CK_BURST */
2887                switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
2888                  case 2: duplex = 0; continue;
2889                  case 1: duplex = 1;
2890                  default: continue;
2891                }
2892            }
2893#endif /* TNCODE */
2894#else  /* SCRIPTTERM */
2895            scriptwrtbuf(y);            /* Handles Telnet negotiations */
2896#endif /* SCRIPTTERM */
2897
2898            /* Real input character to be checked */
2899
2900#ifdef CK_BURST
2901            burst--;                    /* One less character waiting */
2902#endif /* CK_BURST */
2903            c = (CHAR) (cmask & (CHAR) y); /* Mask off parity */
2904
2905            inchar[0] = c;              /* Remember character for \v(inchar) */
2906#ifdef CK_BURST
2907            /* Update "lastchar" time only once during input burst */
2908            if (burst <= 0)
2909#endif /* CK_BURST */
2910              lastchar = gtimer();      /* Remember when it came */
2911
2912            if (c == '\0') {            /* NUL, we can't use it */
2913                if (anychar) {          /* Except if any character will do? */
2914                    x = 1;              /* Yes, done. */
2915                    incount = 1;        /* This must be the first and only. */
2916                    break;
2917                } else continue;        /* Otherwise continue INPUTting */
2918            }
2919            *inpbp++ = c;               /* Store char in circular buffer */
2920            incount++;                  /* Count it for \v(incount) */
2921
2922            if (inpbp >= inpbuf + inbufsize) { /* Time to wrap around? */
2923                *inpbp = NUL ;          /* Make it null-terminated */
2924                inpbp = inpbuf;         /* Yes. */
2925            }
2926#ifdef MAC
2927            {
2928                extern char *ttermw;    /* fake pointer cast */
2929                if (inecho) {
2930                    outchar(ttermw, c); /* echo to terminal window */
2931                    /* this might be too much overhead to do here ? */
2932                    updatecommand(ttermw);
2933                }
2934            }
2935#else /* Not MAC */
2936            if (inecho) conbuf[concnt++] = c; /* Buffer console output */
2937#endif /* MAC */
2938#ifndef SCRIPTTERM
2939        if (seslog) {
2940#ifdef UNIX
2941                if (sessft != 0 || c != '\r')
2942#else
2943#ifdef OSK
2944                if (sessft != 0 || c != '\012')
2945#endif /* OSK */
2946#endif /* UNIX */
2947                  sesbuf[sescnt++] = c; /* Buffer session log output */
2948            }
2949#endif /* SCRIPTTERM */
2950            if (anychar) {              /* Any character will do? */
2951                x = 1;
2952                break;
2953            }
2954            if (!inpcas[cmdlvl]) {      /* Ignore alphabetic case? */
2955                if (isupper(c))         /* Yes, convert input char to lower */
2956                  c = (CHAR) tolower(c);
2957            }
2958            debug(F000,"doinput char","",c);
2959            y = -1;                     /* Loop thru search strings */
2960            while (s = ms[++y]) {       /* ...as many as we have. */
2961                i = mi[y];              /* Match-position in this one. */
2962                debug(F000,"compare char","",(CHAR)s[i]);
2963                if (c == (CHAR) s[i]) { /* Check for match */
2964                    i++;                /* Got one, go to next character */
2965                } else {                /* Don't have a match */
2966                    int j;
2967                    for (j = i; i > 0; ) { /* Back up in search string */
2968                        i--; /* (Do this here to prevent compiler foulup) */
2969                        /* j is the length of the substring that matched */
2970                        if (c == (CHAR) s[i]) {
2971                            if (!strncmp(s,&s[j-i],i)) {
2972                                i++;          /* c actually matches -- cfk */
2973                                break;
2974                            }
2975                        }
2976                    }
2977                }
2978                if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
2979                    x = 1;              /* Yes, */
2980                    break;              /* done. */
2981                }
2982                mi[y] = i;              /* No, remember match-position */
2983            }
2984            if (x == 1) {               /* Set \v(minput) result */
2985                m_found = y + 1;
2986                break;
2987            }
2988        }
2989#ifdef CK_BURST
2990        if (burst <= 0) {
2991            myflsh();                   /* Flush buffered output */
2992            if (local) {                /* Get size of next input burst */
2993                burst = ttchk();
2994                if (icn = conchk()) {   /* Interrupted from keyboard? */
2995                    debug(F101,"input interrupted from keyboard","",icn);
2996                    while (icn--) coninc(0); /* Yes, absorb what was typed. */
2997                    break;              /* And fail. */
2998                }
2999            } else {
3000                burst = conchk();
3001            }
3002            /* Prevent overflow of "conbuf" and "sesbuf" */
3003            if (burst > MAXBURST)
3004              burst = MAXBURST;
3005
3006            /* Did not match, timer exceeded? */
3007            if (((t = gtimer()) >= timo) && (timo > -1))
3008              break;
3009            else if (insilence > 0 && (t - lastchar) > insilence)
3010              break;
3011        }
3012#else
3013        myflsh();                       /* Flush buffered output */
3014        /* Did not match, timer exceeded? */
3015        if (((t = gtimer()) >= timo) && (timo > -1))
3016          break;
3017        else if (insilence > 0 && (t - lastchar) > insilence)
3018          break;
3019#endif /* CK_BURST */
3020    }                                   /* Still have time left, continue. */
3021    myflsh();                           /* Flush buffered output. */
3022    if (x > 0)
3023      instatus = 0;
3024    return(x);                          /* Return the return code. */
3025}
3026#endif /* NOSPL */
3027
3028#ifndef NOSPL
3029/* REINPUT Command */
3030
3031/*
3032  Note, the timeout parameter is required, but ignored.  Syntax is compatible
3033  with MS-DOS Kermit except timeout can't be omitted.  This function only
3034  looks at the characters already received and does not read any new
3035  characters from the connection.
3036*/
3037int
3038doreinp(timo,s) int timo; char *s; {
3039    int x, y, i;
3040    char *xx, *xp, *xq = (char *)0;
3041    CHAR c;
3042
3043    y = (int)strlen(s);
3044    debug(F111,"doreinput",s,y);
3045
3046    if (y > inbufsize)                  /* If search string longer than */
3047      return(0);                        /* input buffer, fail. */
3048
3049    x = 0;                              /* Return code, assume failure */
3050    i = 0;                              /* String pattern match position */
3051
3052    if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
3053        xp = malloc(y+2);               /* Make a separate copy of the */
3054        if (!xp) {                      /* search string. */
3055            printf("?malloc error 6\n");
3056            return(x);
3057        } else xq = xp;                 /* Keep pointer to beginning. */
3058        while (*s) {                    /* Yes, convert to lowercase */
3059            *xp = *s;
3060            if (isupper(*xp)) *xp = (char) tolower(*xp);
3061            xp++; s++;
3062        }
3063        *xp = NUL;                      /* Terminate it! */
3064        s = xq;                         /* Move search pointer to it. */
3065    }
3066    xx = inpbp;                         /* Current INPUT buffer pointer */
3067    do {
3068        c = *xx++;                      /* Get next character */
3069        if (xx >= inpbuf + inbufsize)   /* Wrap around if necessary */
3070          xx = inpbuf;
3071        if (!inpcas[cmdlvl]) {          /* Ignore alphabetic case? */
3072            if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
3073        }
3074        debug(F000,"doreinp char","",c);
3075        debug(F000,"compare char","",(CHAR) s[i]);
3076        if (((char) c) == ((char) s[i])) { /* Check for match */
3077            i++;                        /* Got one, go to next character */
3078        } else {                        /* Don't have a match */
3079            int j;
3080            for (j = i; i > 0; ) {      /* [jrs] search backwards for it  */
3081                i--;
3082                if (((char) c) == ((char) s[i])) {
3083                    if (!strncmp(s,&s[j-i],i)) {
3084                        i++;
3085                        break;
3086                    }
3087                }
3088            }
3089        }                               /* [jrs] or return to zero from -1 */
3090        if (s[i] == '\0') {             /* Matched all the way to end? */
3091            x = 1;                      /* Yes, */
3092            break;                      /* done. */
3093        }
3094    } while (xx != inpbp);              /* Until back where we started. */
3095
3096    if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
3097    return(x);                          /* Return search result. */
3098}
3099#ifndef NOSPL
3100
3101#endif /* NOSPL */
3102/*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
3103/*  Z Z S T R I N G  --  (new name...)  */
3104/*
3105 Copies result to new string.
3106  strips enclosing braces or doublequotes.
3107  interprets backslash escapes.
3108  returns 0 on success, nonzero on failure.
3109  tries to be compatible with MS-DOS Kermit.
3110
3111 Syntax of input string:
3112  string = chars | "chars" | {chars}
3113  chars = (c*e*)*
3114  where c = any printable character, ascii 32-126
3115  and e = a backslash escape
3116  and * means 0 or more repetitions of preceding quantity
3117  backslash escape = \operand
3118  operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
3119  number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
3120  radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
3121*/
3122
3123#ifndef NOFRILLS
3124int
3125yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
3126    int x;
3127    static char *new;
3128    new = *s2;
3129    if (!s || !new) return(-1);         /* Watch out for null pointers. */
3130    if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
3131        *new = '\0';
3132        return(0);
3133    }
3134    x--;                                /* Otherwise, call self */
3135    *new++ = s[x];                      /* to reverse rest of string. */
3136    s[x] = 0;
3137    return(yystring(s,&new));
3138}
3139#endif /* NOFRILLS */
3140
3141#define FNVALL 1024
3142char fnval[FNVALL+2];                   /* Return value */
3143
3144static char ipabuf[16] = { NUL };       /* IP address buffer */
3145
3146static char *
3147getip(s) char *s; {
3148    char c=NUL;                         /* Workers... */
3149    int i=0, p=0, d=0;
3150    int state = 0;                      /* State of 2-state FSA */
3151
3152    while (c = *s++) {
3153        switch(state) {
3154          case 0:                       /* Find first digit */
3155            i = 0;                      /* Output buffer index */
3156            ipabuf[i] = NUL;            /* Initialize output buffer */
3157            p = 0;                      /* Period counter */
3158            d = 0;                      /* Digit counter */
3159            if (isdigit(c)) {           /* Have first digit */
3160                d = 1;                  /* Count it */
3161                ipabuf[i++] = c;        /* Copy it */
3162                state = 1;              /* Change state */
3163            }
3164            break;
3165
3166          case 1:                       /* In numeric field */
3167            if (isdigit(c)) {           /* Have digit */
3168                if (++d > 3)            /* Too many */
3169                  state = 0;            /* Start over */
3170                else                    /* Not too many */
3171                  ipabuf[i++] = c;      /* Keep it */
3172            } else if (c == '.' && p < 3) { /* Have a period */
3173                p++;                    /* Count it */
3174                if (d == 0)             /* Not preceded by a digit */
3175                  state = 0;            /* Start over */
3176                else                    /* OK */
3177                  ipabuf[i++] = c;      /* Keep it */
3178                d = 0;                  /* Reset digit counter */
3179            } else if (p == 3 && d > 0) { /* Not part of address */
3180                ipabuf[i] = NUL;        /* If we have full IP address */
3181                return((char *)ipabuf); /* Return it */
3182            } else {                    /* Otherwise */
3183                state = 0;              /* Start over */
3184                ipabuf[0] = NUL;        /* (in case no more chars left) */
3185            }
3186        }
3187    }                                   /* Fall thru at end of string */
3188    ipabuf[i] = NUL;                    /* Maybe we have one */
3189    return((p == 3 && d > 0) ? (char *)ipabuf : "");
3190}
3191
3192static char *                           /* Evaluate builtin function */
3193fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
3194    int i, j, k, len1, len2, len3, n, x, y;
3195    char *bp[FNARGS];                   /* Pointers to malloc'd strings */
3196    char c;
3197    char *p, *s;
3198    char *val1, *val2;                  /* Pointers to numeric string values */
3199
3200    if (!fn) fn = "";                   /* Protect against null pointers */
3201    debug(F111,"fneval",fn,argn);
3202    debug(F110,"fneval",argp[0],0);
3203    y = lookup(fnctab,fn,nfuncs,&x);
3204    if (y < 0)                          /* bad function name */
3205      return("");                       /* so value is null */
3206
3207#ifdef DEBUG
3208    if (deblog) {
3209        int j;
3210        for (j = 0; j < argn; j++)
3211          debug(F111,"fneval function arg",argp[j],j);
3212    }
3213#endif /* DEBUG */
3214
3215    if (y == FN_LIT) {                  /* literal(arg1) */
3216        debug(F110,"flit",xp,0);
3217        return(xp ? xp : "");           /* return a pointer to arg itself */
3218    }
3219    if (y == FN_CON) {                  /* Contents of variable, unexpanded. */
3220        char c;
3221        if (!(p = argp[0]) || !*p) return("");
3222        p = brstrip(p);
3223        if (*p == CMDQ) p++;
3224        if ((c = *p) == '%') {          /* Scalar variable. */
3225            c = *++p;                   /* Get ID character. */
3226            p = "";                     /* Assume definition is empty */
3227            if (!c) return(p);          /* Double paranoia */
3228            if (c >= '0' && c <= '9') { /* Digit for macro arg */
3229                if (maclvl < 0)         /* Digit variables are global */
3230                  p = g_var[c];         /* if no macro is active */
3231                else                    /* otherwise */
3232                  p = m_arg[maclvl][c - '0']; /* they're on the stack */
3233            } else {
3234                if (isupper(c)) c -= ('a'-'A');
3235                p = g_var[c];           /* Letter for global variable */
3236            }
3237            return(p ? p : "");
3238        }
3239        if (c == '&') {                 /* Array reference. */
3240            int vbi, d;
3241            if (arraynam(p,&vbi,&d) < 0) /* Get name and subscript */
3242              return("");
3243            if (chkarray(vbi,d) > 0) {  /* Array is declared? */
3244                vbi -= ARRAYBASE;       /* Convert name to index */
3245                if (a_dim[vbi] >= d) {  /* If subscript in range */
3246                    char **ap;
3247                    ap = a_ptr[vbi];    /* get data pointer */
3248                    if (ap) {           /* and if there is one */
3249                        return(ap[d]);  /* return what it points to */
3250                    }
3251                }
3252            }
3253            else return("");            /* Otherwise its enexpanded value. */
3254        }
3255    }
3256
3257    for (i = 0; i < argn; i++) {        /* Not literal, expand the args */
3258        n = 1024;                       /* allow 1K per expanded arg, yow! */
3259        bp[i] = s = malloc(n);          /* get the new space */
3260        if (bp[i] == NULL) {            /* handle failure to get space */
3261            for (k = 0; k < i; k++) if (bp[k]) free(bp[k]);
3262            debug(F101,"fneval malloc failure, arg","",i);
3263            return("");
3264        }
3265        p = argp[i] ? argp[i] : "";     /* Point to this argument */
3266
3267/*
3268  Trim leading and trailing spaces from the original argument, before
3269  evaluation.  This code new to edit 184.
3270*/
3271
3272#ifdef COMMENT
3273/* Don't trim 1st REPEAT argument or second TRIM or LTRIM argument */
3274        if (!((y == FN_REP && i == 0) ||
3275              ((y == FN_TRM || y == FN_LTR) && i == 1))
3276            )
3277/* In edit 192 we can use braces to include spaces, commas, etc in/as args */
3278#endif /* COMMENT */
3279        {
3280            int x, j;                   /* All others... */
3281            x = strlen(p);
3282            if (*p == '{' && *(p+x-1) == '}') {
3283                p[x-1] = NUL;
3284                p++;
3285                x -= 2;
3286            } else {
3287                j = x - 1;              /* Trim trailing whitespace */
3288                while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
3289                  *(p + j--) = NUL;
3290                while (*p == SP || *p == HT) /* Strip leading whitespace */
3291                  p++;
3292            }
3293        }
3294
3295/* Now evaluate the argument */
3296
3297        if (zzstring(p,&s,&n) < 0) {    /* Expand arg into new space */
3298            debug(F101,"fneval xxstring fails, arg","",i);
3299            for (k = 0; k <= i; k++)    /* Free up previous space on error */
3300              if (bp[k]) free(bp[k]);
3301            return("");                 /* and return null string. */
3302        }
3303        debug(F111,"fneval arg",bp[i],i);
3304    }
3305
3306#ifdef DEBUG
3307    if (deblog) {
3308        int j;
3309        for (j = 0; j < argn; j++) {
3310            debug(F111,"fneval arg post eval",argp[j],j);
3311            debug(F111,"fneval evaluated arg",bp[j],j);
3312        }
3313    }
3314#endif /* DEBUG */
3315
3316    switch (y) {                        /* Do function on expanded args */
3317
3318      case FN_DEF:
3319        k = mlook(mactab,bp[0],nmac);   /* def(arg1) - Return a macro def */
3320        p = (k > -1) ? mactab[k].mval : "";
3321        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3322        return(p ? p : "");
3323
3324      case FN_EVA:                      /* eval(arg1) */
3325        p = evala(bp[0]);
3326        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3327        return(p ? p : "");
3328
3329      case FN_EXE:                      /* execute(arg1) */
3330        j = (int)strlen(s = bp[0]);     /* Length of macro invocation */
3331        p = "";                         /* Initialize return value to null */
3332        if (j) {                        /* If there is a macro to execute */
3333            while (*s == SP) s++,j--;   /* strip leading spaces */
3334            p = s;                      /* remember beginning of macro name */
3335            for (i = 0; i < j; i++) {   /* find end of macro name */
3336                if (*s == SP)
3337                  break;
3338                s++;
3339            }
3340            if (*s == SP)       {       /* if there was a space after */
3341                *s++ = NUL;             /* terminate the macro name */
3342                while (*s == SP) s++;   /* skip past any extra spaces */
3343            } else s = "";              /* maybe there are no arguments */
3344            if (p && *p)
3345              k = mlook(mactab,p,nmac); /* Look up the macro name */
3346            else k = -1;
3347/*
3348  This is just a WEE bit dangerous because we are copying up to 9 arguments
3349  into the space reserved for one.  It won't overrun the buffer or anything
3350  like that, but if there are lots of long arguments we might lose some.
3351  The other problem is that if the macro has more than 3 arguments, the 4th
3352  through last are all concatenated onto the third.  (The workaround is to
3353  use spaces rather than commas to separate them.)
3354  Leaving it like this for now to avoid having to allocate tons more buffers.
3355*/
3356            if (argn > 1) {             /* Commas used instead of spaces */
3357                int i;
3358                char *p = bp[0];        /* Reuse this space */
3359                *p = NUL;               /* Make into dodo() arg list */
3360                for (i = 1; i < argn; i++) {
3361                    strncat(p,bp[i],1023);
3362                    strncat(p," ",1023);
3363                }                   
3364                s = bp[0];              /* Point to new list */
3365            }
3366            p = "";                     /* Initialize return value */
3367            if (k >= 0) {               /* If macro found in table */
3368                /* Go set it up (like DO cmd) */
3369                if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
3370                    if (cmpush() > -1) { /* Push command parser state */
3371                        extern int ifc;
3372                        int ifcsav = ifc; /* Push IF condition on stack */
3373                        k = parser(1);  /* Call parser to execute the macro */
3374                        cmpop();        /* Pop command parser */
3375                        ifc = ifcsav;   /* Restore IF condition */
3376                        if (k == 0) {   /* No errors, ignore action cmds. */
3377                            p = mrval[maclvl+1]; /* If OK, set return value. */
3378                            if (p == NULL) p = "";
3379                        }
3380                    } else {            /* Can't push any more */
3381                        debug(F100,"fexec pushed too deep","",0);
3382                        printf("\n?\\fexec() too deeply nested\n");
3383                        while (cmpop() > -1) ;
3384                        p = "";
3385                    }
3386                }
3387            }
3388        }
3389        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3390        return(p ? p : "");
3391
3392      case FN_FC:                       /* File count. */
3393        p = fnval;
3394        *p = NUL;
3395        if (argn > 0) {
3396            k = zxpand(bp[0]);
3397            sprintf(fnval,"%d",k);
3398            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3399        }
3400        return(p);
3401
3402      case FN_FIL:                      /* Next file in list. */
3403        p = fnval;                      /* (no args) */
3404        *p = NUL;
3405        znext(p);
3406        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3407        return(p ? p : "");
3408
3409      case FN_IND:                      /* index(arg1,arg2,arg3) */
3410      case FN_RIX:                      /* rindex(arg1,arg2,arg3) */
3411        if (argn > 1) {                 /* Only works if we have 2 or 3 args */
3412            int start;
3413            len1 = (int)strlen(bp[0]);  /* length of string to look for */
3414            len2 = (int)strlen(s = bp[1]); /* length of string to look in */
3415            if (len1 < 0) return("");   /* paranoia */
3416            if (len2 < 0) return("");
3417            j = len2 - len1;            /* length difference */
3418            start = (y == FN_IND) ? 0 : j; /* Starting position */
3419            if (argn > 2) {
3420                val1 = evala(bp[2]);
3421                if (chknum(val1)) {
3422                    int t;
3423                    t = atoi(val1) - 1;
3424                    if (t < 0) t = 0;
3425                    start = (y == FN_IND) ? t : start - t - 1;
3426                    if (start < 0) start = 0;
3427                }
3428            }
3429            start = ckindex(bp[0],bp[1],start,(y==FN_IND)?0:1,inpcas[cmdlvl]);
3430            sprintf(fnval,"%d",start);
3431            p = fnval;
3432        } else p = "0";
3433        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3434        return(p);
3435
3436      case FN_RPL:                      /* replace(s1,s2,s3) */
3437      /*
3438        s = bp[0] = source string
3439            bp[1] = match string
3440            bp[2] = replacement string
3441        p = fnval = destination (result) string
3442      */
3443        p = fnval;
3444        if (argn < 2) {                 /* Only works if we have 2 or 3 args */
3445            strcpy(p,bp[0]);
3446        } else  {                       
3447            len1 = (int)strlen(bp[0]);  /* length of string to look in */
3448            len2 = (int)strlen(bp[1]);  /* length of string to look for */
3449            len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
3450            j = len1 - len2 + 1;
3451            if (j < 1 || len1 == 0 || len2 == 0) { /* Args out of whack */
3452                strcpy(p,bp[0]);        /* so just return original string */
3453            } else {
3454                s = bp[0];              /* Point to beginning of string */
3455                while (j--) {           /* For each character */
3456                    if (inpcas[cmdlvl] ?
3457                        !strncmp(bp[1],s,len2) :
3458                        !xxstrcmp(bp[1],s,len2) ) { /* To be replaced? */
3459                        if (len3) {                 /* Yes, */
3460                            strncpy(p,bp[2],len3);  /* replace it */
3461                            p += len3;
3462                        }
3463                        s += len2;                  /* and skip past it. */
3464                    } else {            /* No, */
3465                        *p++ = *s++;    /* just copy this character */
3466                    }
3467                }
3468                *p = NUL;
3469                while (*p++ = *s++);
3470            }
3471        }
3472        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3473        return(p = fnval);
3474
3475      case FN_CHR:                      /* character(arg1) */
3476        val1 = evala(bp[0]);
3477        if (chknum(val1)) {             /* Must be numeric */
3478            i = atoi(val1);
3479            if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
3480                p = fnval;
3481                *p++ = (char) i;
3482                *p = NUL;
3483                p = fnval;
3484            } else p = "";              /* Otherwise return null */
3485        } else p = "";                  /* Otherwise return null */
3486        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3487        return(p);
3488
3489      case FN_COD:                      /* code(char) */
3490        p = "";
3491        if ((int)strlen(bp[0]) > 0) {
3492            p = fnval;
3493            i = *bp[0];
3494            sprintf(p,"%d",(i & 0xff));
3495        }
3496        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3497        return(p);
3498
3499      case FN_LEN:                      /* length(arg1) */
3500        p = fnval;
3501        sprintf(p,"%d",(int)strlen(bp[0]));
3502        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3503        return(p);
3504
3505      case FN_LOW:                      /* lower(arg1) */
3506        s = bp[0];
3507        p = fnval;
3508
3509        while (*s) {
3510            if (isupper(*s))
3511              *p = (char) tolower(*s);
3512            else
3513              *p = *s;
3514            p++; s++;
3515        }
3516        *p = NUL;
3517        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3518        p = fnval;
3519        return(p);
3520
3521      case FN_MAX:                      /* max(arg1,arg2) */
3522      case FN_MIN:                      /* min(arg1,arg2) */
3523      case FN_MOD:                      /* mod(arg1,arg2) */
3524        val1 = evala(bp[0]);
3525        if (bp[0]) {                    /* Have to copy this */
3526            free(bp[0]);                /* because evala() returns */
3527            bp[0] = malloc((int)strlen(val1)+1); /* pointer to same */
3528            strcpy(bp[0],val1);
3529            val1 = bp[0];               /* buffer next time. */
3530        }
3531        val2 = evala(bp[1]);
3532        if (chknum(val1) && chknum(val2)) {
3533            i = atoi(val1);
3534            j = atoi(val2);
3535            switch (y) {
3536              case FN_MAX:
3537                if (j < i) j = i;
3538                break;
3539              case FN_MIN:
3540                if (j > i) j = i;
3541                break;
3542              case FN_MOD:
3543                j = i % j;
3544                break;
3545            }
3546            p = fnval;
3547            sprintf(p,"%d",j);
3548        } else p = "";
3549        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3550        return(p);
3551
3552      case FN_SUB:                      /* substr(arg1,arg2,arg3) */
3553      case FN_RIG:                      /* right(arg1,arg2) */
3554        val1 = argn > 1 ? evala(bp[1]) : "";
3555        if (bp[1]) {                    /* Have to copy this */
3556            free(bp[1]);
3557            bp[1] = malloc((int)strlen(val1)+1);
3558            strcpy(bp[1],val1);
3559            val1 = bp[1];
3560        }
3561        val2 = argn > 2 ? evala(bp[2]) : "";
3562        if (
3563            ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
3564            ((y == FN_SUB) &&
3565              ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
3566            ) {
3567            p = "";                     /* if either, return null */
3568        } else {
3569            int lx;
3570            p = fnval;                  /* pointer to result */
3571            lx = strlen(bp[0]);         /* length of arg1 */
3572            if (y == FN_SUB) {          /* substring */
3573                k = (argn > 2) ? atoi(val2) : 1023; /* length */
3574                j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
3575            } else {                             /* right */
3576                k = (argn > 1) ? atoi(val1) : lx; /* length */
3577                j = lx - k + 1;                  /* start pos for right */
3578                if (j < 1) j = 1;
3579            }
3580            if (k > 0 && j <= lx) {              /* if start pos in range */
3581                s = bp[0]+j-1;                   /* point to source string */
3582                for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
3583            }
3584            *p = NUL;                   /* terminate the result */
3585            p = fnval;                  /* and point to it. */
3586        }
3587        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); /* Free temp mem */
3588        return(p);
3589
3590      case FN_UPP:                      /* upper(arg1) */
3591        s = bp[0];
3592        p = fnval;
3593        while (*s) {
3594            if (islower(*s))
3595              *p = (char) toupper(*s);
3596            else
3597              *p = *s;
3598            p++; s++;
3599        }
3600        *p = NUL;
3601        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3602        p = fnval;
3603        return(p);
3604
3605      case FN_REP:                      /* Repeat */
3606        p = "";                         /* Return value */
3607        val1 = evala(bp[1]);
3608        if (chknum(val1)) {             /* Repeat count */
3609            n = atoi(val1);
3610            if (n > 0) {                /* Make n copies */
3611                p = fnval;
3612                *p = '\0';
3613                k = (int)strlen(bp[0]); /* Make sure string has some length */
3614                if (k > 0) {
3615                    for (i = 0; i < n; i++) {
3616                        s = bp[0];
3617                        for (j = 0; j < k; j++) {
3618                            if ((p - fnval) >= FNVALL) { /* Protect against */
3619                                p = "";              /* core dumps... */
3620                                break;
3621                            } else *p++ = *s++;
3622                        }
3623                    }
3624                    *p = NUL;
3625                }
3626            }
3627        }
3628        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3629        p = fnval;
3630        return(p);
3631
3632#ifndef NOFRILLS
3633      case FN_REV:
3634        p = fnval;
3635        yystring(bp[0],&p);
3636        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3637        return(p);
3638#endif /* NOFRILLS */
3639
3640      case FN_RPA:                      /* RPAD and LPAD */
3641      case FN_LPA:
3642        *fnval = NUL;                   /* Return value */
3643        val1 = evala(bp[1]);
3644        if (argn == 1) {                /* If a number wasn't given */
3645            p = fnval;                  /* just return the original string */
3646            strncpy(p,bp[0],FNVALL);
3647        } else if (chknum(val1)) {      /* Repeat count */
3648            char pc;
3649            n = atoi(val1);
3650            if (n >= 0) {               /* Pad it out */
3651                p = fnval;
3652                k = (int)strlen(bp[0]); /* Length of string to be padded */
3653                pc = (char) ((argn < 3) ? SP : *bp[2]); /* Padding character */
3654                if (n > FNVALL) n = FNVALL-1; /* protect against overruns */
3655                if (k > FNVALL) k = FNVALL-1; /* and silly args. */
3656                if (k > n) k = n;
3657                if (y == FN_RPA) {      /* RPAD */
3658                    strncpy(p,bp[0],k);
3659                    p += k;
3660                    for (i = k; i < n; i++)
3661                      *p++ = pc;
3662                } else {                /* LPAD */
3663                    n -= k;
3664                    for (i = 0; i < n; i++)
3665                      *p++ = pc;
3666                    strncpy(p,bp[0],k);
3667                    p += k;
3668                }
3669                *p = NUL;
3670            }
3671        }
3672        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3673        p = fnval;
3674        return(p);
3675
3676#ifdef ZFCDAT
3677      case FN_FD:                       /* \fdate(filename) */
3678        p = fnval;
3679        *p = NUL;
3680        if (argn > 0) {
3681            sprintf(fnval,"%s",zfcdat(bp[0]));
3682            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3683        }
3684        return(p);
3685#endif /* ZFCDAT */
3686
3687      case FN_FS:                       /* \fsize(filename) */
3688        p = fnval;
3689        *p = NUL;
3690        if (argn > 0) {
3691            sprintf(fnval,"%ld",zchki(bp[0]));
3692            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3693        }
3694        return(p);
3695
3696      case FN_VER:                      /* VERIFY */
3697        if (argn > 1) {                 /* Only works if we have 2 or 3 args */
3698            int start;
3699            char *s2;
3700            start = 0;
3701            if (argn > 2) {             /* Starting position specified */
3702                val1 = evala(bp[1]);
3703                if (chknum(val1)) {
3704                    start = atoi(val1) - 1;
3705                    if (start < 0) start = 0;
3706                }
3707            }
3708            i = start;
3709            p = "0";
3710            for (s = bp[1] + start; *s; s++,i++) {
3711                j = 0;
3712                for (s2 = bp[0]; *s2; s2++) {
3713                    if (*s2 == *s) {
3714                        j = 1;
3715                        break;
3716                    }
3717                }
3718                if (j == 0) {
3719                    sprintf(fnval,"%d",i+1);
3720                    p = fnval;
3721                    break;
3722                }
3723            }
3724            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3725            return(p);
3726        }
3727
3728      case FN_IPA:                      /* Find and return IP address */
3729        if (argn > 0) {                 /* in argument string. */
3730            int start;
3731            char *s2;
3732            start = 0;
3733            if (argn > 1) {             /* Starting position specified */
3734                if (chknum(bp[1])) {
3735                    start = atoi(bp[1]) - 1;
3736                    if (start < 0) start = 0;
3737                }
3738            }
3739            p = getip(bp[0]+start);
3740            for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3741            return(p);
3742        }
3743
3744#ifdef OS2
3745      case FN_CRY:
3746        p = "";
3747        if (argn > 0) {
3748            p = fnval;
3749            strcpy(p,bp[0]);
3750            ck_encrypt(p);
3751        }
3752        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3753        return(p);
3754
3755      case FN_OOX:
3756        p = "";
3757        if (argn > 0)
3758          p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
3759        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3760        return(p);
3761#endif /* OS2 */
3762
3763      case FN_HEX:
3764        p = "";
3765        if ((int)strlen(bp[0]) < (FNVALL / 2)) {
3766            s = bp[0];
3767            p = fnval;
3768            while (*s) {
3769                x = (*s >> 4) & 0x0f;
3770                *p++ = hexdigits[x];
3771                x = *s++ & 0x0f;
3772                *p++ = hexdigits[x];       
3773            }
3774            *p = NUL;
3775            p = fnval;
3776        }
3777        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3778        return(p);
3779
3780      case FN_UNH: {
3781          int c[2], i;
3782          p = "";
3783          if ((int)strlen(bp[0]) < (FNVALL * 2)) {
3784              s = bp[0];
3785              p = fnval;
3786              while (*s) {
3787                  for (i = 0; i < 2; i++) {
3788                      c[i] = *s++;
3789                      if (!c[i]) { p = ""; goto unhexfin; }
3790                      if (islower(c[i])) c[i] = toupper(c[i]);
3791                      if (c[i] >= '0' && c[i] <= '9')
3792                        c[i] -= 0x30;
3793                      else if (c[i] >= 'A' && c[i] <= 'F')
3794                        c[i] -= 0x37;
3795                      else { p = ""; goto unhexfin; }
3796                  }
3797                  *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
3798              }
3799              *p = NUL;
3800              p = fnval;
3801          }
3802  unhexfin:
3803          for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3804          return(p);
3805      }
3806
3807      case FN_BRK: {                    /* Break */
3808          char * c;                     /* Characters to break on */
3809          int done = 0;
3810          s = bp[0];                    /* Source pointer */
3811          p = fnval;                    /* Desination pointer */
3812          while (*s && !done) {
3813              c = bp[1];                /* Character to break on */
3814              while (*c) {
3815                  if (*s == *c++) {
3816                      done = 1;
3817                      break;
3818                  }
3819              }
3820              if (done) break;
3821              *p++ = *s++;
3822          }
3823          *p = NUL;                     /* terminate the result */
3824          p = fnval;                    /* and point to it. */
3825          for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3826          return(p);
3827      }
3828
3829      case FN_SPN: {                    /* Span */
3830          char *q;
3831          char c1, c2;
3832          s = bp[0];                    /* Source string */
3833          p = fnval;                    /* Result pointer */
3834          if ((int)strlen(bp[1]) > 0) { /* If span string is not empty */
3835              while (*s) {              /* Loop thru source string */
3836                  q = bp[1];            /* Span string */
3837                  c1 = *s;
3838                  if (!inpcas[cmdlvl])
3839                    if (islower(c1)) c1 = toupper(c1);
3840                  x = 0;
3841                  while (c2 = *q++) {
3842                      if (!inpcas[cmdlvl])
3843                        if (islower(c2)) c2 = toupper(c2);
3844                      if (c1 == c2) { x = 1; break; }
3845                  }
3846                  if (!x) break;
3847                  *p++ = *s++;
3848              }
3849          }
3850          *p = NUL;                     /* Terminate and return the result */
3851          p = fnval;
3852          for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3853          return(p);
3854      }
3855
3856      case FN_TRM:                      /* Trim(s1[,s2]) */
3857      case FN_LTR:                      /* Left-Trim(s1[,s2]) */
3858
3859        if (argn > 0 && (len1 = (int)strlen(bp[0])) > 0) {
3860            s = " \t";
3861            if (argn > 1)               /* Trim list given */
3862              s = bp[1];
3863            len2 = (int)strlen(s);
3864
3865            if (len2 < 1) {             /* or not... */
3866                s = " \t";              /* Default is to trim whitespace */
3867                len2 = 2;
3868            }
3869            if (y == FN_TRM) {          /* Trim from right */
3870                char * q;
3871                strncpy(fnval,bp[0],FNVALL); /* Copy string to output */
3872                p = fnval + len1 - 1;   /* Point to last character */
3873                while (p >= (char *)fnval) { /* Go backwards */
3874                    q = s;              /* Point to trim list */
3875                    while (*q) {        /* Is this char in trim list? */
3876                        if (*q == *p) { /* Yes, null it out */
3877                            *p = NUL;
3878                            break;
3879                        }
3880                        q++;
3881                    }
3882                    if (!*q)            /* Trim list exhausted */
3883                      break;            /* So we're done. */
3884                    p--;                /* Else keep trimming */
3885                }
3886            } else {                    /* Trim from left */
3887                char * q;
3888                p = bp[0];              /* Source */
3889                while (*p) {
3890                    q = s;
3891                    while (*q) {        /* Is this char in trim list? */
3892                        if (*q == *p) { /* Yes, point past it */
3893                            p++;        /* and try next source character */
3894                            break;
3895                        }
3896                        q++;            /* No, try next trim character */
3897                    }
3898                    if (!*q)            /* Trim list exhausted */
3899                      break;            /* So we're done. */
3900                }
3901                strncpy(fnval,p,FNVALL);
3902            }
3903            p = fnval;
3904        } else p = "0";
3905        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3906        return(p);
3907
3908      case FN_CAP:                      /* Capitalize */
3909        s = bp[0];
3910        p = fnval;
3911        x = 0;
3912        while (c = *s++) {
3913            if (isalpha(c)) {
3914                if (x == 0) {
3915                    x = 1;
3916                    if (islower(c))
3917                      c = toupper(c);
3918                } else if (isupper(c))
3919                  c = tolower(c);
3920            }
3921            *p++ = c;
3922        }
3923        *p = NUL;
3924        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3925        p = fnval;
3926        return(p);
3927
3928      case FN_TOD:
3929        p = fnval;
3930        sprintf(p,"%ld",tod2sec(bp[0]));
3931        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3932        return(p);
3933
3934      case FN_FFN:
3935        p = fnval;
3936        *p = NUL;
3937        if (bp[0])
3938#ifdef ZFNQFP
3939          zfnqfp(bp[0],FNVALL,p);
3940#else
3941          strcpy(p,bp[0]);
3942#endif /* ZFNQFP */
3943        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3944        return(p ? p : "");
3945
3946      case FN_CHK: {
3947          long chk = 0;
3948          p = bp[0] ? bp[0] : "";
3949          while (*p) chk += *p++;
3950          sprintf(fnval,"%lu",chk);
3951          for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3952          return((char *)fnval);
3953      }
3954      case FN_CRC:
3955        *fnval = NUL;
3956        if (bp[0])
3957          sprintf(fnval,"%u",chk3((CHAR *)bp[0],0));
3958        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3959        return((char *)fnval);
3960
3961      case FN_BSN:
3962        if (bp[0])
3963          zstrip(bp[0],&p);
3964        for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
3965        return(p);
3966
3967      default:
3968        return("");
3969    }
3970}
3971#endif /* NOSPL */
3972
3973static char ndatbuf[10];
3974
3975char *
3976zzndate() {
3977    char * p;
3978    int x;
3979
3980    ztime(&p);                          /* Get "asctime" string */
3981    if (p == NULL || *p == NUL) return("");
3982    for (x = 20; x < 24; x++)           /* yyyy */
3983      ndatbuf[x - 20] = p[x];
3984    ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
3985    ndatbuf[7] = p[9];                  /* dd */
3986    for (x = 0; x < 12; x++)            /* mm */
3987      if (!strncmp(p+4,months[x],3)) break;
3988    if (x == 12) {
3989        ndatbuf[4] = ndatbuf[5] = '?';
3990    } else {
3991        x++;
3992        ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
3993        ndatbuf[5] = (char) ((x % 10) + 48);
3994    }
3995    ndatbuf[8] = NUL;
3996    return((char *)ndatbuf);
3997}
3998
3999#ifndef NOSPL
4000char *                                  /* Evaluate builtin variable */
4001nvlook(s) char *s; {
4002    int x, y;
4003    long z;
4004    char *p;
4005#ifndef NODIAL
4006    MDMINF * m;
4007#endif /* NODIAL */
4008#ifndef NOKVERBS                        /* Keyboard macro material */
4009    extern int keymac, keymacx;
4010#endif /* NOKVERBS */
4011    x = 30;
4012    p = vvbuf;
4013    if (zzstring(s,&p,&x) < 0) {
4014        y = -1;
4015    } else {
4016        s = vvbuf;
4017        if ((y = lookup(vartab,s,nvars,&x)) < 0) return(NULL);
4018    }
4019#ifndef NODIAL
4020    m = (mdmtyp > 0) ? modemp[mdmtyp - 1] : NULL;
4021#endif /* NODIAL */
4022    switch (y) {
4023      case VN_ARGC:                     /* ARGC */
4024        sprintf(vvbuf,"%d",macargc[maclvl]);
4025        return(vvbuf);
4026
4027      case VN_ARGS:                     /* ARGS */
4028        sprintf(vvbuf,"%d",xargs);
4029        return(vvbuf);
4030
4031      case VN_COUN:                     /* COUNT */
4032        sprintf(vvbuf,"%d",count[cmdlvl]);
4033        return(vvbuf);
4034
4035      case VN_DATE:                     /* DATE */
4036        ztime(&p);                      /* Get "asctime" string */
4037        if (p == NULL || *p == NUL) return(NULL);
4038        vvbuf[0] = p[8];                /* dd */
4039        vvbuf[1] = p[9];
4040        vvbuf[2] = SP;
4041        vvbuf[3] = p[4];                /* mmm */
4042        vvbuf[4] = p[5];
4043        vvbuf[5] = p[6];
4044        vvbuf[6] = SP;
4045        for (x = 20; x < 24; x++)       /* yyyy */
4046          vvbuf[x - 13] = p[x];
4047        vvbuf[11] = NUL;
4048        return(vvbuf);
4049
4050      case VN_NDAT:                     /* Numeric date */
4051        strcpy(vvbuf,zzndate());
4052        return(vvbuf);
4053
4054      case VN_DIRE:                     /* DIRECTORY */
4055        return(zgtdir());
4056
4057      case VN_FILE:                     /* filespec */
4058        return(fspec);
4059
4060      case VN_HOST:                     /* host name */
4061        if (*myhost) {                  /* If known */
4062            return(myhost);             /* return it. */
4063        } else {                        /* Otherwise */
4064            strcpy(vvbuf,"unknown");    /* just say "unknown" */
4065            return(vvbuf);
4066        }
4067
4068      case VN_SYST:                     /* System type */
4069#ifdef UNIX
4070        strcpy(vvbuf,"UNIX");
4071#else
4072#ifdef VMS
4073        strcpy(vvbuf,"VMS");
4074#else
4075#ifdef OSK
4076        strcpy(vvbuf,"OS9/68K");
4077#else
4078#ifdef AMIGA
4079        strcpy(vvbuf,"Amiga");
4080#else
4081#ifdef MAC
4082        strcpy(vvbuf,"Macintosh");
4083#else
4084#ifdef OS2
4085#ifdef NT
4086        strcpy(vvbuf,"WIN32") ;
4087#else /* NT */
4088        strcpy(vvbuf,"OS/2");
4089#endif /* NT */
4090#else
4091#ifdef datageneral
4092        strcpy(vvbuf,"AOS/VS");
4093#else
4094#ifdef GEMDOS
4095        strcpy(vvbuf,"Atari_ST");
4096#else
4097#ifdef STRATUS
4098        strcpy(vvbuf,"Stratus_VOS");
4099#else
4100        strcpy(vvbuf,"unknown");
4101#endif /* STRATUS */
4102#endif /* GEMDOS */
4103#endif /* datageneral */
4104#endif /* OS2 */
4105#endif /* MAC */
4106#endif /* AMIGA */
4107#endif /* OSK */
4108#endif /* VMS */
4109#endif /* UNIX */
4110        return(vvbuf);
4111
4112      case VN_SYSV:                     /* System herald */
4113        for (x = y = 0; x < VVBUFL; x++) {
4114            if (ckxsys[x] == SP && y == 0) continue;
4115            vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
4116        }
4117        vvbuf[y] = NUL;
4118        return(vvbuf);
4119
4120      case VN_TIME:                     /* TIME. Assumes that ztime returns */
4121        ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
4122        if (p == NULL || *p == NUL)     /* like asctime()! */
4123          return(NULL);
4124        for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
4125          vvbuf[x - 11] = p[x];         /* to vvbuf */
4126        vvbuf[8] = NUL;                 /* terminate */
4127        return(vvbuf);                  /* and return it */
4128
4129      case VN_NTIM:                     /* Numeric time */
4130        ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
4131        if (p == NULL || *p == NUL)     /* like asctime()! */
4132          return(NULL);
4133        z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
4134        sprintf(vvbuf,"%ld",z);
4135        return(vvbuf);
4136
4137#ifdef CK_TTYFD
4138      case VN_TTYF:                     /* TTY file descriptor */
4139        sprintf(vvbuf,"%d",
4140#ifdef VMS
4141                vmsttyfd()
4142#else
4143                ttyfd
4144#endif /* VMS */
4145                );
4146        return(vvbuf);
4147#endif /* CK_TTYFD */
4148
4149      case VN_VERS:                     /* Numeric Kermit version number */
4150        sprintf(vvbuf,"%ld",vernum);
4151        return(vvbuf);
4152
4153      case VN_XVNUM:                    /* Product-specific version number */
4154        sprintf(vvbuf,"%ld",xvernum);
4155        return(vvbuf);
4156
4157      case VN_HOME:                     /* Home directory */
4158#ifdef UNIX
4159        sprintf(vvbuf,"%s/",zhome());
4160        return(vvbuf);
4161#else
4162#ifdef OSK
4163        sprintf(vvbuf,"%s/",zhome());
4164        return(vvbuf);
4165#else
4166#ifdef STRATUS
4167        sprintf(vvbuf,"%s>",zhome());
4168        return(vvbuf);
4169#else
4170        return(zhome());
4171#endif /* STRATUS */
4172#endif /* OSK */
4173#endif /* UNIX */
4174
4175      case VN_IBUF:                     /* INPUT buffer */
4176        return((char *)inpbuf);
4177
4178      case VN_ICHR:                     /* INPUT character */
4179        inchar[1] = NUL;
4180        return((char *)inchar);
4181
4182      case VN_ICNT:                     /* INPUT character count */
4183        sprintf(vvbuf,"%d",incount);
4184        return(vvbuf);
4185
4186      case VN_SPEE: {                   /* Transmission SPEED */
4187          long t;
4188          t = ttgspd();
4189          if (t < 0L)
4190            sprintf(vvbuf,"unknown");
4191          else
4192            sprintf(vvbuf,"%ld",t);
4193          return(vvbuf);
4194      }
4195      case VN_SUCC:                     /* SUCCESS flag */
4196        sprintf(vvbuf,"%d",(success == 0) ? 1 : 0);
4197        return(vvbuf);
4198
4199      case VN_LINE:                     /* LINE */
4200        p = (char *) ttname;
4201        return(p);
4202
4203      case VN_PROG:                     /* Program name */
4204        return("C-Kermit");
4205
4206      case VN_RET:                      /* Value of most recent RETURN */
4207        p = mrval[maclvl+1];
4208        if (p == NULL) p = "";
4209        return(p);
4210
4211      case VN_FFC:                      /* Size of most recent file */
4212        sprintf(vvbuf, "%ld", ffc);
4213        return(vvbuf);
4214
4215      case VN_TFC:                      /* Size of most recent file group */
4216        sprintf(vvbuf, "%ld", tfc);
4217        return(vvbuf);
4218
4219    case VN_CPU:                        /* CPU type */
4220#ifdef OS2
4221         {
4222            char * getcpu(void) ;
4223            return getcpu();
4224         }
4225#else /* OS2 */
4226#ifdef CKCPU
4227        return(CKCPU);
4228#else
4229        return("unknown");
4230#endif /* CKCPU */
4231#endif /* OS2 */
4232
4233      case VN_CMDL:                     /* Command level */
4234        sprintf(vvbuf, "%d", cmdlvl);
4235        return(vvbuf);
4236
4237      case VN_DAY:                      /* Day of week */
4238      case VN_NDAY:
4239/*
4240  Depends on ztime() returning ENGLISH asctime()-format string!
4241  asctime() format is: "Thu Feb  8 12:00:00 1990".
4242  Needs updating to accommodate non-English asctime() strings.
4243*/
4244        ztime(&p);
4245        if (p != NULL && *p != NUL) {   /* ztime() succeeded. */
4246            if (y == VN_DAY) {          /* String day. */
4247                strncpy(vvbuf,p,3);
4248            } else {                    /* Numeric day. */
4249                for (x = 0; x < 7; x++)   /* Look up day string in table */
4250                  if (!strncmp(p,wkdays[x],3))
4251                    break;
4252                if (x > 6) x = -1;      /* Not found */
4253                sprintf(vvbuf,"%d",x);  /* Return the number */
4254            }
4255        } else vvbuf[0] = NUL;          /* ztime() failed. */
4256        return(vvbuf);                  /* Return what we got. */
4257
4258      case VN_LCL:                      /* Local (vs remote) mode */
4259        strcpy(vvbuf, local ? "1" : "0");
4260        return(vvbuf);
4261
4262      case VN_CMDS:                     /* Command source */
4263        if (cmdstk[cmdlvl].src == CMD_KB)
4264          strcpy(vvbuf,"prompt");
4265        else if (cmdstk[cmdlvl].src == CMD_MD)
4266          strcpy(vvbuf,"macro");
4267        else if (cmdstk[cmdlvl].src == CMD_TF)
4268          strcpy(vvbuf,"file");
4269        else strcpy(vvbuf,"unknown");
4270        return(vvbuf);
4271
4272      case VN_CMDF:                     /* Current command file name */
4273#ifdef COMMENT                          /* (see comments above) */
4274        if (tfnam[tlevel]) {            /* (near dblbs declaration) */
4275            dblbs(tfnam[tlevel],vvbuf,VVBUFL);
4276            return(vvbuf);
4277        } else return("");
4278#else
4279        if (tlevel < 0)
4280          return("");
4281        else
4282          return(tfnam[tlevel] ? tfnam[tlevel] : "");
4283#endif /* COMMENT */
4284
4285      case VN_MAC:                      /* Current macro name */
4286        return((maclvl > -1) ? m_arg[maclvl][0] : "");
4287
4288      case VN_EXIT:
4289        sprintf(vvbuf,"%d",xitsta);
4290        return(vvbuf);
4291
4292      case VN_PRTY: {                   /* Parity */
4293          char *s;
4294          switch (parity) {
4295            case 0:   s = "none";  break;
4296            case 'e': s = "even";  break;
4297            case 'm': s = "mark";  break;
4298            case 'o': s = "odd";   break;
4299            case 's': s = "space"; break;
4300            default:  s = "unknown"; break;
4301          }
4302          strcpy(vvbuf,s);
4303          return(vvbuf);
4304      }
4305
4306      case VN_DIAL:
4307        sprintf(vvbuf,"%d",
4308#ifndef NODIAL
4309                dialsta
4310#else
4311                -1
4312#endif /* NODIAL */
4313                );
4314        return(vvbuf);
4315
4316#ifdef OS2
4317      case VN_KEYB:
4318        strncpy(vvbuf,conkbg(),VVBUFL);
4319        return(vvbuf);
4320
4321      case VN_SELCT: {
4322          extern char * selection ;
4323          return( selection ? selection : "" ) ;
4324      }
4325#endif /* OS2 */
4326
4327      case VN_CPS:
4328        if (tsecs > 0)
4329          sprintf(vvbuf, "%ld", tfc / (long) tsecs);
4330        else strcpy(vvbuf,"0");
4331        return(vvbuf);
4332
4333      case VN_MODE:                     /* File transfer mode */
4334        switch (binary) {
4335          case XYFT_T: strcpy(vvbuf,"text"); break;
4336          case XYFT_B:
4337          case XYFT_U: strcpy(vvbuf,"binary"); break;
4338          case XYFT_I: strcpy(vvbuf,"image"); break;
4339          case XYFT_L: strcpy(vvbuf,"labeled"); break;
4340          case XYFT_M: strcpy(vvbuf,"macbinary"); break;
4341          default:     strcpy(vvbuf,"unknown");
4342        }
4343        return(vvbuf);
4344
4345#ifdef CK_REXX
4346      case VN_REXX:
4347        return(rexxbuf);
4348#endif /* CK_REXX */
4349
4350      case VN_NEWL:                     /* System newline char or sequence */
4351#ifdef UNIX
4352        strcpy(vvbuf,"\n");
4353#else
4354#ifdef datageneral
4355        strcpy(vvbuf,"\n");
4356#else
4357#ifdef OSK
4358        strcpy(vvbuf,"\15");            /* Remember, these are octal... */
4359#else
4360#ifdef MAC
4361        strcpy(vvbuf,"\15");
4362#else
4363#ifdef OS2
4364        strcpy(vvbuf,"\15\12");
4365#else
4366#ifdef STRATUS
4367        strcpy(vvbuf,"\n");
4368#else
4369#ifdef VMS
4370        strcpy(vvbuf,"\15\12");
4371#else
4372#ifdef AMIGA
4373        strcpy(vvbuf,"\n");
4374#else
4375#ifdef GEMDOS
4376        strcpy(vvbuf,"\n");
4377#else
4378        strcpy(vvbuf,"\n");
4379#endif /* GEMDOS */
4380#endif /* AMIGA */
4381#endif /* VMS */
4382#endif /* STRATUS */
4383#endif /* OS2 */
4384#endif /* MAC */
4385#endif /* OSK */
4386#endif /* datageneral */
4387#endif /* UNIX */
4388        return(vvbuf);
4389
4390      case VN_ROWS:                     /* ROWS */
4391      case VN_COLS:                     /* COLS */
4392        strcpy(vvbuf,(y == VN_ROWS) ? "24" : "80"); /* Default */
4393#ifdef CK_TTGWSIZ
4394#ifdef OS2
4395        if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
4396          ttgwsiz();
4397        sprintf(vvbuf,"%d",(y == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
4398#else /* OS2 */
4399        if (ttgwsiz() > 0)              /* Get window size */
4400          if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
4401            sprintf(vvbuf,"%d",(y == VN_ROWS) ? tt_rows : tt_cols);
4402#endif /* OS2 */
4403#endif /* CK_TTGWSIZ */
4404        return(vvbuf);
4405
4406      case VN_TTYP:
4407#ifdef OS2
4408        sprintf(vvbuf, "%s",
4409                (tt_type >= 0 && tt_type <= max_tt) ?
4410                tt_info[tt_type].x_name :
4411                "unknown"
4412                );
4413#else
4414#ifdef MAC
4415        strcpy(vvbuf,"vt320");
4416#else
4417        p = getenv("TERM");
4418        sprintf(vvbuf,"%s", p ? p : "unknown");
4419#endif /* MAC */
4420#endif /* OS2 */
4421        return(vvbuf);
4422
4423      case VN_MINP:                     /* MINPUT */
4424        sprintf(vvbuf, "%d", m_found);
4425        return(vvbuf);
4426
4427      case VN_CONN:                     /* CONNECTION */
4428        if (!local) {
4429          strcpy(vvbuf,"remote");
4430        } else {
4431            if (!network)
4432              strcpy(vvbuf,"serial");
4433#ifdef TCPSOCKET
4434            else if (nettype == NET_TCPB || nettype == NET_TCPA) {
4435                if (ttnproto == NP_TELNET)
4436                  strcpy(vvbuf,"tcp/ip_telnet");
4437                else
4438                  strcpy(vvbuf,"tcp/ip");
4439            }
4440#endif /* TCPSOCKET */
4441#ifdef ANYX25
4442            else if (nettype == NET_SX25 || nettype == NET_VX25)
4443              strcpy(vvbuf,"x.25");
4444#endif /* ANYX25 */
4445#ifdef DECNET
4446            else if (nettype == NET_DEC) {
4447                if ( ttnproto == NP_LAT ) strcpy(vvbuf,"decnet_lat");
4448                else if ( ttnproto == NP_CTERM ) sprintf(vvbuf,"decnet_cterm");
4449                else strcpy(vvbuf,"decnet");
4450            }
4451#endif /* DECNET */
4452#ifdef SUPERLAT
4453        else if ( nettype == NET_SLAT )
4454           strcpy(vvbuf,"superlat");
4455#endif /* SUPERLAT */
4456#ifdef NETFILE
4457        else if ( nettype == NET_FILE )
4458           strcpy(vvbuf,"local file");
4459#endif /* NETFILE */
4460
4461#ifdef NPIPE
4462            else if (nettype == NET_PIPE)
4463              strcpy(vvbuf,"named_pipe");
4464#endif /* NPIPE */
4465#ifdef CK_NETBIOS
4466            else if (nettype == NET_BIOS)
4467              strcpy(vvbuf,"netbios");
4468#endif /* CK_NETBIOS */
4469            else
4470              strcpy(vvbuf,"unknown");
4471        }
4472        return(vvbuf);
4473
4474      case VN_SYSI:                     /* System ID, Kermit code */
4475        return((char *)cksysid);
4476
4477#ifdef OS2
4478      case VN_SPA:
4479        sprintf(vvbuf,"%ld",zdskspace(0));
4480        return(vvbuf);
4481#endif /* OS2 */
4482
4483      case VN_QUE: {
4484          extern char querybuf[];
4485          return(querybuf);
4486      }
4487#ifndef NOCSETS
4488      case VN_CSET:
4489#ifdef OS2
4490        sprintf(vvbuf,"cp%d",os2getcp());
4491#else
4492        sprintf(vvbuf,"%s",fcsinfo[fcharset].keyword);
4493#endif /* OS2 */
4494        return(vvbuf);
4495#endif /* NOCSETS */
4496
4497#ifdef OS2
4498      case VN_STAR:
4499        return(startupdir);
4500
4501      case VN_EXEDIR:
4502        return(exedir);   
4503#endif /* OS2 */
4504
4505      case VN_INI:
4506        return(inidir) ;
4507
4508      case VN_MDM:
4509        return(gmdmtyp());
4510
4511      case VN_EVAL:
4512        return(evalbuf);
4513
4514#ifndef NODIAL
4515      case VN_D_CC:                     /* DIAL COUNTRY-CODE */
4516        return(diallcc ? diallcc : "");
4517       
4518      case VN_D_AC:                     /* DIAL AREA-CODE */
4519        return(diallac ? diallac : "");
4520
4521      case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
4522        return(dialixp ? dialixp : "");
4523
4524      case VN_D_LP:                     /* DIAL LD-PREFIX */
4525        return(dialldp ? dialldp : "");
4526#else
4527      case VN_D_CC:                     /* DIAL COUNTRY-CODE */
4528      case VN_D_AC:                     /* DIAL AREA-CODE */
4529      case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
4530      case VN_D_LP:                     /* DIAL LD-PREFIX */
4531        return("");
4532#endif /* NODIAL */
4533      case VN_UID:
4534        return((char *)uidbuf);
4535
4536      case VN_PWD:
4537#ifdef OS2
4538        if (activecmd == XXOUT) {
4539            strncpy(vvbuf,pwbuf,VVBUFL);
4540            ck_encrypt((char *)vvbuf);
4541            return((char *)vvbuf);
4542        } else
4543#endif /* OS2 */
4544          return((char *)pwbuf);
4545
4546      case VN_PRM:
4547        return((char *)prmbuf);
4548
4549      case VN_PROTO:
4550#ifdef CK_XYZ
4551        return(ptab[protocol].p_name);
4552#else
4553        return("kermit");
4554#endif /* CK_XYZ */
4555
4556#ifdef CK_TMPDIR
4557      case VN_DLDIR:
4558        return(dldir ? dldir : "");
4559#endif /* CK_TMPDIR */
4560
4561#ifndef NODIAL
4562      case VN_M_INI:                    /* Modem init string */
4563        return(dialini ? dialini : (m ? m->wake_str : ""));
4564
4565      case VN_M_DCM:                    /* Modem dial command */
4566        return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
4567
4568      case VN_M_DCO:                    /* Modem data compression on */
4569        return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
4570
4571      case VN_M_DCX:                    /* Modem data compression off */
4572        return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
4573
4574      case VN_M_ECO:                    /* Modem error correction on */
4575        return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
4576
4577      case VN_M_ECX:                    /* Modem error correction off */
4578        return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
4579
4580      case VN_M_AAO:                    /* Modem autoanswer on */
4581        return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
4582
4583      case VN_M_AAX:                    /* Modem autoanswer off */
4584        return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
4585
4586      case VN_M_HUP:                    /* Modem hangup command */
4587        return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
4588
4589      case VN_M_HWF:                    /* Modem hardware flow command */
4590        return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
4591
4592      case VN_M_SWF:                    /* Modem software flow command */
4593        return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
4594
4595      case VN_M_NFC:                    /* Modem no flow-control command */
4596        return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
4597
4598      case VN_M_PDM:                    /* Modem pulse dialing mode */
4599        return(dialpulse ? dialpulse : (m ? m->pulse : ""));
4600
4601      case VN_M_TDM:                    /* Modem tone dialing mode */
4602        return(dialtone ? dialtone : (m ? m->tone : ""));
4603#else
4604      case VN_M_INI:                    /* Modem init string */
4605      case VN_M_DCM:                    /* Modem dial command */
4606      case VN_M_DCO:                    /* Modem data compression on */
4607      case VN_M_DCX:                    /* Modem data compression off */
4608      case VN_M_ECO:                    /* Modem error correction on */
4609      case VN_M_ECX:                    /* Modem error correction off */
4610      case VN_M_AAO:                    /* Modem autoanswer on */
4611      case VN_M_AAX:                    /* Modem autoanswer off */
4612      case VN_M_HUP:                    /* Modem hangup command */
4613      case VN_M_HWF:                    /* Modem hardware flow command */
4614      case VN_M_SWF:                    /* Modem software flow command */
4615      case VN_M_NFC:                    /* Modem no flow-control command */
4616      case VN_M_PDM:                    /* Modem pulse dialing mode */
4617      case VN_M_TDM:                    /* Modem tone dialing mode */
4618        return("");
4619#endif /* NODIAL */
4620
4621      case VN_ISTAT:                    /* INPUT status */
4622        sprintf(vvbuf, "%d", instatus);
4623        return(vvbuf);
4624
4625      case VN_TEMP:                     /* Temporary directory */
4626        if (tempdir) {
4627            p = tempdir;
4628        } else {
4629#ifdef OS2
4630#ifdef NT
4631            p = getenv("K95TMP");
4632#else
4633            p = getenv("K2TMP");
4634#endif /* NT */
4635            if ( !p )
4636                p = getenv("CK_TMP");
4637            if (!p)
4638#endif /* OS2 */
4639            p = getenv("TEMP");
4640            if (!p) p = getenv("TMP");
4641            if (!p)
4642#ifdef UNIX                             /* Systems that have a standard */
4643              p = "/tmp/";              /* temporary directory... */
4644#else
4645#ifdef datageneral
4646              p = ":TMP:";
4647#else
4648              p = "";
4649#endif /* datageneral */
4650#endif /* UNIX */
4651        }
4652        strncpy(vvbuf,p,VVBUFL - 1);
4653        p = vvbuf;
4654
4655/* This needs generalizing for VOS, AOS/VS, etc... */
4656
4657        while (*p) {
4658#ifdef OS2
4659            if (*p == '\\') *p = '/';
4660#endif /* OS2 */
4661            p++;
4662        }
4663        if (p > vvbuf) {
4664            char c =                    /* Directory termination character */
4665#ifdef MAC
4666              ':'
4667#else
4668#ifdef datageneral
4669              ':'
4670#else
4671#ifdef STRATUS
4672              '>'
4673#else
4674              '/'
4675#endif /* STRATUS */
4676#endif /* datageneral */
4677#endif /* MAC */
4678                ;
4679
4680            if (*(p-1) != c) {
4681                *p++ = c;
4682                *p = NUL;
4683            }
4684        }
4685        return(vvbuf);
4686
4687      case VN_ERRNO:                    /* Error number */
4688        sprintf(vvbuf, "%d", errno);
4689        return(vvbuf);
4690
4691      case VN_ERSTR:                    /* Error string */
4692        strncpy(vvbuf,ck_errstr(),VVBUFL - 1);
4693        return(vvbuf);
4694
4695      case VN_RPSIZ:                    /* RECEIVE packet-length */
4696        sprintf(vvbuf,"%d",urpsiz);
4697        return(vvbuf);
4698
4699      case VN_WINDO:
4700        sprintf(vvbuf,"%d",wslotr);
4701        return(vvbuf);
4702
4703      case VN_TFLN:                     /* TAKE-file line number */
4704        if (tlevel > -1) {
4705            sprintf(vvbuf, "%d", tfline[tlevel]);
4706            return(vvbuf);
4707        } else
4708          return("0");
4709
4710      case VN_MDMSG:                    /* DIALRESULT */
4711#ifndef NODIAL
4712        return((char *)modemmsg);
4713#else
4714        return("");
4715#endif /* NODIAL */
4716
4717      case VN_DNUM:                     /* DIALNUMBER */
4718#ifndef NODIAL
4719        return(dialnum ? (char *) dialnum : "");
4720#else
4721        return("");
4722#endif /* NODIAL */
4723
4724      case VN_APC:
4725        sprintf(vvbuf, "%d",
4726#ifdef CK_APC
4727                apcactive
4728#else
4729                0
4730#endif /* CK_APC */
4731                );
4732        return((char *)vvbuf);
4733
4734      case VN_TRMK:
4735          sprintf(vvbuf, "%d",
4736#ifdef OS2
4737                keymac
4738#else
4739                0
4740#endif /* OS2 */
4741                );
4742        return((char *)vvbuf);
4743
4744      case VN_IPADDR:
4745        sprintf(vvbuf, "%s",
4746#ifdef TCPSOCKET
4747                (char *) myipaddr
4748#else
4749                ""
4750#endif /* TCPSOCKET */
4751                );
4752        return((char *)vvbuf);
4753
4754      case VN_CRC16:                    /* CRC-16 of most recent transfer */
4755        sprintf(vvbuf,"%ld",crc16);
4756        return(vvbuf);
4757
4758      default:
4759        return(NULL);
4760    }
4761}
4762#endif /* NOSPL */
4763
4764
4765/*
4766  X X S T R I N G  --  Expand variables and backslash codes.
4767
4768    int xxtstring(s,&s2,&n);
4769
4770  Expands \ escapes via recursive descent.
4771  Argument s is a pointer to string to expand (source).
4772  Argument s2 is the address of where to put result (destination).
4773  Argument n is the length of the destination string (to prevent overruns).
4774  Returns -1 on failure, 0 on success,
4775    with destination string null-terminated and s2 pointing to the
4776    terminating null, so that subsequent characters can be added.
4777*/
4778
4779#define XXDEPLIM 100                    /* Recursion depth limit */
4780
4781int
4782zzstring(s,s2,n) char *s; char **s2; int *n; {
4783    int x,                              /* Current character */
4784        y,                              /* Worker */
4785        pp,                             /* Paren level */
4786        kp,                             /* Brace level */
4787        argn,                           /* Function argument counter */
4788        n2,                             /* Local copy of n */
4789        d,                              /* Array dimension */
4790        vbi,                            /* Variable id (integer form) */
4791        argl;                           /* String argument length */
4792
4793    char vb,                            /* Variable id (char form) */
4794        *vp,                            /* Pointer to variable definition */
4795        *new,                           /* Local pointer to target string */
4796        *p,                             /* Worker */
4797        *q;                             /* Worker */
4798    char *r  = (char *)0;               /* For holding function args */
4799    char *r2 = (char *)0;
4800    char *r3p;
4801
4802#ifndef NOSPL
4803    char vnambuf[VNAML];                /* Buffer for variable/function name */
4804    char *argp[FNARGS];                 /* Pointers to function args */
4805#endif /* NOSPL */
4806
4807    static int depth = 0;               /* Call depth, avoid overflow */
4808
4809    n2 = *n;                            /* Make local copies of args */
4810    new = *s2;                          /* for one less level of indirection */
4811
4812    depth++;                            /* Sink to a new depth */
4813    if (depth > XXDEPLIM) {             /* Too deep? */
4814        printf("?definition is circular or too deep\n");
4815        depth = 0;
4816        *new = NUL;
4817        return(-1);
4818    }
4819    if (!s || !new) {                   /* Watch out for null pointers */
4820        depth = 0;
4821        *new = NUL;
4822        return(-1);
4823    }
4824    argl = (int)strlen(s);              /* Get length of source string */
4825    debug(F111,"xxstring",s,argl);
4826    if (argl < 0) {                     /* Watch out for garbage */
4827        depth = 0;
4828        *new = NUL;
4829        return(-1);
4830    }
4831    while ( x = *s ) {                  /* Loop for all characters */
4832        if (x != CMDQ) {                /* Is it the command-quote char? */
4833            *new++ = *s++;              /* No, normal char, just copy */
4834            if (n2-- < 0) {             /* and count it, careful of overflow */
4835                return(-1);
4836            }
4837            continue;
4838        }
4839
4840/* We have the command-quote character. */
4841
4842        x = *(s+1);                     /* Get the following character. */
4843
4844        switch (x) {                    /* Act according to variable type */
4845#ifndef NOSPL
4846          case 0:                       /* It's a lone backslash */
4847            *new++ = *s++;
4848            if (n2-- < 0)
4849              return(-1);
4850            break;
4851          case '%':                     /* Variable */
4852            s += 2;                     /* Get the letter or digit */
4853            vb = *s++;                  /* and move source pointer past it */
4854            vp = NULL;                  /* Assume definition is empty */
4855            if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
4856                if (maclvl < 0)         /* Digit variables are global */
4857                  vp = g_var[vb];       /* if no macro is active */
4858                else                    /* otherwise */
4859                  vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
4860            } else {
4861                if (isupper(vb)) vb += ('a'-'A');
4862                vp = g_var[vb];         /* Letter for global variable */
4863            }
4864            if (vp) {                   /* If definition not empty */
4865                if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
4866                    return(-1);         /* Pass along failure */
4867                }
4868            }
4869            break;
4870          case '&':                     /* An array reference */
4871            if (arraynam(s,&vbi,&d) < 0) { /* Get name and subscript */
4872                return(-1);
4873            }
4874            pp = 0;                     /* Bracket counter */
4875            while (*s) {                /* Advance source pointer */
4876                if (*s == '[') pp++;
4877                if (*s == ']' && --pp == 0) break;
4878                s++;
4879            }
4880            if (*s == ']') s++;         /* past the closing bracket. */
4881            if (chkarray(vbi,d) > 0) {  /* Array is declared? */
4882                vbi -= ARRAYBASE;       /* Convert name to index */
4883                if (a_dim[vbi] >= d) {  /* If subscript in range */
4884                    char **ap;
4885                    ap = a_ptr[vbi];    /* get data pointer */
4886                    if (ap) {           /* and if there is one */
4887                        if (ap[d]) {    /* If definition not empty */
4888                            if (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
4889                                return(-1); /* Pass along failure */
4890                            }
4891                        }
4892                    }
4893                }
4894            }
4895            break;
4896
4897          case 'F':                     /* A builtin function */
4898          case 'f':
4899            q = vnambuf;                /* Copy the name */
4900            y = 0;                      /* into a separate buffer */
4901            s += 2;                     /* point past 'F' */
4902            while (y++ < VNAML) {
4903                if (*s == '(') { s++; break; } /* Look for open paren */
4904                if ((*q = *s) == NUL) break;   /* or end of string */
4905                s++; q++;
4906            }
4907            *q = NUL;                   /* Terminate function name */
4908            if (y >= VNAML) {           /* Handle pathological case */
4909                while (*s && (*s != '(')) /* of very long string entered */
4910                  s++;                    /* as function name. */
4911                if (*s == ')') s++;       /* Skip past it. */
4912            }
4913            r = r2 = malloc(argl+2);    /* And make a place to copy args */
4914            debug(F101,"xxstring r2","",r2);
4915            if (!r2) {                  /* Watch out for malloc failure */
4916                depth = 0;
4917                *new = NUL;
4918                return(-1);
4919            }
4920            if (r3) free(r3); /* And another to copy literal arg string */
4921            r3 = malloc(argl+2);
4922            debug(F101,"xxstring r3","",r3);
4923            if (!r3) {
4924                depth = 0;
4925                *new = NUL;
4926                return(-1);
4927            } else
4928              r3p = r3;
4929            argn = 0;                   /* Argument counter */
4930            argp[argn++] = r;           /* Point to first argument */
4931            y = 0;                      /* Completion flag */
4932            pp = 1;                     /* Paren level (already have one). */
4933            kp = 0;
4934            while (1) {                 /* Copy each argument, char by char. */
4935                *r3p++ = *s;            /* This is a literal copy for \flit */
4936                if (!*s) break;
4937
4938                if (*s == '{') {        /* Left brace */
4939#ifdef COMMENT
4940                    if (kp++ == 0) {    /* Skip it if it's the outer one */
4941                        s++;
4942                        *r3p++ = *s;
4943                    }
4944#else
4945                    kp++;
4946#endif /* COMMENT */
4947                }
4948                if (*s == '}') {        /* Right brace */
4949#ifdef COMMENT
4950                    if (--kp == 0) {    /* Skip it if it's the outer one */
4951                        s++;
4952                        *r3p++ = *s;
4953                    }
4954#else
4955                    kp--;
4956#endif /* COMMENT */
4957                }
4958                if (*s == '(' && kp <= 0) { /* Open paren not in brace */
4959                    pp++;               /* Count it */
4960                }
4961                *r = *s;                /* Now copy resulting byte */
4962                if (!*r)                /* If NUL, done. */
4963                  break;
4964                if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
4965                    if (--pp == 0) {    /* Final one? */
4966                        *r = NUL;       /* Make it a terminating null */
4967                        *(r3p - 1) = NUL;
4968                        s++;            /* Point past it in source string */
4969                        y = 1;          /* Flag we've got all the args */
4970                        break;          /* Done with while loop */
4971                    }
4972                }
4973                if (*r == ',' && kp <= 0) { /* Comma */
4974                    if (pp == 1) {          /* If not within ()'s, */
4975                        if (argn >= FNARGS) { /* Too many args */
4976                            s++; r++;   /* Keep collecting flit() string */
4977                            continue;
4978                        }
4979                        *r = NUL;           /* New arg, skip past comma */
4980                        argp[argn++] = r+1; /* In range, point to new arg */
4981                    }                   /* Otherwise just skip past  */
4982                }
4983                s++; r++;               /* Advance pointers */
4984            }
4985            debug(F111,"xxstring function name",vnambuf,y);
4986            debug(F110,"xxstring function r3",r3,0);
4987            if (!y) {                   /* If we didn't find closing paren */
4988                debug(F101,"xxstring r2 before free","",r2);
4989                if (r2) {
4990                    free(r2);           /* free the temporary storage */
4991                    r2 = NULL;
4992                }
4993                return(-1);             /* and return failure. */
4994            }
4995#ifdef DEBUG
4996            if (deblog)
4997              for (y = 0; y < argn; y++)
4998                debug(F111,"xxstring function arg",argp[y],y);
4999#endif /* DEBUG */
5000            vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
5001            if (vp) {                   /* If definition not empty */
5002                while (*new++ = *vp++)  /* copy it to output string */
5003                  if (n2-- < 0) return(-1); /* mindful of overflow */
5004                new--;                  /* Back up over terminating null */
5005                n2++;                   /* to allow for further deposits. */
5006            }
5007            if (r2) {
5008                debug(F101,"xxstring freeing r2","",r2);
5009                free(r2);               /* Now free the temporary storage */
5010                r2 = NULL;
5011            }
5012            break;
5013          case '$':                     /* An environment variable */
5014          case 'V':                     /* Or a named builtin variable. */
5015          case 'v':
5016          case 'M':                     /* Or a macro = long variable */
5017          case 'm':
5018            p = s+2;                    /* $/V/M must be followed by (name) */
5019            if (*p != '(') {            /* as in \$(HOME) or \V(count) */
5020                *new++ = *s++;          /* If not, just copy it */
5021                if (n2-- < 0) {
5022                    return(-1);
5023                }
5024                break;
5025            }
5026            p++;                        /* Point to 1st char of name */
5027            q = vnambuf;                /* Copy the name */
5028            y = 0;                      /* into a separate buffer */
5029            while (y++ < VNAML) {       /* Watch out for name too long */
5030                if (*p == ')') {        /* Name properly terminated with ')' */
5031                    p++;                /* Move source pointer past ')' */
5032                    break;
5033                }
5034                if ((*q = *p) == NUL)   /* String ends before ')' */
5035                  break;
5036                p++; q++;               /* Advance pointers */
5037            }
5038            *q = NUL;                   /* Terminate the variable name */
5039            if (y >= VNAML) {           /* Handle pathological case */
5040                while (*p && (*p != ')')) /* of very long string entered */
5041                  p++;                    /* as variable name. */
5042                if (*p == ')') p++;       /* Skip ahead to the end of it. */
5043            }
5044            s = p;                      /* Adjust global source pointer */
5045            p = malloc((int)strlen(vnambuf) + 1); /* Make temporary space */
5046            if (p) {                    /* If we got the space */
5047                vp = vnambuf;           /* Point to original */
5048                strcpy(p,vp);           /* Make a copy of it */
5049                y = VNAML;              /* Length of name buffer */
5050                zzstring(p,&vp,&y);     /* Evaluate the copy */
5051                free(p);                /* Free the temporary space */
5052                p = NULL;
5053            }
5054            debug(F110,"xxstring vname",vnambuf,0);
5055            q = NULL;
5056            if (x == '$') {             /* Look up its value */
5057                vp = getenv(vnambuf);   /* This way for environment variable */
5058            } else if (x == 'm' || x == 'M') { /* or this way for macro */
5059                y = mlook(mactab,vnambuf,nmac); /* get definition */
5060                if (y > -1) {           /* Got definition */
5061                    vp = mactab[y].mval;
5062#ifdef COMMENT
5063/*
5064  This works, but it breaks too many things, like CKERMIT.INI!
5065  We need a new \_() function for this, which fully evaluates the name
5066  of the macro before retrieving its definition.
5067*/
5068                    q = p = malloc(1024); /* Now evaluate it */
5069                    if (p) {
5070                        y = 1023;
5071                        zzstring(vp,&p,&y);
5072                    }
5073                    vp = q;             /* Point to evaluated definition */
5074#endif /* COMMENT */
5075                } else vp = NULL;
5076            } else {                    /*  or */
5077                vp = nvlook(vnambuf);   /* this way for builtin variable */
5078            }
5079            if (vp) {                   /* If definition not empty */
5080                while (*new++ = *vp++)  /* copy it to output string. */
5081                  if (n2-- < 0) {
5082                      if (q) free(q);
5083                      return(-1);
5084                  }
5085                new--;                  /* Back up over terminating null */
5086                n2++;                   /* to allow for further deposits. */
5087            }
5088            if (q) {
5089                free(q);
5090                q = NULL;
5091            }
5092            break;
5093#endif /* NOSPL */                      /* Handle \nnn even if NOSPL. */
5094
5095#ifndef NOKVERBS
5096        case 'K':
5097        case 'k': {
5098            extern struct keytab kverbs[];
5099            extern int nkverbs;
5100#define K_BUFLEN 30
5101            char kbuf[K_BUFLEN + 1];    /* Key verb name buffer */
5102            int x, y, z, brace = 0;
5103            s += 2;
5104/*
5105  We assume that the verb name is {braced}, or it extends to the end of the
5106  string, s, or it ends with a space, control character, or backslash.
5107*/
5108            p = kbuf;                   /* Copy verb name into local buffer */
5109            x = 0;
5110            if (*s == '{')  {
5111                s++;
5112                brace++;
5113            }
5114            while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
5115                if (brace && *s == '}') {
5116                    s++;
5117                    break;
5118                }       
5119                *p++ = *s++;
5120            }
5121            brace = 0;
5122            *p = NUL;                   /* Terminate. */
5123            p = kbuf;                   /* Point back to beginning */
5124            debug(F110,"zzstring kverb",p,0);
5125            y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
5126            debug(F101,"zzstring lookup",0,y);
5127            if (y > -1) {
5128                dokverb(VTERM,y);
5129#ifndef NOSPL
5130            } else {                    /* Is it a macro? */
5131                y = mxlook(mactab,p,nmac);
5132                if (y > -1) {
5133                    debug(F111,"zzstring mxlook",s,y);
5134                    if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
5135                        if (cmpush() > -1) {  /* Push command parser state */
5136                            extern int ifc;
5137                            int ifcsav = ifc; /* Push IF condition on stack */
5138                            y = parser(1);    /* New parser to execute macro */
5139                            cmpop();          /* Pop command parser */
5140                            ifc = ifcsav;     /* Restore IF condition */
5141                            if (y == 0) {     /* No errors, ignore actions */
5142                                p = mrval[maclvl+1]; /* If OK set return val */
5143                                if (p == NULL) p = "";
5144                            }
5145                        } else {                /* Can't push any more */
5146                            debug(F100,"zzstring pushed too deep","",0);
5147                            printf("\n?zzstring too deeply nested\n");
5148                            while (cmpop() > -1);
5149                            p = "";
5150                        }
5151                    }
5152                }
5153#endif /* NOSPL */
5154            }
5155            break;
5156        }
5157#endif /* NOKVERBS */
5158
5159        default:                        /* Maybe it's a backslash code */
5160          y = xxesc(&s);                /* Go interpret it */
5161          if (y < 0) {                  /* Upon failure */
5162              *new++ = (char) x;        /* Just quote the next character */
5163              s += 2;                   /* Move past the pair */
5164              n2 -= 2;
5165              if (n2 < 0) {
5166                  return(-1);
5167              }
5168              continue;                 /* and go back for more */
5169          } else {
5170              *new++ = (char) y;        /* else deposit interpreted value */
5171              if (n2-- < 0) {
5172                  return(-1);
5173              }
5174          }
5175        }
5176    }
5177    *new = NUL;                         /* Terminate the new string */
5178    depth--;                            /* Adjust stack depth gauge */
5179    *s2 = new;                          /* Copy results back into */
5180    *n = n2;                            /* the argument addresses */
5181    return(0);                          /* and return. */
5182}
5183#endif /* NOICP */
Note: See TracBrowser for help on using the repository browser.