apply 010_makefile-destdir-support
[ckermit.git] / ckuus4.c
1 #include "ckcsym.h"
2
3 /*  C K U U S 4 --  "User Interface" for C-Kermit, part 4  */
4
5 /*
6   Authors:
7     Frank da Cruz <fdc@columbia.edu>,
8       The Kermit Project, Columbia University, New York City
9     Jeffrey E Altman <jaltman@secure-endpoints.com>
10       Secure Endpoints Inc., New York City
11
12   Copyright (C) 1985, 2004,
13     Trustees of Columbia University in the City of New York.
14     All rights reserved.  See the C-Kermit COPYING.TXT file or the
15     copyright text in the ckcmai.c module for disclaimer and permissions.
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 "ckcnet.h"                     /* Network symbols */
26 #include "ckuusr.h"
27 #include "ckuver.h"
28 #include "ckcxla.h"                     /* Character sets */
29
30 #ifdef CK_AUTHENTICATION
31 #include "ckuath.h"
32 #endif /* CK_AUTHENTICATION */
33 #ifdef CK_SSL
34 #include "ck_ssl.h"
35 #endif /* CK_SSL */
36
37 #ifdef VMS
38 #include <errno.h>                      /* For \v(errno) */
39 extern char * ckvmserrstr(unsigned long);
40 #ifndef OLD_VMS
41 #include <lib$routines.h>               /* Not for VAX C 2.4 */
42 #else
43 #include <libdef.h>
44 #endif /* OLD_VMS */
45 _PROTOTYP(int vmsttyfd, (void) );
46 #endif /* VMS */
47
48 #ifdef OS2
49 #ifndef NT
50 #define INCL_NOPM
51 #define INCL_VIO                        /* Needed for ckocon.h */
52 #include <os2.h>
53 #undef COMMENT
54 #else
55 #include <windows.h>
56 #include <tapi.h>
57 #include "ckntap.h"
58 #define APIRET ULONG
59 #endif /* NT */
60 #include "ckocon.h"
61 #include "ckoetc.h"
62 int StartedFromDialer = 0;
63 HWND hwndDialer = 0;
64 LONG KermitDialerID = 0;
65 #ifdef putchar
66 #undef putchar
67 #endif /* putchar */
68 #define putchar(x) conoc(x)
69 #ifdef CK_PID
70 #include <process.h>
71 #endif /* CK_PID */
72 #endif /* OS2 */
73
74 #ifdef KUI
75 extern struct keytab * term_font;
76 extern int ntermfont, tt_font, tt_font_size;
77 #endif /* KUI */
78
79 extern xx_strp xxstring;
80
81 #ifdef DEC_TCPIP
82 #include <descrip>
83 #include <dvidef>
84 #include <dcdef>
85 #endif /* DEC_TCPIP */
86
87 #ifdef FNFLOAT
88 #include <math.h>                       /* Floating-point functions */
89 #endif /* FNFLOAT */
90
91 extern int quiet, network, xitsta, escape, nopush, xferstat,
92   exitonclose, tn_exit, ttnproto, autodl, flow, byteorder, what, lastxfer;
93
94 extern int filepeek, nscanfile, makestrlen;
95 extern char * k_info_dir;
96
97 #ifndef MAC
98 #ifndef AMIGA
99 extern int ttyfd;
100 #endif /* MAC */
101 #endif /* AMIGA */
102
103 #ifdef TNCODE
104 extern int tn_nlm, tn_b_nlm, tn_b_xfer, tn_sb_bug;
105 extern int tn_rem_echo;
106 extern int tn_b_meu, tn_b_ume, tn_auth_krb5_des_bug;
107 #endif /* TNCODE */
108
109 char * xferfile = NULL;
110 int xferlog = 0;
111
112 extern int local, xargc, stayflg, rcflag, bgset, backgrd, cfilef,
113   inserver, srvcdmsg, success;
114
115 #ifdef VMS
116 extern int batch;
117 #endif /* VMS */
118
119 extern char cmdfil[], *versio, *ckxsys, **xargv;
120 #ifdef DEBUG
121 extern char debfil[];                   /* Debug log file name */
122 extern int debtim;
123 #endif /* DEBUG */
124
125 extern int noinit;
126
127 static char ndatbuf[10];
128
129 char *months[] = {
130     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
131     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
132 };
133
134 char *
135 zzndate() {                             /* Returns today's date as yyyymmdd */
136     char * p = NULL;
137     int x;
138
139 /* WARNING - This will fail if asctime() returns non-English month names */
140
141     ztime(&p);                          /* Get "asctime" string */
142     if (p == NULL || *p == NUL) return("");
143     for (x = 20; x < 24; x++)           /* yyyy */
144       ndatbuf[x - 20] = p[x];
145     ndatbuf[6] = (char) ((p[8] == ' ') ? '0' : p[8]);
146     ndatbuf[7] = p[9];                  /* dd */
147     for (x = 0; x < 12; x++)            /* mm */
148       if (!strncmp(p+4,months[x],3)) break;
149     if (x == 12) {
150         ndatbuf[4] = ndatbuf[5] = '?';
151     } else {
152         x++;
153         ndatbuf[4] = (char) ((x < 10) ? '0' : '1');
154         ndatbuf[5] = (char) ((x % 10) + 48);
155     }
156     ndatbuf[8] = NUL;
157     debug(F110,"zzndate return",ndatbuf,0);
158     return((char *)ndatbuf);
159 }
160
161 #ifdef DCMDBUF
162 extern struct cmdptr *cmdstk;
163 extern char *line, *tmpbuf;
164 #else
165 extern struct cmdptr cmdstk[];
166 extern char line[], tmpbuf[];
167 #endif /* DCMDBUF */
168
169 #ifdef OS2
170 extern char exedir[];
171 #else
172 extern char * exedir;
173 #endif /* OS2 */
174
175 extern int nettype;
176
177 #ifndef NOICP                           /* Most of this file... */
178 #ifdef CKLOGDIAL
179 extern char diafil[];
180 #endif /* CKLOGDIAL */
181
182 #ifndef AMIGA
183 #ifndef MAC
184 #include <signal.h>
185 #endif /* MAC */
186 #endif /* AMIGA */
187
188 #ifdef STRATUS                          /* Stratus Computer, Inc.  VOS */
189 #ifdef putchar
190 #undef putchar
191 #endif /* putchar */
192 #define putchar(x) conoc(x)
193 #ifdef getchar
194 #undef getchar
195 #endif /* getchar */
196 #define getchar(x) coninc(0)
197 #endif /* STRATUS */
198
199
200 #ifdef ANYX25
201 extern int revcall, closgr, cudata;
202 int x25ver;
203 extern char udata[];
204 #ifndef IBMX25
205 extern int npadx3;
206 extern CHAR padparms[];
207 extern struct keytab padx3tab[];
208 #endif /* !IBMX25 */
209 #ifdef IBMX25
210 /* global variables only available for IBM X.25 - possibly interesting for
211  * other implementations
212  */
213 extern x25addr_t local_nua;
214 extern x25addr_t remote_nua;
215 #endif /* IBMX25 */
216 #endif /* ANYX25 */
217
218 #ifdef NETCONN
219 #ifndef NODIAL
220 extern int nnetdir;
221 extern char *netdir[];
222 #endif /* NODIAL */
223 extern char ipaddr[];
224
225 #ifdef CK_NETBIOS
226 extern unsigned short netbiosAvail;
227 extern unsigned long NetbeuiAPI;
228 extern unsigned char NetBiosName[];
229 extern unsigned char NetBiosAdapter;
230 extern unsigned char NetBiosLSN;
231 #endif /* CK_NETBIOS */
232
233 #ifdef TCPSOCKET
234 extern char myipaddr[];
235 extern int tcp_rdns;
236 #ifdef CK_DNS_SRV
237 extern int tcp_dns_srv;
238 #endif /* CK_DNS_SRV */
239 extern char * tcp_address;
240 #ifndef NOHTTP
241 extern char * tcp_http_proxy;
242 #endif /* NOHTTP */
243 #ifdef NT
244 #ifdef CK_SOCKS
245 extern char * tcp_socks_svr;
246 #ifdef CK_SOCKS_NS
247 extern char * tcp_socks_ns;
248 #endif /* CK_SOCKS_NS */
249 #endif /* CK_SOCKS */
250 #endif /* NT */
251
252 #ifndef NOTCPOPTS
253 #ifdef SOL_SOCKET
254 #ifdef SO_LINGER
255 extern int tcp_linger;
256 extern int tcp_linger_tmo;
257 #endif /* SO_LINGER */
258 #ifdef SO_DONTROUTE
259 extern int tcp_dontroute;
260 #endif /* SO_DONTROUTE */
261 #ifdef TCP_NODELAY
262 extern int tcp_nodelay;
263 #endif /* TCP_NODELAY */
264 #ifdef SO_SNDBUF
265 extern int tcp_sendbuf;
266 #endif /* SO_SNDBUF */
267 #ifdef SO_RCVBUF
268 extern int tcp_recvbuf;
269 #endif /* SO_RCVBUF */
270 #ifdef SO_KEEPALIVE
271 extern int tcp_keepalive;
272 #endif /* SO_KEEPALIVE */
273 #endif /* SOL_SOCKET */
274 #endif /* NOTCPOPTS */
275 #endif /* TCPSOCKET */
276 #endif /* NETCONN */
277
278 extern char * floname[];
279
280 #ifndef NOSPL
281 extern int fndiags;                     /* Function diagnostics on/off */
282 extern int divbyzero;
283 int ispattern = 0;
284 int isjoin = 0;
285 #ifdef CK_APC
286 extern int apcactive;                   /* Nonzero = APC command was rec'd */
287 extern int apcstatus;                   /* Are APC commands being processed? */
288 #ifdef DCMDBUF
289 extern char *apcbuf;                    /* APC command buffer */
290 #else
291 extern char apcbuf[];
292 #endif /* DCMDBUF */
293 #endif /* CK_APC */
294
295 extern char evalbuf[];                  /* EVALUATE result */
296 extern char uidbuf[], pwbuf[], prmbuf[];
297 _PROTOTYP( static char * fneval, (char *, char * [], int, char * ) );
298 _PROTOTYP( static VOID myflsh, (void) );
299 _PROTOTYP( static char * getip, (char *) );
300 _PROTOTYP( int delta2sec, (char *, long *) );
301
302 #ifdef NEWFTP
303 _PROTOTYP( char * ftp_cpl_mode, (void) );
304 _PROTOTYP( char * ftp_dpl_mode, (void) );
305 _PROTOTYP( char * ftp_authtype, (void) );
306 #endif /* NEWFTP */
307
308 #ifndef NOHTTP
309 _PROTOTYP( char * http_host, (void) );
310 _PROTOTYP( int http_isconnected, (void) );
311 _PROTOTYP( char * http_security, (void) );
312 #endif /* NOHTTP */
313
314 #ifndef NOSEXP
315 _PROTOTYP( char * dosexp, (char *) );
316 int fsexpflag = 0;
317 #endif /* NOSEXP */
318
319 static char hexdigits[16] = {
320     '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
321 };
322 extern char * tempdir;
323
324 #ifdef CK_REXX
325 extern char rexxbuf[];
326 #endif /* CK_REXX */
327
328 extern int tfline[];
329
330 /* These need to be internationalized... */
331
332 static
333 char *wkdays[] = {
334     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
335 };
336 #endif /* NOSPL */
337
338 #ifdef OS2
339 extern char startupdir[], inidir[];
340 #else
341 #ifdef VMSORUNIX
342 extern char startupdir[];
343 #endif /* VMSORUNIX */
344 #endif /* OS2 */
345
346 #ifdef OS2
347 _PROTOTYP (int os2getcp, (void) );
348 #ifdef TCPSOCKET
349 extern char tcpname[];
350 #endif /* TCPSOCKET */
351 extern int tcp_avail;
352 #ifdef DECNET
353 extern int dnet_avail;
354 #endif /* DECNET */
355 #ifdef SUPERLAT
356 extern int slat_avail;
357 #endif /* SUPERLAT */
358
359 #ifndef NOTERM
360 extern int tt_type, max_tt;
361 extern struct tt_info_rec tt_info[];
362 #endif /* NOTERM */
363 extern int tt_rows[], tt_cols[];
364 #else /* OS2 */
365 extern int tt_rows, tt_cols;
366 #endif /* OS2 */
367
368 #ifdef CK_TAPI
369 extern int tttapi;
370 extern int tapipass;
371 extern struct keytab * tapilinetab;
372 extern struct keytab * _tapilinetab;
373 extern int ntapiline;
374 #endif /* CK_TAPI */
375
376 extern struct keytab colxtab[];
377 extern int ncolx;
378
379 extern char ttname[], *zinptr, *kermrc;
380 extern char inidir[];
381
382 extern int activecmd, remonly, cmd_rows, cmd_cols, parity, seslog,
383   sessft, sosi, hwparity, tsecs, xargs, zincnt, tlevel, insilence, cmdmsk,
384   timint, timef, inbufsize, dialog, binary, carrier, cdtimo, cmask, duplex,
385   fmask, inecho, nmac, turnch, turn, kbchar;
386
387 #ifndef NOXFER
388 extern CHAR eol,  mypadc, mystch, padch, seol, stchr, * epktmsg, feol;
389 extern char *cksysid;
390 extern struct ck_p ptab[];
391 extern int
392   protocol, prefixing, xfrbel, xfrcan, xfrint, xfrchr, xfrnum, pktpaus,
393   lscapr, lscapu, xfermode, dest, slostart, maxrps, maxsps, maxtry, mypadn,
394   npad, pkttim, bigrbsiz, bigsbsiz, keep, atcapr, autopar, bctr, bctu,
395   crunched, ckdelay, ebq, ebqflg, pktlog, retrans, rpackets, rptflg, rptq,
396   rtimo, spackets, spsiz, spsizf, spsizr, timeouts, fncact, fncnv, urpsiz,
397   wmax, wslotn, wslotr, fdispla, spmax, fnrpath, fnspath, crc16;
398 #endif /* NOXFER */
399
400 #ifdef OS2
401 extern int zxpn;
402 extern int viewonly;
403 #endif /* OS2 */
404
405 #ifndef NOXFER
406 #ifdef GFTIMER
407 extern CKFLOAT fptsecs, fpxfsecs;
408 #endif /* GFTIMER */
409 extern long xfsecs, tfcps;
410
411 #ifdef CK_TMPDIR
412 extern char *dldir;
413 #endif /* CK_TMPDIR */
414 #endif /* NOXFER */
415
416 #ifdef RECURSIVE
417 extern int recursive;
418 #endif /* RECURSIVE */
419
420 #ifdef VMS
421   extern int frecl;
422 #endif /* VMS */
423
424 extern long
425   ffc, filcnt, rptn, speed, tfc, tlci, tlco, ccu, ccp, vernum, xvernum;
426
427 #ifndef NOSPL
428 extern char fspec[], myhost[];
429 #endif /* NOSPL */
430
431 extern char *tfnam[];                   /* Command file names */
432
433 extern char pktfil[],                   /* Packet log file name */
434 #ifdef TLOG
435   trafil[],                             /* Transaction log file name */
436 #endif /* TLOG */
437   sesfil[];                             /* Session log file name */
438
439 #ifndef NOXMIT                          /* TRANSMIT command variables */
440 extern char xmitbuf[];
441 extern int xmitf, xmitl, xmitx, xmits, xmitw, xmitt;
442 #endif /* NOXMIT */
443
444 extern int cmdlvl;
445
446 #ifndef NOSPL
447 /* Script programming language items */
448 extern char **a_ptr[];                  /* Arrays */
449 extern int a_dim[];
450 static char * inpmatch = NULL;
451 #ifdef CKFLOAT
452 char * inpscale = NULL;
453 #endif  /* CKFLOAT */
454 extern char * inpbuf, inchar[];         /* Buffers for INPUT and REINPUT */
455 extern char *inpbp;                     /* And pointer to same */
456 static char *r3 = (char *)0;
457 extern int incount;                     /* INPUT character count */
458 extern int m_found;                     /* MINPUT result */
459 extern int maclvl;                      /* Macro invocation level */
460 extern struct mtab *mactab;             /* Macro table */
461 extern char *mrval[];
462 extern int macargc[], topargc;
463
464 #ifdef COMMENT
465 extern char *m_line[];
466 extern char *topline;
467 #endif /* COMMENT */
468
469 extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
470 extern char *g_var[GVARS];        /* for external 2-dimensional arrays. */
471 #ifdef DCMDBUF
472 extern int *count, *inpcas;
473 #else
474 extern int count[], inpcas[];
475 #endif /* DCMDBUF */
476 #endif /* NOSPL */
477
478 #ifdef UNIX
479 extern int haslock;                     /* For UUCP locks */
480 extern char flfnam[];
481 #ifndef USETTYLOCK
482 extern char lock2[];
483 #endif /* USETTYLOCK */
484 #endif /* UNIX */
485
486 #ifdef OS2ORUNIX
487 extern int maxnam, maxpath;             /* Longest name, path length */
488 #endif /* OS2ORUNIX */
489
490 extern int mdmtyp, mdmsav;
491
492 #ifndef NODIAL
493 /* DIAL-related variables */
494 extern char modemmsg[];
495 extern MDMINF *modemp[];                /* Pointers to modem info structs */
496 extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialsrt, dialsta;
497 extern int dialrtr, dialint, dialrstr, dialcon, dialcq, dialfld;
498 extern int mdmspd, dialec, dialdc, dialmth, dialmauto, dialesc;
499 extern char *dialnum,   *dialini,  *dialdir[], *dialcmd,  *dialnpr,
500  *dialdcon, *dialdcoff, *dialecon, *dialecoff, *dialhcmd, *diallac,
501  *dialhwfc, *dialswfc,  *dialnofc, *dialpulse, *dialtone, *dialname,
502  *dialaaon, *dialaaoff, *dialmac;
503 extern char *diallcc,   *dialixp,  *dialixs,   *dialldp,  *diallds,
504  *dialpxi,  *dialpxo,   *dialsfx,  *dialtfp;
505 extern char *diallcp,   *diallcs;
506 extern int ntollfree, ndialpxx, nlocalac;
507 extern char *dialtfc[], *diallcac[], *dialpxx[], *matchpxx;
508 extern int ndialpucc, ndialtocc;
509 extern char *dialtocc[], *dialpucc[];
510 extern int ndialdir, dialcnf, dialcvt, dialidt, dialpace;
511 extern long dialmax, dialcapas;
512
513 extern struct keytab mdmtab[];
514
515 #ifdef BIGBUFOK
516 #define ARGBUFSIZ 8191
517 #else
518 #define ARGBUFSIZ 1023
519 #endif /* BIGBUFOK */
520
521 #ifdef BIGBUFOK
522 extern char * dialmsg[];
523 #endif /* BIGBUFOK */
524
525 #endif /* NODIAL */
526
527 #ifndef NOCSETS
528 /* Translation stuff */
529 extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
530 extern int dcset7, dcset8;
531 extern struct keytab lngtab[];
532 extern struct csinfo fcsinfo[], tcsinfo[];
533 extern struct langinfo langs[];
534 #ifdef CK_ANSIC
535 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
536 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
537 #else
538 extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
539 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
540 #endif /* CK_ANSIC */
541 #ifdef UNICODE
542     extern int ucsbom, ucsorder;
543 #endif /* UNICODE */
544 #endif /* NOCSETS */
545
546 #ifndef NOSPL
547 /* Built-in variable names, maximum length VNAML (20 characters) */
548
549 struct keytab vartab[] = {
550     { "_line",     VN_TFLN,  CM_INV},   /* 192 */
551 #ifdef OS2
552     { "_regname",  VN_REGN,  CM_INV},   /* 1.1.12 */
553     { "_regorg",   VN_REGO,  CM_INV},   /* 1.1.12 */
554     { "_regnum",   VN_REGS,  CM_INV},   /* 1.1.12 */
555 #endif /* OS2 */
556     { "apcactive", VN_APC,   CM_INV},   /* 192 */
557 #ifdef NT
558     { "appdata",   VN_APPDATA, 0},      /* 201 */
559 #endif /* NT */
560     { "argc",      VN_ARGC,  0},
561     { "args",      VN_ARGS,  0},
562     { "authname",  VN_AUTHN, 0},        /* 196 */
563     { "authstate", VN_AUTHS, 0},        /* 195 */
564     { "authtype",  VN_AUTHT, 0},        /* 195 */
565     { "blockcheck",VN_BLK,   0},        /* 195 */
566 #ifdef BROWSER
567     { "browser",   VN_BROWSR,0},        /* 193 */
568     { "browsopts", VN_BROPT, 0},        /* 193 */
569     { "browsurl",  VN_URL,   0},        /* 193 */
570     { "buildid",   VN_BUILD, 0},        /* 199 */
571 #endif /* BROWSER */
572     { "byteorder", VN_BYTE,  0},        /* 195 */
573 #ifndef NOCSETS
574     { "charset",   VN_CSET,  0},        /* 192 */
575 #endif /* NOCSETS */
576     { "cmdbufsize",VN_CMDBL, 0},        /* 195 */
577     { "cmdfile",   VN_CMDF,  0},
578     { "cmdlevel",  VN_CMDL,  0},
579     { "cmdsource", VN_CMDS,  0},
580     { "cols",      VN_COLS,  0},        /* 190 */
581 #ifdef NT
582     { "common",    VN_COMMON, 0},       /* 201 */
583 #endif /* NT */
584     { "connection",VN_CONN,  0},        /* 190 */
585     { "count",     VN_COUN,  0},
586 #ifndef NOXFER
587     { "cps",       VN_CPS,   0},        /* 190 */
588 #endif /* NOXFER */
589     { "cpu",       VN_CPU,   0},
590 #ifndef NOXFER
591     { "crc16",     VN_CRC16, 0},        /* 192 */
592     { "ctty",      VN_TTYNAM,0},        /* 196 */
593 #endif /* NOXFER */
594 #ifndef NOLOGDIAL
595 #ifndef NOLOCAL
596     { "cx_time",   VN_CXTIME,0},        /* 195 */
597     { "cx_status", VN_CX_STA,0},        /* 199 */
598 #endif /* NOLOCAL */
599 #endif /* NOLOGDIAL */
600 #ifndef NODIAL
601     { "d$ac",      VN_D_AC,  0},        /* 192 */
602     { "d$cc",      VN_D_CC,  0},        /* 192 */
603     { "d$ip",      VN_D_IP,  0},        /* 192 */
604     { "d$lc",      VN_D_LCP, 0},        /* 193 */
605     { "d$lcp",     VN_D_LCP, CM_INV},   /* 193 */
606     { "d$lp",      VN_D_LP,  0},        /* 192 */
607     { "d$px",      VN_D_PXX, 0},        /* 195 */
608     { "d$pxx",     VN_D_PXX, CM_INV},   /* 195 */
609 #endif /* NODIAL */
610     { "date",      VN_DATE,  0},
611     { "day",       VN_DAY,   0},
612 #ifdef NT
613     { "desktop",   VN_DESKTOP, 0},     /* 201 */
614 #endif /* NT */
615 #ifndef NODIAL
616     { "dialcount", VN_DRTR,  0},        /* 195 */
617     { "dialnumber",VN_DNUM,  0},        /* 192 */
618     { "dialresult",VN_MDMSG, 0},        /* 192 */
619     { "dialstatus",VN_DIAL,  0},        /* 190 */
620     { "dialsuffix",VN_PDSFX, 0},        /* 193 */
621     { "dialtype",  VN_DTYPE, 0},        /* 193 */
622 #endif /* NODIAL */
623     { "directory", VN_DIRE,  0},
624 #ifndef NODIAL
625     { "dm_hf",     VN_DM_HF, 0},        /* 199 */
626     { "dm_lp",     VN_DM_LP, 0},        /* 195 */
627     { "dm_sp",     VN_DM_SP, 0},        /* 195 */
628     { "dm_pd",     VN_DM_PD, 0},        /* 195 */
629     { "dm_td",     VN_DM_TD, 0},        /* 195 */
630     { "dm_wa",     VN_DM_WA, 0},        /* 195 */
631     { "dm_wb",     VN_DM_WB, 0},        /* 199 */
632     { "dm_wd",     VN_DM_WD, 0},        /* 195 */
633     { "dm_rc",     VN_DM_RC, 0},        /* 195 */
634 #endif /* NODIAL */
635 #ifndef NOXFER
636     { "download",  VN_DLDIR, 0},        /* 192 */
637 #endif /* NOXFER */
638     { "editor",    VN_EDITOR,0},
639     { "editfile",  VN_EDFILE,0},
640     { "editopts",  VN_EDOPT, 0},
641     { "errno",     VN_ERRNO, 0},        /* 192 */
642     { "errstring", VN_ERSTR, 0},        /* 192 */
643     { "escape",    VN_ESC,   0},        /* 193 */
644     { "evaluate",  VN_EVAL,  0},        /* 190 */
645 #ifdef OS2ORUNIX
646     { "exedir",    VN_EXEDIR,0},        /* 192 */
647 #endif /* OS2ORUNIX */
648     { "exitstatus",VN_EXIT,  0},
649 #ifdef CKCHANNELIO
650     { "f_count",   VN_FCOU,  0},        /* 195 */
651     { "f_error",   VN_FERR,  0},        /* 195 */
652     { "f_max",     VN_FMAX,  0},        /* 195 */
653     { "fileerror", VN_FERR,  CM_INV},   /* 195 */
654     { "filemax",   VN_FERR,  CM_INV},   /* 195 */
655 #endif /* CKCHANNELIO */
656     { "filename",  VN_FNAM,  0},        /* 193 */
657     { "filenumber",VN_FNUM,  0},        /* 193 */
658     { "filespec",  VN_FILE,  0},
659     { "fsize",     VN_FFC,   0},        /* 190 */
660 #ifdef GFTIMER
661     { "ftime",     VN_FTIME, 0},        /* 199 */
662 #else
663     { "ftime",     VN_NTIM,  CM_INV},
664 #endif /* GFTIMER */
665 #ifndef NOFTP
666 #ifndef SYSFTP
667     { "ftp_code",         VN_FTP_C, 0}, /* 199 */
668     { "ftp_cpl",          VN_FTP_B, 0}, /* 199 */
669     { "ftp_connected",    VN_FTP_X, 0}, /* 199 */
670     { "ftp_dpl",          VN_FTP_D, 0}, /* 199 */
671     { "ftp_getputremote", VN_FTP_G, 0}, /* 199 */
672     { "ftp_host",         VN_FTP_H, 0}, /* 199 */
673     { "ftp_loggedin",     VN_FTP_L, 0}, /* 199 */
674     { "ftp_message",      VN_FTP_M, 0}, /* 199 */
675     { "ftp_msg",          VN_FTP_M, CM_INV}, /* 199 */
676     { "ftp_security",     VN_FTP_Z, 0}, /* 199 */
677     { "ftp_server",       VN_FTP_S, 0}, /* 199 */
678 #endif /* SYSFTP */
679 #endif /* NOFTP */
680     { "ftype",     VN_MODE,  0},        /* 190 */
681 #ifdef KUI
682     { "gui_fontname", VN_GUI_FNM, 0},   /* 205 */
683     { "gui_fontsize", VN_GUI_FSZ, 0},   /* 205 */
684     { "gui_runmode", VN_GUI_RUN, 0},    /* 205 */
685     { "gui_xpos",    VN_GUI_XP,  0},    /* 205 */
686     { "gui_xres",    VN_GUI_XR,  0},    /* 205 */
687     { "gui_ypos",    VN_GUI_YP,  0},    /* 205 */
688     { "gui_yres",    VN_GUI_YR,  0},    /* 205 */
689 #endif /* KUI */
690     { "herald",    VN_HERALD, 0},
691     { "home",      VN_HOME,   0},
692     { "host",      VN_HOST,   0},
693     { "hour",      VN_HOUR,   0},       /* 200 */
694 #ifndef NOHTTP
695     { "http_code",      VN_HTTP_C, 0},  /* 199 */
696     { "http_connected", VN_HTTP_N, 0},  /* 199 */
697     { "http_host",      VN_HTTP_H, 0},  /* 199 */
698     { "http_message",   VN_HTTP_M, 0},  /* 199 */
699     { "http_security",  VN_HTTP_S, 0},  /* 199 */
700 #endif /* NOHTTP */
701     { "hwparity",  VN_HWPAR, 0},        /* 195 */
702     { "input",     VN_IBUF,  0},
703     { "inchar",    VN_ICHR,  0},
704     { "incount",   VN_ICNT,  0},
705     { "inidir",    VN_INI,   0},        /* 192 */
706     { "inmatch",   VN_MATCH, 0},        /* 196 */
707     { "inscale",   VN_ISCALE,0},        /* 210 */
708     { "instatus",  VN_ISTAT, 0},        /* 192 */
709     { "intime",    VN_INTIME,0},        /* 193 */
710     { "inwait",    VN_INTMO, 0},        /* 195 */
711     { "ip",        VN_IPADDR, CM_ABR|CM_INV},
712     { "ipaddress", VN_IPADDR,0},        /* 192 */
713     { "iprompt",   VN_PROMPT,0},        /* 199 */
714     { "kbchar",    VN_KBCHAR,0},        /* 196 */
715 #ifndef NOLOCAL
716 #ifdef OS2
717     { "keyboard",  VN_KEYB,  0},
718 #endif /* OS2 */
719 #endif /* NOLOCAL */
720 #ifdef CK_KERBEROS
721     { "krb4errmsg",    VN_K4EMSG,0},
722     { "krb4errno",     VN_K4ENO, 0},
723     { "krb4principal", VN_K4PRN, 0},
724     { "krb4realm",     VN_K4RLM, 0},
725     { "krb4service",   VN_K4SRV, 0},
726     { "krb5cc",        VN_K5CC,  0},
727     { "krb5errmsg",    VN_K5EMSG,0},
728     { "krb5errno",     VN_K5ENO, 0},
729     { "krb5principal", VN_K5PRN, 0},
730     { "krb5realm",     VN_K5RLM, 0},
731     { "krb5service",   VN_K5SRV, 0},
732 #endif /* CK_KERBEROS */
733     { "line",      VN_LINE,  0},
734     { "local",     VN_LCL,   0},
735 #ifdef UNIX
736     { "lockdir",   VN_LCKDIR,0},        /* 195 */
737     { "lockpid",   VN_LCKPID,0},        /* 195 */
738 #endif /* UNIX */
739     { "log_connection", VN_LOG_CON, 0}, /* 206 */
740     { "log_debug", VN_LOG_DEB, 0},      /* 206 */
741     { "log_packet", VN_LOG_PKT, 0},     /* 206 */
742     { "log_session", VN_LOG_SES, 0},    /* 206 */
743     { "log_transaction", VN_LOG_TRA, 0},/* 206 */
744     { "maclevel",  VN_MACLVL,0},        /* 195 */
745     { "macro",     VN_MAC,   0},
746 #ifdef FNFLOAT
747     { "math_e",    VN_MA_E,  0},        /* 195 */
748     { "math_pi",   VN_MA_PI, 0},        /* 195 */
749     { "math_precision", VN_MA_PR, 0},   /* 195 */
750 #endif /* FNFLOAT */
751     { "minput",    VN_MINP,  0},        /* 192 */
752     { "model",     VN_MODL,  0},        /* 193 */
753     { "modem",     VN_MDM,   0},
754 #ifndef NOLOCAL
755 #ifdef OS2
756     { "mousecurx", VN_MOU_X, 0},        /* K95 1.1.14 */
757     { "mousecury", VN_MOU_Y, 0},        /* K95 1.1.14 */
758 #endif /* OS2 */
759 #endif /* NOLOCAL */
760 #ifndef NODIAL
761     { "m_aa_off",  VN_M_AAX, 0},        /* all 192... */
762     { "m_aa_on",   VN_M_AAO, 0},
763     { "m_dc_off",  VN_M_DCX, 0},
764     { "m_dc_on",   VN_M_DCO, 0},
765     { "m_dial",    VN_M_DCM, 0},
766     { "m_ec_off",  VN_M_ECX, 0},
767     { "m_ec_on",   VN_M_ECO, 0},
768     { "m_fc_hw",   VN_M_HWF, 0},
769     { "m_fc_no",   VN_M_NFC, 0},
770     { "m_fc_sw",   VN_M_SWF, 0},
771     { "m_hup",     VN_M_HUP, 0},
772     { "m_init",    VN_M_INI, 0},
773     { "m_name",    VN_M_NAM, 0},        /* 195 */
774     { "m_pulse",   VN_M_PDM, 0},
775     { "m_sig_cd",  VN_MS_CD, 0},        /* 195 */
776     { "m_sig_cts", VN_MS_CTS,0},        /* 195 */
777     { "m_sig_dsr", VN_MS_DSR,0},        /* 195 */
778     { "m_sig_dtr", VN_MS_DTR,0},        /* 195 */
779     { "m_sig_ri",  VN_MS_RI, 0},        /* 195 */
780     { "m_sig_rts", VN_MS_RTS,0},        /* 195 */
781     { "m_tone",    VN_M_TDM, 0},
782 #endif /* NODIAL */
783     { "name",      VN_NAME,  0},
784     { "ndate",     VN_NDAT,  0},
785     { "nday",      VN_NDAY,  0},
786     { "newline",   VN_NEWL,  0},
787     { "ntime",     VN_NTIM,  0},
788     { "osname",    VN_OSNAM, 0},        /* 193 */
789     { "osrelease", VN_OSREL, 0},        /* 193 */
790     { "osversion", VN_OSVER, 0},        /* 193 */
791 #ifndef NOXFER
792     { "packetlen", VN_RPSIZ, 0},        /* 192 */
793 #endif /* NOXFER */
794     { "parity",    VN_PRTY,  0},        /* 190 */
795     { "password",  VN_PWD,   CM_INV},   /* 192 */
796 #ifdef NT
797     { "personal",  VN_PERSONAL, 0},     /* 201 */
798 #endif /* NT */
799 #ifdef PEXITSTAT
800     { "pexitstat", VN_PEXIT, 0},        /* 193 */
801 #endif /* PEXITSTAT */
802 #ifdef CK_PID
803     { "pid",       VN_PID,   0},        /* 193 */
804 #endif /* CK_PID */
805     { "platform",  VN_SYSV,  0},
806     { "printer",   VN_PRINT, 0},        /* 193 */
807     { "program",   VN_PROG,  0},
808     { "prompt",    VN_PRM,   CM_INV},   /* 192 */
809 #ifndef NOXFER
810     { "protocol",  VN_PROTO, 0},        /* 192 */
811     { "p_8bit",    VN_P_8BIT,0},        /* 193 */
812     { "p_ctl",     VN_P_CTL, 0},        /* 193 */
813     { "p_rpt",     VN_P_RPT, 0},        /* 193 */
814     { "query",     VN_QUE,   0},        /* 190 */
815 #endif /* NOXFER */
816     { "return",    VN_RET,   0},
817 #ifdef CK_REXX
818     { "rexx",      VN_REXX,  0},        /* 190 */
819 #endif /* CK_REXX */
820 #ifdef TN_COMPORT
821     { "rfc2217_signature", VN_TNC_SIG, 0}, /* 201 */
822     { "rfc2717_signature", VN_TNC_SIG, CM_INV}, /* 202 */
823 #endif /* TN_COMPORT */
824     { "rows",      VN_ROWS,  0},        /* 190 */
825 #ifndef NOSEXP
826     { "sdepth",    VN_LSEXP,0},         /* 199 */
827 #endif /* NOSEXP */
828     { "secure",    VN_SECURE, 0},       /* 199 */
829 #ifndef NOLOCAL
830 #ifdef OS2
831     { "select",    VN_SELCT, 0},        /* 192 */
832 #endif /* OS2 */
833 #endif /* NOLOCAL */
834     { "sendlist",  VN_SNDL,  0},
835     { "serial",    VN_SERIAL,0},        /* 195 */
836     { "setlinemsg",VN_SLMSG, 0},        /* 195 */
837 #ifndef NOSEXP
838     { "sexpression",VN_SEXP, 0},        /* 199 */
839 #endif /* NOSEXP */
840     { "speed",     VN_SPEE,  0},
841 #ifdef OS2
842     { "space",     VN_SPA,   0},
843     { "startup",   VN_STAR,  0},        /* 190 */
844 #else
845 #ifdef UNIX
846     { "startup",   VN_STAR,  0},        /* 193 */
847 #else
848 #ifdef VMS
849     { "startup",   VN_STAR,  0},        /* 193 */
850 #endif /* VMS */
851 #endif /* UNIX */
852 #endif /* OS2 */
853     { "status",    VN_SUCC,  0},
854 #ifndef NOSEXP
855     { "svalue",    VN_VSEXP, 0},        /* 199 */
856 #endif /* NOSEXP */
857 #ifndef NOXFER
858     { "sysid",     VN_SYSI,  0},
859 #endif /* NOXFER */
860     { "system",    VN_SYST,  0},
861     { "terminal",  VN_TTYP,  0},
862 #ifdef OS2
863 #ifndef NOKVERBS
864     { "termkey",   VN_TRMK,  CM_INV},   /* 192 */
865 #endif /* NOKVERBS */
866 #endif /* OS2 */
867     { "test",      VN_TEST,  0},        /* 193 */
868     { "textdir",   VN_TXTDIR,0},        /* 195 */
869 #ifndef NOXFER
870     { "tfsize",    VN_TFC,   0},
871     { "tftime",    VN_TFTIM, 0},        /* 195 */
872 #endif /* NOXFER */
873     { "time",      VN_TIME,  0},
874     { "timestamp", VN_NOW,   0},        /* 200 */
875     { "tmpdir",    VN_TEMP,  0},        /* 192 */
876 #ifdef CK_TRIGGER
877     { "trigger",   VN_TRIG,  0},        /* 193 */
878 #endif /* CK_TRIGGER */
879 #ifdef CK_TTYFD
880     { "ttyfd",     VN_TTYF,  0},
881 #endif /* CK_TTYFD */
882     { "ty_ln",     VN_TY_LN, 0},        /* 195 */
883     { "ty_lc",     VN_TY_LC, 0},        /* 195 */
884     { "ty_lm",     VN_TY_LM, 0},        /* 195 */
885 #ifdef BROWSER
886     { "url",       VN_URL,   CM_INV},   /* 193 */
887 #endif /* BROWSER */
888     { "userid",    VN_UID,   0},        /* 192 */
889     { "version",   VN_VERS,  0},
890 #ifndef NOXFER
891     { "window",    VN_WINDO, 0},        /* 192 */
892 #endif /* NOXFER */
893 #ifdef IBMX25
894     { "x25local_nua", VN_X25LA, 0},     /* 193 */
895     { "x25remote_nua", VN_X25RA, 0},    /* 193 */
896 #endif /* IBMX25 */
897 #ifdef CK_SSL
898     { "x509_issuer",  VN_X509_I, 0},
899     { "x509_subject", VN_X509_S, 0},
900 #endif /* CK_SSL */
901 #ifndef NOXFER
902     { "xferstatus",VN_XFSTAT,0},        /* 193 */
903     { "xfermsg",   VN_XFMSG, 0},        /* 193 */
904     { "xfer_badpackets", VN_XF_BC, 0},  /* 195 */
905     { "xfer_timeouts",   VN_XF_TM, 0},  /* 195 */
906     { "xfer_retransmits",VN_XF_RX, 0},  /* 195 */
907 #endif /* NOXFER */
908     { "xprogram",  VN_XPROG, 0},        /* 193 */
909     { "xversion",  VN_XVNUM, 0}         /* 192 */
910 };
911 int nvars = (sizeof(vartab) / sizeof(struct keytab));
912 #endif /* NOSPL */
913
914 #ifndef NOSPL
915 struct keytab fnctab[] = {              /* Function names */
916 #ifdef OS2
917     { ".oox",       FN_OOX, CM_INV},    /* ... */
918 #endif /* OS2 */
919
920 #ifdef CKCHANNELIO
921     { "_eof",       FN_FEOF,   0},
922     { "_errmsg",    FN_FERMSG, 0},
923     { "_getblock",  FN_FGBLK,  0},
924     { "_getchar",   FN_FGCHAR, 0},
925     { "_getline",   FN_FGLINE, 0},
926     { "_handle",    FN_FILNO,  0},
927     { "_line",      FN_NLINE,  0},
928     { "_pos",       FN_FPOS,   0},
929     { "_putblock",  FN_FPBLK,  0},
930     { "_putchar",   FN_FPCHAR, 0},
931     { "_putline",   FN_FPLINE, 0},
932     { "_status",    FN_FSTAT,  0},
933 #endif /* CKCHANNELIO */
934
935     { "aaconvert",  FN_AADUMP, 0},      /* Associative Array conversion */
936     { "absolute",   FN_ABS,  0},        /* Absolute value */
937 #ifdef TCPSOCKET
938     { "addr2name",  FN_HSTADD,CM_INV},  /* IP Address to Hostname */
939     { "addrtoname", FN_HSTADD,CM_INV},  /* IP Address to Hostname */
940 #endif /* TCPSOCKET */
941     { "arraylook",  FN_ALOOK,0},        /* Array lookup */
942     { "b64decode",  FN_FMB64,0},        /* Base-64 conversion */
943     { "b64encode",  FN_TOB64,0},        /* ... */
944     { "basename",   FN_BSN,  0},        /* Basename */
945     { "break",      FN_BRK,  0},        /* Break (as in Snobol) */
946     { "ca",         FN_CAP,  CM_INV|CM_ABR}, /* Abbreviation for capitablize */
947     { "cap",        FN_CAP,  CM_INV|CM_ABR}, /* Abbreviation for capitablize */
948     { "capitalize", FN_CAP,  0},        /* First Letter -> uppercase */
949     { "caps",       FN_CAP,  CM_INV},   /* ditto */
950     { "character",  FN_CHR,  0},        /* Character from code */
951     { "checksum",   FN_CHK,  0},        /* Checksum */
952     { "cmdstack",   FN_CMDSTK,0},       /* Command stack */
953     { "cmpdates",   FN_CMPDATE,0},      /* Compare dates */
954     { "code",       FN_COD,  0},        /* Code from character */
955 #ifndef NOPUSH
956     { "command",    FN_CMD,  0},        /* Output from a command */
957 #endif /* NOPUSH */
958     { "contents",   FN_CON,  0},        /* Definition (contents) of variable */
959     { "crc16",      FN_CRC,  0},        /* CRC-16 */
960 #ifdef OS2
961     { "crypt",      FN_CRY, CM_INV},
962 #endif /* OS2 */
963     { "cvtdate",    FN_DTIM, 0},        /* Convert free date/time to std */
964 #ifdef ZFCDAT
965     { "date",       FN_FD,   0},        /* File modification/creation date */
966 #endif /* ZFCDAT */
967     { "day",        FN_DAY,  0},        /* Day of week */
968     { "dayofyear",  FN_JDATE,0},        /* Date to Day of Year */
969     { "definition", FN_DEF,  0},        /* Return definition of given macro */
970     { "delta2secs", FN_DELSEC, 0},      /* Delta time to seconds */
971     { "deltatosecs", FN_DELSEC, CM_INV}, /* Delta time to seconds */
972 #ifndef NODIAL
973     { "dialconvert",FN_PNCVT,0},        /* Convert portable phone number */
974 #endif /* NODIAL */
975     { "diffdates",  FN_DIFDATE,0},      /* Difference of two date-times */
976     { "dimension",  FN_DIM,  0},        /* Dimension of array */
977     { "directories",FN_DIR,  0},        /* List of directories */
978     { "dirname",    FN_DNAM, 0},        /* Directory part of filename */
979     { "dos2unixpath",FN_PC_DU, },       /* DOS to UNIX path */
980     { "dostounixpath",FN_PC_DU, CM_INV}, /* DOS to UNIX path */
981     { "doy",        FN_JDATE,CM_INV},   /* Date to Day of Year */
982     { "doy2date",   FN_DATEJ,0},        /* Day of Year to date */
983     { "doytodate",  FN_DATEJ,CM_INV},   /* Day of Year to date */
984 #ifdef FN_ERRMSG
985     { "errstring",  FN_ERRMSG,0},       /* Error code to message */
986 #endif /* FN_ERRMSG */
987     { "evaluate",   FN_EVA,  0},        /* Evaluate given arith expression */
988     { "execute",    FN_EXE,  0},        /* Execute given macro */
989     { "files",      FN_FC,   0},        /* File count */
990 #ifdef FNFLOAT
991     { "fpabsolute", FN_FPABS, 0},       /* Floating-point absolute value */
992     { "fpadd",      FN_FPADD, 0},       /* FP add */
993     { "fpcosine",   FN_FPCOS, 0},       /* FP cosine */
994     { "fpdivide",   FN_FPDIV, 0},       /* FP divide */
995     { "fpexp",      FN_FPEXP, 0},       /* FP e to the x */
996     { "fpint",      FN_FPINT, 0},       /* FP to integer */
997     { "fplog10",    FN_FPLOG, 0},       /* FP base-10 logarithm */
998     { "fplogn",     FN_FPLN,  0},       /* FP natural logarithm */
999     { "fpmaximum",  FN_FPMAX, 0},       /* FP maxinum */
1000     { "fpminimum",  FN_FPMIN, 0},       /* FP mininum */
1001     { "fpmodulus",  FN_FPMOD, 0},       /* FP modulus */
1002     { "fpmultiply", FN_FPMUL, 0},       /* FP multiply */
1003     { "fpraise",    FN_FPPOW, 0},       /* FP raise to a power */
1004     { "fpround",    FN_FPROU, 0},       /* FP round */
1005     { "fpsine",     FN_FPSIN, 0},       /* FP sine */
1006     { "fpsqrt",     FN_FPSQR, 0},       /* FP square root */
1007     { "fpsubtract", FN_FPSUB, 0},       /* FP subtract */
1008     { "fptangent",  FN_FPTAN, 0},       /* FP tangent */
1009 #endif /* FNFLOAT */
1010     { "hex2ip",     FN_HEX2IP,0},       /* Hex to IP address */
1011     { "hextoip",    FN_HEX2IP,CM_INV},  /* Hex to IP address */
1012     { "hex2n",      FN_HEX2N, CM_INV},  /* Hex to decimal number */
1013     { "hexify",     FN_HEX,   0},       /* Hexify (string) */
1014     { "index",      FN_IND,   0},       /* Index (string search) */
1015     { "ip2hex",     FN_IP2HEX,0},       /* IP address to hex */
1016     { "iptohex",    FN_IP2HEX,CM_INV},  /* IP address to hex */
1017     { "ipaddress",  FN_IPA,   0},       /* Find and return IP address */
1018     { "jdate",      FN_JDATE, CM_INV},  /* Date to Day of Year */
1019     { "join",       FN_JOIN,  0},       /* Join array elements */
1020     { "keywordvalue",  FN_KWVAL, 0},    /* Keyword=Value */
1021 #ifdef CK_KERBEROS
1022     { "krbflags",      FN_KRB_FG, 0},   /* Kerberos functions */
1023     { "krbisvalid",    FN_KRB_IV, 0},
1024     { "krbnextticket", FN_KRB_NX, 0},
1025     { "krbtickets",    FN_KRB_TK, 0},
1026     { "krbtimeleft",   FN_KRB_TT, 0},
1027 #endif /* CK_KERBEROS */
1028     { "left",       FN_LEF,  0},        /* Leftmost n characters of string */
1029     { "length",     FN_LEN,  0},        /* Return length of argument */
1030     { "literal",    FN_LIT,  0},        /* Return argument literally */
1031 #ifdef NT
1032     { "longpathname",FN_LNAME,0},       /* GetLongPathName() */
1033 #else
1034     { "longpathname",FN_FFN,CM_INV},
1035 #endif /* NT */
1036     { "lop",        FN_STL,  0},        /* Lop */
1037     { "lower",      FN_LOW,  0},        /* Return lowercased argument */
1038     { "lpad",       FN_LPA,  0},        /* Return left-padded argument */
1039     { "ltrim",      FN_LTR,  0},        /* Left-Trim */
1040     { "maximum",    FN_MAX,  0},        /* Return maximum of two arguments */
1041     { "minimum",    FN_MIN,  0},        /* Return minimum of two arguments */
1042     { "mjd",        FN_MJD,  0},        /* Date to Modified Julian Date */
1043     { "mjd2date",   FN_MJD2, 0},        /* MJD to Date */
1044     { "mjdtodate",  FN_MJD2, CM_INV},   /* MJD to Date */
1045     { "modulus",    FN_MOD,  0},        /* Return modulus of two arguments */
1046 #ifdef COMMENT
1047     { "msleep",     FN_MSLEEP,0},       /* Sleep for n milliseconds */
1048 #endif /* COMMENT */
1049     { "n2hex",      FN_2HEX, CM_INV},   /* Number to hex */
1050     { "n2octal",    FN_2OCT, CM_INV},   /* Number to octal */
1051     { "n2time",     FN_N2TIM,0},        /* Number to hh:mm:ss */
1052 #ifdef TCPSOCKET
1053     { "name2addr",  FN_HSTNAM,CM_INV},  /* Hostname to IP Address */
1054 #endif /* TCPSOCKET */
1055     { "nday",       FN_NDAY, 0},        /* Numeric day of week */
1056     { "nextfile",   FN_FIL,  0},        /* Next file in list */
1057     { "ntime",      FN_NTIM, 0},        /* Time to seconds since midnight */
1058     { "ntohex",     FN_2HEX, CM_INV},   /* Number to hex */
1059     { "ntooctal",   FN_2OCT, CM_INV},   /* Number to octal */
1060     { "ntotime",    FN_N2TIM,CM_INV},   /* Number to hh:mm:ss */
1061     { "oct2n",      FN_OCT2N,CM_INV},   /* Octal to decimal number */
1062     { "octton",     FN_OCT2N,CM_INV},   /* Octal to decimal number */
1063     { "pathname",   FN_FFN,  0},        /* Full file name */
1064     { "pattern",    FN_PATTERN, 0},     /* Pattern (for INPUT) */
1065 #ifdef CK_PERMS
1066     { "permissions",FN_PERM, 0},        /* Permissions of file */
1067 #else
1068     { "permissions",FN_PERM, CM_INV},   /* Permissions of file */
1069 #endif /* CK_PERMS */
1070     { "radix",      FN_RADIX,0},        /* Radix conversion */
1071 #ifndef NORANDOM
1072     { "random",     FN_RAND, 0},        /* Random number */
1073 #endif /* NORANDOM */
1074 #ifndef NOPUSH
1075     { "rawcommand", FN_RAW,  0},        /* Output from a command (raw) */
1076 #endif /* NOPUSH */
1077 #ifdef RECURSIVE
1078     { "rdirectories", FN_RDIR, 0},      /* Recursive directory list */
1079     { "rfiles",       FN_RFIL, 0},      /* Recursive file list */
1080 #endif /* RECURSIVE */
1081     { "rep",        FN_REP, CM_INV|CM_ABR},
1082     { "repeat",     FN_REP,  0},        /* Repeat argument given # of times */
1083     { "replace",    FN_RPL,  0},        /* Replace characters in string */
1084     { "reverse",    FN_REV,  0},        /* Reverse the argument string */
1085     { "right",      FN_RIG,  0},        /* Rightmost n characters of string */
1086     { "rindex",     FN_RIX,  0},        /* Right index */
1087     { "rpad",       FN_RPA,  0},        /* Right-pad the argument */
1088     { "rsearch",    FN_RSEARCH, 0},     /* R-L Search for pattern in string */
1089 #ifdef OS2
1090     { "scrncurx",   FN_SCRN_CX,  0},    /* Screen Cursor X Pos */
1091     { "scrncury",   FN_SCRN_CY,  0},    /* Screen Cursor Y Pos */
1092     { "scrnstr",    FN_SCRN_STR, 0},    /* Screen String */
1093 #endif /* OS2 */
1094     { "search",     FN_SEARCH, 0},      /* L-R Search for pattern in string */
1095 #ifndef NOSEXP
1096     { "sexpression",FN_SEXP, 0},        /* S-Expression */
1097 #endif /* NOSEXP */
1098 #ifdef NT
1099     { "shortpathname",FN_SNAME,0},      /* GetShortPathName() */
1100 #else
1101     { "shortpathname",FN_FFN,CM_INV},
1102 #endif /* NT */
1103     { "size",       FN_FS,   0},        /* File size */
1104 #ifdef COMMENT
1105     { "sleep",      FN_SLEEP,0},        /* Sleep for n seconds */
1106 #endif /* COMMENT */
1107     { "span",       FN_SPN,  0},        /* Span - like Snobol */
1108     { "split",      FN_SPLIT,0},        /* Split string into words */
1109     { "stripb",     FN_STB,  0},        /* Strip enclosing braces/brackets */
1110     { "stripn",     FN_STN,  0},        /* Strip n chars */
1111     { "stripx",     FN_STX,  0},        /* Strip suffix */
1112     { "su",         FN_SUB,  CM_INV|CM_ABR},
1113     { "sub",        FN_SUB,  CM_INV|CM_ABR},
1114     { "subs",       FN_SUB,  CM_INV|CM_ABR},
1115     { "subst",      FN_SUB,  CM_INV|CM_ABR},
1116     { "substitute", FN_SUBST,0},        /* Substitute chars */
1117     { "substring",  FN_SUB,  0},        /* Extract substring from argument */
1118     { "tablelook",  FN_TLOOK,0},        /* Table lookup */
1119     { "time",       FN_TIME, 0},        /* Free-format time to hh:mm:ss */
1120     { "tod2secs",   FN_NTIM, CM_INV},   /* Time-of-day-to-secs-since-midnite */
1121     { "todtosecs",  FN_NTIM, CM_INV},   /* Time-of-day-to-secs-since-midnite */
1122     { "trim",       FN_TRM,  0},        /* Trim */
1123     { "unhexify",   FN_UNH,  0},        /* Unhexify */
1124     { "unix2dospath",FN_PC_UD, 0},      /* UNIX to DOS path */
1125     { "unixtodospath",FN_PC_UD, CM_INV}, /* UNIX to DOS path */
1126     { "untabify",   FN_UNTAB,0},        /* Untabify */
1127     { "upper",      FN_UPP,  0},        /* Return uppercased argument */
1128     { "utcdate",    FN_TOGMT,0},        /* Date-time to UTC (GMT) */
1129     { "verify",     FN_VER,  0},        /* Verify */
1130     { "word",       FN_WORD, 0},        /* Extract a word */
1131     { "", 0, 0}
1132 };
1133 int nfuncs = (sizeof(fnctab) / sizeof(struct keytab)) - 1;
1134 #endif /* NOSPL */
1135
1136 #ifndef NOSPL                           /* Buffer for expansion of */
1137 #ifdef BIGBUFOK                         /* built-in variables. */
1138 #define VVBUFL 1024
1139 #else
1140 #define VVBUFL 256
1141 #endif /* BIGBUFOK */
1142 char vvbuf[VVBUFL+1];
1143 #endif /* NOSPL */
1144
1145 struct keytab disptb[] = {              /* Log file disposition */
1146     { "append",    1,  0},
1147     { "new",       0,  0}
1148 };
1149
1150 #ifdef CKFLOAT
1151
1152 /* I N I T F L O A T  --  Deduce floating-point precision by inspection */
1153
1154 int fp_rounding = 0;                /* Nonzero if printf("%f") rounds */
1155 int fp_digits = 0;                  /* Digits of floating point precision */
1156
1157 #ifdef COMMENT
1158 /* For looking at internal floating-point representations */
1159 static char fp_xbuf[128];
1160 static char *
1161 tohex(s, n) CHAR * s; int n; {
1162     int x;
1163     char * p = fp_xbuf;
1164     while (n-- > 0) {
1165         x = (*s >> 4) & 0x0f;
1166         *p++ = hexdigits[x];
1167         x = *s++ & 0x0f;
1168         *p++ = hexdigits[x];
1169     }
1170     *p = NUL;
1171     return((char *)fp_xbuf);
1172 }
1173 #endif /* COMMENT */
1174
1175 char math_pi[] = "3.1415926535897932384626433832795";
1176 char math_e[] =  "2.7182818284590452353602874713527";
1177
1178 VOID
1179 initfloat() {
1180     char * buf = NULL;
1181     int i, x, y;
1182 /*
1183   We malloc a big temporary buffer for sprintf() to minimize likelihood of
1184   (and damage from) sprintf buffer overflows.  In any case, the only way this
1185   could happen would be if sprintf() itself had bugs, since the format
1186   descriptor says to cut it off at 250 decimal places.
1187 */
1188     if ((buf = (char *)malloc(4096))) {
1189         sprintf(buf,"%0.250f",(10.0 / 3.0));
1190         for (i = 2; i < 250 && buf[i] == '3'; i++) ;
1191         x = i - 1;
1192         debug(F111,"initfloat 10.0/3.0",buf,x);
1193         sprintf(buf,"%0.250f",(4.0 / 9.0));
1194         for (i = 2; i < 250 && buf[i] == '4'; i++) ;
1195         y = i - 1;
1196         debug(F111,"initfloat 4.0/9.0",buf,y);
1197         fp_digits = (x < y) ? x : y;
1198         if (fp_digits < sizeof(math_pi) - 1) {
1199             math_pi[fp_digits+1] = NUL;
1200             math_e[fp_digits+1] = NUL;
1201         }
1202         sprintf(buf,"%0.6f",(7.0 / 9.0));
1203         if (buf[7] == '8') fp_rounding = 1;
1204         debug(F111,"initfloat 7.0/9.0",buf,fp_rounding);
1205         debug(F101,"initfloat precision","",fp_digits);
1206         free(buf);
1207     }
1208 }
1209 #endif /* CKFLOAT */
1210
1211 /*
1212   P R E S C A N -- A quick look through the command-line options for
1213   items that must be handled before the initialization file is executed.
1214 */
1215 #ifdef NT
1216 extern int StartedFromDialer;
1217 #endif /* NT */
1218 #ifdef OS2
1219 extern int k95stdio;
1220 unsigned long startflags = 0L;
1221 #endif /* OS2 */
1222
1223 static char *
1224 findinpath(arg) char * arg; {
1225 #ifdef OS2
1226     char * scriptenv, * keymapenv;
1227     int len;
1228 #endif /* OS2 */
1229 #ifdef DCMDBUF
1230     extern char * cmdbuf;
1231 #else
1232     extern char cmdbuf[];
1233 #endif /* DCMDBUF */
1234     char takepath[4096];
1235     char * s;
1236     int x, z;
1237
1238     /* Set up search path... */
1239 #ifdef OS2
1240     char * appdata0 = NULL, *appdata1 = NULL;
1241 #ifdef NT
1242     scriptenv = getenv("K95SCRIPTS");
1243     keymapenv = getenv("K95KEYMAPS");
1244     makestr(&appdata0,(char *)GetAppData(0));
1245     makestr(&appdata1,(char *)GetAppData(1));
1246 #else /* NT */
1247     scriptenv = getenv("K2SCRIPTS");
1248     keymapenv = getenv("K2KEYMAPS");
1249 #endif /* NT */
1250     if (!scriptenv)
1251       scriptenv = getenv("CK_SCRIPTS");
1252     if (!scriptenv)
1253       scriptenv = "";
1254     if (!keymapenv)
1255       keymapenv = getenv("CK_KEYMAPS");
1256     if (!keymapenv)
1257       keymapenv = "";
1258
1259     debug(F110,"startupdir",startupdir,0);
1260     debug(F110,"common appdata directory",appdata1,0);
1261     debug(F110,"appdata directory",appdata0,0);
1262     debug(F110,"inidir",inidir,0);
1263     debug(F110,"home",zhome(),0);
1264     debug(F110,"exedir",exedir,0);
1265
1266     len = strlen(scriptenv) + strlen(keymapenv) + 3*strlen(startupdir)
1267         + 3*strlen(inidir) + 3*strlen(zhome()) + 3*strlen(exedir)
1268         + (appdata0 ? 3*strlen(appdata0) : 0) 
1269         + (appdata1 ? 3*strlen(appdata1) : 0)
1270         + 6*strlen("SCRIPTS/") + 6*strlen("KEYMAPS/") + 16;
1271
1272     if (len >= 4096) {                  /* SAFE (length is checked) */
1273         takepath[0] = '\0';
1274         debug(F111,"findinpath error - path length too long","len",len);
1275     } else
1276       sprintf(takepath,
1277               /* semicolon-separated path list */
1278     "%s%s%s%s%s;%s%s;%s%s;%s%s%s%s%s%s%s%s%s%s%s%s%s;%s%s;%s%s;%s;%s%s;%s%s",
1279               scriptenv,
1280               (scriptenv[0] && scriptenv[strlen(scriptenv)-1]==';')?"":";",
1281               keymapenv,
1282               (keymapenv[0] && keymapenv[strlen(keymapenv)-1]==';')?"":";",
1283               startupdir,
1284               startupdir, "SCRIPTS/",
1285               startupdir, "KEYMAPS/",
1286               appdata1 ? appdata1 : "", 
1287               appdata1 ? "Kermit 95;" : "",
1288               appdata1 ? appdata1 : "",
1289               appdata1 ? "Kermit 95/SCRIPTS/;" : "",
1290               appdata1 ? appdata1 : "",
1291               appdata1 ? "Kermit 95/KEYMAPS/;" : "",
1292               appdata0 ? appdata0 : "",
1293               appdata0 ? "Kermit 95;" : "",
1294               appdata0 ? appdata0 : "",
1295               appdata0 ? "Kermit 95/SCRIPTS/;" : "",
1296               appdata0 ? appdata0 : "",
1297               appdata0 ? "Kermit 95/KEYMAPS/;" : "",
1298               inidir,
1299               inidir, "SCRIPTS/",
1300               inidir, "KEYMAPS/",
1301               zhome(),
1302               zhome(), "SCRIPTS/",
1303               zhome(), "KEYMAPS/",
1304               exedir,
1305               exedir, "SCRIPTS/",
1306               exedir, "KEYMAPS/"
1307               );
1308     debug(F110,"findinpath takepath",takepath,0);
1309 #ifdef NT
1310     makestr(&appdata0,NULL);
1311     makestr(&appdata1,NULL);
1312 #endif /* NT */
1313 #else /* not OS2 */
1314 #ifndef NOSPL
1315     z = 1024;                           /* Look in home directory */
1316     s = takepath;
1317     zzstring("\\v(home)",&s,&z);
1318 #else
1319     takepath[0] = '\0';
1320 #endif /* NOSPL */
1321 #endif /* OS2 */
1322 /*
1323   All the logic for searching the take path is in the command parser.
1324   So even though we aren't parsing commands, we initialize and call the
1325   parser from here, with the purported filename stuffed into the command
1326   buffer, followed by some carriage returns to make the parser return.
1327   If the file is not found, or otherwise not accessible, the parser prints
1328   an appropriate message, and then we just exit.
1329 */
1330     cmdini();                           /* Allocate command buffers etc */
1331     cmini(0);                           /* Initialize them */
1332     /* Stuff filename into command buf with braces in case of spaces */
1333     ckmakmsg(cmdbuf,CMDBL,"{",arg,"}",NULL);
1334     debug(F110,"findinpath cmdbuf",cmdbuf,0);
1335     ckstrncat(cmdbuf,"\r\r",CMDBL);     /* And some carriage returns */
1336     if (cmifip("","",&s,&x,0,takepath,xxstring) < 0)
1337       return(NULL);
1338     cmres();
1339     return(s);
1340 }
1341
1342 static int tr_int;                      /* Flag if TRANSMIT interrupted */
1343
1344 #ifndef MAC
1345 SIGTYP
1346 #ifdef CK_ANSIC
1347 trtrap(int foo)                         /* TRANSMIT interrupt trap */
1348 #else
1349 trtrap(foo) int foo;                    /* TRANSMIT interrupt trap */
1350 #endif /* CK_ANSIC */
1351 /* trtrap */ {
1352 #ifdef __EMX__
1353     signal(SIGINT, SIG_ACK);
1354 #endif
1355     tr_int = 1;                         /* (Need arg for ANSI C) */
1356     SIGRETURN;
1357 }
1358 #endif /* MAC */
1359 #endif /* NOICP */
1360
1361 #ifdef UNIX
1362 VOID
1363 getexedir() {
1364     extern char * xarg0;
1365     long xx;
1366   /*
1367     Unix provides no standard service for this.  We look in argv[0], and if
1368     we're lucky there's a full pathname.  If not we do a PATH search.
1369   */
1370     if (ckstrchr(xarg0,'/')) {          /* Global copy of argv[0] */
1371         int i, k;
1372         char * p = NULL;
1373         if ((k = ckstrncpy(tmpbuf,xarg0,TMPBUFSIZ-2)) > 0) {
1374             p = tmpbuf;
1375             /* Convert to fully qualified pathname */
1376             if (tmpbuf[0]) if (tmpbuf[0] != '/') {
1377                 line[0] = NUL;
1378                 zfnqfp(tmpbuf,LINBUFSIZ-2,(char *)line);
1379                 if (line[0])
1380                   p = line;
1381             }
1382             xx = zchki(p);
1383             if (xx > -1) {              /* Is the result an existing file? */
1384                 k = strlen(p);
1385                 for (i = k-1; i > 0; i--) { /* Yes, strip name part */
1386                     if (p[i] == '/') {
1387                         if (i < k-1)
1388                           p[i+1] = NUL;
1389                         break;
1390                     }
1391                 }
1392             }
1393             makestr(&exedir,p);         /* Save the result */
1394         }
1395     }
1396     if (!exedir && xarg0) {             /* Not found? */
1397         char * p;
1398         p = getenv("PATH");             /* Search the PATH */
1399         if (p) {                        /* If there is one... */
1400             char * q, * PATH = NULL;
1401             int k;
1402             makestr(&PATH,p);           /* Pokeable copy of PATH string */
1403             if (PATH) {                 /* If malloc succeeded... */
1404                 p = PATH;
1405                 while (p && *p) {        /* Loop through segments */
1406                     q = ckstrchr(p,':'); /* End of this segment */
1407                     if (q == p) {       /* Null PATH segment */
1408                         p++;            /* Skip over colon */
1409                         continue;
1410                     }
1411                     if (q)              /* If not at end of PATH string */
1412                       *q++ = NUL;       /* zero out the colon */
1413                     if ((k = ckstrncpy(tmpbuf,p,TMPBUFSIZ)) > 0) {
1414                         if (tmpbuf[k-1] != '/') { /* Copy this PATH segment */
1415                             tmpbuf[k++] = '/';    /* Append '/' if needed */
1416                             tmpbuf[k] = NUL;
1417                         }
1418                         /* Append the argv[0] value */
1419                         if (ckstrncpy(&tmpbuf[k],xarg0,TMPBUFSIZ) > 0) {
1420                             if (zchki(tmpbuf) > -1) { /* File exists? */
1421                                 tmpbuf[k] = NUL;      /* Yes, we're done */
1422                                 zfnqfp(tmpbuf,LINBUFSIZ,(char *)line);
1423                                 makestr(&exedir,line);
1424                                 break;
1425                             }
1426                         } else break;
1427                     } else break;
1428                     p = q;              /* Not found, go to next segment  */
1429                 } /* while */
1430                 free(PATH);             /* Free PATH copy */
1431             }
1432         }
1433         if (!exedir) {                  /* Still nothing? */
1434             if (zchki(xarg0) > -1) {    /* Maybe it's in the current dir */
1435                 zfnqfp(zgtdir(),LINBUFSIZ,(char *)line);
1436                 makestr(&exedir,line);
1437             }
1438         }
1439     }
1440     if (!exedir) {                      /* Still nothing? */
1441         makestr(&exedir,"/");           /* Fake it with with root. */
1442     }
1443 }
1444 #endif /* UNIX */
1445
1446 int arg_x = 0;
1447 static int x_prescan = 0;
1448
1449 /*
1450   The argument y once meant something but I can't imagine what so now
1451   it's ignored.  (Prior to 22 Aug 98, prescan() was called twice by main(),
1452   and the arg differentiated the two calls.  But this caused all sorts of
1453   problems & confusion, so I commented out the second call.  This issue might
1454   need to be revisited.)
1455 */
1456 VOID
1457 prescan(dummy) int dummy; {             /* Arg is ignored. */
1458     extern int howcalled;
1459     int yargc; char **yargv;
1460     char x;
1461     char *yp, *yy;
1462 #ifdef DEBUG
1463     int debcount = 0;
1464 #endif /* DEBUG */
1465     int z;
1466
1467     if (x_prescan)                      /* Only run once */
1468       return;
1469     x_prescan = 1;
1470
1471     yargc = xargc;                      /* Make copy of arg vector */
1472     yargv = xargv;
1473
1474 #ifndef NOICP
1475 #ifdef DCMDBUF
1476     if (!kermrc)
1477       if (!(kermrc = (char *) malloc(KERMRCL+1)))
1478         fatal("prescan: no memory for kermrc");
1479 #endif /* DCMDBUF */
1480     ckstrncpy(kermrc,KERMRC,KERMRCL);   /* Default init file name */
1481 #endif /* NOICP */
1482
1483
1484 #ifdef IKSD
1485     if (howcalled == I_AM_IKSD)         /* Internet Kermit Service daemon */
1486       inserver = 1;                     /* (See inserver section of ckcmai) */
1487 #endif /* IKSD */
1488
1489 /* Command line options for Kermit */
1490
1491 #ifndef NOCMDL
1492     if (yargc > 1
1493         && *yargv[1] != '-'
1494         && (yargv[1][0] != '=')
1495 #ifdef KERBANG
1496         && (yargv[1][0] != '+')
1497 #endif /* KERBANG */
1498 #ifdef IKSD
1499         && (howcalled != I_AM_IKSD)
1500 #endif /* IKSD */
1501         ) {                             /* Filename as 1st argument */
1502 #ifndef NOICP
1503         char *s;
1504 #endif /* NOICP */
1505 #ifndef NOURL
1506         extern int haveurl;
1507         extern struct urldata g_url;
1508         if (urlparse(yargv[1],&g_url)) {
1509             if (!ckstrcmp(g_url.svc,"ftp",-1,0) ||
1510                 !ckstrcmp(g_url.svc,"ftps",-1,0)) {
1511                 haveurl = 1;
1512                 howcalled = I_AM_FTP;
1513             } else if (!ckstrcmp(g_url.svc,"telnet",-1,0) ||
1514                        !ckstrcmp(g_url.svc,"telnets",-1,0)) {
1515                 haveurl = 1;
1516                 howcalled = I_AM_TELNET;
1517             } else if (!ckstrcmp(g_url.svc,"ssh",-1,0)) {
1518                 haveurl = 1;
1519                 howcalled = I_AM_SSH;
1520             } else if (!ckstrcmp(g_url.svc,"iksd",-1,0) ||
1521                        !ckstrcmp(g_url.svc,"kermit",-1,0)) {
1522                 haveurl = 1;
1523                 howcalled = I_AM_KERMIT;
1524             } else if (!ckstrcmp(g_url.svc,"http",-1,0) ||
1525                        !ckstrcmp(g_url.svc,"https",-1,0)) {
1526                 haveurl = 1;
1527                 howcalled = I_AM_HTTP;
1528             }
1529             if (haveurl) {
1530                 while (--yargc > 0) {   /* Go through command-line args */
1531                     yargv++;            /* looking for -Y and -d */
1532                     yp = *yargv+1;
1533                     if (**yargv == '-') {
1534                         x = *(*yargv+1);
1535                         while (x) {
1536                             switch (x) {
1537 #ifndef NOICP
1538                               case '+':
1539                               case '-':
1540                                 if (doxarg(yargv,1) < 0) {
1541                                     fatal("Extended argument error");
1542                                 }
1543                                 yp = "";
1544                                 break;
1545 #endif /* NOICP */
1546                               case 'Y':
1547                                 noinit++;
1548                                 break;
1549                               case 'h':
1550                                   noinit = 1;
1551 #ifdef OS2
1552                                   startflags |= 2;    /* No network DLLs */
1553                                   startflags |= 4;    /* No TAPI DLLs */
1554                                   startflags |= 8;    /* No Security DLLs */
1555                                   startflags |= 16;   /* No Zmodem DLLs */
1556                                   startflags |= 32;   /* Stdin */
1557                                   startflags |= 64;   /* Stdout */
1558 #endif /* OS2 */
1559                                   break;
1560                               case 'd': /* = SET DEBUG ON */
1561 #ifdef DEBUG
1562                                 if (debcount++ > 0)
1563                                   debtim = 1;
1564                                 if (!deblog)
1565                                   deblog = debopn("debug.log",0);
1566 #endif /* DEBUG */
1567                                 break;
1568 #ifdef OS2
1569                               case 'W':
1570                                 if (*(yp+1))
1571                                   fatal("invalid argument bundling after -W");
1572                                 yargv++, yargc--;
1573                                 if (yargc < 1)
1574                                   fatal("Window handle missing");
1575                                 hwndDialer = (HWND) atol(*yargv);
1576                                 StartedFromDialer = 1;
1577                                 yargv++, yargc--;
1578                                 KermitDialerID = atol(*yargv) ;
1579                                 break;
1580                               case '#': /* K95 initialization options */
1581                                 if (*(yp+1)) {
1582                                     fatal("invalid argument bundling");
1583                                 }
1584                                 yargv++, yargc--;
1585                                 if (yargc < 1)
1586                                   fatal("-# argument missing");
1587                                 startflags |= atol(*yargv);
1588                                 break;
1589 #endif /* OS2 */
1590                             }
1591                             if (!yp)
1592                               break;
1593                             x = *++yp;
1594                         }
1595                     }
1596                 }
1597                 return;
1598             }
1599         }
1600         /* after this point non-Kermit personalities must return */
1601         switch (howcalled) {
1602           case I_AM_KERMIT:
1603           case I_AM_IKSD:
1604           case I_AM_SSHSUB:
1605             break;
1606           default:
1607             return;
1608         }
1609 #endif /* NOURL */
1610
1611 #ifndef NOICP
1612         /* If it is not a URL that we recognize, try to treat it as a file */
1613
1614         if (!isabsolute(yargv[1]))      /* If not absolute */
1615           s = findinpath(yargv[1]);     /* Look in PATH */
1616         else
1617           s = yargv[1];
1618         if (!s)
1619           doexit(BAD_EXIT,xitsta);
1620         zfnqfp(s,CKMAXPATH,cmdfil);     /* In case of CD in file */
1621         yargc -= 1;                     /* Skip past the filename */
1622         yargv += 1;                     /* Otherwise we'll get an error */
1623 #endif /* NOICP */
1624     }
1625
1626 #ifndef NOCMDL
1627 #ifdef NEWFTP
1628     if (howcalled == I_AM_FTP) {        /* Kermit's FTP client personality */
1629         while (--yargc > 0) {           /* Go through command-line args */
1630             yargv++;                    /* looking for -Y and -d */
1631             yp = *yargv+1;
1632             if (**yargv == '-') {
1633                 x = *(*yargv+1);
1634                 while (x) {
1635                     switch (x) {
1636 #ifndef NOICP
1637                       case '+':
1638                       case '-':
1639                         if (doxarg(yargv,1) < 0) {
1640                             fatal("Extended argument error");
1641                         }
1642                         yp = "";
1643                         break;
1644 #endif /* NOICP */
1645                       case 'Y':
1646                         noinit++;
1647                         break;
1648                       case 'h':
1649                         noinit = 1;
1650 #ifdef OS2
1651                         startflags |= 2;    /* No network DLLs */
1652                         startflags |= 4;    /* No TAPI DLLs */
1653                         startflags |= 8;    /* No Security DLLs */
1654                         startflags |= 16;   /* No Zmodem DLLs */
1655                         startflags |= 32;   /* Stdin */
1656                         startflags |= 64;   /* Stdout */
1657 #endif /* OS2 */
1658                         break;
1659                       case 'd':             /* = SET DEBUG ON */
1660 #ifdef DEBUG
1661                         if (debcount++ > 0)
1662                           debtim = 1;
1663                         if (!deblog)
1664                           deblog = debopn("debug.log",0);
1665 #endif /* DEBUG */
1666                         break;
1667 #ifdef OS2
1668                       case 'W':
1669                         if (*(yp+1))
1670                           fatal("invalid argument bundling after -W");
1671                         yargv++, yargc--;
1672                         if (yargc < 1)
1673                           fatal("Window handle missing");
1674                         hwndDialer = (HWND) atol(*yargv);
1675                         StartedFromDialer = 1;
1676                         yargv++, yargc--;
1677                         KermitDialerID = atol(*yargv) ;
1678                         break;
1679                       case '#':         /* K95 initialization options */
1680                         if (*(yp+1)) {
1681                             fatal("invalid argument bundling");
1682                         }
1683                         yargv++, yargc--;
1684                         if (yargc < 1)
1685                           fatal("-# argument missing");
1686                         startflags |= atol(*yargv);
1687                         break;
1688 #endif /* OS2 */
1689                     }
1690                     if (!yp)
1691                       break;
1692                     x = *++yp;
1693                 }
1694             }
1695         }
1696         return;
1697     }
1698 #endif /* NEWFTP */
1699 #endif /* NOCMDL */
1700
1701     while (--yargc > 0) {               /* Go through command-line args */
1702         yargv++;
1703         yp = *yargv+1;                  /* Pointer for bundled args */
1704         if (**yargv == '=')             /* Same rules as cmdlin()... */
1705           return;
1706         debug(F110,"prescan *yargv",*yargv,0);
1707
1708 #ifndef NOICP
1709 #ifdef KERBANG
1710         yy = *yargv;
1711         if (!strcmp(yy,"+") || (*yy == '+' && *(yy+1) < (char)33)) {
1712             char * s;
1713             yargv++;
1714             noinit = 1;
1715             if (!*yargv)
1716               return;
1717             cfilef = 1;
1718             s = findinpath(*yargv);
1719             if (s) {
1720                 zfnqfp(s,CKMAXPATH,cmdfil);
1721                 return;
1722             } else
1723               doexit(BAD_EXIT,xitsta);
1724         }
1725 #endif /* KERBANG */
1726 #endif /* NOICP */
1727         if (!strcmp(*yargv,"--"))       /* getopt() conformance */
1728           return;
1729 #ifdef VMS
1730         else if (**yargv == '/')
1731           continue;
1732 #endif /* VMS */
1733         else if (**yargv == '-') {      /* Got an option (begins with dash) */
1734             x = *(*yargv+1);            /* Get option letter */
1735             while (x) {                 /* Allow for bundled options */
1736                 debug(F000,"prescan arg","",x);
1737                 switch (x) {
1738 #ifndef NOICP
1739                   case '+':
1740                   case '-':
1741                     if (doxarg(yargv,1) < 0) {
1742                         fatal("Extended argument error");
1743                     }
1744 #ifndef COMMENT                         /* Jeff 28 Apr 2003 */
1745                     yp = NULL;          /* (not "") */
1746 #else
1747                     yargv++, yargc--;
1748                     yp = *yargv;
1749 #endif /* COMMENT */
1750                     break;
1751 #endif /* NOICP */
1752
1753                   case '7':             /* Undocumented... */
1754                     sstelnet = 1;       /* (because it doesn't work) */
1755                     break;
1756 #ifdef IKSD
1757                   case 'A': {
1758                       char * p;
1759                       inserver = 1;     /* Flag that we are doing this */
1760                       srvcdmsg = 2;     /* Preset this */
1761                       /* See inserver section of ckcmai.c for more settings */
1762 #ifdef OS2
1763                       if (*(yp+1)) {
1764                           fatal("invalid argument bundling after -A");
1765                       }
1766 #ifdef NT
1767                       /* Support for Pragma Systems Telnet/Terminal Servers */
1768                       p = getenv("PRAGMASYS_INETD_SOCK");
1769                       if (p && atoi(p) != 0) {
1770                           ttname[0] = '$';
1771                           ckstrncpy(&ttname[1],p,TTNAMLEN-1);
1772                           break;
1773                       }
1774 #endif /* NT */
1775                       yargv++, yargc--;
1776                       if (yargc < 1 || **yargv == '-') {
1777                           fatal("-A argument missing");
1778                       } else {
1779                           ttname[0] = '$';
1780                           ckstrncpy(&ttname[1],*yargv,TTNAMLEN-1);
1781                       }
1782 #endif /* OS2 */
1783                       break;
1784                   }
1785 #endif /* IKSD */
1786
1787 #ifdef OS2
1788                   case 'W':
1789                     if (*(yp+1))
1790                       fatal("invalid argument bundling after -W");
1791                     yargv++, yargc--;
1792                     if (yargc < 1)
1793                       fatal("Window handle missing");
1794 #ifdef COMMENT
1795                     if (dummy) {
1796                         yargv++, yargc--;
1797                         break;
1798                     } else {
1799 #endif /* COMMENT */
1800                         hwndDialer = (HWND) atol(*yargv);
1801                         StartedFromDialer = 1;
1802                         yargv++, yargc--;
1803                         KermitDialerID = atol(*yargv) ;
1804 #ifdef COMMENT
1805                     }
1806 #endif /* COMMENT */
1807                     break;
1808
1809                   case '#':             /* K95 initialization options */
1810                     if (*(yp+1)) {
1811                         fatal("invalid argument bundling");
1812                     }
1813                     yargv++, yargc--;
1814                     if (yargc < 1)
1815                       fatal("-# argument missing");
1816                     startflags |= atol(*yargv);
1817                     break;
1818 #endif /* OS2 */
1819
1820 #ifndef NOSPL
1821                   case 'M':                             /* My User Name */
1822                     if (*(yp+1)) {
1823                         fatal("invalid argument bundling");
1824                     }
1825                     yargv++, yargc--;
1826                     if ((yargc < 1) || (**yargv == '-')) {
1827                         fatal("missing username");
1828                     }
1829                     if ((int)strlen(*yargv) > UIDBUFLEN) {
1830                         fatal("username too long");
1831                     }
1832 #ifdef COMMENT
1833 /*
1834   This can't work.  uidbuf is overwritten in sysinit() which has yet to be
1835   called.  This cannot be set in prescan().
1836 */
1837 #ifdef IKSD
1838                     if (!inserver)
1839 #endif /* IKSD */
1840                       ckstrncpy(uidbuf,*yargv,UIDBUFLEN);
1841 #endif /* COMMENT */
1842                     break;
1843 #endif /* NOSPL */
1844                   case 'R':             /* Remote-only advisory */
1845 #ifdef CK_IFRO
1846                     remonly = 1;
1847 #endif /* CK_IFRO */
1848                     break;
1849                   case 'S':             /* STAY */
1850                     stayflg = 1;
1851                     break;
1852                   case 'h':
1853                     noinit = 1;
1854 #ifdef OS2
1855                     startflags |= 2;    /* No network DLLs */
1856                     startflags |= 4;    /* No TAPI DLLs */
1857                     startflags |= 8;    /* No Security DLLs */
1858                     startflags |= 16;   /* No Zmodem DLLs */
1859                     startflags |= 32;   /* Stdin */
1860                     startflags |= 64;   /* Stdout */
1861 #endif /* OS2 */
1862                     break;
1863 #ifndef NOICP
1864                   case 'Y':             /* No init file */
1865                     noinit = 1;
1866                     break;
1867 #endif /* NOICP */
1868                   case 'd':             /* = SET DEBUG ON */
1869 #ifdef DEBUG
1870                     if (debcount++ > 0)
1871                       debtim = 1;
1872                     if (!deblog)
1873                       deblog = debopn("debug.log",0);
1874 #endif /* DEBUG */
1875                     break;
1876
1877                   case 'x':             /* Server */
1878                     arg_x = 1;          /* Note in advance */
1879                     break;
1880 #ifndef NOICP
1881                   case 'y':             /* Alternative init file */
1882                     noinit = 0;
1883                     yargv++, yargc--;
1884                     if (yargc < 1) fatal("missing name in -y");
1885                     /* Replace init file name */
1886                     ckstrncpy(kermrc,*yargv,KERMRCL);
1887                     rcflag = 1;         /* Flag that this has been done */
1888                     debug(F111,"prescan kermrc",kermrc,rcflag);
1889                     break;
1890 #endif /* NOICP */
1891                   case 'z':             /* = SET BACKGROUND OFF */
1892                     bgset = 0;
1893                     backgrd = 0;
1894 #ifdef VMS
1895                     batch = 0;
1896 #endif /* VMS */
1897                     break;
1898
1899                   case 'B':             /* Force background (batch) */
1900                     bgset = 1;
1901                     backgrd = 1;
1902 #ifdef VMS
1903                     batch = 1;
1904 #endif /* VMS */
1905                     break;
1906
1907 #ifdef CK_NETBIOS
1908                   case 'N':
1909                     {
1910                         int n ;
1911                         yargv++, yargc--;
1912 #ifdef COMMENT
1913                         if (y)
1914                           break;
1915 #endif /* COMMENT */
1916                         if (strlen(*yargv) != 1 || (*yargv)[0] == 'X') {
1917                             NetBiosAdapter = -1;
1918                         } else {
1919                             n = atoi(*yargv);
1920                             if (n >= 0 && n <= 9)
1921                               NetBiosAdapter = n;
1922                             else
1923                               NetBiosAdapter = -1;
1924                         }
1925                     }
1926                     break;
1927 #endif /* CK_NETBIOS */
1928                   default:
1929                     break;
1930                 }
1931                 if (!yp)
1932                   break;
1933                 x = *++yp;              /* See if options are bundled */
1934             }
1935         }
1936     }
1937 #endif /* NOCMDL */
1938 }
1939
1940 /*  G E T T C S  --  Get Transfer (Intermediate) Character Set  */
1941
1942 /*
1943   Given two file character sets, this routine picks out the appropriate
1944   "transfer" character set to use for translating between them.
1945   The transfer character set number is returned.
1946
1947   Translation between two file character sets is done, for example,
1948   by the CONNECT, TRANSMIT, and TRANSLATE commands.
1949
1950   Translation between Kanji character sets is not yet supported.
1951 */
1952 int
1953 gettcs(cs1,cs2) int cs1, cs2; {
1954 #ifdef NOCSETS                          /* No character-set support */
1955     return(0);                          /* so no translation */
1956 #else
1957     int tcs = TC_TRANSP;
1958 #ifdef KANJI
1959 /* Kanji not supported yet */
1960     if (fcsinfo[cs1].alphabet == AL_JAPAN ||
1961         fcsinfo[cs2].alphabet == AL_JAPAN )
1962       tcs = TC_TRANSP;
1963     else
1964 #endif /* KANJI */
1965 #ifdef CYRILLIC
1966 /*
1967   I can't remember why we don't test both sets here, but I think there
1968   must have been a reason...
1969 */
1970       if (fcsinfo[cs2].alphabet == AL_CYRIL)
1971         tcs = TC_CYRILL;
1972       else
1973 #endif /* CYRILLIC */
1974 #ifdef HEBREW
1975           if (fcsinfo[cs1].alphabet == AL_HEBREW ||
1976               fcsinfo[cs2].alphabet == AL_HEBREW )
1977             tcs = TC_HEBREW;
1978           else
1979 #endif /* HEBREW */
1980 #ifdef GREEK
1981           if (fcsinfo[cs1].alphabet == AL_GREEK ||
1982               fcsinfo[cs2].alphabet == AL_GREEK )
1983             tcs = TC_GREEK;
1984           else
1985 #endif /* GREEK */
1986
1987             /* Roman sets ... */
1988
1989 #ifdef LATIN2                           /* East European */
1990         if (cs1 == FC_2LATIN  || cs2 == FC_2LATIN || /* Latin-2 */
1991             cs1 == FC_CP852   || cs2 == FC_CP852  || /* CP852 */
1992             cs1 == FC_CP1250  || cs2 == FC_CP1250 || /* Windows Latin-2 */
1993             cs1 == FC_MAZOVIA || cs2 == FC_MAZOVIA)  /* Polish Mazovia */
1994           tcs = TC_2LATIN;
1995         else
1996 #endif /* LATIN2 */
1997                                         /* West European Euro-aware */
1998           if (cs1 == FC_CP858 || cs1 == FC_9LATIN ||
1999               cs2 == FC_CP858 || cs2 == FC_9LATIN)
2000             tcs = TC_9LATIN;
2001           else                          /* Traditional West European */
2002             tcs = TC_1LATIN;
2003     return(tcs);
2004 #endif /* NOCSETS */
2005 }
2006
2007 #ifndef NOLOCAL
2008 /*  D O C O N E C T  --  Do the connect command  */
2009 /*
2010   q = 0 means issue normal informational message about how to get back, etc.
2011   q != 0 means to skip the message.
2012 */
2013
2014 int
2015 doconect(q,async) int q, async; {
2016     int x;                              /* Return code */
2017 #ifdef CK_AUTODL
2018     extern CHAR ksbuf[];
2019 #endif /* CK_AUTODL */
2020 #ifndef NOKVERBS                        /* Keyboard macro material */
2021     extern int keymac, keymacx;
2022 #endif /* NOKVERBS */
2023     extern int justone, adl_err;
2024     int qsave;                          /* For remembering "quiet" value */
2025 #ifdef OS2
2026     extern int term_io;
2027     extern int display_demo;
2028     int term_io_save;
2029 #ifdef KUI
2030     extern int kui_async;
2031 #endif /* KUI */
2032 #endif /* OS2 */
2033     int is_tn = 0;
2034
2035 #ifdef IKSD
2036     if (inserver) {
2037         if (!quiet)
2038           printf("?Sorry, IKSD cannot CONNECT.\r\n");
2039         return(success = 0);
2040     }
2041 #endif /* IKSD */
2042
2043     is_tn =
2044 #ifdef TNCODE
2045       (local && network && IS_TELNET()) || (!local && sstelnet)
2046 #else
2047         0
2048 #endif /* TNCODE */
2049           ;
2050 /*
2051   Saving, changing, and restoring the global "quiet" variable around calls
2052   to conect() to control whether the verbose CONNECT message is printed is
2053   obviously less elegant than passing a parameter to conect(), but we do it
2054   this way to avoid the need to change all of the ck?con.c modules.  NOTE:
2055   it is important to restore the value immediately upon return in case there
2056   is an autodownload or APC.
2057 */
2058     qsave = quiet;                      /* Save it */
2059     if (!quiet && q > -1)
2060       quiet = q;                        /* Use argument temporarily */
2061     conres();                           /* Put console back to normal */
2062     debug(F101,"doconect justone 1","",justone);
2063 #ifdef CK_AUTODL
2064     ksbuf[0] = NUL;                     /* Autodownload packet buffer */
2065 #endif /* CK_AUTODL */
2066 #ifdef OS2
2067     display_demo = 1;                   /* Remember to display demo */
2068 #endif /* OS2 */
2069
2070 #ifdef IKS_OPTION
2071     if (is_tn && TELOPT_U(TELOPT_KERMIT) && ttchk() >= 0
2072 #ifdef OS2
2073        && !viewonly
2074 #endif /* OS2 */
2075         ) {
2076         /* If the remote side is in a state of IKS START-SERVER    */
2077         /* we request that the state be changed.  We will detect   */
2078         /* a failure to adhere to the request when we call ttinc() */
2079         if (!iks_wait(KERMIT_REQ_STOP,0) && !tcp_incoming) {
2080             if (!quiet) {
2081                 printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
2082                 printf(
2083 " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
2084                 printf(" SEND and GET for file transfer.\r\n");
2085                 printf(" REMOTE commands for file management.\r\n");
2086                 printf(" FINISH to terminate Client/Server mode.\r\n");
2087                 printf(" BYE to terminate and close connection.\r\n");
2088                 printf(" REMOTE HELP for additional information.\r\n\r\n");
2089             }
2090             quiet = qsave;
2091             return(0);      /* Failure */
2092         }
2093     }
2094
2095     /* Let our peer know our state. */
2096 #ifdef CK_AUTODL
2097     if (is_tn && TELOPT_ME(TELOPT_KERMIT)
2098 #ifdef OS2
2099         && !viewonly
2100 #endif /* OS2 */
2101          ) {
2102         if (autodl && !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2103             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
2104         } else if (!autodl && TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
2105             tn_siks(KERMIT_STOP);
2106         }
2107     }
2108 #else /* CK_AUTODL */
2109     if (is_tn && TELOPT_ME(TELOPT_KERMIT) &&
2110         TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
2111         tn_siks(KERMIT_STOP);
2112 #endif /* CK_AUTODL */
2113 #endif /* IKS_OPTION */
2114
2115     debug(F101,"doconect flow","",flow);
2116 #ifdef OS2
2117     debug(F101,"doconect async","",async);
2118 #ifdef KUI
2119     if (kui_async)
2120       async = 1;;
2121 #endif /* KUI */
2122     x = conect(async);                  /* Connect the first time */
2123 #else /* OS2 */
2124     x = conect();
2125 #endif /* OS2 */
2126     debok = 1;
2127
2128 #ifdef IKS_OPTION
2129     if (TELOPT_U(TELOPT_KERMIT) &&
2130         TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
2131         !tcp_incoming && !quiet && ttchk() >= 0
2132         ) {
2133         printf("\r\nEnter Client/Server Mode...  Use:\r\n\r\n");
2134         printf(
2135 " REMOTE LOGIN <user> <password> to log in to the server if necessary.\r\n");
2136         printf(" SEND and GET for file transfer.\r\n");
2137         printf(" REMOTE commands for file management.\r\n");
2138         printf(" FINISH to terminate Client/Server mode.\r\n");
2139         printf(" BYE to terminate and close connection.\r\n");
2140         printf(" REMOTE HELP for additional information.\r\n\r\n");
2141     }
2142 #endif /* IKS_OPTION */
2143
2144     quiet = qsave;                      /* Restore "quiet" value */
2145     debug(F101,"doconect justone 2","",justone);
2146
2147 #ifdef NETCONN
2148     if (network && tn_exit && ttchk() < 0)
2149       doexit(GOOD_EXIT,xitsta);         /* Exit with good status */
2150 #endif /* NETCONN */
2151
2152 #ifdef OS2ORUNIX
2153     /* Exit on disconnect if the port is not open or carrier detect */
2154     if (exitonclose && (ttchk() < 0))
2155       doexit(GOOD_EXIT,xitsta);
2156 #endif /* OS2ORUNIX */
2157
2158 #ifdef CKCONINTB4CB
2159     /* The order makes a difference in HP-UX 8.00. */
2160     /* The other order makes it think it's in the background when it */
2161     /* returns from CONNECT (Apr 1999). */
2162     setint();
2163     concb((char)escape);                /* Restore console for commands */
2164 #else
2165     /* This is how it has always been so better leave it */
2166     /* this way for all non-HP-UX-8.00 builds. */
2167     concb((char)escape);                /* Restore console for commands */
2168     setint();
2169 #endif /* CKCONINTB4CB */
2170
2171 #ifdef OS2
2172     if (!async) {
2173         term_io_save = term_io;         /* Disable I/O by emulator */
2174         term_io = 0;
2175 #endif /* OS2 */
2176
2177 #ifdef CK_APC
2178 /*
2179   If an APC command was received during CONNECT mode, we define it now
2180   as a macro, execute the macro, and then return to CONNECT mode.
2181   We do this in a WHILE loop in case additional APCs come during subsequent
2182   CONNECT sessions.
2183 */
2184         debug(F101,"doconect apcactive","",apcactive);
2185         debug(F101,"doconect success","",success);
2186
2187         while (x > 0 && (apcactive == APC_LOCAL ||
2188                          (apcactive == APC_REMOTE && apcstatus != APC_OFF))) {
2189             debug(F101,"doconect justone 3","",justone);
2190             if (mlook(mactab,"_apc_commands",nmac) == -1) {
2191                 debug(F110,"doconect about to execute APC",apcbuf,0);
2192                 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
2193                 delmac("_apc_commands",1);
2194 #ifdef DEBUG
2195             } else {
2196                 debug(F100,"doconect APC in progress","",0);
2197 #endif /* DEBUG */
2198             }
2199             debug(F101,"doconect apcactive after domac","",apcactive);
2200             if (!apcactive) {               /* In case CLEAR APC was in APC */
2201                 debug(F101,"doconect quit APC loop: apcactive","",apcactive);
2202                 break;
2203             }
2204             /* Also don't reconnect if autodownload failed - very confusing! */
2205             /* Let them view the local screen to see what happened. - fdc */
2206
2207             /* This should be conditional.  If someone is relying on the */
2208             /* connect mode autodownload for the kermit server to use with */
2209             /* a remotely executed script we should be able to return to */
2210             /* connect mode on the failure.  What we really need to do is */
2211             /* report the status of the transfer and then return to CONNECT. */
2212             /* In unix this would simply be a printf(), but in K95 it could */
2213             /* use a popup dialog to report the status. - Jeff */
2214
2215 #ifndef NOXFER
2216             debug(F101,"doconect xferstat","",xferstat);
2217             if (apcactive == APC_LOCAL && !xferstat && adl_err != 0) {
2218                 debug(F101,"doconect quit APC loop: xferstat","",xferstat);
2219                 apcactive = APC_INACTIVE;
2220                 break;
2221             }
2222 #endif /* NOXFER */
2223 #ifdef OS2
2224             msleep(250);
2225 #endif /* OS2 */
2226             debug(F101,"doconect justone 4","",justone);
2227             qsave = quiet;              /* Do this again... */
2228             if (!quiet && q > -1)
2229               quiet = q;
2230 #ifdef CK_AUTODL
2231             ksbuf[0] = NUL;
2232 #endif /* CK_AUTODL */
2233 #ifdef IKS_OPTION
2234 #ifdef CK_AUTODL
2235             if (is_tn &&
2236                 TELOPT_ME(TELOPT_KERMIT) &&
2237                 !TELOPT_SB(TELOPT_KERMIT).kermit.me_start &&
2238                 autodl
2239 #ifdef CK_APC
2240                 && !apcactive
2241 #endif /* CK_APC */
2242 #ifdef OS2
2243                 && !viewonly
2244 #endif /* OS2 */
2245                 ) {
2246                 tn_siks(KERMIT_START);  /* Send Kermit-Server Start */
2247             }
2248 #endif /* CK_AUTODL */
2249 #endif /* IKS_OPTION */
2250 #ifndef OS2
2251             x = conect();               /* Re-CONNECT. */
2252 #else /* OS2 */
2253             x = conect(0);
2254             term_io = term_io_save;
2255 #endif /* OS2 */
2256             debok = 1;
2257             quiet = qsave;
2258             debug(F101,"doconect justone 5","",justone);
2259 #ifdef NETCONN
2260             if (network && ttchk() < 0) {
2261                 if (tn_exit || exitonclose)
2262                   doexit(GOOD_EXIT,xitsta);
2263                 else
2264                   break;
2265             }
2266 #endif /* NETCONN */
2267
2268 #ifdef OS2ORUNIX
2269             /* If connection dropped */
2270             if (ttchk() < 0) {
2271                 concb((char)escape);    /* Restore console. */
2272                 if (exitonclose)
2273                   doexit(GOOD_EXIT,xitsta);
2274                 else
2275                   break;
2276             }
2277 #endif /* OS2ORUNIX */
2278         } /* Loop back for more. */
2279 #endif /* CK_APC */
2280
2281 #ifndef NOKVERBS
2282         if ((keymac > 0) && (keymacx > -1)) { /* Executing a keyboard macro? */
2283             /* Set up the macro and return */
2284             /* Do not clear the keymac flag */
2285 #ifdef OS2
2286             term_io = term_io_save;
2287 #endif /* OS2 */
2288             return(dodo(keymacx,NULL,CF_KMAC|cmdstk[cmdlvl].ccflgs));
2289         }
2290 #endif /* NOKVERBS */
2291 #ifdef OS2
2292         term_io = term_io_save;
2293     } /* if (!async) */
2294 #endif /* OS2 */
2295
2296 #ifdef CKCONINTB4CB
2297     /* The order makes a difference in HP-UX 8.00. */
2298     /* The other order makes it think it's in the background when it */
2299     /* returns from CONNECT (Apr 1999). */
2300     setint();
2301     concb((char)escape);                /* Restore console for commands */
2302 #else
2303     /* This is how it has always been so better leave it */
2304     /* this way for all non-HP-UX-8.00 builds. */
2305     concb((char)escape);                /* Restore console for commands */
2306     setint();
2307 #endif /* CKCONINTB4CB */
2308 #ifdef OS2
2309     if (!async)
2310 #endif /* OS2 */
2311       what = W_COMMAND;                 /* Back in command mode. */
2312     return(x);                          /* Done. */
2313 }
2314 #endif /* NOLOCAL */
2315
2316 #ifndef NOICP
2317 #ifdef COMMENT
2318 /*
2319   It seemed that this was needed for OS/2, in which \v(cmdfile) and other
2320   file-oriented variables or functions can return filenames containing
2321   backslashes, which are subsequently interpreted as quotes rather than
2322   directory separators (e.g. see commented section for VN_CMDF below).
2323   But the problem can't be cured at this level.  Example:
2324
2325     type \v(cmdfile)
2326
2327   Without doubling, the filename is parsed correctly, but then when passed
2328   to UNIX 'cat' through the shell, the backslash is removed, and then cat
2329   can't open the file.  With doubling, the filename is not parsed correctly
2330   and the TYPE command fails immediately with a "file not found" error.
2331 */
2332 /*
2333   Utility routine to double all backslashes in a string.
2334   s1 is pointer to source string, s2 is pointer to destination string,
2335   n is length of destination string, both NUL-terminated.
2336   Returns 0 if OK, -1 if not OK (destination string too short).
2337 */
2338 int
2339 dblbs(s1,s2,n) char *s1, *s2; int n; {
2340     int i = 0;
2341     while (*s1) {
2342         if (*s1 == '\\') {
2343             if (++i > n) return(-1);
2344             *s2++ = '\\';
2345         }
2346         if (++i > n) return(-1);
2347         *s2++ = *s1++;
2348     }
2349     *s2 = NUL;
2350     return(0);
2351 }
2352 #endif /* COMMENT */
2353
2354 char *
2355 gmdmtyp() {                             /* Get modem type */
2356 #ifndef NODIAL
2357     int i, x;
2358
2359     debug(F111,"gmdmtyp","mdmtyp",mdmtyp);
2360     debug(F111,"gmdmtyp","mdmsav",mdmsav);
2361
2362     x = mdmtyp;
2363     if (x < 0)                          /* In case of network dialing */
2364       x = mdmsav;
2365     if (x < 1)
2366       return("none");
2367     else
2368       for (i = 0; i < nmdm; i++)
2369         if ((mdmtab[i].kwval == x) && (mdmtab[i].flgs == 0))
2370           return(mdmtab[i].kwd);
2371 #endif /* NODIAL */
2372     return("none");
2373 }
2374
2375 #ifndef NOXMIT
2376 #ifndef NOLOCAL
2377 /*  T R A N S M I T  --  Raw upload  */
2378
2379 /*  Obey current line, duplex, parity, flow, text/binary settings. */
2380 /*  Returns 0 upon apparent success, 1 on obvious failure.  */
2381
2382 /***
2383  Things to add:
2384  . Make both text and binary mode obey set file bytesize.
2385  . Maybe allow user to specify terminators other than CR?
2386  . Maybe allow user to specify prompts other than single characters?
2387  . Make STATISTICS also work for TRANSMIT.
2388  . If TRANSMIT is done without echo, make some kind of (optional) display.
2389  . Make the same optimization for binary-mode transmit that was done for
2390    text-mode (in the no-echo / no-prompt / no-pause case).
2391 ***/
2392
2393 /*  T R A N S M I T  --  Raw upload  */
2394
2395 /*  s is the filename, t is the turnaround (prompt) character  */
2396
2397 /*
2398   Maximum number of characters to buffer.
2399   Must be less than LINBUFSIZ
2400 */
2401 #ifdef OS2
2402 #define XMBUFS 4096                     /* For compatibility with XYZmodem */
2403 #else /* OS2 */
2404 #define XMBUFS 1024
2405 #endif /* OS2 */
2406
2407 #ifdef TNCODE
2408 #ifndef IAC
2409 #define IAC 255
2410 #endif /* IAC */
2411 #endif /* TNCODE */
2412
2413 #define OUTXBUFSIZ 15
2414 static CHAR inxbuf[OUTXBUFSIZ+1];       /* Host-to-screen expansion buffer */
2415 static int inxcount = 0;                /* and count */
2416 static CHAR outxbuf[OUTXBUFSIZ+1];      /* Keyboard-to-host expansion buf */
2417 static int outxcount = 0;               /* and count */
2418
2419 /*  T R A N S M I T  --  Unguarded non-protocol file transmission  */
2420 /*
2421   Call with:
2422     char * s:   Name of file to transmit.
2423     char t:     Turnaround char for text-mode transmission (normally LF).
2424     int xlate:  nonzero = charset translation for text-mode xfer, 0 = skip.
2425     int binary: nonzero = transmit in binary mode, 0 = in text mode.
2426 */
2427 #define XBBUFSIZ 252                    /* For binary blasting */
2428 static CHAR xbbuf[XBBUFSIZ+4];
2429
2430 int
2431 #ifdef CK_ANSIC
2432 transmit(char * s, char t, int xlate, int binary, int xxecho)
2433 #else
2434 transmit(s,t,xlate,binary,xxecho) char *s; char t; int xlate, binary, xxecho;
2435 #endif /* CK_ANSIC */
2436 /* transmit */ {
2437 #ifdef MAC
2438     extern char sstate;
2439     int count = 100;
2440 #else
2441     int count = 0;
2442 #ifdef OS2
2443 #ifdef NT
2444     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
2445 #else /* NT */
2446     SIGTYP (* volatile oldsig)(int);
2447 #endif /* NT */
2448
2449 #else /* OS2 */
2450     SIGTYP (* oldsig)();
2451 #endif /* OS2 */
2452 #endif /* MAC */
2453     int eof = 0;                        /* End of File flag */
2454     int eol = 0;                        /* End of Line flag */
2455     int rc = 1;                         /* Return code. 0=fail, 1=succeed. */
2456     int myflow;                         /* Local copy of global flow... */
2457     int is_tn = 0;                      /* Do Telnet negotiations */
2458     int xbufsiz = XMBUFS;               /* Size of TRANSMIT buffer */
2459     int x, y, c, i;                     /* Int workers... */
2460     int control = 0;                    /* Echo loop control */
2461     long nbytes = 0;                    /* File byte count */
2462     long zz;                            /* Long worker */
2463     char *p;                            /* Char * worker */
2464
2465 #ifdef PIPESEND
2466     extern int pipesend;
2467 #endif /* PIPESEND */
2468
2469 #ifndef NOCSETS
2470     int tcs = TC_TRANSP;                /* Intermediate (xfer) char set */
2471     int langsv = L_USASCII;             /* Save current language */
2472     int unicode = 0;
2473     int tcssize = 0;
2474
2475 #ifdef CK_ANSIC /* ANSI C prototypes... */
2476     CHAR (*sxo)(CHAR);
2477     CHAR (*rxo)(CHAR);
2478     CHAR (*sxi)(CHAR);
2479     CHAR (*rxi)(CHAR);
2480 #else /* Not ANSI C... */
2481     CHAR (*sxo)();
2482     CHAR (*rxo)();
2483     CHAR (*sxi)();
2484     CHAR (*rxi)();
2485 #endif /* CK_ANSIC */
2486 #ifdef UNICODE
2487     union ck_short uc;
2488     int bomorder = 0;
2489 #ifdef CK_ANSIC
2490     extern int (*xl_ufc[MAXFCSETS+1])(USHORT);  /* Unicode to FCS */
2491     extern USHORT (*xl_fcu[MAXFCSETS+1])(CHAR); /* FCS to Unicode */
2492     extern int (*xuf)(USHORT);
2493     extern USHORT (*xfu)(CHAR);
2494 #else
2495     extern int (*xl_ufc[MAXFCSETS+1])();
2496     extern USHORT (*xl_fcu[MAXFCSETS+1])();
2497     extern int (*xuf)();
2498     extern USHORT (*xfu)();
2499 #endif /* CK_ANSIC */
2500 #endif /* UNICODE */
2501 #endif /* NOCSETS */
2502
2503     debug(F101,"xmit t","",t);
2504     debug(F101,"xmit xlate","",xlate);
2505     debug(F101,"xmit binary","",binary);
2506
2507 #ifdef PIPESEND
2508     if (pipesend) {
2509         if (nopush) return(-2);
2510         if (zxcmd(ZIFILE,s) < 1) {
2511             printf("?Can't start command: %s\n",s);
2512             return(0);
2513         }
2514     } else
2515 #endif /* PIPESEND */
2516     if (zopeni(ZIFILE,s) == 0) {        /* Open the file to be transmitted */
2517         printf("?Can't open file %s\n",s);
2518         return(0);
2519     }
2520     x = -1;                             /* Open the communication channel */
2521     if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) {  /* (no harm if already open) */
2522         printf("Can't open device %s\n",ttname);
2523         return(0);
2524     }
2525     zz = x ? speed : -1L;
2526     if (binary) {                       /* Binary file transmission */
2527         myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
2528
2529         if (ttvt(zz,myflow) < 0) {      /* So no Xon/Xoff! */
2530             printf("Can't condition line\n");
2531             return(0);
2532         }
2533     } else {
2534         if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
2535             printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
2536             return(0);
2537         }
2538     }
2539     is_tn =
2540 #ifdef TNCODE
2541       (local && network && IS_TELNET()) || (!local && sstelnet)
2542 #else
2543         0
2544 #endif /* TNCODE */
2545           ;
2546
2547 #ifndef NOCSETS
2548 /* Set up character set translations */
2549
2550     tcs = 0;                            /* "Transfer" or "Other" charset */
2551     sxo = rxo = NULL;                   /* Initialize byte-to-byte functions */
2552     sxi = rxi = NULL;
2553     unicode = 0;                        /* Assume Unicode won't be involved */
2554     if (!binary && xlate) {             /* Set up charset translations */
2555 /*
2556   In the SENDING direction, we are converting from the local file's
2557   character-set (fcharset) to the remote terminal charset (tcsr).  In the
2558   RECEIVING direction (echoing) we are converting from the remote end of the
2559   terminal charset (tcsr) to its local end (tcsl), which is not necessarily
2560   the same as the file character-set.  Especially when the file character
2561   set is UCS-2, which is not a valid terminal character set.  The various
2562   combinations are represented in this table:
2563
2564   FCS = File Character Set
2565   RCS = Remote Terminal Character Set
2566   CCS = Console (Local Terminal) Character Set
2567
2568    8   4   2   1
2569   FCS FCS RCS CCS
2570   UCS UTF UTF UTF
2571    0   0   0   0   =   0   =   No translation
2572    0   0   0   1   =   1   =   FCS -> RCS, Echo RCS -> UTF
2573    0   0   1   0   =   2   =   FCS -> UTF, Echo UTF -> CCS
2574    0   0   1   1   =   3   =   FCS -> UTF, Echo no translation
2575
2576    0   1   0   0   =   4   =   UTF -> RCS, Echo RCS -> CCS
2577    0   1   0   1   =   5   =   UTF -> RCS, Echo RCS -> UTF
2578    0   1   1   0   =   6   =   UTF -> UTF, Echo UTF -> CCS
2579    0   1   1   1   =   7   =   No translation
2580
2581    1   0   0   0   =   8   =   UCS -> RCS, Echo RCS -> CCS
2582    1   0   0   1   =   9   =   UCS -> RCS, Echo RCS -> UTF
2583    1   0   1   0   =  10   =   UCS -> UTF, Echo UTF -> CCS
2584    1   0   1   1   =  11   =   UCS -> UTF, Echo no translation
2585 */
2586 #ifdef UNICODE
2587         xfu = NULL;                     /* Unicode translation functions */
2588         xuf = NULL;
2589         bomorder = ucsorder;            /* UCS-2 byte order */
2590
2591         if (fcharset == FC_UCS2)        /* File charset is UCS-2 */
2592           unicode |= 8;
2593         else if (fcharset == FC_UTF8)   /* File charset is UTF-8 */
2594           unicode |= 4;
2595         if (tcsr == FC_UTF8)            /* Remote term charset is UTF-8 */
2596           unicode |= 2;
2597         if (tcsl == FC_UTF8)            /* Local term charset is UTF-8 */
2598           unicode |= 1;
2599 #endif /* UNICODE */
2600 /*
2601   When Unicode not involved -- TCS is the intermediate (xfer) set, and:
2602   sxo = File-to-Intermediate charset function
2603   rxo = Intermediate-to-Remote-Terminal charset function
2604   sxi = Remote-Terminal-to-Intermediate
2605   rxi = Intermediate-to-Local-Terminal
2606 */
2607         tcs = gettcs(tcsr,fcharset);    /* Get intermediate set. */
2608         sxo = xls[tcs][fcharset];       /* translation function */
2609         rxo = xlr[tcs][tcsr];           /* pointers for output functions */
2610         sxi = xls[tcs][tcsr];           /* and for input functions. */
2611         rxi = xlr[tcs][tcsl];
2612 /*
2613   At this point we have unicode nonzero if Unicode is involved in the
2614   conversion, and to 0 if it is not.
2615   The following is to prevent use of zmstuff() and zdstuff() by translation
2616   functions (stuffing works with file i/o, not with communication i/o).
2617 */
2618         langsv = language;              /* Save current SET LANGUAGE */
2619         language = L_USASCII;           /* No language-specific translations */
2620     }
2621 #endif /* NOCSETS */
2622
2623     i = 0;                              /* Beginning of buffer. */
2624 #ifndef MAC
2625 #ifndef AMIGA
2626     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
2627 #endif /* AMIGA */
2628 #endif /* MAC */
2629     tr_int = 0;                         /* Have not been interrupted (yet). */
2630     rc = 1;                             /* Return code presumed good. */
2631 #ifdef VMS
2632     conres();
2633 #endif /* VMS */
2634
2635 #ifndef NOCSETS
2636     debug(F101,"XMIT unicode","",unicode);
2637 #ifdef UNICODE
2638     debug(F101,"XMIT bomorder","",bomorder);
2639 #endif /* UNICODE */
2640 #endif /* NOCSETS */
2641
2642     c = 0;                              /* Initial condition */
2643     while (c > -1 && !eof) {            /* Loop for all characters in file */
2644         eol = 0;
2645 #ifdef MAC
2646         /*
2647          * It is expensive to run the miniparser so don't do it for
2648          * every character.
2649          */
2650         if (--count < 0) {
2651             count = 100;
2652             miniparser(1);
2653             if (sstate == 'a') {
2654                 sstate = '\0';
2655                 goto xmitfail;
2656             }
2657         }
2658 #else /* Not MAC */
2659         if (tr_int) {                   /* Interrupted? */
2660             printf("^C...\n");          /* Print message */
2661             goto xmitfail;
2662         }
2663 #endif /* MAC */
2664         c = zminchar();                 /* Get a file character */
2665 #ifdef COMMENT
2666 /* too much */
2667 #ifdef DEBUG
2668         if (deblog) {
2669             if (c < 0)
2670               debug(F101,"XMIT zminchar","",c);
2671             else
2672               debug(F000,"XMIT zminchar","",c);
2673         }
2674 #endif /* DEBUG */
2675 #endif /* COMMENT */
2676         if (c < -1) {                   /* Other error */
2677             printf("?TRANSMIT file read error: %s\n",ck_errstr());
2678             goto xmitfail;
2679         } else if (c > -1) {
2680             nbytes++;
2681             c &= fmask;                 /* Apply SET FILE BYTESIZE mask */
2682         } else if (c == -1) {
2683             eof = 1;
2684             debug(F101,"XMIT eof","",eof);
2685         }
2686         if (binary) {                   /* Binary... */
2687             if (c == -1) {              /* If EOF */
2688                 rc = 1;                 /* Success */
2689                 eof = 1;
2690                 goto xmitexit;          /* Done */
2691             }
2692             if (!xmitw && !xxecho) {    /* Special "blast" mode */
2693                 if (count == XBBUFSIZ) { /* File input buffer full... */
2694                     while (count > 0) {
2695                         errno = 0;
2696                         y = ttol(xbbuf,count);
2697                         if (y < 0) {    /* try to send it. */
2698                             printf("?TRANSMIT output error: %s\n",
2699                                    ck_errstr());
2700                             debug(F111,"XMIT binary ttol error",
2701                                   ck_errstr(),errno);
2702                             rc = 0;
2703                             break;
2704                         }
2705                         if (y < 0) break;
2706                         count -= y;
2707                     }
2708                     count = 0;
2709                 }
2710                 xbbuf[count++] = c;
2711 #ifdef TNCODE
2712                 if (c == IAC && is_tn)  /* Telnet IAC */
2713                   xbbuf[count++] = IAC; /* must be doubled */
2714 #endif /* TNCODE */
2715                 continue;
2716             }
2717             if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
2718                 printf("?Can't transmit character\n");
2719                 goto xmitfail;
2720             }
2721 #ifdef TNCODE
2722             if (c == IAC && is_tn)      /* Quote Telnet IAC */
2723               ttoc((char)IAC);
2724 #endif /* TNCODE */
2725
2726             if (xmitw)                  /* Pause if requested */
2727               msleep(xmitw);
2728
2729             if (xxecho) {               /* SET TRANSMIT ECHO ON? */
2730                 if (duplex) {           /* Yes, for half duplex */
2731 #ifndef NOLOCAL
2732 #ifdef OS2
2733                     /* Echo to emulator */
2734                     scriptwrtbuf((USHORT)(c & cmdmsk));
2735 #endif /* OS2 */
2736 #endif /* NOLOCAL */
2737                     if (conoc((char)(c & cmdmsk)) < 0) /* echo locally. */
2738                       goto xmitfail;
2739                 } else {                /* For full duplex, */
2740                     int i, n;           /* display whatever is there. */
2741                     n = ttchk();        /* See how many chars are waiting */
2742                     if (n < 0) {        /* Connection dropped? */
2743                         printf("?Connection lost\n");
2744                         goto xmitfail;
2745                     }
2746                     for (i = 0; i < n; i++) { /* Read and echo that many. */
2747                         x = ttinc(xmitt); /* Timed read just in case. */
2748                         if (x > -1) {   /* If no timeout */
2749                             if (parity) x &= 0x7f; /* display the char, */
2750 #ifndef NOLOCAL
2751 #ifdef OS2
2752                             /* Echo to emulator */
2753                             scriptwrtbuf((USHORT)x);
2754 #endif /* OS2 */
2755 #endif /* NOLOCAL */
2756                             if (conoc((char)(x & cmdmsk)) < 0) {
2757                                 printf("?Output error\n");
2758                                 goto xmitfail;
2759                             }
2760                         } else if (x == -2) {
2761                             printf("Connection closed.\n");
2762                             ttclos(1);
2763                             goto xmitfail;
2764                         } else if (x == -3) {
2765                             printf(
2766                             "Session Limit exceeded - closing connection.\n"
2767                                    );
2768                             ttclos(1);
2769                             goto xmitfail;
2770                         } else {
2771                             printf("?Communications error\n");
2772                             goto xmitfail;
2773                         }
2774                     }
2775                 }
2776             } else ttflui();            /* Not echoing, just flush input. */
2777
2778         } else {                        /* Text mode, line at a time. */
2779 #ifdef UNICODE
2780             if (fcharset == FC_UCS2 && xlate) { /* Special for UCS-2 */
2781                 char xbuf[8];
2782                 x = 1 - (nbytes & 1);   /* Odd or even byte */
2783                 if (x == 0)             /* Note: 1 = the 1st, 0 = 2nd, etc */
2784                   uc.x_short = 0;
2785                 if (bomorder)           /* Little Endian */
2786                   x = 1 - x;            /* Save byte in appropriate half */
2787                 debug(F101,"XMIT UCS2 x","",x);
2788                 uc.x_char[x] = (CHAR) (c & 0xff);
2789                 if (nbytes & 1)         /* First byte, go back for next */
2790                   continue;
2791                 if (nbytes == 2) {      /* UCS-2 Byte Order Mark */
2792                     if (uc.x_short == (USHORT) 0xfeff) {
2793                         debug(F100,"XMIT UCS2 BOM FEFF","",bomorder);
2794                         continue;
2795                     } else if (uc.x_short == (USHORT) 0xfffe) {
2796                         bomorder = 1 - bomorder;
2797                         debug(F100,"XMIT UCS2 BOM FFFE (swap)","",bomorder);
2798                         continue;
2799                     }
2800                 }
2801                 sprintf(xbuf,"%04X",uc.x_short); /* SAFE */
2802                 debug(F111,"XMIT UCS2",xbuf,uc.x_short);
2803                 if (nbytes & 1)         /* Special eol test for UCS-2 */
2804                   if (uc.x_short == '\n')
2805                     eol = 1;
2806 #ifdef COMMENT
2807                 if (uc.x_short == 0x2028 || uc.x_short == 0x2029)
2808                     eol = 1;
2809 #endif /* COMMENT */
2810             } else
2811 #endif /* UNICODE */
2812               if (c == '\n') {          /* Normal eol test otherwise */
2813                   eol = 1;
2814             }
2815             if (eol) {                  /* End of line? */
2816                 int stuff = -1;
2817                 debug(F101,"XMIT eol length","",i);
2818                 if (i == 0) {           /* Blank line? */
2819                     if (xmitf)          /* Yes, insert fill if asked. */
2820                       line[i++] = dopar((char) xmitf);
2821                 }
2822                 if (i == 0 || ((char) line[i-1]) != ((char) dopar(CR)))
2823                   line[i++] = dopar(CR); /* Terminate it with CR */
2824                 if (xmitl) {
2825                     stuff = LF;
2826 #ifdef TNCODE
2827                 } else if (is_tn && (tn_nlm != TNL_CR)) {
2828                     /* TELNET NEWLINE ON/OFF/RAW */
2829                     stuff = (tn_nlm == TNL_CRLF) ? LF : NUL;
2830 #endif /* TNCODE */
2831                 }
2832                 if (stuff > -1)
2833                   line[i++] = dopar((char)stuff);
2834                 line[i] = NUL;
2835                 debug(F111,"XMIT eol line",line,i);
2836
2837             } else if (c != -1) {       /* Not a newline, regular character */
2838                 int k, x;
2839                 outxbuf[0] = c;         /* In case of no translation */
2840                 outxcount = 1;          /* Assume result is one byte */
2841 #ifndef NOCSETS
2842                 switch (unicode) {
2843                   case 0:               /* No Unicode involved */
2844                   case 1:
2845                     if (xlate) {        /* If not /TRANSPARENT */
2846                         /* Local-to-intermediate */
2847                         if (sxo) c = (*sxo)((char)c);
2848                         /* Intermediate-to-remote */
2849                         if (rxo) c = (*rxo)((char)c);
2850                         outxbuf[0] = c;
2851                     }
2852                     break;
2853 #ifdef UNICODE
2854                   case 2:               /* Local byte to UTF-8 */
2855                   case 3:
2856                     xfu = xl_fcu[fcharset];
2857                     tcssize = fcsinfo[fcharset].size;
2858                     outxcount =
2859                       b_to_u((CHAR)c,outxbuf,OUTXBUFSIZ,tcssize);
2860                     break;
2861                   case 4:               /* Local UTF-8 to remote byte */
2862                   case 5:
2863                     xuf = xl_ufc[tcsr];
2864                     x = u_to_b((CHAR)c); /* Convert to byte */
2865                     if (x == -1) {      /* If more input bytes needed */
2866                         continue;       /* go back and get them */
2867                     } else if (x == -2) { /* LS or PS (shouldn't happen) */
2868                         outxbuf[0] = CR;
2869                     } else if (x == -9) { /* UTF-8 error */
2870                         outxbuf[0] = '?'; /* Insert error char */
2871                         outxbuf[1] = u_to_b2(); /* Insert next char */
2872                         outxcount = 2;
2873                     } else {
2874                         outxbuf[0] =    /* Otherwise store result */
2875                           (unsigned)(x & 0xff);
2876                     }
2877                     break;
2878                   case 6:               /* UTF-8 to UTF-8 */
2879                   case 7:
2880                     break;
2881                   case 8:               /* UCS-2 to byte */
2882                   case 9:
2883                     xuf = xl_ufc[tcsr];
2884                     outxbuf[0] = (*xuf)(uc.x_short);
2885                     break;
2886                   case 10:
2887                   case 11: {            /* UCS-2 to UTF-8 */
2888                       int j;
2889                       CHAR * buf = NULL;
2890                       x = ucs2_to_utf8(uc.x_short,&buf);
2891                       if (x < 0) {
2892                           outxbuf[0] = 0xff; /* (= U+FFFD) */
2893                           outxbuf[1] = 0xbd;
2894                           x = 2;
2895                       }
2896                       for (j = 0; j < x; j++)
2897                         outxbuf[j] = buf[j];
2898                       outxcount = x;
2899                       break;
2900                   }
2901 #endif /* UNICODE */
2902                 }
2903 #endif /* NOCSETS */
2904                 outxbuf[outxcount] = NUL;
2905                 debug(F111,"XMIT outxbuf",outxbuf,outxcount);
2906 /*
2907   Now the input character (1 or more bytes) is translated into the output
2908   expansion buffer (1 or more bytes); outxcount = number of bytes to add to
2909   the TRANSMIT line buffer, which we do here, taking care of parity, SI/SO
2910   processing, and quoting Telnet IACs.
2911 */
2912                 for (k = 0; k < outxcount; k++) {
2913                     c = outxbuf[k];
2914                     if (xmits && parity && (c & 0200)) { /* If shifting */
2915                         line[i++] = dopar(SO); /* needs to be done, */
2916                         line[i++] = dopar((char)c); /* do it here, */
2917                         line[i++] = dopar(SI); /* crudely. */
2918                     } else {
2919                         line[i++] = dopar((char)c);
2920 #ifdef TNCODE
2921                         if (c == IAC && is_tn)
2922                           line[i++] = IAC;
2923 #endif /* TNCODE */
2924                     }
2925                 }
2926             }
2927 /*
2928   Send characters if buffer full, or at end of line, or at end of file.
2929   (End of line only if echoing, waiting for a prompt, or pausing.)
2930 */
2931             debug(F000,"XMIT c",ckitoa(i),c);
2932             if (i >= xbufsiz || eof || (eol && (xxecho || xmitw || t))) {
2933                 p = line;
2934                 line[i] = '\0';
2935                 debug(F111,"transmit buf",p,i);
2936                 if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
2937                     printf("?TRANSMIT output error: %s\n",ck_errstr());
2938                     rc = 0;
2939                     break;
2940                 }
2941                 i = 0;                  /* Reset buffer pointer. */
2942 /*
2943   Now we handle the echo.  If the user wants to see it, or if we have to
2944   wait for the turnaround character, t.  If the echo is being displayed,
2945   and terminal character-set translation is required, we do it here.
2946 */
2947                 if (duplex && xxecho) {  /* If local echo, echo it */
2948                     if (parity || cmdmsk == 0x7f) { /* Strip hi bits */
2949                         char *ss = line;             /* if necessary */
2950                         while (*ss) {
2951                             *ss &= 0x7f;
2952                             ss++;
2953                         }
2954                     }
2955 #ifndef NOLOCAL
2956 #ifdef OS2
2957                     {                   /* Echo to emulator */
2958                         char *ss = p;
2959                         while (*ss) {
2960                             scriptwrtbuf((USHORT)*ss);
2961                             ss++;
2962                         }
2963                     }
2964 #endif /* OS2 */
2965 #endif /* NOLOCAL */
2966                     if (conoll(p) < 0)
2967                       goto xmitfail;
2968                 }
2969                 if (xmitw)              /* Sleep TRANSMIT PAUSE interval */
2970                   msleep(xmitw);
2971
2972                 control = 0;            /* Readback loop control */
2973                 if (t != 0 && eol)      /* TRANSMIT PROMPT given and at EOL */
2974                   control |= 1;
2975                 if (xxecho && !duplex)   /* Echo desired and is remote */
2976                   control |= 2;
2977
2978                 if (control) {          /* Do this if reading back the echo */
2979                     int n;
2980                     x = 0;
2981                     while (1) {
2982                         if (control & 1) { /* Termination criterion */
2983                             if (x == t)    /* for turnaround */
2984                               break;
2985                         } else if (control & 2) { /* And for echoing */
2986                             if ((n = ttchk()) < 1)
2987                               break;
2988                         }
2989                         if ((x = ttinc(xmitt)) < 0) { /* Read with timeout */
2990                             switch (x) {
2991                               case -2:
2992                                 printf("Connection closed.\n");
2993                                 ttclos(1);
2994                                 goto xmitfail;
2995                               case -3:
2996                                 printf(
2997                               "Session Limit exceeded - closing connection.\n"
2998                                        );
2999                                 ttclos(1); /* full thru... */
3000                                 goto xmitfail;
3001                               default:
3002                                 printf("?Timeout\n");
3003                                 goto xmitfail;
3004                             }
3005                         }
3006                         if (x > -1 && (control & 2)) { /* Echo any echoes */
3007                             if (parity)
3008                               x &= 0x7f;
3009                             c = x;
3010 #ifndef NOLOCAL
3011 #ifdef OS2
3012                             scriptwrtbuf((USHORT)x);
3013 #endif /* OS2 */
3014 #endif /* NOLOCAL */
3015                             inxbuf[0] = c;
3016                             inxcount = 1;
3017 #ifndef NOCSETS
3018                             switch (unicode & 3) { /* Remote bits */
3019                               case 0:
3020                                 if (xlate) {
3021                                     if (sxi) c = (*sxi)((CHAR)c);
3022                                     if (rxi) c = (*rxi)((CHAR)c);
3023                                     inxbuf[0] = c;
3024                                 }
3025                                 break;
3026 #ifdef UNICODE
3027                               case 1:   /* Remote Byte to local UTF-8 */
3028                                 xfu = xl_fcu[tcsr];
3029                                 tcssize = fcsinfo[tcsr].size;
3030                                 inxcount =
3031                                   b_to_u((CHAR)c,
3032                                          inxbuf,
3033                                          OUTXBUFSIZ,
3034                                          tcssize
3035                                          );
3036                                 break;
3037                               case 2:   /* Remote UTF-8 to local Byte */
3038                                 xuf = xl_ufc[tcsl];
3039                                 x = u_to_b((CHAR)c);
3040                                 if (x < 0)
3041                                   continue;
3042                                 inxbuf[0] = (unsigned)(x & 0xff);
3043                                 break;
3044                               case 3:   /* UTF-8 to UTF-8 */
3045                                 break;
3046 #endif /* UNICODE */
3047                             }
3048 #endif /* NOCSETS */
3049                             inxbuf[inxcount] = NUL;
3050                             if (conxo(inxcount,(char *)inxbuf) < 0)
3051                               goto xmitfail;
3052                         }
3053                     }
3054                 } else                  /* Not echoing */
3055                   ttflui();             /* Just flush input buffer */
3056             } /* End of buffer-dumping block */
3057         } /* End of text mode */
3058         if (eof) {
3059             rc = 1;
3060             goto xmitexit;
3061         }
3062     } /* End of character-reading loop */
3063
3064   xmitfail:                             /* Failure exit point */
3065     rc = 0;
3066
3067   xmitexit:                             /* General exit point */
3068     if (rc > 0) {
3069         if (binary && !xmitw && !xxecho) { /* "blasting"? */
3070             while (count > 0) {            /* Partial buffer still to go? */
3071                 errno = 0;
3072                 y = ttol(xbbuf,count);
3073                 if (y < 0) {
3074                     printf("?TRANSMIT output error: %s\n",
3075                            ck_errstr());
3076                     debug(F111,"XMIT binary eof ttol error",
3077                           ck_errstr(),errno);
3078                     rc = 0;
3079                     break;
3080                 }
3081                 count -= y;
3082             }
3083         } else if (!binary && *xmitbuf) { /* Anything to send at EOF? */
3084             p = xmitbuf;                /* Yes, point to string. */
3085             while (*p)                  /* Send it. */
3086               ttoc(dopar(*p++));        /* Don't worry about echo here. */
3087         }
3088     }
3089
3090 #ifndef AMIGA
3091 #ifndef MAC
3092     signal(SIGINT,oldsig);              /* Put old signal action back. */
3093 #endif /* MAC */
3094 #endif /* AMIGA */
3095 #ifdef VMS
3096     concb(escape);                      /* Put terminal back, */
3097 #endif /* VMS */
3098     zclose(ZIFILE);                     /* Close file, */
3099 #ifndef NOCSETS
3100     language = langsv;                  /* restore language, */
3101 #endif /* NOCSETS */
3102     ttres();                            /* and terminal modes, */
3103     return(rc);                         /* and return successfully. */
3104 }
3105 #endif /* NOLOCAL */
3106 #endif /* NOXMIT */
3107
3108 #ifndef NOCSETS
3109
3110 _PROTOTYP( CHAR (*sxx), (CHAR) );       /* Local translation function */
3111 _PROTOTYP( CHAR (*rxx), (CHAR) );       /* Local translation function */
3112 _PROTOTYP( CHAR zl1as, (CHAR) );        /* Latin-1 to ascii */
3113 _PROTOTYP( CHAR xl1as, (CHAR) );        /* ditto */
3114
3115 /*  X L A T E  --  Translate a local file from one character set to another */
3116
3117 /*
3118   Translates input file (fin) from character set csin to character set csout
3119   and puts the result in the output file (fout).  The two character sets are
3120   file character sets from fcstab.
3121 */
3122
3123 int
3124 xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
3125
3126 #ifndef MAC
3127 #ifdef OS2
3128     extern int k95stdout;
3129     extern int wherex[], wherey[];
3130     extern unsigned char colorcmd;
3131 #ifdef NT
3132     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
3133 #else /* NT */
3134     SIGTYP (* volatile oldsig)(int);    /* For saving old interrupt trap. */
3135 #endif /* NT */
3136 #else /* OS2 */
3137     SIGTYP (* oldsig)();
3138 #endif /* OS2 */
3139 #endif /* MAC */
3140 #ifdef CK_ANSIC
3141     int (*fn)(char);                    /* Output function pointer */
3142 #else
3143     int (*fn)();
3144 #endif /* CK_ANSIC */
3145     extern int xlatype;
3146     int filecode;                       /* Code for output file */
3147     int scrnflg = 0;
3148
3149     int z = 1;                          /* Return code. */
3150     int x, c, c2;                       /* Workers */
3151 #ifndef UNICODE
3152     int tcs;
3153 #endif /* UNICODE */
3154
3155     ffc = 0L;
3156
3157     if (zopeni(ZIFILE,fin) == 0) {      /* Open the file to be translated */
3158 #ifdef COMMENT
3159         /* An error message was already printed by zopeni() */
3160         printf("?Can't open input file %s\n",fin);
3161 #endif /* COMMENT */
3162         return(0);
3163     }
3164 #ifdef MAC
3165 /*
3166   If user specified no output file, it goes to the screen.  For the Mac,
3167   this must be done a special way (result goes to a new window); the Mac
3168   doesn't have a "controlling terminal" device name.
3169 */
3170     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
3171 #else
3172 #ifdef VMS
3173     filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZMFILE;
3174 #else
3175 #ifdef OS2
3176     filecode = (!stricmp(fout,"con") || !stricmp(fout,"con:")) ?
3177         ZCTERM : ZMFILE;
3178     if ((filecode == ZCTERM) && !k95stdout && !inserver)
3179         csout = FC_UCS2;
3180 #else /* OS2 */
3181     filecode = ZOFILE;
3182 #endif /* OS2 */
3183 #endif /* VMS */
3184 #endif /* MAC */
3185     if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
3186         printf("?Can't open output file %s\n",fout);
3187         return(0);
3188     }
3189 #ifndef AMIGA
3190 #ifndef MAC
3191     oldsig = signal(SIGINT, trtrap);    /* Save current interrupt trap. */
3192 #endif /* MAC */
3193 #endif /* AMIGA */
3194
3195     scrnflg = (filecode == ZCTERM);     /* Set output function */
3196     if (scrnflg)
3197       fn = NULL;
3198     else if (filecode == ZMFILE)
3199       fn = putmfil;
3200     else
3201       fn = putfil;
3202
3203     tr_int = 0;                         /* Have not been interrupted (yet). */
3204     z = 1;                              /* Return code presumed good. */
3205
3206     if (!scrnflg && !quiet)
3207       printf(" %s (%s) => %s (%s)\n",   /* Say what we're doing. */
3208              fin, fcsinfo[csin].keyword,
3209              fout,fcsinfo[csout].keyword
3210              );
3211
3212 #ifndef UNICODE
3213 /*
3214   Non-Unicode picks the "most appropriate" transfer character set as the
3215   intermediate set, which results in loss of any characters that the source
3216   and target sets have in common, but are lacking from the intermediate set.
3217 */
3218 #ifdef KANJI
3219     /* Special handling for Japanese... */
3220
3221     if (fcsinfo[csin].alphabet == AL_JAPAN ||
3222          fcsinfo[csout].alphabet == AL_JAPAN) {
3223         USHORT eu;
3224         int c, x, y;
3225
3226         xpnbyte(-1,0,0,NULL);           /* Reset output machine */
3227         xlatype = XLA_JAPAN;
3228
3229         while ((c = xgnbyte(FC_JEUC,csin,NULL)) > -1) { /* Get an EUC byte */
3230             if (tr_int) {               /* Interrupted? */
3231                 printf("^C...\n");      /* Print message */
3232                 z = 0;
3233                 break;
3234             }
3235             /* Send EUC byte to output machine */
3236             if ((x = xpnbyte(c,TC_JEUC,csout,fn)) < 0) {
3237                 z = -1;
3238                 break;
3239             }
3240         }
3241         goto xxlate;
3242     }
3243 #endif /* KANJI */
3244
3245     /* Regular bytewise conversion... */
3246
3247     tcs = gettcs(csin,csout);           /* Get intermediate set. */
3248     if (csin == csout) {                /* Input and output sets the same? */
3249         sxx = rxx = NULL;               /* If so, no translation. */
3250     } else {                            /* Otherwise, set up */
3251         if (tcs < 0 || tcs > MAXTCSETS ||
3252             csin < 0 || csin > MAXFCSETS ||
3253             csout < 0 || csout > MAXFCSETS) {
3254             debug(F100,"XLATE csets out of range","",0);
3255             sxx = rxx = NULL;
3256         } else {
3257             sxx = xls[tcs][csin];       /* translation function */
3258             rxx = xlr[tcs][csout];      /* pointers. */
3259             if (rxx == zl1as) rxx = xl1as;
3260         }
3261     }
3262     while ((c = zminchar()) != -1) { /* Loop for all characters in file */
3263         if (tr_int) {                   /* Interrupted? */
3264             printf("^C...\n");          /* Print message */
3265             z = 0;
3266             break;
3267         }
3268         if (sxx) c = (*sxx)((CHAR)c);   /* From fcs1 to tcs */
3269         if (rxx) c = (*rxx)((CHAR)c);   /* from tcs to fcs2 */
3270         if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
3271             z = -1;
3272             break;
3273         }
3274     }
3275     goto xxlate;                        /* Done. */
3276
3277 #else  /* UNICODE */
3278 /*
3279    Use Unicode as the intermediate character set.  It's simple and gives
3280    little or no loss, but the overhead is a bit higher.
3281 */
3282     initxlate(csin,csout);              /* Set up translation functions */
3283
3284     if (xlatype == XLA_NONE) {
3285         while ((c = zminchar()) != -1) { /* Loop for all characters in file */
3286             if (tr_int) {               /* Interrupted? */
3287                 printf("^C...\n");      /* Print message */
3288                 z = 0;
3289                 break;
3290             }
3291             if (zchout(filecode,(char)c) < 0) { /* Output xlated character */
3292                 z = -1;
3293                 break;
3294             }
3295         }
3296         goto xxlate;                    /* Done. */
3297     }
3298
3299
3300 #ifndef NOLOCAL
3301 #ifdef OS2
3302     if (csout == FC_UCS2 &&             /* we're translating to UCS-2 */
3303         filecode == ZCTERM &&           /* for the real screen... */
3304         !k95stdout && !inserver
3305         ) {
3306         union {
3307             USHORT ucs2;
3308             UCHAR  bytes[2];
3309         } output;
3310
3311         while (1) {                     /* In this case we go two-by-two. */
3312             if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
3313               break;
3314             output.bytes[0] = c;
3315             if ((c = xgnbyte(FC_UCS2,csin,NULL)) < 0)
3316               break;
3317             output.bytes[1] = c;
3318
3319             if (tr_int) {               /* Interrupted? */
3320                 printf("^C...\n");      /* Print message */
3321                 z = 0;
3322                 break;
3323             }
3324
3325             VscrnWrtUCS2StrAtt(VCMD,
3326                                &output.ucs2,
3327                                1,
3328                                wherey[VCMD],
3329                                wherex[VCMD],
3330                                &colorcmd
3331                                );
3332         }
3333     } else
3334 #endif /* OS2 */
3335 #endif /* NOLOCAL */
3336
3337       /* General case: Get next byte translated from fcs to UCS-2 */
3338
3339 #ifdef COMMENT
3340       while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1 &&
3341               (c2 = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
3342           extern int fileorder;
3343
3344           if (tr_int) {                 /* Interrupted? */
3345               printf("^C...\n");        /* Print message */
3346               z = 0;
3347               break;
3348           }
3349           debug(F001,"XLATE c","",c);
3350           debug(F001,"XLATE c2","",c2);
3351
3352           /* And then send UCS-2 byte to translate-and-output machine */
3353
3354           if ((x = xpnbyte(fileorder?c2:c,TC_UCS2,csout,fn)) < 0) {
3355               z = -1;
3356               break;
3357           }
3358           if ((x = xpnbyte(fileorder?c:c2,TC_UCS2,csout,fn)) < 0) {
3359               z = -1;
3360               break;
3361           }
3362       }
3363 #else
3364     while ((c = xgnbyte(FC_UCS2,csin,NULL)) > -1) {
3365           if (tr_int) {                 /* Interrupted? */
3366               printf("^C...\n");        /* Print message */
3367               z = 0;
3368               break;
3369           }
3370           if ((x = xpnbyte(c,TC_UCS2,csout,fn)) < 0) {
3371               z = -1;
3372               break;
3373           }
3374       }
3375 #endif /* COMMENT */
3376
3377 #endif /* UNICODE */
3378
3379   xxlate:                               /* Common exit point */
3380
3381 #ifndef AMIGA
3382 #ifndef MAC
3383     signal(SIGINT,oldsig);              /* Put old signal action back. */
3384 #endif /* MAC */
3385 #endif /* AMIGA */
3386     tr_int = 0;
3387     if (z < 0) {
3388         if (z == -1)
3389           printf("?File output error: %s\n",ck_errstr());
3390         z = 0;
3391     }
3392     zclose(ZIFILE);                     /* Close files */
3393     zclose(filecode);                   /* ... */
3394     return(success = z);                /* and return status. */
3395 }
3396
3397 int
3398 doxlate() {
3399 #ifdef OS2ONLY
3400     extern int tt_font;
3401 #endif /* OS2ONLY */
3402 #ifdef UNIX
3403     extern char ** mtchs;               /* zxpand() file list */
3404 #endif /* UNIX */
3405     extern int nfilc;
3406     extern struct keytab fcstab[];
3407     int x, y, incs, outcs, multiple = 0, wild = 0, fc = 0, len = 0;
3408     int ofisdir = 0;
3409     char * s, * tocs = "";
3410
3411     if ((x = cmifi("File(s) to translate","",&s,&wild,xxstring)) < 0) {
3412         if (x == -3) {
3413             printf("?Name of an existing file\n");
3414             return(-9);
3415         } else
3416           return(x);
3417     }
3418     ckstrncpy(line,s,LINBUFSIZ);        /* Save copy of string just parsed. */
3419
3420     if ((incs = cmkey(fcstab,nfilc,"from character-set","",xxstring)) < 0)
3421       return(incs);
3422
3423 #ifdef OS2
3424     if (isunicode())
3425       tocs = "ucs2";
3426     else
3427 #endif /* OS2 */
3428       tocs = getdcset();
3429
3430     if ((outcs = cmkey(fcstab,nfilc,"to character-set",tocs,xxstring)) < 0)
3431       return(outcs);
3432     if ((x = cmofi("output file",CTTNAM,&s,xxstring)) < 0) return(x);
3433     if (x > 1)
3434       ofisdir = 1;
3435
3436     len = ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3437     if ((y = cmcfm()) < 0) return(y);   /* Confirm the command */
3438
3439     if (len < 1)
3440       return(-2);
3441
3442     if (ofisdir)
3443       multiple = 2;
3444     else if (wild) {
3445         if (isdir(tmpbuf))
3446           multiple = 2;
3447         else if (!strcmp(tmpbuf,CTTNAM))
3448           multiple = 1;
3449 #ifdef OS2
3450         else if (!stricmp(tmpbuf,"con") || !stricmp(tmpbuf,"con:"))
3451           multiple = 1;
3452 #else
3453 #ifdef UNIXOROSK
3454         else if (!strncmp(tmpbuf,"/dev/",4))
3455           multiple = 1;
3456 #endif /* UNIXOROSK */
3457 #endif /* OS2 */
3458         if (!multiple) {
3459             printf("?A single file please\n");
3460             return(-9);
3461         }
3462     }
3463     if (!multiple) {                    /* Just one file */
3464         return(success = xlate(line,tmpbuf,incs,outcs));
3465     } else {                            /* Translate multiple files */
3466         char dirbuf[CKMAXPATH+4];
3467         int k;
3468 #ifndef ZXREWIND
3469         int flags = ZX_FILONLY;
3470 #endif /* ZXREWIND */
3471
3472         if (multiple == 2) {            /* Target is a directory */
3473             k = ckstrncpy(dirbuf,tmpbuf,CKMAXPATH+1) - 1;
3474             if (k < 0)
3475               return(-2);
3476 #ifdef OS2ORUNIX
3477             if (dirbuf[k] != '/') {
3478                 dirbuf[k+1] = '/';
3479                 dirbuf[k+2] = NUL;
3480             }
3481 #else
3482 #ifdef OSK
3483             if (dirbuf[k] != '/') {
3484                 dirbuf[k+1] = '/';
3485                 dirbuf[k+2] = NUL;
3486             }
3487 #else
3488 #ifdef VMS
3489             if (ckmatch("*.DIR;1",s,0,0))
3490               k = cvtdir(tmpbuf,dirbuf,TMPBUFSIZ);
3491             if (dirbuf[k] != ']' &&
3492                 dirbuf[k] != '>' &&
3493                 dirbuf[k] != ':')
3494               return(-2);
3495 #else
3496 #ifdef datageneral
3497             if (dirbuf[k] != ':') {
3498                 dirbuf[k+1] = ':';
3499                 dirbuf[k+2] = NUL;
3500             }
3501 #else
3502 #ifdef STRATUS
3503             if (dirbuf[k] != '>') {
3504                 dirbuf[k+1] = '>';
3505                 dirbuf[k+2] = NUL;
3506             }
3507 #endif /* STRATUS */
3508 #endif /* datageneral */
3509 #endif /* VMS */
3510 #endif /* OSK */
3511 #endif /* OS2ORUNIX */
3512         }
3513
3514 #ifdef ZXREWIND
3515         fc = zxrewind();                /* Rewind the file list */
3516 #else
3517         if (matchdot)  flags |= ZX_MATCHDOT;
3518         fc = nzxpand(line,flags);
3519 #endif /* ZXREWIND */
3520
3521         if (fc < 1) {
3522             printf("?Wildcard expansion error\n");
3523             return(-9);
3524         }
3525 #ifdef UNIX
3526         sh_sort(mtchs,NULL,fc,0,0,filecase); /* Sort the file list */
3527 #endif /* UNIX */
3528
3529         while (1) {                     /* Loop through the files */
3530             znext(line);
3531             if (!line[0])
3532               break;
3533             if (multiple == 2)
3534               ckmakmsg(tmpbuf,TMPBUFSIZ,dirbuf,line,NULL,NULL);
3535             if (xlate(line,tmpbuf,incs,outcs) < 1)
3536               return(success = 0);
3537         }
3538     }
3539     return(success = 1);
3540 }
3541 #endif /* NOCSETS */
3542
3543 static char hompthbuf[CKMAXPATH+1];
3544
3545 char *
3546 homepath() {
3547     int x;
3548     extern char * myhome;
3549     char * h;
3550
3551     h = myhome ? myhome : zhome();
3552     hompthbuf[0] = NUL;
3553 #ifdef UNIXOROSK
3554     x = ckstrncpy(hompthbuf,h,CKMAXPATH+1);
3555     if (x <= 0) {
3556         hompthbuf[0] = '/';
3557         hompthbuf[1] = NUL;
3558     } else if (x < CKMAXPATH - 2 && hompthbuf[x-1] != '/') {
3559         hompthbuf[x] = '/';
3560         hompthbuf[x+1] = NUL;
3561     }
3562     return(hompthbuf);
3563 #else
3564 #ifdef STRATUS
3565     if (strlen(h) < CKMAXPATH)
3566       sprintf(hompthbuf,"%s>",h);       /* SAFE */
3567     return(hompthbuf);
3568 #else
3569     return(h);
3570 #endif /* STRATUS */
3571 #endif /* UNIXOROSK */
3572 }
3573
3574 /*  D O L O G  --  Do the log command  */
3575
3576 int
3577 dolog(x) int x; {
3578     int y, disp; char *s = NULL, * p = NULL, * q = NULL;
3579     extern int isguest;
3580 #ifdef ZFNQFP
3581     struct zfnfp * fnp;
3582 #endif /* ZFNQFP */
3583
3584     if (isguest) {
3585         printf("?Anonymous log creation not allowed\n");
3586         return(-9);
3587     }
3588     switch (x) {                        /* Which log... */
3589
3590 #ifdef DEBUG
3591       case LOGD:
3592         q = "debug.log";
3593         y = cmofi("Name of debugging log file",q,&s,xxstring);
3594         break;
3595 #endif /* DEBUG */
3596
3597       case LOGP:
3598         q = "packet.log";
3599         y = cmofi("Name of packet log file",q,&s,xxstring);
3600         break;
3601
3602 #ifndef NOLOCAL
3603       case LOGS:
3604         q = "session.log";
3605         y = cmofi("Name of session log file",q,&s,xxstring);
3606         break;
3607 #endif /* NOLOCAL */
3608
3609 #ifdef TLOG
3610       case LOGT:
3611         q = "transact.log";
3612         y = cmofi("Name of transaction log file",q,&s,xxstring);
3613         break;
3614 #endif /* TLOG */
3615
3616 #ifdef CKLOGDIAL
3617       case LOGM: {
3618           int m, n;
3619           char mypath[CKMAXPATH+1];
3620           q = CXLOGFILE;
3621           m = ckstrncpy(mypath,homepath(),CKMAXPATH);
3622           n = strlen(CXLOGFILE);
3623           if (m + n < CKMAXPATH)
3624             ckstrncat(mypath,CXLOGFILE,CKMAXPATH);
3625           else
3626             ckstrncpy(mypath,CXLOGFILE,CKMAXPATH);
3627           y = cmofi("Name of connection log file",mypath,&s,xxstring);
3628           break;
3629       }
3630 #endif /* CKLOGDIAL */
3631
3632       default:
3633         printf("\n?Unknown log designator - %d\n",x);
3634         return(-2);
3635     }
3636     if (y < 0) return(y);
3637     if (y == 2) {                       /* If they gave a directory name */
3638         int k;
3639         char * ds = "/";
3640         k = strlen(s);
3641         if (k > 0 && s[k-1] == '/') ds = "";
3642         ckmakmsg(tmpbuf,TMPBUFSIZ,s,ds,q,NULL);
3643         s = tmpbuf;
3644     }
3645 #ifdef ZFNQFP
3646 #ifdef OS2ORUNIX
3647     if (*s != '|')                      /* Allow for pipes */
3648 #else
3649 #ifdef OSK
3650     if (*s != '|')
3651 #endif /* OSK */
3652 #endif /* OS2ORUNIX */
3653       if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
3654           if (fnp->fpath)
3655             if ((int) strlen(fnp->fpath) > 0)
3656               s = fnp->fpath;
3657       } /* else if error keep original string */
3658 #endif /* ZFNQFP */
3659
3660     ckstrncpy(line,s,LINBUFSIZ);
3661     s = line;
3662 #ifdef MAC
3663     y = 0;
3664 #else
3665
3666     p = "new";
3667 #ifdef TLOG
3668     if ((x == LOGT && tlogfmt == 2) || x == LOGM)
3669       p = "append";
3670 #endif /* TLOG */
3671
3672     if ((y = cmkey(disptb,2,"Disposition",p,xxstring)) < 0)
3673       return(y);
3674 #endif /* MAC */
3675     disp = y;
3676     if ((y = cmcfm()) < 0) return(y);
3677
3678     switch (x) {
3679
3680 #ifdef DEBUG
3681       case LOGD:
3682         return(deblog = debopn(s,disp));
3683 #endif /* DEBUG */
3684
3685 #ifndef NOXFER
3686       case LOGP:
3687         return(pktlog = pktopn(s,disp));
3688 #endif /* NOXFER */
3689
3690 #ifndef NOLOCAL
3691       case LOGS:
3692         setseslog(sesopn(s,disp));
3693         return(seslog);
3694 #endif /* NOLOCAL */
3695
3696 #ifdef TLOG
3697       case LOGT:
3698         return(tralog = traopn(s,disp));
3699 #endif /* TLOG */
3700
3701 #ifdef CKLOGDIAL
3702       case LOGM:
3703         return(dialog = diaopn(s,disp,0));
3704 #endif /* CKLOGDIAL */
3705
3706       default:
3707         return(-2);
3708     }
3709 }
3710
3711 #ifndef NOXFER
3712 int
3713 pktopn(s,disp) char *s; int disp; {
3714     static struct filinfo xx;
3715
3716     if (!s)
3717       s = "";
3718     if (!*s)
3719       return(0);
3720
3721     debug(F111,"pktopn",s,disp);
3722
3723     zclose(ZPFILE);
3724
3725 #ifdef OS2ORUNIX
3726     if (s[0] == '|') {                  /* Pipe */
3727         char * p = s + 1;
3728         debug(F110,"pktopn p",p,0);
3729         while (*p) {
3730             if (*p != ' ')
3731               break;
3732             else
3733               p++;
3734         }
3735         debug(F110,"pktopn pipe",p,0);
3736         pktlog = zxcmd(ZPFILE,p);
3737         debug(F101,"pktopn seslog","",seslog);
3738     } else {                            /* File */
3739 #endif /* OS2ORUNIX */
3740         if (disp) {
3741             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3742             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3743             xx.lblopts = 0;
3744             pktlog = zopeno(ZPFILE,s,NULL,&xx);
3745         } else pktlog = zopeno(ZPFILE,s,NULL,NULL);
3746         if (!pktlog)
3747           printf("?%s - %s\n",s,ck_errstr());
3748 #ifdef OS2ORUNIX
3749     }
3750 #endif /* OS2ORUNIX */
3751     if (pktlog > 0)
3752       ckstrncpy(pktfil,s,CKMAXPATH+1);
3753     else
3754       *pktfil = '\0';
3755     return(pktlog);
3756 }
3757 #endif /* NOXFER */
3758
3759 int
3760 traopn(s,disp) char *s; int disp; {
3761 #ifdef TLOG
3762     static struct filinfo xx;
3763
3764     if (!s)
3765       s = "";
3766     if (!*s)
3767       return(0);
3768
3769     debug(F111,"traopn",s,disp);
3770     debug(F101,"traopn tlogfmt","",tlogfmt);
3771
3772     zclose(ZTFILE);
3773
3774 #ifdef OS2ORUNIX
3775     if (tlogfmt == 2) {                 /* FTP format is special... */
3776         VOID doiklog();
3777         if (!disp)                      /* Append? */
3778           if (zchki(s) > -1)            /* No - does file exist? */
3779             (VOID) zdelet(s);           /* Yes - delete it. */
3780         xferlog = 1;
3781         ckstrncpy(trafil,s,CKMAXPATH);
3782         makestr(&xferfile,s);
3783         doiklog();
3784         return(1);
3785     }
3786     if (s[0] == '|') {                  /* Pipe */
3787         char * p = s + 1;
3788         debug(F110,"traopn p",p,0);
3789         while (*p) {
3790             if (*p != ' ')
3791               break;
3792             else
3793               p++;
3794         }
3795         debug(F110,"traopn pipe",p,0);
3796         tralog = zxcmd(ZTFILE,p);
3797         debug(F101,"traopn tralog","",tralog);
3798     }
3799 #endif /* OS2ORUNIX */
3800
3801     if (s[0] != '|') {                  /* File */
3802         if (disp) {
3803             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3804             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3805             xx.lblopts = 0;
3806             tralog = zopeno(ZTFILE,s,NULL,&xx);
3807         } else tralog = zopeno(ZTFILE,s,NULL,NULL);
3808     }
3809     if (!tralog)
3810       printf("?%s - %s\n",s,ck_errstr());
3811     if (tralog > 0 && tlogfmt > 0) {
3812         ckstrncpy(trafil,s,CKMAXPATH);
3813         tlog(F110,"Transaction Log:",versio,0L);
3814 #ifndef MAC
3815         tlog(F100,ckxsys,"",0L);
3816 #endif /* MAC */
3817         ztime(&s);
3818         tlog(F100,s,"",0L);
3819     } else
3820       *trafil = '\0';
3821     return(tralog);
3822 #else
3823     return(0);
3824 #endif /* TLOG */
3825 }
3826
3827 #ifndef NOLOCAL
3828 int
3829 sesopn(s,disp) char * s; int disp; {
3830     static struct filinfo xx;
3831     extern int tsstate;
3832
3833     tsstate = 0;                        /* Session log timestamp state */
3834
3835     if (!s)
3836       s = "";
3837     if (!*s)
3838       return(0);
3839
3840     debug(F111,"sesopn",s,disp);
3841
3842     zclose(ZSFILE);
3843
3844 #ifdef OS2ORUNIX
3845     if (s[0] == '|') {                  /* Pipe */
3846         char * p = s + 1;
3847         debug(F110,"sesopn p",p,0);
3848         while (*p) {
3849             if (*p != ' ')
3850               break;
3851             else
3852               p++;
3853         }
3854         debug(F110,"sesopn pipe",p,0);
3855         setseslog(zxcmd(ZSFILE,p));
3856         debug(F101,"sesopn seslog","",seslog);
3857     } else {                            /* File */
3858 #endif /* OS2ORUNIX */
3859         if (disp) {
3860             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3861             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3862             xx.lblopts = 0;
3863             setseslog(zopeno(ZSFILE,s,NULL,&xx));
3864         } else
3865           setseslog(zopeno(ZSFILE,s,NULL,NULL));
3866         if (!seslog)
3867           printf("?%s - %s\n",s,ck_errstr());
3868 #ifdef OS2ORUNIX
3869     }
3870 #endif /* OS2ORUNIX */
3871     if (seslog > 0)
3872       ckstrncpy(sesfil,s,CKMAXPATH+1);
3873     else
3874       *sesfil = '\0';
3875     return(seslog);
3876 }
3877 #endif /* NOLOCAL */
3878 #endif /* NOICP */
3879
3880 int
3881 debopn(s,disp) char *s; int disp; {
3882 #ifdef DEBUG
3883 #ifdef CK_UTSNAME
3884     extern char unm_mch[], unm_nam[], unm_rel[], unm_ver[], unm_mod[];
3885 #endif /* CK_UTSNAME */
3886 #ifdef OS2
3887     extern char ckxsystem[];
3888 #endif /* OS2 */
3889     char *tp;
3890     static struct filinfo xx;
3891
3892     if (!s)
3893       s = "";
3894     if (!*s)
3895       return(0);
3896
3897     zclose(ZDFILE);
3898
3899 #ifdef OS2ORUNIX
3900     if (s[0] == '|') {                  /* Pipe */
3901         char * p = s + 1;
3902         debug(F110,"debopn p",p,0);
3903         while (*p) {
3904             if (*p != ' ')
3905               break;
3906             else
3907               p++;
3908         }
3909         debug(F110,"debopn pipe",p,0);
3910         deblog = zxcmd(ZDFILE,p);
3911         debug(F101,"debopn deblog","",deblog);
3912     } else {                            /* File */
3913 #endif /* OS2ORUNIX */
3914         if (disp) {
3915             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
3916             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
3917             xx.lblopts = 0;
3918             deblog = zopeno(ZDFILE,s,NULL,&xx);
3919         } else
3920           deblog = zopeno(ZDFILE,s,NULL,NULL);
3921         if (!deblog)
3922           printf("?%s - %s\n",s,ck_errstr());
3923 #ifdef OS2ORUNIX
3924     }
3925 #endif /* OS2ORUNIX */
3926     if (deblog > 0) {
3927         ckstrncpy(debfil,s,CKMAXPATH+1);
3928         debug(F110,"Debug Log ",versio,0);
3929 #ifndef MAC
3930 #ifdef OS2
3931         debug(F110,ckxsys,ckxsystem,0);
3932 #else /* OS2 */
3933         debug(F100,ckxsys,"",0);
3934 #endif /* OS2 */
3935 #endif /* MAC */
3936 #ifdef CK_UTSNAME
3937         if (unm_mch[0]) {
3938             debug(F110,"uname machine",unm_mch,0);
3939             if (unm_mod[0])
3940               debug(F110,"uname model  ",unm_mod,0);
3941             debug(F110,"uname sysname",unm_nam,0);
3942             debug(F110,"uname release",unm_rel,0);
3943             debug(F110,"uname version",unm_ver,0);
3944         }
3945 #ifdef KTARGET
3946         {
3947             char * s;                   /* Makefile target */
3948             s = KTARGET;
3949             if (!s) s = "";
3950             if (!*s) s = "(unknown)";
3951             debug(F110,"build target",s,0);
3952         }
3953 #endif /* KTARGET */
3954         deblog = 0;
3955         ztime(&tp);
3956         deblog = 1;
3957         debug(F100,tp,"",0);
3958 #endif /* UTSNAME */
3959         debug(F101,"byteorder","",byteorder);
3960 #ifndef NOICP
3961 #ifndef NOLOCAL
3962         if (local) {
3963             debug(F110,"Active connection: ",ttname,0);
3964             if (!network) {
3965                 debug(F101,"Speed","",speed);
3966                 if (hwparity)
3967                   debug(F110,"Parity[hardware]",parnam((char)hwparity),0);
3968                 else
3969                   debug(F110,"Parity",parnam((char)parity),0);
3970                 deblog = 0;
3971                 debug(F110,"Modem",gmdmtyp(),0);
3972                 deblog = 1;
3973             }
3974         } else {
3975             debug(F110,"Active connection: ","none",0);
3976         }
3977 #endif /* NOLOCAL */
3978 #endif /* NOICP */
3979     } else *debfil = '\0';
3980     return(deblog);
3981 #else
3982     return(0);
3983 #endif /* MAC */
3984 }
3985
3986
3987 /*  C K D A T E  --  Returns current date/time in standard format  */
3988
3989 static char nowbuf[18];
3990
3991 char *
3992 ckdate() {
3993     extern struct keytab cmonths[];
3994     int x;
3995     char * t;                   /* Substitute today's date */
3996     char dbuf[32];
3997     ztime(&t);
3998
3999 /*  012345678901234567890123 */
4000 /*  Sat Jul  4 12:16:43 1998 */
4001
4002     ckstrncpy(dbuf,t,32);
4003     t = dbuf;
4004     debug(F110,"ckdate dbuf",dbuf,0);
4005     nowbuf[0] = t[20];
4006     nowbuf[1] = t[21];
4007     nowbuf[2] = t[22];
4008     nowbuf[3] = t[23];
4009
4010     nowbuf[4] = NUL;
4011     debug(F110,"ckdate nowbuf",nowbuf,0);
4012
4013     t[7] = NUL;
4014     if ((x = lookup(cmonths,t+4,12,NULL)) < 0) {
4015         debug(F110,"ckdate bad month",t,0);
4016         return("<BAD_MONTH>");
4017     }
4018     sprintf(nowbuf+4,"%02d",x);         /* SAFE */
4019     nowbuf[6] = (t[8] == SP) ? '0' : t[8];
4020     nowbuf[7] = t[9];
4021     nowbuf[8] = ' ';
4022
4023     nowbuf[9] = NUL;
4024     debug(F110,"ckdate nowbuf",nowbuf,0);
4025
4026     for (x = 11; x < 19; x++) nowbuf[x-2] = t[x];
4027     nowbuf[17] = NUL;
4028     debug(F110,"ckdate nowbuf",nowbuf,0);
4029
4030     return((char *)nowbuf);
4031 }
4032
4033 #ifndef NOICP
4034 #ifdef CKLOGDIAL
4035
4036 /*
4037   fc = 0 for initial open, meaning open, then close immediately.
4038   fc > 0 for subsequent opens, meaning open for use, leave open.
4039 */
4040 int
4041 diaopn(s,disp,fc) char *s; int disp, fc; {
4042     static struct filinfo xx;
4043
4044     if (!s)
4045       s = "";
4046     if (!*s)
4047       return(0);
4048
4049     debug(F110,"diaopn log",s,0);
4050     debug(F101,"diaopn fc",s,fc);
4051     debug(F101,"diaopn disp 1",s,disp);
4052     if (fc) disp = 1;                   /* Force append if open for use */
4053     debug(F101,"diaopn disp 2",s,disp);
4054
4055     zclose(ZDIFIL);                     /* In case a log was already open */
4056
4057 #ifdef OS2ORUNIX
4058     if (s[0] == '|') {                  /* Pipe */
4059         char * p = s + 1;
4060         debug(F110,"diaopn p",p,0);
4061         while (*p) {
4062             if (*p != ' ')
4063               break;
4064             else
4065               p++;
4066         }
4067         debug(F110,"diaopn pipe",p,0);
4068         dialog = zxcmd(ZDIFIL,p);
4069         debug(F101,"diaopn dialog","",dialog);
4070     } else {                            /* File */
4071 #endif /* OS2ORUNIX */
4072         if (disp) {
4073             xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
4074             xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
4075             xx.lblopts = 0;
4076             dialog = zopeno(ZDIFIL,s,NULL,&xx);
4077         } else dialog = zopeno(ZDIFIL,s,NULL,NULL);
4078         if (!dialog)
4079           printf("?%s - %s\n",s,ck_errstr());
4080 #ifdef OS2ORUNIX
4081     }
4082 #endif /* OS2ORUNIX */
4083     if (dialog > 0)
4084       ckstrncpy(diafil,s,CKMAXPATH+1);
4085     else
4086       *diafil = '\0';
4087     if (fc == 0)                        /* Initial open */
4088       zclose(ZDIFIL);                   /* close it */
4089     return(dialog);
4090 }
4091 #endif /* CKLOGDIAL */
4092
4093 #ifndef NOSHOW
4094
4095 /*  SHOW command routines */
4096
4097 char *
4098 shoxm() {
4099     char * s;
4100     switch (binary) {
4101       case XYFT_T: s = "text";         break;
4102 #ifdef VMS
4103       case XYFT_B: s = "binary fixed"; break;
4104       case XYFT_I: s = "image";        break;
4105       case XYFT_L: s = "labeled";      break;
4106       case XYFT_U: s = "binary undef"; break;
4107 #else
4108 #ifdef MAC
4109       case XYFT_B: s = "binary";       break;
4110       case XYFT_M: s = "macbinary";    break;
4111 #else
4112       case XYFT_B: s = "binary";       break;
4113 #ifdef CK_LABELED
4114       case XYFT_L: s = "labeled";      break;
4115 #endif /* CK_LABELED */
4116 #endif /* MAC */
4117 #endif /* VMS */
4118       default: s = "unknown"; break;
4119     }
4120     return(s);
4121 }
4122
4123 #ifndef NOXFER
4124 VOID                                    /* SHOW TRANSFER */
4125 shoxfer() {
4126     extern int docrc, usepipes, xfrxla, whereflg;
4127     extern char * xfrmsg;
4128     printf("\n");
4129     printf(" Transfer Bell: %s\n",showoff(xfrbel));
4130     printf(" Transfer Interruption: %s\n",showoff(xfrint));
4131     printf(" Transfer Cancellation: %s\n",showoff(xfrcan));
4132 #ifndef NOCSETS
4133     printf(" Transfer Translation:  %s\n",showoff(xfrxla));
4134     printf(" Transfer Character-set: ");
4135     if (tcharset == TC_TRANSP)
4136       printf("Transparent\n");
4137     else
4138       printf("%s\n",tcsinfo[tcharset].keyword);
4139 #endif /* NOCSETS */
4140     printf(" Transfer CRC-calculation: %s\n",showoff(docrc));
4141     printf(" Transfer Display: ");
4142     switch (fdispla) {
4143       case XYFD_N: printf("%s\n","none"); break;
4144       case XYFD_R: printf("%s\n","serial"); break;
4145       case XYFD_C: printf("%s\n","fullscreen"); break;
4146       case XYFD_S: printf("%s\n","crt"); break;
4147       case XYFD_B: printf("%s\n","brief"); break;
4148       case XYFD_G: printf("%s\n","gui"); break;
4149     }
4150     printf(" Transfer Message: %s\n", xfrmsg ? xfrmsg : "(none)");
4151     printf(" Transfer Locking-shift: ");
4152     if (lscapu == 2) {
4153         printf("forced");
4154     } else {
4155         printf("%s", (lscapr ? "enabled" : "disabled"));
4156         if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
4157     }
4158     printf("\n Transfer Mode: %s\n",
4159            xfermode == XMODE_A ?
4160            "automatic" :
4161            "manual"
4162            );
4163     printf(" Transfer Pipes: %s\n", showoff(usepipes));
4164     printf(" Transfer Protocol: %s\n",ptab[protocol].p_name);
4165     printf(" Transfer Report: %s\n",showoff(whereflg));
4166     printf(" Transfer Slow-start: %s\n",showoff(slostart));
4167     printf("\n");
4168 }
4169 #endif /* NOXFER */
4170
4171 VOID
4172 shoflow() {
4173     int i, x;
4174     extern int cxflow[], cxtype, ncxname, nfloname, autoflow;
4175     extern char * cxname[];
4176     printf("\nConnection type:        %s\n",cxname[cxtype]);
4177     if (autoflow) {
4178         printf("Current flow-control:   %s\n", floname[cxflow[cxtype]]);
4179         printf("Switches automatically: yes\n");
4180     } else {
4181         printf("Current flow-control:   %s\n", floname[flow]);
4182         printf("Switches automatically: no\n");
4183     }
4184     printf("\nDefaults by connection type:\n");
4185     debug(F111,"shoflow cxtype",cxname[cxtype],cxtype);
4186     debug(F101,"shoflow flow","",flow);
4187     for (i = 0; i < ncxname; i++) {
4188 #ifdef NOLOCAL
4189         if (i > 0) break;
4190 #endif /* NOLOCAL */
4191 #ifndef NETCONN
4192         if (i > 2) break;
4193 #endif /* NETCONN */
4194 #ifndef DECNET
4195         if (i == CXT_DECNET) continue;
4196 #endif /* DECNET */
4197 #ifndef DECNET
4198 #ifndef SUPERLAT
4199         if (i == CXT_LAT) continue;
4200 #endif /* SUPERLAT */
4201 #endif /* DECNET */
4202 #ifndef CK_NETBIOS
4203         if (i == CXT_NETBIOS) continue;
4204 #endif /* CK_NETBIOS */
4205 #ifndef NPIPE
4206         if (i == CXT_NPIPE) continue;
4207 #endif /* NPIPE */
4208 #ifndef NETCMD
4209         if (i == CXT_PIPE) continue;
4210 #endif /* NETCMD */
4211 #ifndef ANYX25
4212         if (i == CXT_X25) continue;
4213 #endif /* ANYX25 */
4214         x = cxflow[i];
4215         debug(F101,"shoflow x","",x);
4216         if (x < nfloname)
4217           printf("  %-14s: %s\n",cxname[i],floname[x]);
4218         else
4219           printf("  %-14s: (%d)\n",cxname[i],x);
4220     }
4221     printf("\n");
4222 }
4223
4224 #ifndef NOLOCAL
4225 #ifdef ANYX25
4226 int
4227 shox25(n) int n; {
4228     if (nettype == NET_SX25) {
4229         printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
4230         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
4231         printf("\n");
4232         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4233         printf(" Reverse charge call %s",
4234                revcall ? "selected" : "not selected");
4235         printf (", Closed user group ");
4236         if (closgr > -1)
4237           printf ("%d",closgr);
4238         else
4239           printf ("not selected");
4240         printf("\n");
4241         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4242         printf(" Call user data %s.\n", cudata ? udata : "not selected");
4243         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4244     } else if (nettype == NET_VX25) {
4245         if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
4246         printf("\n");
4247         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4248         printf(" Reverse charge call %s",
4249                revcall ? "selected" : "not selected");
4250         printf (", Closed user group [unsupported]");
4251         if (closgr > -1)
4252           printf ("%d",closgr);
4253         else
4254           printf ("not selected");
4255         printf (",");
4256         printf("\n");
4257         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4258         printf(" Call user data %s.\n", cudata ? udata : "not selected");
4259         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4260     } else if (nettype == NET_IX25) {
4261         printf("AIX NPI X.25\n");
4262         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4263         printf("\n Reverse charge call %s",
4264                revcall ? "selected" : "not selected");
4265         printf (", Closed user group [unsupported]");
4266         if (closgr > -1)
4267           printf ("%d",closgr);
4268         else
4269           printf ("not selected");
4270         printf (",");
4271         printf("\n Call user data %s.\n", cudata ? udata : "not selected");
4272     }
4273     return(n);
4274 }
4275
4276 #ifndef IBMX25
4277 int
4278 shopad(n) int n; {
4279     int i;
4280     printf("\nX.3 PAD Parameters:\n");
4281     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4282     for (i = 0; i < npadx3; i++) {
4283         printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
4284                padparms[padx3tab[i].kwval]);
4285         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4286     }
4287     return(n);
4288 }
4289 #endif /* IBMX25 */
4290 #endif /* ANYX25 */
4291
4292 VOID
4293 shoparc() {
4294     extern int reliable, stopbits, clsondisc;
4295     int i; char *s;
4296     long zz;
4297
4298 #ifdef NEWFTP
4299     if (ftpisconnected()) {
4300         shoftp(1);
4301         printf("\n");
4302     }
4303 #endif /* NEWFTP */
4304
4305     printf("Communications Parameters:\n");
4306
4307     if (network
4308 #ifdef IKSD
4309          || inserver
4310 #endif /* IKSD */
4311          ) {
4312         printf(" Network Host: %s%s",ttname,
4313                (reliable == SET_ON || (reliable == SET_AUTO && !local)
4314 #ifdef TN_COMPORT
4315                && !istncomport()
4316 #endif /* TN_COMPORT */
4317 #ifdef IKSD
4318                || inserver
4319 #endif /* IKSD */
4320                ) ? " (reliable)" : "");
4321 #ifdef TN_COMPORT
4322         if (istncomport()) {
4323             int modemstate;
4324             char * oflow, * iflow = "", * parity, * stopsize, * signature;
4325             int baud = tnc_get_baud();
4326
4327             switch (tnc_get_oflow()) {
4328               case TNC_CTL_OFLOW_NONE:
4329                 oflow = "none";
4330                 break;
4331               case TNC_CTL_OFLOW_XON_XOFF:
4332                 oflow = "xon/xoff";
4333                 break;
4334               case TNC_CTL_OFLOW_RTS_CTS:
4335                 oflow = "rts/cts";
4336                 break;
4337               case TNC_CTL_OFLOW_DCD:
4338                 oflow = "dcd";
4339                 break;
4340               case TNC_CTL_OFLOW_DSR:
4341                 oflow = "dsr";
4342                 break;
4343               default:
4344                 oflow = "(unknown)";
4345             }
4346             switch (tnc_get_iflow()) {
4347               case TNC_CTL_IFLOW_NONE:
4348                 iflow = "none";
4349                 break;
4350               case TNC_CTL_IFLOW_XON_XOFF:
4351                 iflow = "xon/xoff";
4352                 break;
4353               case TNC_CTL_IFLOW_RTS_CTS:
4354                 iflow = "rts/cts";
4355                 break;
4356               case TNC_CTL_IFLOW_DTR:
4357                 break;
4358               default:
4359                 iflow = oflow;
4360             }
4361             switch (tnc_get_parity()) {
4362               case TNC_PAR_NONE:
4363                 parity = "none";
4364                 break;
4365               case TNC_PAR_ODD:
4366                 parity = "odd";
4367                 break;
4368               case TNC_PAR_EVEN:
4369                 parity = "even";
4370                 break;
4371               case TNC_PAR_MARK:
4372                 parity = "mark";
4373                 break;
4374               case TNC_PAR_SPACE:
4375                 parity = "space";
4376                 break;
4377               default:
4378                 parity = "(unknown)";
4379             }
4380             switch (tnc_get_stopsize()) {
4381               case TNC_SB_1:
4382                 stopsize = "1";
4383                 break;
4384               case TNC_SB_1_5:
4385                 stopsize = "1.5";
4386                 break;
4387               case TNC_SB_2:
4388                 stopsize = "2";
4389                 break;
4390               default:
4391                 stopsize = "(unknown)";
4392             }
4393             signature = (char *)tnc_get_signature();
4394             printf("\n  Signature            : %s\n",signature?signature:"");
4395             if (baud <= 0)
4396               printf("  Speed                : (unknown)\n");
4397             else
4398               printf("  Speed                : %d\n", baud);
4399             printf("  Outbound Flow Control: %s\n", oflow);
4400             printf("  Inbound Flow Control : %s\n", iflow);
4401             printf("  Parity               : %s\n", parity);
4402             printf("  Data Size            : %d\n", tnc_get_datasize());
4403             printf("  Stop Bits            : %s\n", stopsize);
4404             printf("  DTR Signal           : %d\n", tnc_get_dtr_state());
4405             printf("  RTS Signal           : %d\n", tnc_get_rts_state());
4406             printf("  Modem State:\n");
4407             modemstate = tnc_get_ms();
4408             if (modemstate & TNC_MS_EDGE_RING)
4409               printf("    Trailing Edge Ring Detector On\n");
4410             else
4411               printf("    Trailing Edge Ring Detector Off\n");
4412             if (modemstate & TNC_MS_CTS_SIG)
4413               printf("    CTS Signal On\n");
4414             else
4415               printf("    CTS Signal Off\n");
4416             if (modemstate & TNC_MS_DSR_SIG)
4417               printf("    DSR Signal On\n");
4418             else
4419               printf("    DSR Signal Off\n");
4420             if (modemstate & TNC_MS_RI_SIG)
4421               printf("    Ring Indicator On\n");
4422             else
4423               printf("    Ring Indicator Off\n");
4424             if (modemstate & TNC_MS_RLSD_SIG)
4425               printf("    RLSD (CD) Signal On\n");
4426             else
4427               printf("    RLSD (CD) Signal Off\n");
4428             printf("\n");
4429         }
4430 #endif /* TN_COMPORT */
4431     } else {
4432
4433         printf(" %s: %s%s, speed: ",
4434 #ifdef OS2
4435                "Port",
4436 #else
4437                "Line",
4438 #endif /* OS2 */
4439                ttname,
4440 #ifdef CK_TTYFD
4441                (local &&
4442 #ifdef VMS
4443                 vmsttyfd() < 0
4444 #else
4445                 ttyfd == -1
4446 #endif /* VMS */
4447                 ) ?
4448                  " (closed)" :
4449                    (reliable == SET_ON ? " (reliable)" : "")
4450 #else
4451                ""
4452 #endif /* CK_TTYFD */
4453                );
4454         if (
4455 #ifdef CK_TTYFD
4456 #ifdef VMS
4457             vmsttyfd() < 0
4458 #else
4459             ttyfd == -1
4460 #endif /* VMS */
4461             ||
4462 #endif /* CK_TTYFD */
4463             (zz = ttgspd()) < 0) {
4464             printf("unknown");
4465         } else {
4466             if (speed == 8880) printf("75/1200");
4467             else if (speed == 134) printf("134.5");
4468             else printf("%ld",zz);
4469         }
4470     }
4471     if (network
4472 #ifdef IKSD
4473          || inserver
4474 #endif /* IKSD */
4475          )
4476       printf("\n Mode: ");
4477     else
4478       printf(", mode: ");
4479     if (local) printf("local"); else printf("remote");
4480     if (network == 0
4481 #ifdef IKSD
4482          && !inserver
4483 #endif/* IKSD */
4484          ) {
4485 #ifdef CK_TAPI
4486         if (tttapi && !tapipass )
4487           printf(", modem: %s","TAPI");
4488         else
4489 #endif /* CK_TAPI */
4490         printf(", modem: %s",gmdmtyp());
4491     } else {
4492 #ifdef NETCONN
4493        if (nettype == NET_TCPA) printf(", TCP/IP");
4494        if (nettype == NET_TCPB) printf(", TCP/IP");
4495        if (nettype == NET_DEC) {
4496            if (ttnproto == NP_LAT) printf(", DECnet LAT");
4497            else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
4498            else printf(", DECnet");
4499        }
4500        if (nettype == NET_SLAT) printf(", Meridian Technologies' SuperLAT");
4501 #ifdef NETFILE
4502        if (nettype == NET_FILE) printf(", local file");
4503 #endif /* NETFILE */
4504 #ifdef NETCMD
4505        if (nettype == NET_CMD) printf(", pipe");
4506 #endif /* NETCMD */
4507 #ifdef NETPTY
4508        if (nettype == NET_PTY) printf(", pseudoterminal");
4509 #endif /* NETPTY */
4510 #ifdef NETDLL
4511        if (nettype == NET_DLL) printf(", dynamic load library");
4512 #endif /* NETDLL */
4513        if (nettype == NET_PIPE) printf(", Named Pipes");
4514 #ifdef SSHBUILTIN
4515        if (nettype == NET_SSH)
4516          printf(", Secure Shell protocol (SECURE)");
4517 #endif /* SSHBUILTIN */
4518 #ifdef ANYX25
4519        if (shox25(0) < 0) return;
4520 #endif /* ANYX25 */
4521        if (IS_TELNET()) {
4522            printf(", telnet protocol");
4523            if (0
4524 #ifdef CK_ENCRYPTION
4525                || ck_tn_encrypting() && ck_tn_decrypting()
4526 #endif /* CK_ENCRYPTION */
4527 #ifdef CK_SSL
4528                || tls_active_flag || ssl_active_flag
4529 #endif /* CK_SSL */
4530                )
4531              printf(" (SECURE)");
4532        }
4533 #ifdef RLOGCODE
4534        else if (ttnproto == NP_RLOGIN || ttnproto == NP_K4LOGIN ||
4535                 ttnproto == NP_K5LOGIN)
4536          printf(", rlogin protocol");
4537        else if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN)
4538          printf(", rlogin protocol (SECURE)");
4539 #endif /* RLOGCODE */
4540 #ifdef CK_KERBEROS
4541 #ifdef KRB5
4542        else if (ttnproto == NP_K5U2U)
4543          printf(", Kerberos 5 User to User protocol (SECURE)");
4544 #endif /* KRB5 */
4545 #endif /* CK_KERBEROS */
4546 #endif /* NETCONN */
4547     }
4548     printf("\n");
4549     if (hwparity && local && !network)
4550       s = parnam((char)hwparity);
4551     else
4552       s = parnam((char)parity);
4553     printf(" Parity: %s%s",hwparity ? "hardware " : "", s);
4554 #ifndef NOLOCAL
4555     if (local && !network) {
4556         int sb;
4557         char c;
4558         c = s[0];
4559         if (islower(c)) c = toupper(c);
4560         sb = stopbits;
4561         if (sb < 1) {
4562             sb = (speed > 0 && speed <= 110L) ? 2 : 1;
4563             printf(", stop-bits: (default)");
4564         } else {
4565             printf(", stop-bits: %d",sb);
4566         }
4567         if (hwparity)
4568           printf(" (8%c%d)",c,sb);
4569         else if (parity)
4570           printf(" (7%c%d)",c,sb);
4571         else
4572           printf(" (8N%d)",sb);
4573         printf("\n D");
4574     } else
4575       printf(", d");
4576 #endif /* NOLOCAL */
4577
4578     printf("uplex: %s, ", duplex ? "half" : "full");
4579     debug(F101,"shoparp flow","",flow);
4580     printf("flow: %s", floname[flow]);
4581     printf(", handshake: ");
4582     if (turn) printf("%d\n",turnch); else printf("none\n");
4583 #ifdef COMMENT
4584     if (local && !network) {            /* SET CARRIER-WATCH */
4585 #endif /* COMMENT */
4586         if (carrier == CAR_OFF) s = "off";
4587         else if (carrier == CAR_ON) s = "on";
4588         else if (carrier == CAR_AUT) s = "auto";
4589         else s = "unknown";
4590         printf(" Carrier-watch: %s", s);
4591         if (carrier == CAR_ON) {
4592             if (cdtimo) printf(", timeout: %d sec", cdtimo);
4593             else printf(", timeout: none");
4594         }
4595 #ifdef COMMENT
4596     }
4597 #endif /* COMMENT */
4598     printf(", close-on-disconnect: %s\n",showoff(clsondisc));
4599
4600 #ifdef UNIX                             /* UUCP lockfile, UNIX only */
4601     if (local) {
4602 #ifndef NOUUCP
4603         if (!network && haslock && *flfnam)
4604           printf(" Lockfile: %s",flfnam);
4605 #ifndef USETTYLOCK
4606         if (!network && haslock && lock2[0])
4607           printf("\n Secondary lockfile: %s",lock2);
4608 #endif /* USETTYLOCK */
4609 #else
4610 #ifdef QNX
4611         {
4612             extern int qnxportlock, qnxopencount();
4613             if (local)
4614               printf(" Qnx-port-lock: %s, Open count: %d",
4615                      showoff(qnxportlock),
4616                      qnxopencount()
4617                      );
4618             else
4619               printf(" Qnx-port-lock: %s", showoff(qnxportlock));
4620         }
4621 #endif /* QNX */
4622 #endif /* NOUUCP */
4623         printf("\n");
4624     } else {
4625         char * s, * ttglckdir();
4626         s = ttglckdir();
4627         if (!s) s = "";
4628         printf(" Lockfile directory: %s\n", *s ? s : "(none)");
4629     }
4630 #endif /* UNIX */
4631 #ifndef MACOSX
4632     if (!local) {
4633         printf(" Typical port device name: %s\n",ttgtpn());
4634     }
4635 #endif  /* MACOSX */
4636     if (local) {
4637         int i;
4638         i = parity ? 7 : 8;
4639         if (i == 8) i = (cmask == 0177) ? 7 : 8;
4640         printf(" Terminal bytesize: %d,",i);
4641         printf(" escape character: %d (^%c)\n",escape,ctl(escape));
4642     }
4643 }
4644
4645 int
4646 shotcp(n) int n; {
4647 #ifdef TCPSOCKET
4648     if (nettype == NET_TCPA || nettype == NET_TCPB) {
4649         printf("SET TCP parameters:\n");
4650         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4651         printf(" Reverse DNS lookup: %s\n", showooa(tcp_rdns));
4652         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4653
4654 #ifdef CK_DNS_SRV
4655         printf(" DNS Service Records lookup: %s\n", showooa(tcp_dns_srv));
4656         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4657 #endif /* CK_DNS_SRV */
4658
4659 #ifndef NOTCPOPTS
4660 #ifdef SOL_SOCKET
4661 #ifdef SO_KEEPALIVE
4662         printf(" Keepalive: %s\n", showoff(tcp_keepalive));
4663         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4664 #endif /* SO_KEEPALIVE */
4665
4666 #ifdef SO_LINGER
4667         printf(" Linger: %s", tcp_linger ? "on, " : "off\n" );
4668         if (tcp_linger) {
4669             if (tcp_linger_tmo)
4670               printf("%d x 10 milliseconds\n",tcp_linger_tmo);
4671             else
4672               printf("no timeout\n");
4673         }
4674         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4675 #endif /* SO_LINGER */
4676
4677 #ifdef SO_DONTROUTE
4678         printf(" DontRoute: %s\n", tcp_dontroute ? "on" : "off" );
4679         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4680 #endif /* SO_DONTROUTE */
4681
4682 #ifdef TCP_NODELAY
4683         printf(" Nodelay: %s\n", showoff(tcp_nodelay));
4684         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4685 #endif /* TCP_NODELAY */
4686
4687 #ifdef SO_SNDBUF
4688         if (tcp_sendbuf <= 0)
4689           printf(" Send buffer: (default size)\n");
4690         else
4691           printf(" Send buffer: %d bytes\n", tcp_sendbuf);
4692         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4693 #endif /* SO_SNDBUF */
4694 #ifdef SO_RCVBUF
4695         if (tcp_recvbuf <= 0)
4696           printf(" Receive buffer: (default size)\n");
4697         else
4698           printf(" Receive buffer: %d bytes\n", tcp_recvbuf);
4699         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
4700 #endif /* SO_RCVBUF */
4701 #endif /* SOL_SOCKET */
4702 #endif /* NOTCPOPTS */
4703         printf(" address: %s\n",tcp_address ? tcp_address : "(none)");
4704         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4705 #ifndef NOHTTP
4706         printf(" http-proxy: %s\n",tcp_http_proxy ? tcp_http_proxy : "(none)");
4707         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4708 #endif /* NOHTTP */
4709 #ifdef NT
4710 #ifdef CK_SOCKS
4711         printf(" socks-server: %s\n",tcp_socks_svr ? tcp_socks_svr : "(none)");
4712         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4713 #ifdef CK_SOCKS_NS
4714         printf(" socks-name-server: %s\n",
4715                tcp_socks_ns ? tcp_socks_ns : "(none)");
4716         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4717 #endif /* CK_SOCKS_NS */
4718 #endif /* CK_SOCKS */
4719 #endif /* NT */
4720     }
4721 #endif /* TCPSOCKET */
4722     return(n);
4723 }
4724
4725 #ifdef TNCODE
4726 int
4727 shotopt(n) int n; {
4728     int opt;
4729
4730     printf("%-21s %12s %12s %12s %12s\n\n",
4731            "Telnet Option","Me (client)","U (client)",
4732            "Me (server)","U (server)");
4733     n += 2;
4734     if (n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4735
4736     for ( opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) {
4737         switch (opt) {
4738           case TELOPT_AUTHENTICATION:
4739           case TELOPT_ENCRYPTION:
4740           case TELOPT_TTYPE:
4741           case TELOPT_NAWS:
4742           case TELOPT_BINARY:
4743           case TELOPT_NEWENVIRON:
4744           case TELOPT_SNDLOC:
4745           case TELOPT_XDISPLOC:
4746           case TELOPT_SGA:
4747           case TELOPT_ECHO:
4748           case TELOPT_KERMIT:
4749           case TELOPT_START_TLS:
4750           case TELOPT_FORWARD_X:
4751           case TELOPT_COMPORT:
4752             break;
4753           default:
4754             continue;
4755         }
4756         printf("%03d %-17s ",
4757                opt, TELOPT(opt)
4758                );
4759         printf("%12s %12s ",
4760                TELOPT_MODE(TELOPT_DEF_C_ME_MODE(opt)),
4761                TELOPT_MODE(TELOPT_DEF_C_U_MODE(opt))
4762                );
4763         printf("%12s %12s\n",
4764                TELOPT_MODE(TELOPT_DEF_S_ME_MODE(opt)),
4765                TELOPT_MODE(TELOPT_DEF_S_U_MODE(opt))
4766                );
4767
4768         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4769         if (sstelnet)
4770           printf("%21s %12s %12s %12s %12s\n",
4771                  "",
4772                  "",
4773                  "",
4774                  (TELOPT_ME(opt)?"WILL":"WONT"),
4775                  (TELOPT_U(opt)?"DO":"DONT")
4776                  );
4777         else
4778           printf("%21s %12s %12s %12s %12s\n",
4779                  "",
4780                  (TELOPT_ME(opt)?"WILL":"WONT"),
4781                  (TELOPT_U(opt)?"DO":"DONT"),
4782                  "",
4783                  ""
4784                  );
4785         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4786     }
4787     return(n);
4788 }
4789
4790 int
4791 shotel(n) int n; {
4792     extern int tn_duplex;
4793 #ifdef CK_ENVIRONMENT
4794     extern int tn_env_flg;
4795     extern char tn_env_acct[];
4796     extern char tn_env_job[];
4797     extern char tn_env_prnt[];
4798     extern char tn_env_sys[];
4799     extern char * tn_env_uservar[8][2];
4800     int x;
4801 #endif /* CK_ENVIRONMENT */
4802 #ifdef CK_SNDLOC
4803     extern char * tn_loc;
4804 #endif /* CK_SNDLOC */
4805     printf("SET TELNET parameters:\n echo: %s\n NVT newline-mode: ",
4806            tn_duplex ? "local" : "remote");
4807     switch (tn_nlm) {
4808       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
4809       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
4810       case TNL_CR:    printf("%s\n","raw (cr)"); break;
4811       case TNL_LF:    printf("%s\n","(lf)"); break;
4812     }
4813     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4814 #ifdef CK_AUTHENTICATION
4815     {
4816         int type = ck_tn_authenticated();
4817         printf(" authentication: ");
4818         switch (sstelnet ?
4819                 TELOPT_U_MODE(TELOPT_AUTHENTICATION) :
4820                  TELOPT_ME_MODE(TELOPT_AUTHENTICATION)
4821                 ) {
4822           case TN_NG_AC: printf( "accepted " ); break;
4823           case TN_NG_RF: printf( "refused  " ); break;
4824           case TN_NG_RQ: printf( "requested"); break;
4825           case TN_NG_MU: printf( "required "); break;
4826         }
4827
4828 #ifdef CK_SSL
4829         if ((ssl_active_flag || tls_active_flag) &&
4830              ck_tn_auth_valid() == AUTH_VALID &&
4831              (!TELOPT_U(TELOPT_AUTHENTICATION) ||
4832                type == AUTHTYPE_NULL ||
4833                type == AUTHTYPE_AUTO))
4834             printf("   in use: X.509 certificate\n");
4835         else
4836 #endif /* CK_SSL */
4837           printf("   in use: %s\n",AUTHTYPE_NAME(type));
4838         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4839         if (forward_flag)
4840           printf("  credentials forwarding requested %s\n",
4841                  forwarded_tickets ? "and completed" :
4842                  "but not completed");
4843         else
4844           printf("  credentials forwarding disabled\n");
4845         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4846     }
4847 #endif /* CK_AUTHENTICATION */
4848 #ifdef CK_ENCRYPTION
4849     {
4850         int i,x;
4851         int e_type = ck_tn_encrypting();
4852         int d_type = ck_tn_decrypting();
4853         char * e_str = NULL, * d_str = NULL;
4854         static struct keytab * tnetbl = NULL;
4855         static int ntnetbl = 0;
4856
4857         x = ck_get_crypt_table(&tnetbl,&ntnetbl);
4858
4859         for (i = 0; i < ntnetbl; i++) {
4860             if (e_type == tnetbl[i].kwval)
4861               e_str = tnetbl[i].kwd;
4862             if (d_type == tnetbl[i].kwval)
4863               d_str = tnetbl[i].kwd;
4864         }
4865         printf(" encryption: ");
4866         switch (TELOPT_ME_MODE(TELOPT_ENCRYPTION)) {
4867           /* This should be changed to report both ME and U modes */
4868           case TN_NG_AC: printf( "accepted " ); break;
4869           case TN_NG_RF: printf( "refused  " ); break;
4870           case TN_NG_RQ: printf( "requested"); break;
4871           case TN_NG_MU: printf( "required "); break;
4872         }
4873         printf("       in use: ");
4874         switch ((e_type ? 1 : 0) | (d_type ? 2 : 0)) {
4875           case 0:
4876             printf("plain text in both directions");
4877             break;
4878           case 1:
4879             printf("%s output, plain text input",e_str);
4880             break;
4881           case 2:
4882             printf("plain text output, %s input",d_str);
4883             break;
4884           case 3:
4885             printf("%s output, %s input",e_str,d_str);
4886             break;
4887         }
4888         printf("\n");
4889         if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4890     }
4891 #endif /* CK_ENCRYPTION */
4892 #ifdef IKS_OPTION
4893     printf(" kermit: ");
4894     switch (TELOPT_U_MODE(TELOPT_KERMIT)) {
4895       case TN_NG_AC: printf( "u, accepted;  " ); break;
4896       case TN_NG_RF: printf( "u, refused;   " ); break;
4897       case TN_NG_RQ: printf( "u, requested; "); break;
4898       case TN_NG_MU: printf( "u, required;  "); break;
4899     }
4900     switch (TELOPT_ME_MODE(TELOPT_KERMIT)) {
4901       case TN_NG_AC: printf( "me, accepted;  " ); break;
4902       case TN_NG_RF: printf( "me, refused;   " ); break;
4903       case TN_NG_RQ: printf( "me, requested; "); break;
4904       case TN_NG_MU: printf( "me, required;  "); break;
4905     }
4906     if (TELOPT_U(TELOPT_KERMIT))
4907       printf(" u, %s",
4908              TELOPT_SB(TELOPT_KERMIT).kermit.u_start ?
4909              "started" :
4910              "stopped"
4911              );
4912     else
4913       printf(" u, n/a");
4914     if (TELOPT_ME(TELOPT_KERMIT))
4915       printf(" me, %s;",
4916              TELOPT_SB(TELOPT_KERMIT).kermit.me_start ?
4917              "started" :
4918              "stopped"
4919              );
4920     else
4921       printf(" me, n/a;");
4922     printf("\n");
4923     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4924 #endif /* IKS_OPTION */
4925     printf(" BINARY newline-mode: ");
4926     switch (tn_b_nlm) {
4927       case TNL_CRNUL: printf("%s\n","off (cr-nul)"); break;
4928       case TNL_CRLF:  printf("%s\n","on (cr-lf)"); break;
4929       case TNL_CR:    printf("%s\n","raw (cr)"); break;
4930       case TNL_LF:    printf("%s\n","(lf)"); break;
4931     }
4932     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4933     printf(" binary-mode: ");
4934     switch (TELOPT_U_MODE(TELOPT_BINARY)) {
4935       case TN_NG_AC: printf( "u, accepted;  " ); break;
4936       case TN_NG_RF: printf( "u, refused;   " ); break;
4937       case TN_NG_RQ: printf( "u, requested; "); break;
4938       case TN_NG_MU: printf( "u, required;  "); break;
4939     }
4940     switch (TELOPT_ME_MODE(TELOPT_BINARY)) {
4941       case TN_NG_AC: printf( "me, accepted; " ); break ;
4942       case TN_NG_RF: printf( "me, refused; " ); break;
4943       case TN_NG_RQ: printf( "me, requested; "); break;
4944       case TN_NG_MU: printf( "me, required;  "); break;
4945     }
4946     printf("u, %s; me, %s\n",
4947            TELOPT_U(TELOPT_BINARY) ? "BINARY" : "NVT",
4948            TELOPT_ME(TELOPT_BINARY) ? "BINARY" : "NVT"
4949            );
4950     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4951     printf(" binary-transfer-mode: %s\n",showoff(tn_b_xfer));
4952     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4953     printf(" bug binary-me-means-u-too: %s\n",showoff(tn_b_meu));
4954     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4955     printf(" bug binary-u-means-me-too: %s\n",showoff(tn_b_ume));
4956     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4957     printf(" bug sb-implies-will-do: %s\n",showoff(tn_sb_bug));
4958     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4959     printf(" bug auth-krb5-des: %s\n",showoff(tn_auth_krb5_des_bug));
4960     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4961     printf(" terminal-type: ");
4962     if (tn_term) {
4963         printf("%s\n",tn_term);
4964     } else {
4965         char *p;
4966 #ifdef OS2
4967         p = (tt_type >= 0 && tt_type <= max_tt) ?
4968           tt_info[tt_type].x_name :
4969             "UNKNOWN";
4970 #else
4971         p = getenv("TERM");
4972 #endif /* OS2 */
4973         if (p)
4974           printf("none (%s will be used)\n",p);
4975         else printf("none\n");
4976     }
4977     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4978 #ifdef CK_ENVIRONMENT
4979     printf(" environment: %s\n", showoff(tn_env_flg));
4980     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4981     printf("   ACCOUNT: %s\n",tn_env_acct);
4982     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4983     printf("   DISPLAY: %s\n",(char *)tn_get_display() ?
4984             (char *)tn_get_display() : "");
4985     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4986     printf("   JOB    : %s\n",tn_env_job);
4987     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4988     printf("   PRINTER: %s\n",tn_env_prnt);
4989     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4990 #ifndef NOSPL
4991     printf("   USER   : %s\n",uidbuf);
4992     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4993 #endif /* NOSPL */
4994     printf("   SYSTEM : %s\n",tn_env_sys);
4995     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
4996     for (x = 0; x < 8; x++) {
4997         if (tn_env_uservar[x][0] && tn_env_uservar[x][1]) {
4998             printf("   %-7s: %s\n",tn_env_uservar[x][0],
4999                    tn_env_uservar[x][1]);
5000             if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5001         }
5002     }
5003 #endif /* CK_ENVIRONMENT */
5004 #ifdef CK_SNDLOC
5005     printf("  LOCATION: %s\n", tn_loc ? tn_loc : "");
5006     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5007 #endif /* CK_SNDLOC */
5008 #ifdef CK_FORWARD_X
5009     printf(" .Xauthority-file: %s\n", (char *)XauFileName() ?
5010             (char *)XauFileName() : "(none)");
5011     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5012 #endif /* CK_FORWARD_X */
5013     return(n);
5014 }
5015 #endif /* TNCODE */
5016
5017 #ifdef CK_NETBIOS
5018 static int
5019 shonb(n) int n; {
5020     printf("NETBIOS parameters:\n");
5021     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5022     printf(" API       : %s\n",
5023            NetbeuiAPI ?
5024            "NETAPI.DLL - IBM Extended Services or Novell Netware Requester"
5025            : "ACSNETB.DLL - IBM Network Transport Services/2" ) ;
5026     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5027     printf(" Local Name: [%s]\n", NetBiosName);
5028     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5029     printf(" Adapter   : %d\n", NetBiosAdapter);
5030     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5031     if (NetBiosLSN > 0xFF) {
5032         printf(" Session   : %d\n", NetBiosLSN);
5033     } else {
5034         printf(" Session   : none active\n");
5035     }
5036     if (++n > cmd_rows - 3) if (!askmore()) return(-1); else n = 0;
5037     return(n);
5038 }
5039 #endif /* CK_NETBIOS */
5040
5041 #ifndef NONET
5042 int
5043 shonet() {
5044
5045 #ifndef NETCONN
5046     printf("\nNo networks are supported in this version of C-Kermit\n");
5047
5048 #else
5049 #ifdef NOLOCAL
5050     printf("\nNo networks are supported in this version of C-Kermit\n");
5051
5052 #else /* rest of this routine */
5053
5054     int i, n = 4;
5055
5056 #ifndef NODIAL
5057     if (nnetdir <= 1) {
5058         printf("\nNetwork directory: %s\n",netdir[0] ? netdir[0] : "(none)");
5059         n++;
5060     } else {
5061         int i;
5062         printf("\nNetwork directories:\n");
5063         for (i = 0; i < nnetdir; i++) {
5064             printf("%2d. %s\n",i,netdir[i]);
5065             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5066         }
5067     }
5068 #endif /* NODIAL */
5069
5070 #ifdef SSHCMD
5071     {
5072         extern char * sshcmd;
5073         printf("SSH COMMAND: %s\n",sshcmd ? sshcmd : "ssh -e none");
5074         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5075     }
5076 #endif /* SSHCMD */
5077
5078 #ifdef OS2
5079     printf("\nNetwork availability:\n");
5080 #else
5081     printf("\nSupported networks:\n");
5082 #endif /* OS2 */
5083     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5084
5085 #ifdef VMS
5086
5087 #ifdef TCPWARE
5088     printf(" Process Software Corporation TCPware for OpenVMS");
5089 #else
5090 #ifdef MULTINET
5091     printf(" TGV MultiNet TCP/IP");
5092 #else
5093 #ifdef WINTCP
5094     printf(" WOLLONGONG WIN/TCP");
5095 #else
5096 #ifdef DEC_TCPIP
5097     {
5098         static $DESCRIPTOR(tcp_desc,"_TCP0:");
5099         int status;
5100         long devclass;
5101         static int itmcod = DVI$_DEVCLASS;
5102
5103 #ifdef COMMENT
5104         status = LIB$GETDVI(&itmcod, 0, &tcp_desc, &devclass);
5105 #else
5106         /* Martin Zinser 9/96 */
5107         status = lib$getdvi(&itmcod, 0, &tcp_desc, &devclass);
5108 #endif /* COMMENT */
5109         if ((status & 1) && (devclass == DC$_SCOM))
5110           printf(" Process Software Corporation TCPware for OpenVMS");
5111         else
5112 #ifdef UCX50
5113           printf(" DEC TCP/IP Services for (Open)VMS 5.0");
5114 #else
5115           printf(" DEC TCP/IP Services for (Open)VMS");
5116 #endif /* UCX50 */
5117     }
5118 #else
5119 #ifdef CMU_TCPIP
5120     printf(" CMU-OpenVMS/IP");
5121 #else
5122     printf(" None");
5123 #endif /* CMU_TCPIP */
5124 #endif /* DEC_TCPIP */
5125 #endif /* WINTCP */
5126 #endif /* MULTINET */
5127 #endif /* TCPWARE */
5128     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5129 #ifdef TNCODE
5130     printf(", TELNET protocol\n\n");
5131     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5132     n = shotel(n);
5133     if (n < 0) return(0);
5134     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5135 #endif /* TNCODE */
5136     printf("\n");
5137     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5138     printf("\n");
5139     n = shotcp(++n);
5140     if (n < 0) return(0);
5141 #else /* Not VMS */
5142
5143 #ifdef SUNX25
5144     printf(" SunLink X.25\n");
5145     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5146 #endif /* SUNX25 */
5147
5148 #ifdef STRATUSX25
5149     printf(" Stratus VOS X.25\n");
5150     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5151 #endif /* STRATUSX25 */
5152
5153 #ifdef IBMX25
5154     printf(" IBM AIX X.25\n");
5155     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5156 #endif /* IBMX25 */
5157
5158 #ifdef HPX25
5159     printf(" HP-UX X.25\n");
5160     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5161 #endif /* HPX25 */
5162
5163 #ifdef SSHBUILTIN
5164     if (ck_ssleay_is_installed())
5165         printf(" SSH V1 and V2 protocols\n");
5166     else
5167         printf(" SSH V1 and V2 protocols - not available\n");
5168 #endif /* SSHBUILTIN */
5169
5170 #ifdef DECNET
5171 #ifdef OS2
5172 #ifdef NT
5173     if (dnet_avail)
5174       printf(" DECnet, LAT and CTERM protocols\n");
5175     else
5176       printf(" DECnet, LAT and CTERM protocols - not available\n");
5177     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5178 #else /* NT */
5179     if (dnet_avail)
5180       printf(" DECnet, LAT protocol\n");
5181     else
5182       printf(" DECnet, LAT protocol - not available\n");
5183     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5184 #endif /* NT */
5185 #else
5186     printf(" DECnet\n");
5187     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5188 #endif /* OS2 */
5189 #endif /* DECNET */
5190
5191 #ifdef NPIPE
5192     printf(" Named Pipes\n");
5193     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5194 #endif /* NPIPE */
5195
5196 #ifdef CK_NETBIOS
5197     if (netbiosAvail)
5198       printf(" NETBIOS\n");
5199     else
5200       printf(" NETBIOS - not available\n");
5201     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5202 #endif /* CK_NETBIOS */
5203
5204 #ifdef SUPERLAT
5205     if (slat_avail)
5206       printf(" SuperLAT\n");
5207     else
5208       printf(" SuperLAT - not available\n") ;
5209     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5210 #endif /* SUPERLAT */
5211
5212 #ifdef TCPSOCKET
5213     if (
5214 #ifdef OS2
5215         tcp_avail
5216 #else
5217         1
5218 #endif /* OS2 */
5219         ) {
5220         char ipaddr[16];
5221
5222         if (getlocalipaddrs(ipaddr,16,0) < 0) {
5223 #ifdef OS2ONLY
5224             printf(" TCP/IP via %s\n", tcpname);
5225 #else
5226             printf(" TCP/IP\n");
5227 #endif /* OS2ONLY */
5228             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5229         } else {
5230             int i = 1;
5231 #ifdef OS2ONLY
5232           printf(" TCP/IP [%16s] via %s\n", ipaddr, tcpname);
5233 #else
5234           printf(" TCP/IP [%16s]\n",ipaddr);
5235 #endif /* OS2ONLY */
5236             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5237
5238             while (getlocalipaddrs(ipaddr,16,i++) >= 0) {
5239                 printf("        [%16s]\n",ipaddr);
5240                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5241             }
5242         }
5243         if (nettype == NET_TCPB) {
5244             printf("\n");
5245             n = shotcp(++n);
5246             if (n < 0) return(0);
5247 #ifdef TNCODE
5248             printf("\n");
5249             n = shotel(++n);
5250             if (n < 0) return(0);
5251 #endif /* TNCODE */
5252             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5253         }
5254 #ifdef OS2
5255     } else {
5256         printf(" TCP/IP - not available%s\n",tcpname[0] ? tcpname : "" );
5257         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5258 #endif /* OS2 */
5259     }
5260 #endif /* TCPSOCKET */
5261
5262 #ifdef CK_NETBIOS
5263     if (netbiosAvail && nettype == NET_BIOS) {
5264        printf("\n") ;
5265        if ((n = shonb(++n)) < 0) return(0);
5266        if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5267     }
5268 #endif /* CK_NETBIOS */
5269
5270 #endif /* VMS */
5271
5272     printf("\nActive network connection:\n");
5273     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5274
5275     if (network) {
5276         printf(" Host: %s",ttname);
5277         if ((nettype == NET_TCPA || nettype == NET_TCPB) && *ipaddr)
5278           printf(" [%s]",ipaddr);
5279     } else
5280       printf(" Host: none");
5281     printf(", via: ");
5282     if (nettype == NET_TCPA || nettype == NET_TCPB)
5283       printf("tcp/ip\n");
5284     else if (nettype == NET_SX25)
5285       printf("SunLink X.25\n");
5286     else if (nettype == NET_VX25)
5287       printf("Stratus VOS X.25\n");
5288     else if (nettype == NET_IX25)
5289       printf("IBM AIX X.25\n");
5290     else if (nettype == NET_HX25)
5291       printf("HP-UX X.25\n");
5292     else if (nettype == NET_DEC) {
5293         if ( ttnproto == NP_LAT )
5294           printf("DECnet LAT\n");
5295         else if ( ttnproto == NP_CTERM )
5296           printf("DECnet CTERM\n");
5297         else
5298           printf("DECnet\n");
5299     } else if (nettype == NET_PIPE)
5300       printf("Named Pipes\n");
5301     else if (nettype == NET_BIOS)
5302       printf("NetBIOS\n");
5303     else if (nettype == NET_SLAT)
5304       printf("SuperLAT\n");
5305
5306 #ifdef NETFILE
5307     else if ( nettype == NET_FILE )
5308       printf("local file\n");
5309 #endif /* NETFILE */
5310 #ifdef NETCMD
5311     else if ( nettype == NET_CMD )
5312       printf("pipe\n");
5313 #endif /* NETCMD */
5314 #ifdef NETPTY
5315     else if ( nettype == NET_PTY )
5316         printf("pseudoterminal\n");
5317 #endif /* NETPTY */
5318 #ifdef NETDLL
5319     else if ( nettype == NET_DLL )
5320       printf("dynamic link library\n");
5321 #endif /* NETDLL */
5322     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5323
5324 #ifdef ANYX25
5325     if ((nettype == NET_SX25) ||
5326         (nettype == NET_VX25) ||
5327         (nettype == NET_IX25))
5328       if ((n = shox25(n)) < 0) return(0);
5329 #endif /* ANYX25 */
5330
5331 #ifdef SSHBUILTIN
5332     if (nettype == NET_SSH) {
5333         printf("Secure Shell protocol\n");
5334         if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5335     }
5336 #endif /* SSHBUILTIN */
5337
5338     if (nettype == NET_TCPA || nettype == NET_TCPB) {
5339 #ifdef RLOGCODE
5340         if (ttnproto == NP_RLOGIN) {
5341             printf(" LOGIN (rlogin) protocol\n");
5342             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5343         }
5344 #ifdef CK_KERBEROS
5345         else if (ttnproto == NP_K4LOGIN) {
5346             printf(" Kerberos 4 LOGIN (klogin) protocol\n");
5347             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5348         }
5349         else if (ttnproto == NP_EK4LOGIN) {
5350             printf(" Encrypted Kerberos 4 LOGIN (eklogin) protocol\n");
5351             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5352         }
5353         else if (ttnproto == NP_K5LOGIN) {
5354             printf(" Kerberos 5 LOGIN (klogin) protocol\n");
5355             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5356         }
5357         else if (ttnproto == NP_EK5LOGIN) {
5358             printf(" Encrypted Kerberos 5 LOGIN (eklogin) protocol\n");
5359             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5360         }
5361 #endif /* CK_KERBEROS */
5362 #endif /* RLOGCODE */
5363 #ifdef CK_KERBEROS
5364         if (ttnproto == NP_K5U2U) {
5365             printf(" Kerberos 5 User to User protocol\n");
5366             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5367         }
5368 #endif /* CK_KERBEROS */
5369
5370 #ifdef TNCODE
5371         if (IS_TELNET()) {
5372             printf(" TELNET protocol\n");
5373             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5374             printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
5375             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5376         }
5377 #endif /* TNCODE */
5378         if (ttnproto == NP_TCPRAW) {
5379             printf(" Raw TCP socket\n");
5380             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5381         }
5382     }
5383     printf("\n");
5384 #endif /* NOLOCAL */
5385 #endif /* NETCONN */
5386     return(0);
5387 }
5388 #endif /* NONET */
5389
5390 #ifndef NODIAL
5391 VOID
5392 shodial() {
5393     if (mdmtyp >= 0 || local != 0) doshodial();
5394 }
5395
5396 VOID
5397 shods(s) char *s; {                     /* Show a dial-related string */
5398     char c;
5399     if (s == NULL || !(*s)) {           /* Empty? */
5400         printf("(none)\n");
5401     } else {                            /* Not empty. */
5402         while ((c = *s++))              /* Can contain controls */
5403           if (c == '\\')                /* a backslash */
5404             printf("\\\\");
5405           else if (c > 31 && c < 127) {
5406               putchar(c);
5407           } else
5408             printf("\\{%d}",c);
5409         printf("\n");
5410     }
5411 }
5412
5413 int
5414 doshodial() {
5415
5416     int i, n = 2;
5417
5418     printf(" Dial status:  %d", dialsta);
5419
5420 #ifdef BIGBUFOK
5421     if (dialsta > 90)
5422       printf(" = Unknown error");
5423     else if (dialsta < 0)
5424       printf(" = (none)");
5425     else if (dialsta < 35 && dialmsg[dialsta])
5426       printf(" = %s", dialmsg[dialsta]);
5427 #endif /* BIGBUFOK */
5428     n++;
5429     if (ndialdir <= 1) {
5430         printf("\n Dial directory: %s\n",dialdir[0] ? dialdir[0] : "(none)");
5431     } else {
5432         int i;
5433         printf("\n Dial directories:\n");
5434         for (i = 0; i < ndialdir; i++)
5435           printf("%2d. %s\n",i+1,dialdir[i]);
5436         n += ndialdir;
5437     }
5438     printf(" Dial method:  ");
5439     if      (dialmauto)         printf("auto   ");
5440     else if (dialmth == XYDM_D) printf("default");
5441     else if (dialmth == XYDM_P) printf("pulse  ");
5442     else if (dialmth == XYDM_T) printf("tone   ");
5443     printf("         Dial sort: %s\n",dialsrt ? "on" : "off");
5444     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5445     printf(" Dial hangup:  %s             Dial display: %s\n",
5446            dialhng ? "on " : "off", dialdpy ? "on" : "off");
5447     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5448     if (dialrtr > 0) {
5449         printf(" Dial retries: %-12d    Dial interval: %d\n",
5450                dialrtr, dialint);
5451     } else {
5452         printf(" Dial retries: (auto)          Dial interval: %d\n", dialint);
5453     }
5454     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5455     printf(" Dial timeout: ");
5456 #ifdef CK_TAPI
5457     if (tttapi && !tapipass)
5458         printf("(tapi)");
5459     else
5460 #endif /* CK_TAPI */
5461     if (dialtmo > 0)
5462       printf("%4d sec", dialtmo);
5463     else
5464       printf("0 (auto)");
5465     printf("        Redial number: %s\n",dialnum ? dialnum : "(none)");
5466     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5467     printf(" Dial confirmation: %s        Dial convert-directory: %s\n",
5468            dialcnf ? "on " : "off",
5469            dialcvt ? ((dialcvt == 1) ? "on" : "ask") : "off");
5470     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5471     printf(" Dial ignore-dialtone: %s", dialidt ? "on " : "off");
5472     printf("     Dial pacing: %d\n",dialpace);
5473     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5474     printf(
5475 " Dial prefix:                  %s\n", dialnpr ? dialnpr : "(none)");
5476     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5477     printf(
5478 " Dial suffix:                  %s\n", dialsfx ? dialsfx : "(none)");
5479     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5480     printf(
5481 " Dial country-code:            %-12s", diallcc ? diallcc : "(none)");
5482     printf("Dial connect:  %s", dialcon ? ((dialcon == 1) ? "on" : "auto")
5483            : "off");
5484     if (dialcon != CAR_OFF)
5485       printf(" %s", dialcq ? "quiet" : "verbose");
5486     printf(
5487 "\n Dial area-code:               %-12s", diallac ? diallac : "(none)");
5488     n++;
5489     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5490     printf("Dial restrict: ");
5491     if (dialrstr == 5) printf("international\n");
5492     else if (dialrstr == 4) printf("long-distance\n");
5493     else if (dialrstr == 2) printf("local\n");
5494     else if (dialrstr == 6) printf("none\n");
5495     else printf("?\n");
5496     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5497     printf(" Dial lc-area-codes:           ");
5498     if (nlocalac == 0)
5499       printf("(none)");
5500     else
5501       for (i = 0; i < nlocalac; i++)
5502         printf("%s ", diallcac[i]);
5503     printf(
5504 "\n Dial lc-prefix:               %s\n", diallcp ? diallcp : "(none)");
5505     n++;
5506     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5507     printf(
5508 " Dial lc-suffix:               %s\n", diallcs ? diallcs : "(none)");
5509     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5510     printf(
5511 " Dial ld-prefix:               %s\n", dialldp ? dialldp : "(none)");
5512     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5513     printf(
5514 " Dial ld-suffix:               %s\n", diallds ? diallds : "(none)");
5515     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5516     printf(
5517 " Dial force-long-distance      %s\n", showoff(dialfld));
5518     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5519     printf(
5520 " Dial intl-prefix:             %s\n", dialixp ? dialixp : "(none)");
5521     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5522     printf(
5523 " Dial intl-suffix:             %s\n", dialixs ? dialixs : "(none)");
5524     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5525     printf(
5526 " Dial toll-free-area-code:     ");
5527     if (ntollfree == 0)
5528       printf("(none)");
5529     else
5530       for (i = 0; i < ntollfree; i++)
5531         printf("%s ", dialtfc[i]);
5532     printf("\n");
5533     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5534
5535     printf(
5536 " Dial pulse-countries:         ");
5537     if (ndialpucc == 0)
5538       printf("(none)");
5539     else
5540       for (i = 0; i < ndialpucc; i++)
5541         printf("%s ", dialpucc[i]);
5542     printf("\n");
5543     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5544
5545     printf(
5546 " Dial tone-countries:          ");
5547     if (ndialtocc == 0)
5548       printf("(none)");
5549     else
5550       for (i = 0; i < ndialtocc; i++)
5551         printf("%s ", dialtocc[i]);
5552     printf("\n");
5553     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5554
5555     printf(
5556         " Dial toll-free-prefix:        %s\n",
5557         dialtfp ? dialtfp :
5558         (dialldp ? dialldp : "(none)")
5559         );
5560     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5561     printf(" Dial pbx-exchange:            ");
5562     if (ndialpxx == 0)
5563       printf("(none)");
5564     else
5565       for (i = 0; i < ndialpxx; i++)
5566         printf("%s ", dialpxx[i]);
5567     printf("\n");
5568
5569     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5570     printf(
5571 " Dial pbx-inside-prefix:       %s\n", dialpxi ? dialpxi : "(none)");
5572     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5573     printf(
5574 " Dial pbx-outside-prefix:      %s\n", dialpxo ? dialpxo : "(none)");
5575     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
5576     printf(
5577 " Dial macro:                   %s\n", dialmac ? dialmac : "(none)");
5578     return(0);
5579 }
5580 #endif /* NODIAL */
5581 #endif /* NOLOCAL */
5582
5583 /*  Show File Parameters */
5584
5585 static char *
5586 pathval(x) int x; {
5587     switch (x) {
5588       case PATH_OFF:  return("off");
5589       case PATH_ABS:  return("absolute");
5590       case PATH_REL:  return("relative");
5591       case PATH_AUTO: return("auto");
5592       default: return("unknown");
5593     }
5594 }
5595
5596 VOID
5597 shofil() {
5598     char *s; int i = 0, n = 1;
5599     extern char * ifdnam[];
5600 #ifdef UNIX
5601     extern int wildxpand;
5602 #endif /* UNIX */
5603     extern char * snd_move, * snd_rename, * rcv_move, * rcv_rename;
5604 #ifdef PATTERNS
5605     extern int patterns;
5606 #endif /* PATTERNS */
5607     extern char * rfspec, * sfspec;
5608 #ifdef UNIX
5609     extern int zobufsize, zofbuffer, zofblock;
5610 #endif /* UNIX */
5611 #ifdef CK_CTRLZ
5612     extern int eofmethod;
5613 #endif /* CK_CTRLZ */
5614
5615     printf("\n");
5616
5617 #ifdef VMS
5618     printf(" File record-Length:      %5d\n",frecl);
5619     n++;
5620 #endif /* VMS */
5621
5622 #ifndef NOXFER
5623     printf(" Transfer mode:           %s\n",
5624            xfermode == XMODE_A ?
5625            "automatic" :
5626            "manual"
5627            );
5628     n++;
5629 #ifdef PATTERNS
5630     printf(" File patterns:           %s", showooa(patterns));
5631     if (xfermode == XMODE_M && patterns)
5632       printf(" (but disabled by TRANSFER-MODE MANUAL)");
5633     else if (patterns)
5634       printf(" (SHOW PATTERNS for list)");
5635     printf("\n");
5636     n++;
5637 #endif /* PATTERNS */
5638     if (filepeek)
5639       printf(" File scan:               on %d\n", nscanfile);
5640     else
5641       printf(" File scan:               off\n");
5642     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5643     if (xfermode == XMODE_A)
5644       printf(" Default file type:       %s\n",shoxm());
5645     else
5646       printf(" File type:               %s\n",shoxm());
5647     n++;
5648     if (fncnv == XYFN_L)
5649       s = "literal";
5650     else if (fncnv == XYFN_C)
5651       s = "converted";
5652     else
5653       s = "(unknown)";
5654     printf(" File names:              %s\n",s);
5655     n++;
5656     printf(" Send pathnames:          %s\n", pathval(fnspath));
5657     n++;
5658     printf(" Receive pathnames:       %s\n", pathval(fnrpath));
5659     n++;
5660 #ifdef UNIXOROSK
5661     printf(" Match dot files:         %s\n", matchdot ? "yes" : "no");
5662     n++;
5663 #ifdef UNIX
5664     printf(" Wildcard-expansion:      %s\n", wildxpand ? "shell" : "kermit");
5665     n++;
5666 #endif /* UNIX */
5667 #endif /* UNIXOROSK */
5668     printf(" File collision:          ");
5669     for (i = 0; i < ncolx; i++)
5670       if (colxtab[i].kwval == fncact) break;
5671     printf("%s\n", (i == ncolx) ? "unknown" : colxtab[i].kwd);
5672     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5673     printf(" File destination:        %s\n",
5674            (dest == DEST_D) ? "disk" :
5675            ((dest == DEST_S) ? "screen" :
5676             ((dest == DEST_N) ? "nowhere" :
5677             "printer"))
5678            );
5679     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5680     s = (keep >= 0 && keep <= 2) ? ifdnam[keep] : "keep";
5681     printf(" File incomplete:         %s\n",s);
5682     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5683     printf(" File bytesize:           %d\n",(fmask == 0177) ? 7 : 8);
5684     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5685 #ifndef NOCSETS
5686     printf(" File character-set:      %s\n",fcsinfo[fcharset].keyword);
5687     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5688     printf(" File default 7-bit:      %s\n",fcsinfo[dcset7].keyword);
5689     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5690     printf(" File default 8-bit:      %s\n",fcsinfo[dcset8].keyword);
5691     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5692 #ifdef UNICODE
5693     printf(" File UCS bom:            %s\n",showoff(ucsbom));
5694     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5695     printf(" File UCS byte-order:     %s-endian\n",
5696            ucsorder ? "little" : "big");
5697     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5698     printf(" Computer byteorder:      %s-endian\n",
5699            byteorder ? "little" : "big");
5700     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5701 #endif /* UNICODE */
5702 #endif /* NOCSETS */
5703
5704     printf(" File end-of-line:        ");
5705     i = feol;
5706     switch (feol) {
5707       case XYFA_C: printf("%s\n","cr"); break;
5708       case XYFA_L: printf("%s\n","lf"); break;
5709       case XYFA_2: printf("%s\n","crlf"); break;
5710       default: printf("%d\n",i);
5711     }
5712     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5713 #endif /* NOXFER */
5714
5715 #ifdef CK_CTRLZ
5716     printf(" File eof:                %s\n", eofmethod ? "ctrl-z" : "length");
5717     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5718 #endif /* CK_CTRLZ */
5719 #ifndef NOXFER
5720 #ifdef CK_TMPDIR
5721     printf(" File download-directory: %s\n", dldir ? dldir : "(none)");
5722     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5723 #ifdef COMMENT
5724     i = 256;
5725     s = line;
5726     zzstring("\\v(tmpdir)",&s,&i);
5727     printf(" Temporary directory:     %s\n", line);
5728     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5729 #endif /* COMMENT */
5730 #endif /* CK_TMPDIR */
5731 #ifdef VMS
5732     {
5733         extern int vmssversions, vmsrversions;
5734         printf(" Send version-numbers:    %s\n",showoff(vmssversions));
5735         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5736         printf(" Receive version-numbers: %s\n",showoff(vmsrversions));
5737         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5738     }
5739 #endif /* VMS */
5740     printf(" Send move-to:            %s\n",
5741            snd_move ? snd_move : "(none)");
5742     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5743     printf(" Send rename-to:          %s\n",
5744            snd_rename ? snd_rename : "(none)");
5745     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5746     printf(" Receive move-to:         %s\n",
5747            rcv_move ? rcv_move : "(none)");
5748     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5749     printf(" Receive rename-to:       %s\n",
5750            rcv_rename ? rcv_rename : "(none)");
5751     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5752 #endif /* NOXFER */
5753 #ifdef KERMRC
5754     printf(" Initialization file:     %s\n", noinit ? "(none)" :
5755 #ifdef CK_SYSINI
5756            CK_SYSINI
5757 #else
5758            kermrc
5759 #endif /* CK_SYSINI */
5760            );
5761 #endif /* KERMRC */
5762     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5763
5764     if (k_info_dir) {
5765         printf(" Kermit doc files:        %s\n", k_info_dir);
5766         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5767     }
5768
5769 #ifdef CKROOT
5770     s = zgetroot();
5771     printf(" Root set:                %s\n", s ? s : "(none)");
5772 #endif /* CKROOT */
5773
5774 #ifdef UNIX
5775     printf(" Disk output buffer:      %d (writes are %s, %s)\n",
5776            zobufsize,
5777            zofbuffer ? "buffered" : "unbuffered",
5778            zofblock ? "blocking" : "nonblocking"
5779            );
5780     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5781 #ifdef DYNAMIC
5782     printf(" Stringspace:             %d\n", zsetfil(0,2));
5783     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5784     printf(" Listsize:                %d\n", zsetfil(0,4));
5785     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5786 #endif /* DYNAMIC */
5787 #endif /* UNIX */
5788 #ifdef OS2ORUNIX
5789     printf(" Longest filename:        %d\n", maxnam);
5790     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5791     printf(" Longest pathname:        %d\n", maxpath);
5792     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5793 #endif /* OS2ORUNIX */
5794
5795     printf(" Last file sent:          %s\n", sfspec ? sfspec : "(none)");
5796     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5797     printf(" Last file received:      %s\n", rfspec ? rfspec : "(none)");
5798     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5799     printf("\n Also see:\n");
5800     n++;
5801     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
5802     printf(" SHOW PROTOCOL, SHOW XFER");
5803 #ifdef CK_LABELED
5804     printf(", SHOW LABELED");
5805 #endif /* CK_LABELED */
5806 #ifdef PATTERNS
5807     printf(", SHOW PATTERNS");
5808 #endif /* PATTERNS */
5809 #ifdef STREAMING
5810     printf(", SHOW STREAMING");
5811 #endif /* STREAMING */
5812 #ifndef NOCSETS
5813     printf(", SHOW CHARACTER-SETS");
5814 #endif /* NOCSETS */
5815     printf("\n\n");
5816 }
5817
5818 #ifndef NOXFER
5819 VOID
5820 shoparp() {                             /* Protocol */
5821     extern int docrc, skipbup;
5822     char *s;
5823
5824 #ifdef CK_TIMERS
5825     extern int rttflg;
5826 #endif /* CK_TIMERS */
5827
5828     printf("Protocol: %s\n",ptab[protocol].p_name);
5829
5830     if (protocol == PROTO_K) {
5831         printf("\nProtocol Parameters:   Send    Receive");
5832         if (timef)
5833           printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
5834         else
5835           printf("\n Timeout (used=%2d):%7d%9d ",  timint, rtimo, pkttim);
5836 #ifdef XFRCAN
5837         printf("       Cancellation:    %s",showoff(xfrcan));
5838         if (xfrcan)
5839           printf(" %d %d", xfrchr, xfrnum);
5840 #endif /* XFRCAN */
5841         printf("\n Padding:      %11d%9d", npad,   mypadn);
5842         if (bctr == 4)
5843           printf("        Block Check: blank-free-2\n");
5844         else
5845           printf("        Block Check: %6d\n",bctr);
5846         printf(  " Pad Character:%11d%9d", padch,  mypadc);
5847         printf("        Delay:       %6d\n",ckdelay);
5848         printf(  " Pause:        %11d%9d", pktpaus, pktpaus);
5849         printf("        Attributes:      %s\n",showoff(atcapr));
5850         printf(  " Packet Start: %11d%9d", mystch, stchr);
5851         printf("        Max Retries: %6d%s\n",
5852                maxtry,
5853                (maxtry == 0) ? " (unlimited)" : ""
5854                );
5855         printf(  " Packet End:   %11d%9d", seol,   eol);
5856         if (ebqflg)
5857           printf("        8th-Bit Prefix: '%c'",ebq);
5858         else
5859           printf("        8th-Bit Prefix: ('%c' but not used)",ebq);
5860         printf(  "\n Packet Length:%11d ", spmax);
5861         printf("%8d     ",  urpsiz);
5862         if (rptflg)
5863           printf("   Repeat Prefix:  '%c'",rptq);
5864         else
5865           printf("   Repeat Prefix:  ('%c' but not used)",rptq);
5866         printf(  "\n Maximum Length: %9d%9d", maxsps, maxrps);
5867         printf("        Window Size:%7d set, %d used\n",wslotr,wmax);
5868         printf(    " Buffer Size:  %11d%9d", bigsbsiz, bigrbsiz);
5869         printf("        Locking-Shift:    ");
5870         if (lscapu == 2) {
5871             printf("forced");
5872         } else {
5873             printf("%s", (lscapr ? "enabled" : "disabled"));
5874             if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
5875         }
5876         printf("\n\n");
5877
5878         if (!(s = ptab[protocol].h_b_init)) s = "";
5879         printf(" Auto-upload command (binary): ");
5880         if (*s) {
5881             shostrdef((CHAR *)s);
5882             printf("\n");
5883         } else {
5884             printf("(none)\n");
5885         }
5886         if (!(s = ptab[protocol].h_t_init)) s = "";
5887         printf(" Auto-upload command (text):   ");
5888         if (*s) {
5889             shostrdef((CHAR *)s);
5890             printf("\n");
5891         } else {
5892             printf("(none)\n");
5893         }
5894         if (!(s = ptab[protocol].h_x_init)) s = "";
5895         printf(" Auto-server command:          ");
5896         if (*s) {
5897             shostrdef((CHAR *)s);
5898             printf("\n");
5899         } else {
5900             printf("(none)\n");
5901         }
5902         tmpbuf[0] = NUL;
5903 #ifdef CK_TIMERS
5904         if (rttflg) {
5905             extern int mintime, maxtime;
5906             sprintf(tmpbuf," Packet timeouts: dynamic %d:%d", /* SAFE */
5907                     mintime,
5908                     maxtime);
5909         } else {
5910             sprintf(tmpbuf," Packet timeouts: fixed"); /* SAFE */
5911         }
5912 #endif /* CK_TIMERS */
5913         if (tmpbuf[0])
5914           printf("%-31s",tmpbuf);
5915         printf("Send backup: %s\n",showoff(!skipbup));
5916
5917         printf(" Transfer mode:   %s", xfermode == XMODE_A ?
5918                "automatic   " :
5919                "manual      "
5920                );
5921         printf(" Transfer slow-start: %s, crc: %s\n",
5922                showoff(slostart),
5923                showoff(docrc)
5924                );
5925 #ifdef PIPESEND
5926         {
5927             extern int usepipes;
5928             printf(" Transfer pipes:  %s         ",usepipes ? "on " : "off");
5929         }
5930 #endif /* PIPESEND */
5931 #ifndef NOCSETS
5932         printf(" Transfer character-set: ");
5933         if (tcharset == TC_TRANSP)
5934           printf("transparent\n");
5935         else
5936           printf("%s\n", tcsinfo[tcharset].keyword );
5937 #endif /* NOCSETS */
5938 #ifdef PIPESEND
5939         {
5940             extern char * sndfilter, * rcvfilter;
5941             printf(" Send filter:     %s\n", sndfilter ? sndfilter : "(none)");
5942             printf(" Receive filter:  %s\n", rcvfilter ? rcvfilter : "(none)");
5943         }
5944 #endif /* PIPESEND */
5945         printf("\nAlso see:\n");
5946         printf(" SHOW FILE, SHOW XFER");
5947
5948 #ifdef CK_LABELED
5949         printf(", SHOW LABELED");
5950 #endif /* CK_LABELED */
5951 #ifdef PATTERNS
5952         printf(", SHOW PATTERNS");
5953 #endif /* PATTERNS */
5954 #ifdef STREAMING
5955         printf(", SHOW STREAMING");
5956 #endif /* STREAMING */
5957 #ifndef NOCSETS
5958         printf(", SHOW CHARACTER-SETS");
5959 #endif /* NOCSETS */
5960     }
5961
5962 #ifdef CK_XYZ
5963 #ifdef XYZ_INTERNAL
5964     if (protocol != PROTO_K) {
5965         int i;
5966         int x;
5967         printf(" File type: %s\n", binary ? "binary" : "text");
5968         if (protocol == PROTO_Z) {              /* Zmodem */
5969             printf(" Window size:   ");
5970             if (ptab[protocol].winsize < 1)
5971               printf("none\n");
5972             else
5973               printf("%d\n",wslotr);
5974 #ifdef COMMENT
5975             printf(" Packet (frame) length: ");
5976             if (ptab[protocol].spktlen < 0)
5977               printf("none\n");
5978             else
5979               printf("%d\n",spmax);
5980 #endif /* COMMENT */
5981         } else {
5982             if (ptab[protocol].spktlen >= 1000)
5983               printf(" 1K packets\n");
5984             else
5985               printf(" 128-byte packets\n");
5986         }
5987         printf(" Pathname stripping when sending:   %s\n",
5988                showoff(ptab[protocol].fnsp)
5989                );
5990         printf(" Pathname stripping when receiving: %s\n",
5991                showoff(ptab[protocol].fnrp)
5992                );
5993         printf(" Filename collision action:         ");
5994         for (i = 0; i < ncolx; i++)
5995           if (colxtab[i].kwval == fncact) break;
5996         printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
5997
5998         printf("\n Escape control characters:          ");
5999         x = ptab[protocol].prefix;
6000         if (x == PX_ALL)
6001           printf("all\n");
6002         else if (x == PX_CAU || x==PX_WIL)
6003           printf("minimal\n");
6004         else
6005           printf("none\n");
6006         if (!(s = ptab[protocol].h_b_init))
6007           s = "";
6008         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
6009         if (!(s = ptab[protocol].h_t_init))
6010           s = "";
6011         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
6012     }
6013 #else
6014     if (protocol != PROTO_K) {
6015         printf("\nExecuted by external commands:\n\n");
6016         s = ptab[protocol].p_b_scmd;
6017         if (!s) s = "";
6018         printf(" SEND command (binary):        %s\n", *s ? s : "(none)");
6019         s = ptab[protocol].p_t_scmd;
6020         if (!s) s = "";
6021         printf(" SEND command (text):          %s\n", *s ? s : "(none)");
6022         s = ptab[protocol].p_b_rcmd;
6023         if (!s) s = "";
6024         printf(" RECEIVE command (binary):     %s\n", *s ? s : "(none)");
6025         s = ptab[protocol].p_t_rcmd;
6026         if (!s) s = "";
6027         printf(" RECEIVE command (text):       %s\n", *s ? s : "(none)");
6028         s = ptab[protocol].h_b_init;
6029         if (!s) s = "";
6030         printf(" Autoreceive command (binary): %s\n", *s ? s : "(none)");
6031         s = ptab[protocol].h_t_init;
6032         if (!s) s = "";
6033         printf(" Autoreceive command (text):   %s\n", *s ? s : "(none)");
6034     }
6035 #endif /* XYZ_INTERNAL */
6036 #endif /* CK_XYZ */
6037 }
6038 #endif /* NOXFER */
6039
6040 #ifndef NOCSETS
6041 /* Character-set items */
6042
6043 extern int s_cset, r_cset, axcset[], afcset[];
6044 extern struct keytab xfrmtab[];
6045
6046 VOID
6047 shoparl() {
6048 #ifdef COMMENT
6049     int i;
6050 /* Misleading... */
6051     printf("\nAvailable Languages:\n");
6052     for (i = 0; i < MAXLANG; i++) {
6053         printf(" %s\n",langs[i].description);
6054     }
6055 #else
6056     printf("\nLanguage-specific translation rules: %s\n",
6057            language == L_USASCII ? "none" : langs[language].description);
6058     shocharset();
6059     printf("\n\n");
6060 #endif /* COMMENT */
6061 }
6062
6063 VOID
6064 shocharset() {
6065     int x;
6066 #ifdef COMMENT
6067     char * s = "Unknown";
6068     extern int xlatype;
6069 #endif /* COMMENT */
6070
6071 #ifndef NOXFER
6072     extern int xfrxla;
6073 #endif /* NOXFER */
6074
6075     debug(F101,"SHOW FILE CHAR","",fcharset);
6076     printf("\n");
6077 #ifndef NOXFER
6078     printf(" Transfer Translation: %s\n", showoff(xfrxla));
6079     if (!xfrxla) {
6080         printf(
6081       " Because transfer translation is off, the following are ignored:\n\n");
6082     }
6083 #endif /* NOXFER */
6084     printf(" File Character-Set: %s (%s), ",
6085            fcsinfo[fcharset].keyword,
6086            fcsinfo[fcharset].name
6087            );
6088     if ((x = fcsinfo[fcharset].size) == 128)
6089       printf("7-bit");
6090     else if (x == 256)
6091       printf("8-bit");
6092     else
6093       printf("multibyte");
6094     printf("\n");
6095     printf(" File Scan: %s\n",showoff(filepeek));
6096     printf("   Default 7bit-Character-Set: %s\n",fcsinfo[dcset7].keyword);
6097     printf("   Default 8bit-Character-Set: %s\n",fcsinfo[dcset8].keyword);
6098     printf(" Transfer Character-Set");
6099 #ifdef COMMENT
6100     if (tslevel == TS_L2)
6101       printf(": (international)");
6102     else
6103 #endif /* COMMENT */
6104     if (tcharset == TC_TRANSP)
6105       printf(": Transparent");
6106     else
6107       printf(": %s (%s)",tcsinfo[tcharset].keyword, tcsinfo[tcharset].name);
6108     printf("\n");
6109 #ifdef COMMENT
6110     switch (xlatype) {
6111       case XLA_NONE: s = "None"; break;
6112       case XLA_BYTE: s = "Byte"; break;
6113       case XLA_JAPAN: s = "Japanese"; break;
6114       case XLA_UNICODE: s = "Unicode"; break;
6115     }
6116     printf("\n Translation type: %s\n",s);
6117 #endif /* COMMENT */
6118     printf(" SEND character-set-selection: %s\n",xfrmtab[s_cset].kwd);
6119     printf(" RECEIVE character-set-selection: %s\n",xfrmtab[r_cset].kwd);
6120     if (s_cset == XMODE_A || r_cset == XMODE_A)
6121       printf(
6122       " (Use SHOW ASSOCIATIONS to list automatic character-set selections.)\n"
6123              );
6124 }
6125
6126 VOID
6127 showassoc() {
6128     int i, k, n = 4;
6129     char * s;
6130     printf("\nFor incoming files:\n\n");
6131     printf("Transfer Character-Set   File Character-Set\n");
6132     for (i = 1; i <= MAXTCSETS; i++) {
6133         k = axcset[i];
6134         if (k < 0 || k > MAXFCSETS)
6135           s = "(none)";
6136         else
6137           s = fcsinfo[k].keyword;
6138         if (!s) s = "";
6139         if (!*s) s = "(none)";
6140         printf(" %-25s%s\n",tcsinfo[i].keyword,s);
6141         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6142     }
6143     printf("\nFor outbound files:\n\n");
6144     n += 2;
6145     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6146     printf("File Character-Set       Transfer Character-Set\n");
6147     if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6148     for (i = 0; i <= MAXFCSETS; i++) {
6149         k = afcset[i];
6150         if (k < 0 || k > MAXTCSETS)
6151           s = "(none)";
6152         else
6153           s = tcsinfo[k].keyword;
6154         if (!s) s = "";
6155         if (!*s) s = "(none)";
6156         printf(" %-25s%s\n",fcsinfo[i].keyword,s);
6157         if (++n > cmd_rows - 3) if (!askmore()) return; else n = 0;
6158     }
6159 }
6160 #endif /* NOCSETS */
6161
6162 VOID
6163 shopar() {
6164     printf("Show what?  (Type \"show ?\" for a list of possibilities.)\n");
6165 }
6166 #endif /* NOSHOW */
6167
6168 #ifndef NOXFER
6169 /*  D O S T A T  --  Display file transfer statistics.  */
6170
6171 int
6172 dostat(brief) int brief; {
6173     extern long filrej, peakcps;
6174     extern int lastspmax, streamed, cleared, streamok;
6175     extern char whoareu[];
6176     int n = 0, ftp = 0;
6177     extern int docrc, interrupted, fatalio;
6178
6179     ftp = lastxfer & W_FTP;
6180
6181 #ifdef CK_TTGWSIZ
6182 #ifdef OS2
6183     if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
6184       ttgwsiz();
6185 #else /* OS2 */
6186     if (ttgwsiz() > 0) {
6187         if (tt_rows > 0 && tt_cols > 0) {
6188             cmd_rows = tt_rows;
6189             cmd_cols = tt_cols;
6190         }
6191     }
6192 #endif /* OS2 */
6193 #endif /* CK_TTGWSIZ */
6194
6195     debug(F101,"dostat xferstat","",xferstat);
6196     if (xferstat < 0) {
6197         printf(" No file transfers yet.\n");
6198         return(1);
6199     }
6200     n = 0;
6201     if (brief) { printf("\n"); n++; };
6202     printf(" protocol               : %s\n",
6203            ftp ? "ftp" : ptab[protocol].p_name);
6204     n++;
6205     printf(" status                 : ");
6206     if (xferstat) printf("SUCCESS\n");
6207     else if (interrupted) printf("FAILURE (interrupted)\n");
6208     else if (fatalio) printf("FAILURE (i/o error)\n");
6209     else printf("FAILURE\n");
6210 #ifndef XYZ_INTERNAL
6211     if (!ftp && protocol != PROTO_K) {
6212         printf("\n external protocol statistics not available\n");
6213         return(1);
6214     }
6215 #endif /* XYZ_INTERNAL */
6216     n++;
6217     if (!ftp) {
6218         if (!xferstat > 0) {
6219             if (docrc)
6220               printf(" crc-16 of file(s)      : %ld\n", crc16);
6221             else
6222               printf(" crc-16 of file(s)      : (disabled)\n");
6223             n++;
6224         }
6225         if (!xferstat && *epktmsg) {
6226             printf(" reason                 : %s\n", epktmsg);
6227             n++;
6228         }
6229     }
6230     if (!brief) {
6231 #ifdef NEWFTP
6232         if (ftp) {
6233             extern char ftp_srvtyp[];
6234             printf(" remote system type     : %s\n",ftp_srvtyp);
6235         } else
6236 #endif /* NEWFTP */
6237           if (whoareu[0]) {
6238             printf(" remote system type     : %s\n",
6239                    getsysid((char *)whoareu));
6240             n++;
6241         }
6242         printf(" files transferred      : %ld\n",filcnt - filrej);
6243         if (!ftp)
6244           printf(" files not transferred  : %ld\n",filrej);
6245         printf(" characters last file   : %ld\n",ffc);
6246         printf(" total file characters  : %ld\n",tfc);
6247         n += ftp ? 3 : 4;
6248         if (!ftp) {
6249             printf(" communication line in  : %ld\n",tlci);
6250             printf(" communication line out : %ld\n",tlco);
6251             printf(" packets sent           : %d\n", spackets);
6252             printf(" packets received       : %d\n", rpackets);
6253             n += 4;
6254         }
6255     }
6256     if (ftp) goto dotimes;
6257
6258     printf(" damaged packets rec'd  : %d\n", crunched);
6259     printf(" timeouts               : %d\n", timeouts);
6260     printf(" retransmissions        : %d\n", retrans);
6261     n += 3;
6262
6263     if (!brief) {
6264         if (filcnt > 0) {
6265             printf(" parity                 : %s",parnam((char)parity));
6266             n++;
6267             if (autopar) { printf(" (detected automatically)"); n++; }
6268             printf(
6269                  "\n control characters     : %ld prefixed, %ld unprefixed\n",
6270                    ccp, ccu);
6271             n++;
6272             printf(" 8th bit prefixing      : ");
6273             n++;
6274             if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
6275             n++;
6276             printf(" locking shifts         : %s\n", lscapu ? "yes" : "no");
6277             n++;
6278         }
6279     }
6280     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6281     if (streamed > 0)
6282       printf(" window slots used      : (streaming)\n");
6283     else
6284       printf(" window slots used      : %d of %d\n", wmax, wslotr);
6285     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6286     printf(" reliable:              : %s%s\n",
6287            streamok ? "" : "not ", "negotiated");
6288     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6289     printf(" clearchannel:          : %s%s\n",
6290            cleared  ? "" : "not ", "negotiated");
6291     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6292
6293     if (!brief) {
6294         printf(" packet length          : %d (send), %d (receive)\n",
6295                lastspmax, urpsiz);
6296         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6297         printf(" compression            : ");
6298         if (rptflg)
6299           printf("yes [%c] (%ld)\n",(char) rptq,rptn);
6300         else
6301           printf("no\n");
6302         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6303         if (bctu == 4)
6304           printf(" block check type used  : blank-free-2\n");
6305         else
6306           printf(" block check type used  : %d\n",bctu);
6307         if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6308     }
6309
6310   dotimes:
6311
6312 #ifdef GFTIMER
6313 #ifdef COMMENT
6314     printf(" elapsed time           : %0.3f sec, %s\n", fptsecs,hhmmss(tsecs));
6315 #endif /* COMMENT */
6316     printf(" elapsed time           : %s (%0.3f sec)\n",
6317            hhmmss((long)(fptsecs + 0.5)),fptsecs);
6318 #else
6319 #ifdef COMMENT
6320     printf(" elapsed time           : %s (%d sec)\n",hhmmss(tsecs),tsecs);
6321 #endif /* COMMENT */
6322     printf(" elapsed time           : %d sec, %s\n",tsecs,hhmmss(tsecs));
6323 #endif /* GFTIMER */
6324     if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6325     if (!ftp && local && !network && !brief) {
6326         if (speed <= 0L) speed = ttgspd();
6327         if (speed > 0L) {
6328             if (speed == 8880)
6329               printf(" transmission rate      : 75/1200 bps\n");
6330             else
6331               printf(" transmission rate      : %ld bps\n",speed);
6332             if (++n > cmd_rows - 3) { if (!askmore()) return(1); else n = 0; }
6333         }
6334     }
6335     if (!ftp && local && !network &&    /* Only makes sense for */
6336         mdmtyp == 0 &&                  /* direct serial connections */
6337         speed > 99L &&                  /* when we really know the speed */
6338         speed != 8880L
6339         ) {
6340         int eff;
6341         eff = (((tfcps * 100L) / (speed / 100L)) + 5L) / 10L;
6342         printf(" effective data rate    : %ld cps (%d%%)\n",tfcps,eff);
6343     } else
6344       printf(" effective data rate    : %ld cps\n", tfcps);
6345     if (!ftp && peakcps > 0L && peakcps > tfcps)
6346       printf(" peak data rate         : %ld cps\n", peakcps);
6347     if (brief)
6348       printf("\nUse STATISTICS /VERBOSE for greater detail.\n\n");
6349     return(1);
6350 }
6351 #endif /* NOXFER */
6352
6353 #ifndef NOSPL
6354
6355 /* The INPUT command */
6356
6357 /*
6358   NOTE: An INPUT timeout of 0 means to perform a nonblocking read of the
6359   material that has already arrived and is waiting to be read, and perform
6360   matches against it, without doing any further reads.  It should succeed
6361   or fail instantaneously.
6362 */
6363
6364 /* Output buffering for "doinput" */
6365
6366 #ifdef pdp11
6367 #define MAXBURST 16             /* Maximum size of input burst */
6368 #else
6369 #define MAXBURST 1024
6370 #endif /* pdp11 */
6371 #ifdef OSK
6372 static CHAR *conbuf;            /* Buffer to hold output for console */
6373 #else
6374 static CHAR conbuf[MAXBURST];   /* Buffer to hold output for console */
6375 #endif /* OSK */
6376 static int concnt = 0;          /* Number of characters buffered */
6377 #ifdef OSK
6378 static CHAR *sesbuf;            /* Buffer to hold output for session log */
6379 #else
6380 static CHAR sesbuf[MAXBURST];   /* Buffer to hold output for session log */
6381 #endif /* OSK */
6382 static int sescnt = 0;          /* Number of characters buffered */
6383
6384 extern int debses;                      /* TERMINAL DEBUG ON/OFF */
6385
6386 static VOID                             /* Flush INPUT echoing */
6387 myflsh() {                              /* and session log output. */
6388     if (concnt > 0) {
6389         if (debses) {                   /* Terminal debugging? */
6390             int i;
6391             for (i = 0; i < concnt; i++)
6392               conol(dbchr(conbuf[i]));
6393         } else
6394           conxo(concnt, (char *) conbuf);
6395         concnt = 0;
6396     }
6397     if (sescnt > 0) {
6398         logstr((char *) sesbuf, sescnt);
6399         sescnt = 0;
6400     }
6401 }
6402
6403 /* Execute the INPUT and MINPUT commands */
6404
6405 int instatus = -1;
6406 long inetime = -1L;
6407 int inwait = 0;
6408
6409 /* For returning the input sequence that matched */
6410
6411 #ifdef BIGBUFOK
6412 #define MATCHBUFSIZ 8191
6413 #else
6414 #define MATCHBUFSIZ 1023
6415 #endif /* BIGBUFOK */
6416 static char * matchbuf = NULL;
6417 static int matchindex = 0;
6418 /*
6419   timo = How long to wait:
6420          < 0 = Wait forever
6421            0 = Don't wait
6422          > 0 = Wait this many seconds
6423   ms   = Array of strings to wait for.
6424   mp   = Array of flags.
6425          If mp[i] == 0, ms[i] is literal, else it's a pattern.
6426   flags = for now, 1 or 0.  If 1, then don't match anything.
6427 */
6428 int
6429 doinput(timo,ms,mp,flags) int timo; char *ms[]; int mp[]; int flags; {
6430     extern int inintr;
6431 #ifdef CK_AUTODL
6432     extern int inautodl;
6433 #endif /* CK_AUTODL */
6434     int x, y, i, t, rt, icn, anychar, mi[MINPMAX];
6435 #ifdef GFTIMER
6436     CKFLOAT fpt = 0.0;
6437 #endif /* GFTIMER */
6438     int nomatch = 0;
6439     int lastchar = 0;
6440     int waiting = 0;
6441     int imask = 0;
6442     char ch, *xp, *s;
6443     CHAR c;
6444 #ifndef NOLOCAL
6445 #ifdef OS2
6446     extern int term_io;
6447     int term_io_save;
6448 #endif /* OS2 */
6449 #endif /* NOLOCAL */
6450 #ifdef TNCODE
6451     static int cr = 0;
6452 #endif /* TNCODE */
6453     int is_tn = 0;
6454     int wrapped = 0;
6455 #ifdef SSHBUILTIN
6456     extern int ssh_cas;
6457     extern char * ssh_cmd;
6458 #endif /* SSHBUILTIN */
6459
6460 #define CK_BURST
6461 /*
6462   This enables the INPUT speedup code, which depends on ttchk() returning
6463   accurate information.  If INPUT fails with this code enabled, change the
6464   above "#define" to "#undef".
6465 */
6466 #ifdef CK_BURST
6467     int burst = 0;                      /* Chars remaining in input burst */
6468 #endif /* CK_BURST */
6469
6470     imask = cmask;
6471     if (parity) imask = 0x7f;
6472     inwait = timo;                      /* For \v(inwait) */
6473     nomatch = flags & 1;
6474     makestr(&inpmatch,NULL);
6475
6476     if (!matchbuf) {
6477         matchbuf = malloc(MATCHBUFSIZ+1);
6478         matchbuf[0] = NUL;
6479     }
6480     matchindex = 0;
6481
6482     is_tn =
6483 #ifdef TNCODE
6484         (local && network && IS_TELNET()) || (!local && sstelnet)
6485 #else
6486          0
6487 #endif /* TNCODE */
6488           ;
6489
6490     instatus = INP_IE;                  /* 3 = internal error */
6491     kbchar = 0;
6492
6493 #ifdef OSK
6494     if (conbuf == NULL) {
6495         if ((conbuf = (CHAR *)malloc(MAXBURST*2)) == NULL) {
6496             return(0);
6497         }
6498         sesbuf = conbuf + MAXBURST;
6499     }
6500 #endif /* OSK */
6501
6502 #ifndef NOLOCAL
6503     if (local) {                        /* In local mode... */
6504         if ((waiting = ttchk()) < 0) {  /* check that connection is open */
6505             if (!quiet) {
6506                 if ((!network 
6507 #ifdef TN_COMPORT
6508                       || istncomport()
6509 #endif /* TN_COMPORT */
6510                       ) && carrier != CAR_OFF)
6511                     printf("?Carrier detect failure on %s.\n", ttname);
6512                 else
6513                     printf("?Connection %s %s is not open.\n",
6514                        network ? "to" : "on",
6515                        ttname
6516                        );
6517             }
6518             instatus = INP_IO;
6519             return(0);
6520         }
6521         debug(F101,"doinput waiting","",waiting);
6522         y = ttvt(speed,flow);           /* Put line in "ttvt" mode */
6523         if (y < 0) {
6524             printf("?INPUT initialization error\n");
6525             instatus = INP_IO;
6526             return(0);                  /* Watch out for failure. */
6527         }
6528     }
6529 #endif /* NOLOCAL */
6530
6531 #ifdef SSHBUILTIN
6532     if ( network && nettype == NET_SSH && ssh_cas && ssh_cmd && 
6533          !(strcmp(ssh_cmd,"kermit") && strcmp(ssh_cmd,"sftp"))) {
6534         if (!quiet)
6535           printf("?SSH Subsystem active: %s\n", ssh_cmd);
6536         instatus = INP_IKS;
6537         return(0);
6538     }
6539 #endif /* SSHBUILTIN */
6540
6541     debug(F111,"doinput ms[0]",ms[0],waiting);
6542
6543     if (!ms[0]) {                       /* If we were passed a NULL pointer */
6544         anychar = 1;                    /*  ... */
6545     } else {
6546         y = (int)strlen(ms[0]);         /* Or if search string is empty */
6547         anychar = (y < 1);              /* any input character will do. */
6548     }
6549     if (flags & 1) anychar = 0;         /* Don't match anything */
6550
6551     if (!anychar && waiting == 0 && timo == 0)
6552       return(0);
6553
6554
6555 #ifndef NODEBUG
6556     if (deblog) {
6557         char xbuf[24];
6558         debug(F101,"doinput anychar","",anychar);
6559         debug(F101,"doinput timo","",timo);
6560         debug(F101,"doinput echo","",inecho);
6561         debug(F101,"doinput burst","",burst);
6562         y = -1;
6563         while (ms[++y]) {
6564             sprintf(xbuf,"doinput string %2d",y); /* SAFE (24) */
6565             debug(F111,xbuf,ms[y],mp[y]);
6566         }
6567     }
6568 #endif /* NODEBUG */
6569
6570 #ifdef IKS_OPTION
6571     if (is_tn) {
6572         /* If the remote side is in a state of IKS START-SERVER    */
6573         /* we request that the state be changed.  We will detect   */
6574         /* a failure to adhere to the request when we call ttinc() */
6575         if (TELOPT_U(TELOPT_KERMIT) &&
6576             TELOPT_SB(TELOPT_KERMIT).kermit.u_start)
6577           iks_wait(KERMIT_REQ_STOP,0);  /* Send Request-Stop */
6578 #ifdef CK_AUTODL
6579         /* If we are processing packets during INPUT and we have not */
6580         /* sent a START message, do so now.                          */
6581         if (inautodl && TELOPT_ME(TELOPT_KERMIT) &&
6582                         !TELOPT_SB(TELOPT_KERMIT).kermit.me_start) {
6583             tn_siks(KERMIT_START);      /* Send Kermit-Server Start */
6584         }
6585 #endif /* CK_AUTODL */
6586     }
6587 #endif /* IKS_OPTION */
6588     x = 0;                              /* Return code, assume failure */
6589     instatus = INP_TO;                  /* Status, assume timeout */
6590
6591     for (y = 0; y < MINPMAX; y++)
6592       mi[y] = 0;                        /* String pattern match position */
6593
6594     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
6595         y = -1;
6596
6597         while ((xp = ms[++y])) {
6598             while (*xp) {               /* Convert to lowercase */
6599                 if (isupper(*xp)) *xp = (char) tolower(*xp);
6600                 xp++;
6601             }
6602         }
6603     }
6604     rtimer();                           /* Reset timer. */
6605 #ifdef GFTIMER
6606     rftimer();                          /* Floating-point timer too. */
6607 #endif /* GFTIMER */
6608     inetime = -1L;                      /* Initialize elapsed time. */
6609     t = 0;                              /* Time now is 0. */
6610     m_found = 0;                        /* Default to timed-out */
6611     incount = 0;                        /* Character counter */
6612     rt = (timo == 0) ? 0 : 1;           /* Character-read timeout interval */
6613
6614 #ifndef NOLOCAL
6615 #ifdef OS2
6616     term_io_save = term_io;             /* Disable I/O by emulator */
6617     term_io = 0;
6618 #endif /* OS2 */
6619 #endif /* NOLOCAL */
6620
6621     while (1) {                         /* Character-getting loop */
6622 #ifdef CK_APC
6623         /* Check to see if there is an Autodown or other APC command */
6624         if (apcactive == APC_LOCAL ||
6625             (apcactive == APC_REMOTE && apcstatus != APC_OFF)) {
6626             if (mlook(mactab,"_apc_commands",nmac) == -1) {
6627                 debug(F110,"doinput about to execute APC",apcbuf,0);
6628                 domac("_apc_commands",apcbuf,cmdstk[cmdlvl].ccflgs|CF_APC);
6629                 delmac("_apc_commands",1);
6630                 apcactive = APC_INACTIVE;
6631 #ifdef DEBUG
6632             } else {
6633                 debug(F100,"doinput APC in progress","",0);
6634 #endif /* DEBUG */
6635             }
6636         }
6637 #endif /* CK_APC */
6638
6639         if (timo == 0 && waiting < 1) { /* Special exit criterion */
6640             instatus = INP_TO;          /* for timeout == 0 */
6641             break;
6642         }
6643         if (local) {                    /* One case for local */
6644             y = ttinc(rt);              /* Get character from comm device */
6645             debug(F101,"doinput ttinc(rt) returns","",y);
6646             if (y < -1) {               /* Connection failed. */
6647                 instatus = INP_IO;      /* Status = i/o error */
6648 #ifndef NOLOCAL
6649 #ifdef OS2
6650                 term_io = term_io_save;
6651 #endif /* OS2 */
6652 #endif /* NOLOCAL */
6653                 switch (y) {
6654                   case -2:              /* Connection lost */
6655                     if (local && !network && carrier != CAR_OFF) {
6656                         dologend();
6657                         printf("Connection closed.\n");
6658                         ttclos(1);
6659                     }
6660                     break;
6661                   case -3:
6662                     dologend();
6663                     printf("Session Limit exceeded - closing connection.\n");
6664                     ttclos(1);
6665                   default:
6666                     break;
6667                 }
6668                 debug(F111,"doinput Connection failed","returning 0",y);
6669                 return(0);
6670             }
6671             if (inintr) {
6672                 debug(F111,"doinput","inintr",inintr);
6673                 if ((icn = conchk()) > 0) { /* Interrupted from keyboard? */
6674                     debug(F101,"input interrupted from keyboard","",icn);
6675                     kbchar = coninc(0);
6676                     if (kbchar >= 0) {
6677                         while (--icn > 0) {
6678                             debug(F110,"doinput","absorbing",0);
6679                             coninc(0);      /* Yes, absorb what was typed. */
6680                         }
6681                         instatus = INP_UI;  /* Fail and remember why. */
6682                         break;
6683                     }
6684                 }
6685             }
6686         } else {                        /* Another for remote */
6687             y = coninc(rt);
6688             debug(F101,"doinput coninc(rt) returns","",y);
6689         }
6690         if (y > -1) {                   /* A character arrived */
6691             debug(F111,"doinput","a character arrived",y);
6692             if (timo == 0)
6693               waiting--;
6694 #ifndef OS2
6695 #define TN_NOLO
6696 #endif /* OS2 */
6697 #ifdef NOLOCAL
6698 #define TN_NOLO
6699 #endif /* NOLOCAL */
6700
6701 #ifdef TN_NOLO
6702             debug(F100,"doinput TN_NOLO","",0);
6703 #ifdef TNCODE
6704             /* Check for telnet protocol negotiation */
6705             if (is_tn) {
6706                 switch (y & 0xff) {
6707                   case IAC:
6708                     cr = 0;
6709                     myflsh();   /* Break from input burst for tn_doop() */
6710 #ifdef CK_BURST
6711                     burst = 0;
6712 #endif /* CK_BURST */
6713                     waiting -= 2;       /* (not necessarily...) */
6714                     switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
6715                       case 2: duplex = 0; continue;
6716                       case 1: duplex = 1; continue;
6717 #ifdef IKS_OPTION
6718                       case 4:
6719                         if (TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
6720                              !tcp_incoming) {
6721                             instatus = INP_IKS;
6722                             printf(
6723  " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
6724                                    );
6725                             break;
6726                         }
6727                         continue;
6728 #endif /* IKS_OPTION */
6729                       case 6:           /* TELNET DO LOGOUT received */
6730                       default: continue;
6731                     }
6732                   case CR:
6733                     cr = 1;
6734                     break;
6735                   case NUL:
6736                     if (!TELOPT_U(TELOPT_BINARY) && cr) {
6737                         cr = 0;
6738                         continue;
6739                     }
6740                     cr = 0;
6741                     break;
6742                   default:
6743                     cr = 0;
6744                 }
6745                 /* I'm echoing remote chars */
6746                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
6747                   ttoc((char)y);
6748             }
6749 #endif /* TNCODE */
6750 #ifdef CK_AUTODL
6751             /* Check for file transfer packets */
6752             if (inautodl) autodown(y);
6753 #endif /* CK_AUTODL */
6754 #else  /* TN_NOLO */
6755             debug(F100,"doinput !TN_NOLO","",0);
6756 #ifdef TNCODE
6757             /* Check for telnet protocol negotiation */
6758             if (is_tn) {
6759                 int tx;
6760                 switch (y & 0xff) {
6761                   case IAC:
6762                     myflsh();   /* Break from input burst for tn_doop() */
6763 #ifdef CK_BURST
6764                     burst = 0;
6765 #endif /* CK_BURST */
6766 #ifdef IKS_OPTION
6767                     tx = scriptwrtbuf((USHORT)y);
6768                     if (tx == 4) {
6769                         if (TELOPT_U(TELOPT_KERMIT) && 
6770                             TELOPT_SB(TELOPT_KERMIT).kermit.u_start &&
6771                             !tcp_incoming
6772                             ) {
6773                             instatus = INP_IKS;
6774                             printf(
6775   " Internet Kermit Service in SERVER mode.\n Please use REMOTE commands.\n"
6776                                    );
6777                             break;
6778                         }
6779                     } else if (tx == 6) {
6780                         /* TELNET DO LOGOUT received */
6781
6782                     }
6783 #else /* IKS_OPTION */
6784                     /* Handles Telnet negotiations */
6785                     tx = scriptwrtbuf((USHORT)y);
6786                     if (tx == 6) {
6787                         /* TELNET DO LOGOUT received */
6788                     }
6789 #endif /* IKS_OPTION */
6790                     waiting -= 2;       /* (not necessarily...) */
6791                     cr = 0;
6792                     continue;           /* and autodownload check */
6793                   case CR:
6794                     cr = 1;
6795                     tx = scriptwrtbuf((USHORT)y);
6796                     if (tx == 6) {
6797                         /* TELNET DO LOGOUT received */
6798                     }
6799                     break;
6800                   case NUL:
6801                     cr = 0;
6802                     if (!TELOPT_U(TELOPT_BINARY) && cr)
6803                       continue;
6804                     tx = scriptwrtbuf((USHORT)y);
6805                     if (tx == 6) {
6806                         /* TELNET DO LOGOUT received */
6807                     }
6808                     break;
6809                   default:
6810                     cr = 0;
6811                     tx = scriptwrtbuf((USHORT)y);
6812                     if (tx == 6) {
6813                         /* TELNET DO LOGOUT received */
6814                     }
6815                 }
6816                 /* I'm echoing remote chars */
6817                 if (TELOPT_ME(TELOPT_ECHO) && tn_rem_echo)
6818                   ttoc((CHAR)y);
6819             } else
6820 #endif /* TNCODE */
6821               /* Handles terminal emulation responses */
6822               scriptwrtbuf((USHORT)y);
6823 #endif /* TN_NOLO */
6824
6825             /* Real input character to be checked */
6826
6827 #ifdef CK_BURST
6828             burst--;                    /* One less character waiting */
6829             debug(F101,"doinput burst","",burst);
6830 #endif /* CK_BURST */
6831             c = (CHAR) (imask & (CHAR) y); /* Mask off any parity */
6832             inchar[0] = c;              /* Remember character for \v(inchar) */
6833 #ifdef COMMENT
6834 #ifdef CK_BURST
6835             /* Update "lastchar" time only once during input burst */
6836             if (burst <= 0)
6837 #endif /* CK_BURST */
6838 #endif /* COMMENT */
6839               lastchar = gtimer();      /* Remember when it came */
6840
6841             if (c == '\0') {            /* NUL, we can't use it */
6842                 if (anychar) {          /* Except if any character will do? */
6843                     x = 1;              /* Yes, done. */
6844                     incount = 1;        /* This must be the first and only. */
6845                     break;
6846                 } else goto refill;     /* Otherwise continue INPUTting */
6847             }
6848             *inpbp++ = c;               /* Store char in circular buffer */
6849             incount++;                  /* Count it for \v(incount) */
6850
6851             /* Don't NUL-terminate here - it's a circular buffer. */
6852
6853             if (inpbp >= inpbuf + inbufsize) { /* Time to wrap around? */
6854                 wrapped++;
6855                 *inpbp = NUL ;          /* Make it null-terminated */
6856                 inpbp = inpbuf;         /* Yes. */
6857             }
6858             if (matchbuf) {
6859                 if (matchindex < MATCHBUFSIZ) {
6860                     matchbuf[matchindex++] = c;
6861                     matchbuf[matchindex] = NUL;
6862                 }
6863             }
6864 #ifdef MAC
6865             {
6866                 extern char *ttermw;    /* fake pointer cast */
6867                 if (inecho) {
6868                     outchar(ttermw, c); /* echo to terminal window */
6869                     /* this might be too much overhead to do here ? */
6870                     updatecommand(ttermw);
6871                 }
6872             }
6873 #else /* Not MAC */
6874             if (inecho) {               /* Buffer console output */
6875                 conbuf[concnt++] = c;
6876             }
6877 #endif /* MAC */
6878 #ifndef OS2
6879             if (seslog) {
6880 #ifdef UNIX
6881                 if (sessft != 0 || c != '\r')
6882 #else
6883 #ifdef OSK
6884                 if (sessft != 0 || c != '\012')
6885 #endif /* OSK */
6886 #endif /* UNIX */
6887                   sesbuf[sescnt++] = c; /* Buffer session log output */
6888             }
6889 #endif /* OS2 */
6890             if (anychar) {              /* Any character will do? */
6891                 x = 1;
6892                 break;
6893             }
6894             if (!inpcas[cmdlvl]) {      /* Ignore alphabetic case? */
6895                 if (isupper(c))         /* Yes, convert input char to lower */
6896                   c = (CHAR) tolower(c);
6897             }
6898             debug(F000,"doinput char","",c);
6899
6900             /* Here is the matching section */
6901
6902             y = -1;                     /* Loop thru search strings */
6903             while (!nomatch && (s = ms[++y])) { /* ...as many as we have. */
6904                 if (mp[y]) {            /* Pattern match? */
6905 #ifdef COMMENT
6906                     int j;
6907                     /* This is gross but it works... */
6908                     /* We could just as easily have prepended '*' to the  */
6909                     /* pattern and skipped the loop, except then we would */
6910                     /* not have any way to identify the matching string.  */
6911                     for (j = 0; j < matchindex; j++) {
6912                         if (ckmatch(s,&matchbuf[j],1,1)) {
6913                             matchindex = j;
6914                             x = 1;
6915                             break;
6916                         }
6917                     }
6918                     if (x > 0)
6919                       break;
6920 #else
6921                     /* July 2001 - ckmatch() returns match position. */
6922                     /* It works and it's not gross. */
6923                     /* (4 = floating pattern) */
6924                     x = ckmatch(s,matchbuf,inpcas[cmdlvl],1+4);
6925                     if (x > 0) {
6926                         matchindex = x - 1;
6927                         x = 1;
6928                         break;
6929                     }
6930 #endif /* COMMENT */
6931                     continue;
6932                 }                       /* Literal match. */
6933                 i = mi[y];              /* Match-position in search string. */
6934                 debug(F000,"compare char","",(CHAR)s[i]);
6935                 if (c == (CHAR) s[i]) { /* Check for match */
6936                     i++;                /* Got one, go to next character */
6937                 } else {                /* Don't have a match */
6938                     int j;
6939                     for (j = i; i > 0; ) { /* Back up in search string */
6940                         i--; /* (Do this here to prevent compiler foulup) */
6941                         /* j is the length of the substring that matched */
6942                         if (c == (CHAR) s[i]) {
6943                             if (!strncmp(s,&s[j-i],i)) {
6944                                 i++;          /* c actually matches -- cfk */
6945                                 break;
6946                             }
6947                         }
6948                     }
6949                 }
6950                 if ((CHAR) s[i] == (CHAR) '\0') { /* Matched to end? */
6951                     ckstrncpy(matchbuf,ms[y],MATCHBUFSIZ);
6952                     matchindex = 0;
6953                     x = 1;              /* Yes, */
6954                     break;              /* done. */
6955                 }
6956                 mi[y] = i;              /* No, remember match-position */
6957             }
6958             if (x == 1) {               /* Set \v(minput) result */
6959                 m_found = y + 1;
6960                 break;
6961             }
6962         }
6963 #ifdef CK_BURST
6964         else if (y <= -1 && burst > 0) {
6965             debug(F111,"doinput (y<=-1&&burst>0)","burst",burst);
6966                                         /* a timo occurred so there can't   */
6967             burst = 0;                  /* be data waiting; must check timo */
6968         }
6969       refill:
6970         if (burst <= 0) {               /* No buffered chars remaining... */
6971             myflsh();                   /* Flush buffered output */
6972             if (local) {                /* Get size of next input burst */
6973                 burst = ttchk();
6974                 if (burst < 0) {        /* ttchk() says connection is closed */
6975                     instatus = INP_IO;  /* Status = i/o error */
6976 #ifndef NOLOCAL
6977 #ifdef OS2
6978                     term_io = term_io_save;
6979 #endif /* OS2 */
6980 #endif /* NOLOCAL */
6981
6982                     if ((!network 
6983 #ifdef TN_COMPORT
6984                          || istncomport()
6985 #endif /* TN_COMPORT */
6986                          ) && carrier != CAR_OFF) {
6987         /* The test is written this way because the Microsoft compiler
6988          * is producing bad code if written:
6989          *
6990          *  if (network && (!istncomport() || carrier == CAR_OFF) )
6991          */
6992                         break;
6993                      } else {
6994                          printf("Fatal error - disconnected.\n");
6995                          ttclos(1);
6996                          break;
6997                      }
6998                 }
6999                 if (inintr) {
7000                     if ((icn = conchk()) > 0) { /* Interrupt from keyboard? */
7001                         kbchar = coninc(0);
7002                         debug(F101,"input interrupted from keyboard","",icn);
7003                         while (--icn > 0) coninc(0); /* Yes, absorb chars. */
7004                         break;          /* And fail. */
7005                     }
7006                 }
7007             } else {
7008                 burst = conchk();
7009             }
7010             debug(F101,"doinput burst","",burst);
7011             /* Prevent overflow of "conbuf" and "sesbuf" */
7012             if (burst > MAXBURST)
7013               burst = MAXBURST;
7014
7015             /* Did not match, timer exceeded? */
7016             t = gtimer();
7017             debug(F111,"doinput gtimer","burst",t);
7018             debug(F101,"doinput timo","",timo);
7019             if ((t >= timo) && (timo > 0))
7020               break;
7021             else if (insilence > 0 && (t - lastchar) > insilence)
7022               break;
7023         } else {
7024             debug(F111,"doinput (burst > 0)","burst",burst);
7025         }
7026 #else
7027         myflsh();                       /* Flush buffered output */
7028         /* Did not match, timer exceeded? */
7029         t = gtimer();
7030         debug(F111,"doinput gtimer","no burst",t);
7031         debug(F101,"doinput timo","",timo);
7032         if ((t >= timo) && (timo > -1))
7033           break;
7034         else if (insilence > 0 && (t - lastchar) > insilence)
7035           break;
7036 #endif /* CK_BURST */
7037     }                                   /* Still have time left, continue. */
7038     if (nomatch) x = 1;                 /* Succeed if nomatch and timed out. */
7039     myflsh();                           /* Flush buffered output. */
7040     if (x > 0 && !nomatch)
7041       instatus = 0;
7042 #ifndef NOLOCAL
7043 #ifdef OS2
7044     term_io = term_io_save;
7045 #endif /* OS2 */
7046 #endif /* NOLOCAL */
7047 #ifdef COMMENT
7048 #ifdef IKS_OPTION
7049 #ifdef CK_AUTODL
7050     if (is_tn && TELOPT_ME(TELOPT_KERMIT) && inautodl) {
7051         tn_siks(KERMIT_STOP);           /* Send Kermit-Server Stop */
7052     }
7053 #endif /* CK_AUTODL */
7054 #endif /* IKS_OPTION */
7055 #endif /* COMMENT */
7056
7057 #ifdef GFTIMER
7058     fpt = gftimer();                    /* Get elapsed time */
7059
7060 /* If a long is 32 bits, it would take about 50 days for this to overflow. */
7061
7062     inetime = (int)(fpt * (CKFLOAT)1000.0);
7063 #else
7064     inetime = (int)(gtimer() * 1000);
7065 #endif /* GFTIMER */
7066
7067     if (!nomatch)
7068       makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
7069     return(x);                          /* Return the return code. */
7070 }
7071 #endif /* NOSPL */
7072
7073 #ifndef NOSPL
7074 /* REINPUT Command */
7075
7076 /*
7077   Note, the timeout parameter is required, but ignored.  Syntax is compatible
7078   with MS-DOS Kermit except timeout can't be omitted.  This function only
7079   looks at the characters already received and does not read any new
7080   characters from the connection.
7081 */
7082 int
7083 doreinp(timo,s,pat) int timo; char *s; int pat; {
7084     int x, y, i;
7085     char *xx, *xp, *xq = (char *)0;
7086     CHAR c;
7087
7088     if (!s) s = "";
7089     debug(F101,"doreinput pat","",pat);
7090
7091     y = (int)strlen(s);
7092     debug(F111,"doreinput search",s,y);
7093
7094     if (y > inbufsize) {                /* If search string longer than */
7095         debug(F101,"doreinput inbufsize","",inbufsize);
7096         return(0);                      /* input buffer, fail. */
7097     }
7098     makestr(&inpmatch,NULL);
7099     if (!matchbuf)
7100       matchbuf = malloc(MATCHBUFSIZ+1);
7101     matchindex = 0;
7102
7103     x = 0;                              /* Return code, assume failure */
7104     i = 0;                              /* String pattern match position */
7105
7106     if (!inpcas[cmdlvl]) {              /* INPUT CASE = IGNORE?  */
7107         xp = malloc(y+2);               /* Make a separate copy of the */
7108         if (!xp) {                      /* search string. */
7109             printf("?malloc error 6\n");
7110             return(x);
7111         } else xq = xp;                 /* Keep pointer to beginning. */
7112         while (*s) {                    /* Yes, convert to lowercase */
7113             *xp = *s;
7114             if (isupper(*xp)) *xp = (char) tolower(*xp);
7115             xp++; s++;
7116         }
7117         *xp = NUL;                      /* Terminate it! */
7118         s = xq;                         /* Move search pointer to it. */
7119     }
7120     xx = *inpbp ? inpbp : inpbuf;       /* Current INPUT buffer pointer */
7121     do {
7122         c = *xx++;                      /* Get next character */
7123         if (!c) break;
7124         if (xx >= inpbuf + inbufsize)   /* Wrap around if necessary */
7125           xx = inpbuf;
7126         if (!inpcas[cmdlvl]) {          /* Ignore alphabetic case? */
7127             if (isupper(c)) c = (CHAR) tolower(c); /* Yes */
7128         }
7129         if (pat) {
7130             int j;
7131             if (matchbuf) {
7132                 if (matchindex < MATCHBUFSIZ) {
7133                     matchbuf[matchindex++] = c;
7134                     matchbuf[matchindex] = NUL;
7135                 }
7136                 for (j = 0; j < matchindex; j++) { /* Gross but effective */
7137                     if (ckmatch(s,&matchbuf[j],1,1)) {
7138                         debug(F101,"GOT IT","",j);
7139                         matchindex = j;
7140                         x = 1;
7141                         break;
7142                     }
7143                 }
7144             }
7145             if (x > 0)
7146               break;
7147             continue;
7148         }
7149         debug(F000,"doreinp char","",c);
7150         debug(F000,"compare char","",(CHAR) s[i]);
7151         if (((char) c) == ((char) s[i])) { /* Check for match */
7152             i++;                        /* Got one, go to next character */
7153         } else {                        /* Don't have a match */
7154             int j;
7155             for (j = i; i > 0; ) {      /* [jrs] search backwards for it  */
7156                 i--;
7157                 if (((char) c) == ((char) s[i])) {
7158                     if (!strncmp(s,&s[j-i],i)) {
7159                         i++;
7160                         break;
7161                     }
7162                 }
7163             }
7164         }                               /* [jrs] or return to zero from -1 */
7165         if (s[i] == '\0') {             /* Matched all the way to end? */
7166             ckstrncpy(matchbuf,s,MATCHBUFSIZ);
7167             matchindex = 0;
7168             x = 1;                      /* Yes, */
7169             break;                      /* done. */
7170         }
7171     } while (xx != inpbp && x < 1);     /* Until back where we started. */
7172
7173     if (!inpcas[cmdlvl]) if (xq) free(xq); /* Free this if it was malloc'd. */
7174     makestr(&inpmatch,&matchbuf[matchindex]); /* \v(inmatch) */
7175     return(x);                          /* Return search result. */
7176 }
7177
7178 /*  X X S T R I N G  --  Interpret strings containing backslash escapes  */
7179 /*  Z Z S T R I N G  --  (new name...)  */
7180 /*
7181  Copies result to new string.
7182   strips enclosing braces or doublequotes.
7183   interprets backslash escapes.
7184   returns 0 on success, nonzero on failure.
7185   tries to be compatible with MS-DOS Kermit.
7186
7187  Syntax of input string:
7188   string = chars | "chars" | {chars}
7189   chars = (c*e*)*
7190   where c = any printable character, ascii 32-126
7191   and e = a backslash escape
7192   and * means 0 or more repetitions of preceding quantity
7193   backslash escape = \operand
7194   operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
7195   number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
7196   radix code is oO (octal), xX (hex), dD or none (decimal) (see xxesc()).
7197 */
7198
7199 #ifndef NOFRILLS
7200 int
7201 yystring(s,s2) char *s; char **s2; {    /* Reverse a string */
7202     int x;
7203     static char *new;
7204     new = *s2;
7205     if (!s || !new) return(-1);         /* Watch out for null pointers. */
7206     if ((x = (int)strlen(s)) == 0) {    /* Recursion done. */
7207         *new = '\0';
7208         return(0);
7209     }
7210     x--;                                /* Otherwise, call self */
7211     *new++ = s[x];                      /* to reverse rest of string. */
7212     s[x] = 0;
7213     return(yystring(s,&new));
7214 }
7215 #endif /* NOFRILLS */
7216
7217 static char ipabuf[16] = { NUL };       /* IP address buffer */
7218
7219 static char *
7220 getip(s) char *s; {
7221     char c=NUL;                         /* Workers... */
7222     int i=0, p=0, d=0;
7223     int state = 0;                      /* State of 2-state FSA */
7224
7225     while ((c = *s++)) {
7226         switch(state) {
7227           case 0:                       /* Find first digit */
7228             i = 0;                      /* Output buffer index */
7229             ipabuf[i] = NUL;            /* Initialize output buffer */
7230             p = 0;                      /* Period counter */
7231             d = 0;                      /* Digit counter */
7232             if (isdigit(c)) {           /* Have first digit */
7233                 d = 1;                  /* Count it */
7234                 ipabuf[i++] = c;        /* Copy it */
7235                 state = 1;              /* Change state */
7236             }
7237             break;
7238
7239           case 1:                       /* In numeric field */
7240             if (isdigit(c)) {           /* Have digit */
7241                 if (++d > 3)            /* Too many */
7242                   state = 0;            /* Start over */
7243                 else                    /* Not too many */
7244                   ipabuf[i++] = c;      /* Keep it */
7245             } else if (c == '.' && p < 3) { /* Have a period */
7246                 p++;                    /* Count it */
7247                 if (d == 0)             /* Not preceded by a digit */
7248                   state = 0;            /* Start over */
7249                 else                    /* OK */
7250                   ipabuf[i++] = c;      /* Keep it */
7251                 d = 0;                  /* Reset digit counter */
7252             } else if (p == 3 && d > 0) { /* Not part of address */
7253                 ipabuf[i] = NUL;        /* If we have full IP address */
7254                 return((char *)ipabuf); /* Return it */
7255             } else {                    /* Otherwise */
7256                 state = 0;              /* Start over */
7257                 ipabuf[0] = NUL;        /* (in case no more chars left) */
7258             }
7259         }
7260     }                                   /* Fall thru at end of string */
7261     ipabuf[i] = NUL;                    /* Maybe we have one */
7262     return((p == 3 && d > 0) ? (char *)ipabuf : "");
7263 }
7264 #endif /* NOSPL */
7265
7266 /* Date Routines */
7267
7268 /* Z J D A T E  --  Convert yyyymmdd date to Day of Year */
7269
7270 static int jdays[12] = {  0,31,59,90,120,151,181,212,243,273,304,334 };
7271 static int ldays[12] = {  0,31,60,91,121,152,182,213,244,274,305,335 };
7272 static char zjdbuf[12] = { NUL, NUL };
7273 /*
7274   Deinde, ne in posterum a XII kalendas aprilis aequinoctium recedat,
7275   statuimus bissextum quarto quoque anno (uti mos est) continuari debere,
7276   praeterquam in centesimis annis; qui, quamvis bissextiles antea semper
7277   fuerint, qualem etiam esse volumus annum MDC, post eum tamen qui deinceps
7278   consequentur centesimi non omnes bissextiles sint, sed in quadringentis
7279   quibusque annis primi quique tres centesimi sine bissexto transigantur,
7280   quartus vero quisque centesimus bissextilis sit, ita ut annus MDCC, MDCCC,
7281   MDCCCC bissextiles non sint. Anno vero MM, more consueto dies bissextus
7282   intercaletur, februario dies XXIX continente, idemque ordo intermittendi
7283   intercalandique bissextum diem in quadringentis quibusque annis perpetuo
7284   conservetur.  - Gregorius XIII, Anno Domini MDLXXXII.
7285 */
7286 char *
7287 zjdate(date) char * date; {             /* date = yyyymmdd */
7288     char year[5];
7289     char month[3];
7290     char day[3];
7291     int d, m, x, y;
7292     int leapday, j;
7293     char * time = NULL;
7294
7295     if (!date) date = "";               /* Validate arg */
7296     x = strlen(date);
7297     if (x < 1) return("0");
7298     if (x < 8) return("-1");
7299     for (x = 0; x < 8; x++)
7300       if (!isdigit(date[x]))
7301         return("-1");
7302
7303     if (date[8]) if (date[9])
7304       time = date + 9;
7305
7306     year[0] = date[0];                  /* Isolate year */
7307     year[1] = date[1];
7308     year[2] = date[2];
7309     year[3] = date[3];
7310     year[4] = '\0';
7311
7312     month[0] = date[4];                 /* Month */
7313     month[1] = date[5];
7314     month[2] = '\0';;
7315
7316     day[0] = date[6];                   /* And day */
7317     day[1] = date[7];
7318     day[2] = '\0';
7319
7320     leapday = 0;                        /* Assume no leap day */
7321     y = atoi(year);
7322     m = atoi(month);
7323     d = atoi(day);
7324     if (m > 2) {                        /* No Leap day before March */
7325         if (y % 4 == 0) {               /* If year is divisible by 4 */
7326             leapday = 1;                /* It's a Leap year */
7327             if (y % 100 == 0) {         /* Except if divisible by 100 */
7328                 if (y % 400 != 0)       /* but not by 400 */
7329                   leapday = 0;
7330             }
7331         }
7332     }
7333     j = jdays[m - 1] + d + leapday;     /* Day of year */
7334     if (time)
7335       sprintf(zjdbuf,"%04d%03d %s",y,j,time); /* SAFE */
7336     else
7337       sprintf(zjdbuf,"%04d%03d",y,j);   /* SAFE */
7338     return((char *)zjdbuf);
7339 }
7340
7341 static char jzdbuf[32];
7342
7343 /* J Z D A T E  --  Convert Day of Year to yyyyddmm date */
7344
7345 char *
7346 jzdate(date) char * date; {             /* date = yyyyddd */
7347     char year[5];                       /* with optional time */
7348     char day[4];
7349     char * time = NULL, * p;
7350     int d, m, x, y;
7351     int leapday, j;
7352     int * zz;
7353
7354     if (!date) date = "";               /* Validate arg */
7355     x = strlen(date);
7356
7357     debug(F111,"jzdate len",date,x);
7358
7359     if (x < 1) return("0");
7360     if (x < 7) return("-1");
7361     if (x > 8) time = date + 8;
7362
7363     for (x = 0; x < 7; x++)
7364       if (!isdigit(date[x]))
7365         return("-1");
7366
7367     year[0] = date[0];                  /* Isolate year */
7368     year[1] = date[1];
7369     year[2] = date[2];
7370     year[3] = date[3];
7371     year[4] = '\0';
7372
7373     debug(F110,"jzdate year",year,0);
7374
7375     day[0] = date[4];                   /* And day */
7376     day[1] = date[5];
7377     day[2] = date[6];
7378     day[3] = '\0';
7379
7380     debug(F110,"jzdate day",day,0);
7381
7382     j = atoi(day);
7383     if (j > 366)
7384       return("-1");
7385
7386     leapday = 0;                        /* Assume no leap day */
7387     y = atoi(year);
7388     if (y % 4 == 0) {                   /* If year is divisible by 4 */
7389         leapday = 1;                    /* It's a Leap year */
7390         if (y % 100 == 0) {             /* Except if divisible by 100 */
7391             if (y % 400 != 0)           /* but not by 400 */
7392               leapday = 0;
7393         }
7394     }
7395     debug(F101,"jzdate leapday","",leapday);
7396     zz = leapday ? ldays : jdays;
7397
7398     for (x = 0; x < 11; x++)
7399       if (j > zz[x] && j <= zz[x+1])
7400         break;
7401     m = x + 1;
7402
7403     debug(F101,"jzdate m","",m);
7404
7405     d = j - zz[x];
7406
7407     debug(F101,"jzdate d","",d);
7408
7409     if (time)
7410       sprintf(jzdbuf,"%04d%02d%02d %s",y,m,d,time); /* SAFE */
7411     else
7412       sprintf(jzdbuf,"%04d%02d%02d",y,m,d); /* SAFE */
7413
7414     debug(F101,"jzdate jzdbuf",jzdbuf,0);
7415
7416     p = ckcvtdate((char *)jzdbuf, 0);   /* Convert to standard form */
7417     ckstrncpy(jzdbuf,p,32);
7418     if (!time) jzdbuf[8] = NUL;         /* Remove time if not wanted */
7419     return((char *)jzdbuf);
7420 }
7421
7422 /* M J D  --  Modified Julian Date */
7423 /*
7424   Call with:
7425     Standard-format date-time string: yyyymmdd[ hh:mm:ss].
7426     The time, if any, is ignored.
7427
7428   Returns:
7429     -1L on error, otherwise:
7430     The number of days since 17 Nov 1858 as a whole number:
7431     16 Nov 1858 = -1, 17 Nov 1858 = 0, 18 Nov 1858 = 1, 19 Nov 1858 = 2, ...
7432
7433   The Modified Julian Date is defined by the International Astronomical
7434   Union as the true Julian date minus 2400000.5 days.  The true Julian
7435   date is the number days since since noon of 1 January 4713 BCE of the
7436   Julian proleptic calendar.  Conversions between calendar dates and
7437   Julian dates, however, assume Gregorian dating.
7438 */
7439 long
7440 mjd(date) char * date; {
7441     char year[5];
7442     char month[3];
7443     char day[3];
7444     int x, a, d, m, y;
7445     long z;
7446
7447     if (!date) date = "";               /* Validate arg */
7448     x = strlen(date);
7449     if (x < 1) return(0L);
7450     if (x < 8) return(-1L);
7451     for (x = 0; x < 8; x++)
7452       if (!isdigit(date[x]))
7453         return(-1L);
7454
7455     year[0] = date[0];                  /* Isolate year */
7456     year[1] = date[1];
7457     year[2] = date[2];
7458     year[3] = date[3];
7459     year[4] = '\0';
7460
7461     month[0] = date[4];                 /* Month */
7462     month[1] = date[5];
7463     month[2] = '\0';;
7464     m = atoi(month);
7465
7466     day[0] = date[6];                   /* And day */
7467     day[1] = date[7];
7468     day[2] = '\0';
7469     d = atoi(day);
7470
7471     a = (14-m)/12;                      /* Calculate true Julian date */
7472     y = atoi(year) + 4800 - a;
7473     m = m + 12 * a - 3;
7474     z = d + (long)(306*m+5)/10 + (long)(y*365) + y/4 - y/100 + y/400 - 32045L;
7475
7476     z -= 2400001L;                      /* Convert JD to MJD */
7477
7478     return(z);
7479 }
7480
7481 static char mjd2dbuf[32];
7482
7483 /*  M J D 2 D A T E  --  Converts MJD to yyyymmdd  */
7484
7485 char *
7486 #ifdef CK_ANSIC
7487 mjd2date(long mjd)
7488 #else
7489 mjd2date(mjd) long mjd;
7490 #endif /* CK_ANSIC */
7491 /* mjd2date */ {
7492     long jd, l, n;
7493     int d, m, y;
7494     jd = (long)(mjd + 2400001L);
7495     l = jd + 68569;
7496     n = 4 * l / 146097L;
7497     l = l - (146097 * n + 3) / 4;
7498     y = 4000 * (l + 1) / 1461001L;
7499     l = l - 1461 * y / 4 + 31;
7500     m = 80 * l / 2447;
7501     d = l - 2447 * m / 80;
7502     l = m / 11;
7503     m = m + 2 - 12 * l;
7504     y = 100 * (n - 49) + y + l;
7505     sprintf(mjd2dbuf,"%04d%02d%02d",y,m,d); /* SAFE */
7506     return((char *)mjd2dbuf);
7507 }
7508
7509 #ifndef NOSPL
7510 static char ** flist = (char **) NULL;  /* File list for \fnextfile() */
7511 static int flistn = 0;                  /* Number of items in file list */
7512
7513 /*
7514   The function return-value buffer must be global, since fneval() returns a
7515   pointer to it.  fneval() is called only by zzstring(), which always copies
7516   the result out of this buffer to somewhere else, so it's OK to have only
7517   one buffer for this in most cases.  However, since function calls can be
7518   nested -- e.g. functions whose arguments are functions, or recursive
7519   functions, at some point we should convert this to an array of buffers,
7520   indexed by function depth (which might or might not be the same as the
7521   "depth" variable).  Also, since function results are potentially quite big,
7522   we'd need to allocate and deallocate dynamically as we descend and ascend
7523   function depth.  Left for a future release...
7524 */
7525 char fnval[FNVALL+2];                   /* Function return value  */
7526 static int fndepth = 0;                 /* (we don't actually use this yet) */
7527 int fnsuccess = 1;
7528 extern int fnerror;
7529
7530 /* f p f o r m a t  --  Floating-point number nicely formatted.  */
7531 /*
7532    Returns results from a circular 1K buffer.
7533    Don't count on too many results remaining available at once; it could
7534    be anywhere from 5 to maybe 100, depending on the sizes of the results.
7535 */
7536 #ifdef CKFLOAT
7537 #define FPFMTSIZ 1024
7538 static char fpfmtbuf[FPFMTSIZ] = { NUL, NUL };
7539 static int fpfbufpos = 0;               /* (why was this char before?) */
7540
7541 char *
7542 fpformat(fpresult,places,round) CKFLOAT fpresult; int places, round; {
7543     char fbuf[16];                      /* For creating printf format */
7544     int nines = 0, sign = 0, x, y, i, j, size = 0;
7545     char * buf;
7546     CKFLOAT ftmp;
7547
7548     x = places ? places : (fp_digits ? fp_digits : 6);
7549
7550     debug(F101,"fpformat fpresult","",fpresult);
7551     debug(F101,"fpformat places","",places);
7552     debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
7553
7554     ftmp = fpresult;
7555     if (ftmp < 0.0) ftmp = 0.0 - fpresult;
7556
7557 #ifdef FNFLOAT
7558     if (!fp_rounding &&                 /* If printf doesn't round, */
7559         (places > 0 ||                  /* round result to decimal places. */
7560          (places == 0 && round)))
7561       fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
7562     y = (ftmp == 0.0) ? 1 : (int)log10(ftmp);
7563     size = y + x + 3;                   /* Estimated length of result */
7564     if (fpresult < 0.0) size++;
7565 #else
7566     size = 200;                         /* No way to estimate, be generous */
7567 #endif /* FNFLOAT */
7568
7569     debug(F101,"fpformat size","",size);
7570
7571     if (fpfbufpos > (FPFMTSIZ - size))  /* Wrap around if necessary */
7572       fpfbufpos = 0;
7573     debug(F101,"fpformat fpfbufpos 1","",fpfbufpos);
7574
7575     buf = &fpfmtbuf[fpfbufpos];
7576
7577     if (places > 0) {                   /* If places specified */
7578         /* use specified places to write given number of digits */
7579         sprintf(fbuf,"%%0.%df",places); /* SAFE */
7580         sprintf(buf,fbuf,fpresult);     /* SAFE */
7581     } else {                            /* Otherwise... */
7582         /* Go for max precision */
7583         sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
7584         sprintf(buf,fbuf,fpresult);     /* SAFE */
7585     }
7586     if (buf[0] == '-') sign = 1;
7587     debug(F111,"fpresult 1 errno",buf,errno); /* Check for over/underflow */
7588     debug(F111,"fpresult 1 fpfbufpos",buf,fpfbufpos);
7589     /* Give requested decimal places */
7590     for (i = sign; i < FPFMTSIZ && buf[i]; i++) {
7591         if (buf[i] == '.')              /* First find the decimal point */
7592           break;
7593         else if (i > fp_digits + sign - 1) /* replacing garbage */
7594           buf[i] = '0';                 /* digits with 0... */
7595     }
7596     if (buf[i] == '.') {                /* Have decimal point */
7597         int gotend = 0;
7598         /* places < 0 so truncate fraction */
7599         if (places < 0 || (places == 0 && round)) {
7600             buf[i] = NUL;
7601         } else if (places > 0) {        /* d > 0 so this many decimal places */
7602             i++;                           /* First digit after decimal */
7603             for (j = 0; j < places; j++) { /* Truncate after d decimal */
7604                 if (!buf[j+i])        /* places or extend to d  */
7605                   gotend = 1;              /* decimal places. */
7606                 if (gotend || j+i+sign > fp_digits)
7607                   buf[j+i] = '0';
7608             }
7609             buf[j+i] = NUL;
7610         } else {                        /* places == 0 so Do The Right Thing */
7611             for (j = (int)strlen(buf) - 1; j > i+1; j--) {
7612                 if ((j - sign) > fp_digits)
7613                   buf[j] = '0';
7614                 if (buf[j] == '0')
7615                   buf[j] = NUL; /* Strip useless trailing 0's. */
7616                 else
7617                   break;
7618             }
7619         }
7620     }
7621     fpfmtbuf[FPFMTSIZ-1] = NUL;
7622     j = strlen(buf);
7623     sign = 0;
7624     for (i = j-1; i >= 0; i--) {
7625         if (buf[i] == '9')
7626           nines++;
7627         else
7628           break;
7629     }
7630     /* Do something about xx.xx99999999... */
7631     if (nines > 5) {
7632         if (isdigit(buf[i]) && i < FPFMTSIZ - 2) {
7633             buf[i] = buf[i] + 1;
7634             buf[i+1] = '0';
7635             buf[i+2] = '\0';
7636         }
7637     }
7638     if (!strncmp(buf,"-0.0",FPFMTSIZ))
7639       ckstrncpy(buf,"0.0",FPFMTSIZ);
7640     fpfbufpos += (int)strlen(buf) + 1;
7641     return((char *)buf);
7642 }
7643 #endif /* CKFLOAT */
7644
7645 static VOID
7646 evalerr(fn) char * fn; {
7647     if (fndiags) {
7648         if (divbyzero)
7649           ckmakmsg(fnval,FNVALL,"<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
7650         else
7651           ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
7652     }
7653 }
7654
7655 char *
7656 dokwval(s,sep) char * s, sep; {
7657     char c = '\0', * p, * kw = NULL, * vp = NULL;
7658     int x;
7659     if (!s) return("0");
7660     if (!*s) return("0");
7661     debug(F110,"kwval arg",s,0);
7662     debug(F110,"kwval sep",ckctoa(sep),0);
7663     p = (char *)malloc((int)strlen(s)+1);
7664     if (!p) return("0");
7665     strcpy(p,s);                        /* SAFE */
7666     s = p;
7667     while (*s < '!' && *s > '\0')       /* Get first nonblank */
7668       s++;
7669     if (!*s) return("0");
7670     if (*s == sep) return("0");
7671     kw = s;                             /* Keyword */
7672     while (*s > ' ') {
7673         if (*s == sep) {                /* keyword=... */
7674             c = *s;
7675             break;
7676         }
7677         s++;
7678     }
7679     *s++ = NUL;                         /* Terminate keyword */
7680     while (*s < '!' && *s > '\0')       /* Skip blanks */
7681       s++;
7682     if (!c && *s == sep) {
7683         c = *s++;                       /* Have separator */
7684         while (*s < '!' && *s > '\0')   /* Skip blanks */
7685           s++;
7686     }
7687     if (c) {
7688         vp = s;
7689         while (*s > ' ')                /* Skip to end */
7690           s++;
7691         *s = NUL;                       /* Terminate value */
7692     }
7693     debug(F110,"kwval c",ckctoa(c),0);
7694     debug(F110,"kwval keyword",kw,0);
7695     debug(F110,"kwval value",vp,0);
7696     x = c ? addmac(kw,vp) : -1;
7697     free(p);
7698     return((x < 0) ? "0" : "1");
7699 }
7700
7701 static int
7702 isaarray(s) char * s; {                 /* Is s an associative array element */
7703     int state = 0;
7704     CHAR c;
7705     if (!s) return(0);
7706     while ((c = *s++)) {
7707         if (!isprint(c)) {
7708             return(0);
7709         } else if (c == '<') {
7710             if (state != 0)
7711               return(0);
7712             state = 1;
7713         } else if (c == '>') {
7714             return((state != 1 || *s) ? 0 : 1);
7715         }
7716     }
7717     return(0);
7718 }
7719
7720 static char *                           /* Evaluate builtin functions */
7721 fneval(fn,argp,argn,xp) char *fn, *argp[]; int argn; char * xp; {
7722     int i=0, j=0, k=0, len1=0, len2=0, len3=0, n=0, t=0, x=0, y=0;
7723     int cx, failed = 0;                 /* Return code, 0 = ok */
7724     long z = 0L;
7725     char *bp[FNARGS + 1];               /* Pointers to malloc'd strings */
7726     char c = NUL;
7727     char *p = NULL, *s = NULL;
7728     char *val1 = NULL, *val2 = NULL;    /* Pointers to numeric string values */
7729
7730 #ifdef RECURSIVE
7731     int rsave = recursive;
7732 #endif /* RECURSIVE */
7733 #ifdef OS2
7734     int zsave = zxpn;
7735 #endif /* OS2 */
7736
7737     if (!fn) fn = "";                   /* Protect against null pointers */
7738     if (!*fn) return("");
7739
7740     for (i = 0; i < FNARGS; i++)        /* Initialize argument pointers */
7741       bp[i] = NULL;
7742 /*
7743   IMPORTANT: Note that argn is not an accurate count of the number of
7744   arguments.  We can't really tell if an argument is null until after we
7745   execute the code below.  So argn is really the maximum number of arguments
7746   we might have.  Argn should always be at least 1, even if the function is
7747   called with empty parentheses (but don't count on it).
7748 */
7749     debug(F111,"fneval",fn,argn);
7750     debug(F110,"fneval",argp[0],0);
7751     if (argn > FNARGS)                  /* Discard excess arguments */
7752       argn = FNARGS;
7753
7754     fndepth++;
7755     debug(F101,"fneval fndepth","",fndepth);
7756     p = fnval;
7757     fnval[0] = NUL;
7758     y = lookup(fnctab,fn,nfuncs,&x);    /* Look up the function name */
7759     cx = y;                             /* Because y is too generic... */
7760     if (cx < 0) {                        /* Not found */
7761         failed = 1;
7762         if (fndiags) {                  /* FUNCTION DIAGNOSTIC ON */
7763             int x;
7764             x = strlen(fn);
7765             /* The following sprintf's are safe */
7766             switch (cx) {
7767               case -1:
7768                 if (x + 32 < FNVALL)
7769                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION:\\f%s()>",fn);
7770                 else
7771                   sprintf(fnval,"<ERROR:NO_SUCH_FUNCTION>");
7772                 break;
7773               case -2:
7774                 if (x + 26 < FNVALL)
7775                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS:\\f%s()>",fn);
7776                 else
7777                   sprintf(fnval,"<ERROR:NAME_AMBIGUOUS>");
7778                 break;
7779               case -3:
7780                 sprintf(fnval,"<ERROR:FUNCTION_NAME_MISSING:\\f()>");
7781                 break;
7782               default:
7783                 if (x + 26 < FNVALL)
7784                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE:\\f%s()>",fn);
7785                 else
7786                   sprintf(fnval,"<ERROR:LOOKUP_FAILURE>");
7787                 break;
7788             }
7789         }
7790         goto fnend;                     /* Always leave via common exit */
7791     }
7792     fn = fnctab[x].kwd;                 /* Full name of function */
7793
7794     if (argn < 0) {
7795         failed = 1;
7796         p = fnval;
7797         if (fndiags)
7798           sprintf(fnval,"<ERROR:MISSING_ARG:\\f%s()>",fn);
7799         goto fnend;
7800     }
7801     if (cx == FN_LIT) {                 /* literal(arg1) */
7802         debug(F010,"flit",xp,0);
7803         p = xp ? xp : "";               /* Return a pointer to arg itself */
7804         goto fnend;
7805     }
7806
7807 #ifdef DEBUG
7808     if (deblog) {
7809         int j;
7810         for (j = 0; j < argn; j++)
7811           debug(F111,"fneval arg",argp[j],j);
7812     }
7813 #endif /* DEBUG */
7814     for (j = argn-1; j >= 0; j--) {     /* Uncount empty trailing args */
7815         if (!argp[j])
7816           argn--;
7817         else if (!*(argp[j]))
7818           argn--;
7819         else break;
7820     }
7821     debug(F111,"fneval argn",fn,argn);
7822 /*
7823   \fliteral() and \fcontents() are special functions that do not evaluate
7824   their arguments, and are treated specially here.  After these come the
7825   functions whose arguments are evaluated in the normal way.
7826 */
7827 #ifdef COMMENT
7828     /* (moved up) */
7829     if (cx == FN_LIT) {                 /* literal(arg1) */
7830         debug(F110,"flit",xp,0);
7831         p = xp ? xp : "";               /* Return a pointer to arg itself */
7832         goto fnend;
7833     }
7834 #endif /* COMMENT */
7835     if (cx == FN_CON) {                 /* Contents of variable, unexpanded. */
7836         char c;
7837         if (!(p = argp[0]) || !*p) {
7838             failed = 1;
7839             p = fnval;
7840             if (fndiags)
7841               sprintf(fnval,"<ERROR:MISSING_ARG:\\fcontents()>");
7842             goto fnend;
7843         }
7844         p = brstrip(p);
7845         if (*p == CMDQ) p++;
7846         if ((c = *p) == '%') {          /* Scalar variable. */
7847             c = *++p;                   /* Get ID character. */
7848             p = "";                     /* Assume definition is empty */
7849             if (!c) {                   /* Double paranoia */
7850                 failed = 1;
7851                 p = fnval;
7852                 if (fndiags)
7853                   sprintf(fnval,"<ERROR:ARG_BAD_VARIABLE:\\fcontents()>");
7854                 goto fnend;
7855             }
7856             if (c >= '0' && c <= '9') { /* Digit for macro arg */
7857                 if (maclvl < 0)         /* Digit variables are global */
7858                   p = g_var[c];         /* if no macro is active */
7859                 else                    /* otherwise */
7860                   p = m_arg[maclvl][c - '0']; /* they're on the stack */
7861             } else if (c == '*') {
7862 #ifdef COMMENT
7863                 p = (maclvl > -1) ? m_line[maclvl] : topline;
7864                 if (!p) p = "";
7865 #else
7866                 int nx = FNVALL;
7867                 char * sx = fnval;
7868                 p = fnval;
7869 #ifdef COMMENT
7870                 if (cmdsrc() == 0 && topline)
7871                   p = topline;
7872                 else
7873 #endif /* COMMENT */
7874                   if (zzstring("\\fjoin(&_[],{ },1)",&sx,&nx) < 0) {
7875                     failed = 1;
7876                     p = fnval;
7877                     if (fndiags)
7878                       sprintf(fnval,"<ERROR:OVERFLOW:\\fcontents()>");
7879                     debug(F110,"zzstring fcontents(\\%*)",p,0);
7880                 }
7881 #endif /* COMMENT */
7882             } else {
7883                 if (isupper(c)) c -= ('a'-'A');
7884                 p = g_var[c];           /* Letter for global variable */
7885             }
7886             if (!p) p = "";
7887             goto fnend;
7888         } else if (c == '&') {          /* Array reference. */
7889             int vbi, d;
7890             if (arraynam(p,&vbi,&d) < 0) { /* Get name and subscript */
7891                 failed = 1;
7892                 p = fnval;
7893                 if (fndiags)
7894                   sprintf(fnval,"<ERROR:ARG_BAD_ARRAY:\\fcontents()>");
7895                 goto fnend;
7896             }
7897             if (chkarray(vbi,d) > 0) {  /* Array is declared? */
7898                 vbi -= ARRAYBASE;       /* Convert name to index */
7899                 if (a_dim[vbi] >= d) {  /* If subscript in range */
7900                     char **ap;
7901                     ap = a_ptr[vbi];    /* get data pointer */
7902                     if (ap) {           /* and if there is one */
7903                         p = ap[d];
7904                         goto fnend;
7905                     }
7906                 }
7907             } else {
7908                 failed = 1;
7909                 p = fnval;
7910                 if (fndiags)
7911                   sprintf(fnval,"<ERROR:ARG_NOT_ARRAY:\\fcontents()>");
7912                 goto fnend;
7913             }
7914         } else {
7915             failed = 1;
7916             p = fnval;
7917             if (fndiags)
7918               sprintf(fnval,"<ERROR:ARG_NOT_VARIABLE:\\fcontents()>");
7919             goto fnend;
7920         }
7921     }
7922     p = fnval;                          /* Default result pointer */
7923     fnval[0] = NUL;                     /* Default result = empty string */
7924
7925
7926     for (i = 0; i < argn; i++) {        /* Loop to expand each argument */
7927         n = MAXARGLEN;                  /* Allow plenty of space */
7928         bp[i] = s = malloc(n+1);        /* Allocate space for this argument */
7929         if (bp[i] == NULL) {            /* Handle failure to get space */
7930             failed = 1;
7931             if (fndiags)
7932               ckmakmsg(fnval,FNVALL,"<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
7933             goto fnend;
7934         }
7935         p = argp[i] ? argp[i] : "";     /* Point to this argument */
7936
7937 /*
7938   Trim leading and trailing spaces from the original argument, before
7939   evaluation.  This code new to edit 184.  Fixed in edit 199 to trim
7940   blanks BEFORE stripping braces.
7941
7942 */
7943         {
7944             int x, j;
7945             x = strlen(p);
7946             j = x - 1;                  /* Trim trailing whitespace */
7947             while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
7948               *(p + j--) = NUL;
7949             while (*p == SP || *p == HT) /* Strip leading whitespace */
7950               p++;
7951             x = strlen(p);
7952             if (*p == '{' && *(p+x-1) == '}') { /* NOW strip braces */
7953                 p[x-1] = NUL;
7954                 p++;
7955                 x -= 2;
7956             }
7957         }
7958
7959 /* Now evaluate the argument */
7960
7961         debug(F111,"fneval calling zzstring",p,n);
7962         t = zzstring(p,&s,&n);          /* Expand arg into new space */
7963         debug(F101,"fneval zzstring","",t);
7964         debug(F101,"fneval zzstring","",n);
7965         if (t < 0) {
7966             debug(F101,"fneval zzstring fails, arg","",i);
7967             failed = 1;
7968             if (fndiags) {
7969                 if (n == 0)
7970                   ckmakmsg(fnval,FNVALL,
7971                            "<ERROR:ARG_TOO_LONG:\\f",fn,"()>",NULL);
7972                 else
7973                   ckmakmsg(fnval,FNVALL,
7974                            "<ERROR:ARG_EVAL_FAILURE:\\f",fn,"()>",NULL);
7975             }
7976             goto fnend;
7977         }
7978         debug(F111,"fneval arg",bp[i],i);
7979     }
7980
7981 #ifdef DEBUG
7982     if (deblog) {
7983         int j;
7984         for (j = 0; j < argn; j++) {
7985             debug(F111,"fneval arg post eval",argp[j],j);
7986             debug(F111,"fneval evaluated arg",bp[j],j);
7987         }
7988     }
7989 #endif /* DEBUG */
7990 /*
7991   From this point on, bp[0..argn-1] are not NULL and all must be freed
7992   before returning.
7993 */
7994     if (argn < 1) {                     /* Catch required args missing */
7995         switch (cx) {
7996           case FN_DEF:
7997           case FN_EVA:
7998           case FN_EXE:
7999           case FN_CHR:
8000           case FN_COD:
8001           case FN_MAX:
8002           case FN_MIN:
8003           case FN_MOD:
8004           case FN_FD:
8005           case FN_FS:
8006           case FN_TOD:
8007           case FN_FFN:
8008           case FN_BSN:
8009           case FN_RAW:
8010           case FN_CMD:
8011           case FN_2HEX:
8012           case FN_2OCT:
8013           case FN_DNAM:
8014 #ifdef FN_ERRMSG
8015           case FN_ERRMSG:
8016 #endif /* FN_ERRMSG */
8017 #ifdef CK_KERBEROS
8018           case FN_KRB_TK:
8019           case FN_KRB_NX:
8020           case FN_KRB_IV:
8021           case FN_KRB_TT:
8022           case FN_KRB_FG:
8023 #endif /* CK_KERBEROS */
8024           case FN_MJD2:
8025           case FN_N2TIM:
8026           case FN_DIM:
8027           case FN_DATEJ:
8028           case FN_PNCVT:
8029           case FN_PERM:
8030           case FN_ALOOK:
8031           case FN_TLOOK:
8032           case FN_ABS:
8033           case FN_AADUMP:
8034           case FN_JOIN:
8035 #ifdef CKFLOAT
8036           case FN_FPABS:
8037           case FN_FPEXP:
8038           case FN_FPLOG:
8039           case FN_FPLN:
8040           case FN_FPMOD:
8041           case FN_FPSQR:
8042           case FN_FPADD:
8043           case FN_FPDIV:
8044           case FN_FPMUL:
8045           case FN_FPPOW:
8046           case FN_FPSUB:
8047           case FN_FPINT:
8048           case FN_FPROU:
8049           case FN_FPSIN:
8050           case FN_FPCOS:
8051           case FN_FPTAN:
8052 #endif /* CKFLOAT */
8053 #ifdef TCPSOCKET
8054           case FN_HSTADD:
8055           case FN_HSTNAM:
8056 #endif /* TCPSOCKET */
8057           case FN_DELSEC:
8058           case FN_KWVAL:
8059 #ifdef COMMENT
8060           case FN_SLEEP:
8061           case FN_MSLEEP:
8062 #endif /* COMMENT */
8063 #ifdef NT
8064           case FN_SNAME:
8065           case FN_LNAME:
8066 #endif /* NT */
8067             failed = 1;
8068             p = fnval;
8069             if (fndiags)
8070               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
8071             goto fnend;
8072         }
8073     }
8074     p = fnval;                          /* Reset these again. */
8075     fnval[0] = NUL;
8076
8077     switch (cx) {                       /* Do function on expanded args. */
8078 #ifdef TCPSOCKET
8079       case FN_HSTADD:
8080         p = ckaddr2name(bp[0]);
8081         goto fnend;
8082       case FN_HSTNAM:
8083         p = ckname2addr(bp[0]);
8084         goto fnend;
8085 #endif /* TCPSOCKET */
8086
8087       case FN_DEF:                      /* \fdefinition(arg1) */
8088         k = isaarray(bp[0]) ?
8089             mxxlook(mactab,bp[0],nmac) :
8090                 mxlook(mactab,bp[0],nmac);
8091         p = (k > -1) ? mactab[k].mval : "";
8092         goto fnend;
8093
8094       case FN_EVA:                      /* \fevaluate(arg1) */
8095         p = *(bp[0]) ? evalx(bp[0]) : "";
8096         if (!*p && fndiags) {
8097             failed = 1;
8098             p = fnval;
8099             evalerr(fn);
8100         }
8101         goto fnend;
8102
8103       case FN_EXE:                      /* \fexecute(arg1) */
8104         j = (int)strlen(s = bp[0]);     /* Length of macro invocation */
8105         p = "";                         /* Initialize return value to null */
8106         if (j) {                        /* If there is a macro to execute */
8107             while (*s == SP) s++,j--;   /* strip leading spaces */
8108             p = s;                      /* remember beginning of macro name */
8109             for (i = 0; i < j; i++) {   /* find end of macro name */
8110                 if (*s == SP)
8111                   break;
8112                 s++;
8113             }
8114             if (*s == SP)       {       /* if there was a space after */
8115                 *s++ = NUL;             /* terminate the macro name */
8116                 while (*s == SP) s++;   /* skip past any extra spaces */
8117             } else
8118               s = "";                   /* maybe there are no arguments */
8119             if (p && *p) {
8120                 k = mlook(mactab,p,nmac); /* Look up the macro name */
8121                 debug(F111,"fexec mlook",p,k);
8122             } else
8123               k = -1;
8124             if (k < 0) {
8125                 char * p2 = p;
8126                 failed = 1;
8127                 p = fnval;
8128                 if (fndiags)
8129                   ckmakxmsg(fnval,FNVALL,
8130                             "<ERROR:NO_SUCH_MACRO:\\f",fn,"(",p2,")>",
8131                             NULL,NULL,NULL,NULL,NULL,NULL,NULL);
8132                 goto fnend;
8133             }
8134 /*
8135   This is just a WEE bit dangerous because we are copying up to 9 arguments
8136   into the space reserved for one.  It won't overrun the buffer, but if there
8137   are lots of long arguments we might lose some.  The other problem is that if
8138   the macro has more than 3 arguments, the 4th through last are all
8139   concatenated onto the third.  (The workaround is to use spaces rather than
8140   commas to separate them.)  Leaving it like this to avoid having to allocate
8141   tons more buffers.
8142 */
8143             if (argn > 1) {             /* Commas used instead of spaces */
8144                 int i;
8145                 char *p = bp[0];        /* Reuse this space */
8146                 *p = NUL;               /* Make into dodo() arg list */
8147                 for (i = 1; i < argn; i++) {
8148                     strncat(p,bp[i],MAXARGLEN);
8149                     strncat(p," ",MAXARGLEN);
8150                 }
8151                 s = bp[0];              /* Point to new list */
8152             }
8153             p = "";                     /* Initialize return value */
8154             if (k >= 0) {               /* If macro found in table */
8155                 /* Go set it up (like DO cmd) */
8156                 if ((j = dodo(k,s,cmdstk[cmdlvl].ccflgs)) > 0) {
8157                     if (cmpush() > -1) { /* Push command parser state */
8158                         extern int ifc;
8159                         int ifcsav = ifc; /* Push IF condition on stack */
8160                         k = parser(1);  /* Call parser to execute the macro */
8161                         cmpop();        /* Pop command parser */
8162                         ifc = ifcsav;   /* Restore IF condition */
8163                         if (k == 0) {   /* No errors, ignore action cmds. */
8164                             p = mrval[maclvl+1]; /* If OK, set return value. */
8165                             if (p == NULL) p = "";
8166                         }
8167                     } else {            /* Can't push any more */
8168                         debug(F100,"zzstring fneval fexec failure","",0);
8169                         printf("\n?\\fexec() too deeply nested\n");
8170                         while (cmpop() > -1) ;
8171                         p = "";
8172                     }
8173                 }
8174             }
8175         }
8176         debug(F110,"zzstring fneval fexecute final p",p,0);
8177         goto fnend;
8178
8179 #ifdef RECURSIVE
8180       case FN_RDIR:                     /* \frdir..() - Recursive dir count */
8181       case FN_RFIL:                     /* \frfiles() - Recursive file count */
8182         /* recursive = 2; */            /* fall thru... */
8183 #endif /* RECURSIVE */
8184       case FN_FC:                       /* \ffiles() - File count. */
8185       case FN_DIR: {                    /* \ffdir.() - Directory count. */
8186           char abuf[16], *s;
8187           char ** ap = NULL;
8188           int x, xflags = 0;
8189           if (matchdot)
8190             xflags |= ZX_MATCHDOT;
8191           if (cx == FN_RDIR || cx == FN_RFIL) {
8192               xflags |= ZX_RECURSE;
8193 #ifdef CKSYMLINK
8194               /* Recursive - don't follow symlinks */
8195               xflags |= ZX_NOLINKS;
8196 #endif /* CKSYMLINK */
8197           }
8198           failed = 0;
8199           if (argn < 1) {
8200               p = "0";
8201               goto fnend;
8202           }
8203           if (cx == FN_DIR || cx == FN_RDIR) { /* Only list directories */
8204               xflags |= ZX_DIRONLY;
8205 #ifdef OS2
8206               zxpn = 1;                 /* Use the alternate list */
8207 #endif /* OS2 */
8208           } else {                      /* List only files */
8209               xflags |= ZX_FILONLY;
8210 #ifdef OS2
8211               zxpn = 1;                 /* Use the alternate list */
8212 #endif /* OS2 */
8213           }
8214           if (*(bp[0])) {
8215               k = nzxpand(bp[0],xflags);
8216               if (k < 0) k = 0;
8217               sprintf(fnval,"%d",k);    /* SAFE */
8218               p = fnval;
8219           } else
8220             p = "0";
8221
8222           if (argn > 1) {               /* Assign list to array */
8223               fnval[0] = NUL;           /* Initial return value */
8224               ckstrncpy(abuf,bp[1],16); /* Get array reference */
8225               s = abuf;
8226               if (*s == CMDQ) s++;
8227               failed = 1;               /* Assume it's bad */
8228               p = fnval;                /* Point to result */
8229               if (fndiags)              /* Default is this error message */
8230                 ckmakmsg(fnval,FNVALL,
8231                          "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
8232               if (s[0] != '&')          /* "Address" of array */
8233                 goto fnend;
8234               if (s[2])
8235                 if (s[2] != '[' || s[3] != ']')
8236                   goto fnend;
8237               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
8238                 s[1] += 32;
8239               if ((x = dclarray(s[1],k)) < 0) /* File list plus count */
8240                 goto fnend;
8241               failed = 0;               /* Unset failure flag */
8242               ap = a_ptr[x];            /* Point to array we just declared */
8243               sprintf(fnval,"%d",k);    /* SAFE */
8244           }
8245 #ifdef OS2
8246           if (ap) {                     /* We are making an array */
8247               int i;
8248               char tmp[16];
8249               ap[0] = NULL;             /* Containing number of files    */
8250               makestr(&(ap[0]),ckitoa(k));
8251
8252               ckstrncpy(tmp,fnval,16);  /* Save return value */
8253
8254               for (i = 1; i <= k; i++) { /* Fill it */
8255                   ap[i] = NULL;
8256                   znext(fnval);         /* Next filename */
8257                   if (!*fnval)          /* No more, done */
8258                     break;              /* In case a premature end */
8259                   makestr(&(ap[i]),fnval);
8260               }
8261 #ifdef ZXREWIND
8262               k = zxrewind();           /* Reset the file expansion */
8263 #else
8264               k = nzxpand(bp[0],xflags);
8265 #endif /* ZXREWIND */
8266               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
8267           }
8268 #else /* OS2 */
8269           {                             /* Make copies of the list */
8270               int i; char tmp[16];
8271               if (flist) {              /* Free old file list, if any */
8272                   for (i = 0; flist[i]; i++) { /* and each string */
8273                       free(flist[i]);
8274                       flist[i] = NULL;
8275                   }
8276                   free((char *)flist);
8277               }
8278               ckstrncpy(tmp,fnval,16);  /* Save our return value */
8279               flist = (char **) malloc((k+1) * sizeof(char *)); /* New array */
8280               if (flist) {
8281                   for (i = 0; i <= k; i++) { /* Fill it */
8282                       flist[i] = NULL;
8283                       znext(fnval);     /* Next filename */
8284                       if (!*fnval)      /* No more, done */
8285                         break;
8286                       makestr(&(flist[i]),fnval);
8287                   }
8288                   if (ap) {             /* If array pointer given */
8289                       ap[0] = NULL;
8290                       makestr(&(ap[0]),ckitoa(k));
8291                       for (i = 0; i < k; i++) { /* Copy file list to array */
8292                           ap[i+1] = NULL;
8293                           makestr(&(ap[i+1]),flist[i]);
8294                       }
8295                   }
8296               }
8297               ckstrncpy(fnval,tmp,FNVALL); /* Restore return value */
8298               flistn = 0;               /* Reset global list pointer */
8299           }
8300 #endif /* OS2 */
8301 #ifdef RECURSIVE
8302           recursive = rsave;
8303 #endif /* RECURSIVE */
8304 #ifdef OS2
8305           zxpn = zsave;
8306 #endif /* OS2 */
8307       }
8308       goto fnend;
8309
8310       case FN_FIL:                      /* \fnextfile() - Next file in list. */
8311         p = fnval;                      /* (no args) */
8312         *p = NUL;
8313 #ifdef OS2
8314         zxpn = 1;                       /* OS/2 - use the alternate list */
8315         znext(p);                       /* Call system-dependent function */
8316         zxpn = zsave;                   /* Restore original list */
8317 #else
8318         if (flist)                      /* Others, use our own list. */
8319           if (flist[flistn])
8320             p = flist[flistn++];
8321 #endif /* OS2 */
8322         goto fnend;
8323
8324     } /* Break up big switch... */
8325
8326     switch (cx) {
8327       case FN_IND:                      /* \findex(s1,s2,start) */
8328       case FN_RIX:                      /* \frindex(s1,s2,start) */
8329       case FN_SEARCH:                   /* \fsearch(pat,string,start) */
8330       case FN_RSEARCH: {                /* \frsearch(pat,string,start) */
8331         int i = 0, right = 0, search = 0;
8332         right = (cx == FN_RIX || cx == FN_RSEARCH);
8333         search = (cx == FN_SEARCH || cx == FN_RSEARCH);
8334         p = "0";
8335         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
8336             int start = 0;
8337             char * pat = NULL;
8338             len1 = (int)strlen(pat = bp[0]); /* length of string to look for */
8339             len2 = (int)strlen(s = bp[1]); /* length of string to look in */
8340             if (len1 < 1 || len2 < 1)   /* Watch out for empty strings */
8341               goto fnend;
8342             start = right ? -1 : 0;     /* Default starting position */
8343             if (argn > 2) {
8344                 val1 = *(bp[2]) ? evalx(bp[2]) : "1";
8345                 if (chknum(val1)) {
8346                     int t;
8347                     t = atoi(val1);
8348                     if (!search) {      /* Index or Rindex */
8349                         j = len2 - len1; /* Length difference */
8350                         t--;             /* Convert position to 0-based */
8351                         if (t < 0) t = 0;
8352                         start = t;
8353                         if (!right && start < 0) start = 0;
8354                     } else {            /* Search or Rsearch */
8355                         int x;
8356                         if (t < 0) t = 0;
8357                         if (right) {    /* Right to left */
8358                             if (t > len2) t = len2;
8359                             start = len2 - t - 1;
8360                             if (start < 0)
8361                               goto fnend;
8362                             x = len2 - t;
8363                             s[x] = NUL;
8364                         } else {        /* Left to right */
8365                             start = t - 1;
8366                             if (start < 0) start = 0;
8367                             if (start >= len2)
8368                               goto fnend;
8369                         }
8370                     }
8371                 } else {
8372                     failed = 1;
8373                     evalerr(fn);
8374                     p = fnval;
8375                     goto fnend;
8376                 }
8377             }
8378             if (search) {               /* \fsearch() or \frsearch() */
8379                 if (right && pat[0] == '^') {
8380                     right = 0;
8381                     start = 0;
8382                 }
8383                 if (right) {
8384                     if (start < 0) start = len2 - 1;
8385                     for (i = start;
8386                          i >= 0 && !ckmatch(pat,s+i,inpcas[cmdlvl],1+4);
8387                          i--) ;
8388                     if (i < 0) i = 0; else i++;
8389                 } else {
8390                     i = ckmatch(pat,&s[start],inpcas[cmdlvl],1+4);
8391                     if (start > 0) i += start;
8392                 }
8393             } else {
8394                 i = ckindex(pat,bp[1],start,right,inpcas[cmdlvl]);
8395             }
8396             sprintf(fnval,"%d",i);      /* SAFE */
8397             p = fnval;
8398         }
8399         goto fnend;
8400       }
8401
8402       case FN_RPL:                      /* \freplace(s1,s2,s3) */
8403       /*
8404         s = bp[0] = source string
8405             bp[1] = match string
8406             bp[2] = replacement string
8407             bp[3] = which occurrence (default = all);
8408         p = fnval = destination (result) string
8409       */
8410         if (argn < 1)                   /* Nothing */
8411           goto fnend;
8412         if (argn < 2) {                 /* Only works if we have 2 or 3 args */
8413             ckstrncpy(p,bp[0],FNVALL);
8414         } else {
8415             int occur = 0, xx = 0, j2;
8416             len1 = (int)strlen(bp[0]);  /* length of string to look in */
8417             len2 = (int)strlen(bp[1]);  /* length of string to look for */
8418             len3 = (argn < 3) ? 0 : (int)strlen(bp[2]); /* Len of replacemnt */
8419             j = len1 - len2 + 1;
8420             j2 = j;
8421             if (argn > 3) {
8422                 if (chknum(bp[3])) {
8423                     occur = atoi(bp[3]);
8424                 } else {
8425                     failed = 1;
8426                     if (fndiags)
8427                       ckmakmsg(fnval,FNVALL,
8428                                "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
8429                     goto fnend;
8430                 }
8431             }
8432             /* If args out of whack... */
8433             if (j < 1 || len1 == 0 || len2 == 0) {
8434                 ckstrncpy(p,bp[0],FNVALL); /* just return original string */
8435                 p[FNVALL] = NUL;
8436             } else {
8437               ragain:
8438                 s = bp[0];              /* Point to beginning of string */
8439                 while (j-- > 0) {       /* For each character */
8440                     if (!ckstrcmp(bp[1],s,len2,inpcas[cmdlvl]) &&
8441                         (occur == 0 || occur == ++xx)) {
8442                         if (len3) {
8443                             ckstrncpy(p,bp[2],FNVALL);
8444                             p += len3;
8445                         }
8446                         s += len2;      /* and skip past it. */
8447                     } else {            /* No, */
8448                         *p++ = *s++;    /* just copy this character */
8449                     }
8450                 }
8451                 *p = NUL;
8452                 while ((*p++ = *s++));
8453                 if (occur < 0) {        /* cheap... */
8454                     occur = xx + occur + 1;
8455                     xx = 0;
8456                     p = fnval;
8457                     j = j2;
8458                     if (occur > 0)
8459                       goto ragain;
8460                 }
8461             }
8462         }
8463         p = fnval;
8464         goto fnend;
8465
8466       case FN_CHR:                      /* \fcharacter(arg1) */
8467         val1 = *(bp[0]) ? evalx(bp[0]) : "";
8468         if (chknum(val1)) {             /* Must be numeric */
8469             i = atoi(val1);
8470             if (i >= 0 && i < 256) {    /* Must be an 8-bit value */
8471                 p = fnval;
8472                 *p++ = (char) i;
8473                 *p = NUL;
8474                 p = fnval;
8475             } else {
8476                 failed = 1;
8477                 if (fndiags)
8478                   ckmakmsg(fnval,FNVALL,
8479                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
8480             }
8481         } else {
8482             failed = 1;
8483             evalerr(fn);
8484         }
8485         goto fnend;
8486
8487       case FN_COD:                      /* \fcode(char) */
8488         if ((int)strlen(bp[0]) > 0) {
8489             p = fnval;
8490             i = *bp[0];
8491             sprintf(p,"%d",(i & 0xff)); /* SAFE */
8492         } else p = "0";                 /* Can't happen */
8493         goto fnend;
8494
8495       case FN_LEN:                      /* \flength(arg1) */
8496         if (argn > 0) {
8497             p = fnval;
8498             sprintf(p,"%d",(int)strlen(bp[0])); /* SAFE */
8499         } else p = "0";
8500         goto fnend;
8501
8502       case FN_LOW:                      /* \flower(arg1) */
8503         s = bp[0] ? bp[0] : "";
8504         p = fnval;
8505         while (*s) {
8506             if (isupper(*s))
8507               *p = (char) tolower(*s);
8508             else
8509               *p = *s;
8510             p++; s++;
8511         }
8512         *p = NUL;
8513         p = fnval;
8514         goto fnend;
8515
8516       case FN_MAX:                      /* \fmax(arg1,arg2) */
8517       case FN_MIN:                      /* \fmin(arg1,arg2) */
8518       case FN_MOD:                      /* \fmod(arg1,arg2) */
8519         val1 = *(bp[0]) ? evalx(bp[0]) : "";
8520 #ifdef COMMENT
8521         /* No longer necessary because evalx() no longer overwrites its */
8522         /* result every time it's called (2000/09/23). */
8523         free(bp[0]);
8524         bp[0] = NULL;
8525 #endif /* COMMENT */
8526         if (argn > 1) {
8527 #ifdef COMMENT
8528             /* Ditto... */
8529             bp[0] = malloc((int)strlen(val1)+1);
8530             if (bp[0])
8531               strcpy(bp[0],val1);       /* safe */
8532             val1 = bp[0];
8533 #endif /* COMMENT */
8534             val2 = *(bp[1]) ? evalx(bp[1]) : "";
8535             if (chknum(val1) && chknum(val2)) {
8536                 i = atoi(val1);
8537                 j = atoi(val2);
8538                 switch (y) {
8539                   case FN_MAX:
8540                     if (j < i) j = i;
8541                     break;
8542                   case FN_MIN:
8543                     if (j > i) j = i;
8544                     break;
8545                   case FN_MOD:
8546                     if (j == 0) {
8547                         failed = 1;
8548                         if (fndiags)
8549                           ckmakmsg(fnval,FNVALL,
8550                                    "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
8551                         else
8552                           fnval[0] = NUL;
8553                         goto fnend;
8554                     } else
8555                       j = i % j;
8556                 }
8557                 p = fnval;
8558                 sprintf(p,"%d",j);      /* SAFE */
8559             } else {
8560                 failed = 1;
8561                 evalerr(fn);
8562             }
8563         } else p = val1;
8564         goto fnend;
8565     } /* Break up big switch... */
8566
8567     switch (y) {
8568       case FN_SUB:                      /* \fsubstr(arg1,arg2,arg3) */
8569       case FN_RIG:                      /* \fright(arg1,arg2) */
8570       case FN_LEF:                      /* \fleft(arg1,arg2) */
8571         if (argn < 1)
8572           goto fnend;
8573         val1 = "";
8574         if (argn > 1)
8575           if (*(bp[1]))
8576             val1 =  evalx(bp[1]);
8577 #ifdef COMMENT
8578         if (bp[1]) free(bp[1]);         /* Have to copy this */
8579         bp[1] = malloc((int)strlen(val1)+1);
8580         if (!bp[1]) {
8581             failed = 1;
8582             if (fndiags) {
8583                 p = fnval;
8584                 ckmakmsg(fnval,FNVALL,
8585                          "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
8586             }
8587             goto fnend;
8588         }
8589         strcpy(bp[1],val1);             /* safe */
8590         val1 = bp[1];
8591 #endif /* COMMENT */
8592         val2 = "";
8593         if (argn > 2)
8594           if (*(bp[2]))
8595             val2 = evalx(bp[2]);
8596         if (
8597             ((argn > 1) && (int)strlen(val1) && !rdigits(val1)) ||
8598             ((cx == FN_SUB) &&
8599               ((argn > 2) && (int)strlen(val2) && !rdigits(val2)))
8600             ) {
8601             failed = 1;
8602             evalerr(fn);
8603         } else {
8604             int lx;
8605             p = fnval;                  /* pointer to result */
8606             lx = strlen(bp[0]);         /* length of arg1 */
8607             if (cx == FN_SUB) {         /* substring */
8608                 k = (argn > 2) ? atoi(val2) : MAXARGLEN; /* length */
8609                 j = (argn > 1) ? atoi(val1) : 1; /* start pos for substr */
8610             } else if (cx == FN_LEF) {  /* left */
8611                 k = (argn > 1) ? atoi(val1) : lx;
8612                 j = 1;
8613             } else {                             /* right */
8614                 k = (argn > 1) ? atoi(val1) : lx; /* length */
8615                 j = lx - k + 1;                  /* start pos for right */
8616                 if (j < 1) j = 1;
8617             }
8618             if (k > 0 && j <= lx) {              /* if start pos in range */
8619                 s = bp[0]+j-1;                   /* point to source string */
8620                 for (i = 0; (i < k) && (*p++ = *s++); i++) ;  /* copy */
8621             }
8622             *p = NUL;                   /* terminate the result */
8623             p = fnval;                  /* and point to it. */
8624         }
8625         goto fnend;
8626
8627       case FN_UPP:                      /* \fupper(arg1) */
8628         s = bp[0] ? bp[0] : "";
8629         p = fnval;
8630         while (*s) {
8631             if (islower(*s))
8632               *p = (char) toupper(*s);
8633             else
8634               *p = *s;
8635             p++; s++;
8636         }
8637         *p = NUL;
8638         p = fnval;
8639         goto fnend;
8640
8641       case FN_REP:                      /* \frepeat(text,number) */
8642         if (argn < 1)
8643           goto fnend;
8644         val1 = "1";
8645         if (argn > 1)
8646           if (*(bp[1]))
8647             val1 = evalx(bp[1]);
8648         if (chknum(val1)) {             /* Repeat count */
8649             n = atoi(val1);
8650             debug(F111,"SUNDAY frepeat n",val1,n);
8651             if (n > 0) {                /* Make n copies */
8652                 p = fnval;
8653                 *p = '\0';
8654                 k = (int)strlen(bp[0]); /* Make sure string has some length */
8655                 debug(F111,"SUNDAY frepeat k","",k);
8656                 debug(F111,"SUNDAY frepeat FNVALL","",FNVALL);
8657                 if (k * n >= FNVALL) {  /* But not too much... */
8658                     failed = 1;
8659                     if (fndiags)
8660                       ckmakmsg(fnval,FNVALL,
8661                                "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
8662                     else
8663                       fnval[0] = NUL;
8664                     p = fnval;
8665                     goto fnend;
8666                 }
8667                 if (k > 0) {            /* If there is something to copy */
8668                     for (i = 0; i < n; i++) { /* Copy loop */
8669                         s = bp[0];
8670                         for (j = 0; j < k; j++) {
8671                             if ((p - fnval) >= FNVALL)
8672                               break;    /* shouldn't happen... */
8673                             else
8674                               *p++ = *s++;
8675                         }
8676                     }
8677                     *p = NUL;
8678                 }
8679             }
8680         } else {
8681             failed = 1;
8682             evalerr(fn);
8683         }
8684         p = fnval;
8685         goto fnend;
8686
8687 #ifndef NOFRILLS
8688       case FN_REV:                      /* \freverse() */
8689         if (argn < 1)
8690           goto fnend;
8691         yystring(bp[0],&p);
8692         goto fnend;
8693 #endif /* NOFRILLS */
8694
8695       case FN_RPA:                      /* \frpad() and \flpad() */
8696       case FN_LPA:
8697         if (argn < 1)
8698           goto fnend;
8699         val1 = "";
8700         if (argn > 1)
8701           if (*(bp[1]))
8702             val1 = evalx(bp[1]);
8703         if (argn == 1) {                /* If a number wasn't given */
8704             p = fnval;                  /* just return the original string */
8705             ckstrncpy(p,bp[0],FNVALL);
8706         } else if (argn > 1 &&  !*val1) {
8707             failed = 1;
8708             evalerr(fn);
8709         } else /* if (chknum(val1)) */ { /* Repeat count */
8710             char pc;
8711             n = atoi(val1);
8712             if (n >= 0) {
8713                 p = fnval;
8714                 k = (int)strlen(bp[0]); /* Length of string to be padded */
8715                 if (k >= n) {           /* It's already long enough */
8716                     ckstrncpy(p,bp[0],FNVALL);
8717                 } else {
8718                     if (n + k <= FNVALL) {
8719                         pc = (char) ((argn < 3) ? SP : *bp[2]);
8720                         if (!pc) pc = SP;
8721                         if (cx == FN_RPA) { /* RPAD */
8722                             strncpy(p,bp[0],k); /* (leave it like this) */
8723                             p[k] = NUL;
8724                             p += k;
8725                             for (i = k; i < n; i++)
8726                               *p++ = pc;
8727                         } else {        /* LPAD */
8728                             n -= k;
8729                             for (i = 0; i < n; i++)
8730                               *p++ = pc;
8731                             strncpy(p,bp[0],k); /* (leave it like this) */
8732                             p[k] = NUL;
8733                             p += k;
8734                         }
8735                     }
8736                     *p = NUL;
8737                 }
8738             }
8739         }
8740         p = fnval;
8741         goto fnend;
8742
8743 #ifdef ZFCDAT
8744       case FN_FD:                       /* \fdate(filename) */
8745         p = fnval;
8746         s = zfcdat(bp[0]);
8747         if (!s) s = "";
8748         if (!*s) {
8749             failed = 1;
8750             if (fndiags)
8751               ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
8752             goto fnend;
8753         }
8754         ckstrncpy(fnval,s,FNVALL);
8755 #endif /* ZFCDAT */
8756         goto fnend;
8757
8758     } /* Break up big switch... */
8759
8760     switch (y) {
8761       case FN_FS:                       /* \fsize(filename) */
8762         p = fnval;
8763         z = zchki(bp[0]);
8764         if (z < 0) {
8765             failed = 1;
8766             if (fndiags) {
8767                 if (z == -1)
8768                   ckmakmsg(fnval,FNVALL,
8769                            "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
8770                 else if (z == -2)
8771                   ckmakmsg(fnval,FNVALL,
8772                            "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
8773                 else if (z == -3)
8774                   ckmakmsg(fnval,FNVALL,
8775                            "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
8776                 else
8777                   ckmakmsg(fnval,FNVALL,
8778                            "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
8779             }
8780             goto fnend;
8781         }
8782         sprintf(fnval,"%ld",z);         /* SAFE */
8783         goto fnend;
8784
8785       case FN_VER:                      /* \fverify() */
8786         p = "-1";
8787         if (argn == 1)                  /* No second arg */
8788           goto fnend;
8789         else if (!bp[1])                /* Or second arg null */
8790           goto fnend;
8791         else if (!*(bp[1]))             /* or empty. */
8792           goto fnend;
8793         p = "0";
8794         if (argn > 1) {                 /* Only works if we have 2 or 3 args */
8795             int start;
8796             char *s2, ch1, ch2;
8797             start = 0;
8798             if (argn > 2) {             /* Starting position specified */
8799                 val1 = *(bp[2]) ? evalx(bp[2]) : "0";
8800                 if (chknum(val1)) {
8801                     start = atoi(val1) /* - 1 */;
8802                     if (start < 0) start = 0;
8803                     if (start > (int)strlen(bp[1]))
8804                       goto verfin;
8805                 } else {
8806                     failed = 1;
8807                     evalerr(fn);
8808                     goto fnend;
8809                 }
8810             }
8811             i = start;
8812             p = "0";
8813             for (s = bp[1] + start; *s; s++,i++) {
8814                 ch1 = *s;
8815                 if (!inpcas[cmdlvl]) if (islower(ch1)) ch1 = toupper(ch1);
8816                 j = 0;
8817                 for (s2 = bp[0]; *s2; s2++) {
8818                     ch2 = *s2;
8819                     if (!inpcas[cmdlvl]) if (islower(ch2)) ch2 = toupper(ch2);
8820                     if (ch1 == ch2) {
8821                         j = 1;
8822                         break;
8823                     }
8824                 }
8825                 if (j == 0) {
8826                     sprintf(fnval,"%d",i+1); /* SAFE */
8827                     p = fnval;
8828                     break;
8829                 }
8830             }
8831         }
8832       verfin:
8833         goto fnend;
8834
8835       case FN_IPA:                      /* Find and return IP address */
8836         if (argn > 0) {                 /* in argument string. */
8837             int start = 0;
8838             if (argn > 1) {             /* Starting position specified */
8839                 if (chknum(bp[1])) {
8840                     start = atoi(bp[1]) - 1;
8841                     if (start < 0) start = 0;
8842                 } else {
8843                     failed = 1;
8844                     if (fndiags)
8845                       ckmakmsg(fnval,FNVALL,
8846                                "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
8847                     goto fnend;
8848                 }
8849             }
8850             p = getip(bp[0]+start);
8851         } else p = "";
8852         goto fnend;
8853
8854 #ifdef OS2
8855       case FN_CRY:
8856         p = "";
8857         if (argn > 0) {
8858             p = fnval;
8859             ckstrncpy(p,bp[0],FNVALL);
8860             ck_encrypt(p);
8861         }
8862         goto fnend;
8863
8864       case FN_OOX:
8865         p = "";
8866         if (argn > 0)
8867           p = (char *) ck_oox(bp[0], (argn > 1) ? bp[1] : "");
8868         goto fnend;
8869 #endif /* OS2 */
8870
8871       case FN_HEX:                      /* \fhexify(arg1) */
8872         if (argn < 1)
8873           goto fnend;
8874         if ((int)strlen(bp[0]) < (FNVALL / 2)) {
8875             s = bp[0];
8876             p = fnval;
8877             while (*s) {
8878                 x = (*s >> 4) & 0x0f;
8879                 *p++ = hexdigits[x];
8880                 x = *s++ & 0x0f;
8881                 *p++ = hexdigits[x];
8882             }
8883             *p = NUL;
8884             p = fnval;
8885         }
8886         goto fnend;
8887
8888       case FN_UNTAB:                    /* \funtab(arg1) */
8889         if (argn < 1)
8890           goto fnend;
8891         if ((int)strlen(bp[0]) < (FNVALL * 2)) {
8892             s = bp[0];
8893             p = fnval;
8894             if (untabify(bp[0],p,FNVALL) < 0) {
8895                 failed = 1;
8896                 if (fndiags)
8897                   ckmakmsg(fnval,FNVALL,
8898                            "<ERROR:OVERFLOW:\\f",fn,"()>",NULL);
8899             }
8900             goto fnend;
8901         }
8902
8903       case FN_UNH: {                    /* \funhex(arg1) */
8904           int c[2], i;
8905           if (argn < 1)
8906             goto fnend;
8907           if ((int)strlen(bp[0]) < (FNVALL * 2)) {
8908               s = bp[0];
8909               p = fnval;
8910               while (*s) {
8911                   for (i = 0; i < 2; i++) {
8912                       c[i] = *s++;
8913                       if (!c[i]) { p = ""; goto unhexfin; }
8914                       if (islower(c[i])) c[i] = toupper(c[i]);
8915                       if (c[i] >= '0' && c[i] <= '9') {
8916                           c[i] -= 0x30;
8917                       } else if (c[i] >= 'A' && c[i] <= 'F') {
8918                           c[i] -= 0x37;
8919                       } else {
8920                           failed = 1;
8921                           if (fndiags)
8922                             ckmakmsg(fnval,
8923                                      FNVALL,
8924                                      "<ERROR:ARG_OUT_OF_RANGE:\\f",
8925                                      fn,
8926                                      "()>",
8927                                      NULL
8928                                      );
8929                           goto fnend;
8930                       }
8931                   }
8932                   *p++ = ((c[0] << 4) & 0xf0) | (c[1] & 0x0f);
8933               }
8934               *p = NUL;
8935               p = fnval;
8936           }
8937         unhexfin:
8938           goto fnend;
8939       }
8940
8941       case FN_BRK: {                    /* \fbreak() */
8942           char * c;                     /* Characters to break on */
8943           char c2, s2;
8944           int start = 0;
8945           int done = 0;
8946           if (argn < 1)
8947             goto fnend;
8948           if (argn > 2) {
8949               s = bp[2] ? bp[2] : "0";
8950               if (chknum(s)) {
8951                   start = atoi(s);
8952                   if (start < 0) start = 0;
8953                   if (start > (int)strlen(bp[0]))
8954                     goto brkfin;
8955               } else {
8956                   failed = 1;
8957                   if (fndiags)
8958                     ckmakmsg(fnval,FNVALL,
8959                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
8960                   goto fnend;
8961               }
8962           }
8963           s = bp[0] + start;            /* Source pointer */
8964
8965           while (*s && !done) {
8966               s2 = *s;
8967               if (!inpcas[cmdlvl] && islower(s2)) s2 = toupper(s2);
8968               c = bp[1] ? bp[1] : "";   /* Character to break on */
8969               while (*c) {
8970                   c2 = *c;
8971                   if (!inpcas[cmdlvl] && islower(c2)) c2 = toupper(c2);
8972                   if (c2 == s2) {
8973                       done = 1;
8974                       break;
8975                   }
8976                   c++;
8977               }
8978               if (done) break;
8979               *p++ = *s++;
8980           }
8981           *p = NUL;                     /* terminate the result */
8982           p = fnval;                    /* and point to it. */
8983         brkfin:
8984           goto fnend;
8985       }
8986
8987       case FN_SPN: {                    /* \fspan() */
8988           char *q;
8989           char c1, c2;
8990           int start = 0;
8991           if (argn < 1)
8992             goto fnend;
8993           if (argn > 2) {               /* Starting position */
8994               s = bp[2] ? bp[2] : "0";
8995               if (chknum(s)) {
8996                   start = atoi(s);
8997                   if (start < 0) start = 0;
8998               } else {
8999                   failed = 1;
9000                   if (fndiags)
9001                     ckmakmsg(fnval,FNVALL,
9002                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9003                   goto fnend;
9004               }
9005           }
9006           s = bp[0] + start;            /* Source pointer */
9007           if (argn > 1 &&
9008               (int)strlen(bp[1]) > 0 &&
9009               start <= (int)strlen(bp[0])) {
9010               while (*s) {              /* Loop thru source string */
9011                   q = bp[1];            /* Span string */
9012                   c1 = *s;
9013                   if (!inpcas[cmdlvl])
9014                     if (islower(c1)) c1 = toupper(c1);
9015                   x = 0;
9016                   while ((c2 = *q++)) {
9017                       if (!inpcas[cmdlvl])
9018                         if (islower(c2)) c2 = toupper(c2);
9019                       if (c1 == c2) { x = 1; break; }
9020                   }
9021                   if (!x) break;
9022                   *p++ = *s++;
9023               }
9024               *p = NUL;                 /* Terminate and return the result */
9025               p = fnval;
9026           }
9027           goto fnend;
9028       }
9029     } /* Break up big switch... */
9030
9031     switch (y) {
9032       case FN_TRM:                      /* \ftrim(s1[,s2]) */
9033       case FN_LTR:                      /* \fltrim(s1[,s2]) */
9034         if (argn < 1)
9035           goto fnend;
9036         if ((len1 = (int)strlen(bp[0])) > 0) {
9037             if (len1 > FNVALL)
9038               len1 = FNVALL;
9039             s = " \t\r\n";
9040             if (argn > 1)               /* Trim list given */
9041               s = bp[1];
9042             len2 = (int)strlen(s);
9043             if (len2 < 1) {             /* or not... */
9044                 s = " \t\r\n";          /* Default is to trim whitespace */
9045                 len2 = 2;
9046             }
9047             if (cx == FN_TRM) {         /* Trim from right */
9048                 char * q, p2, q2;
9049                 ckstrncpy(fnval,bp[0],FNVALL); /* Copy string to output */
9050                 p = fnval + len1 - 1;   /* Point to last character */
9051
9052                 while (p >= (char *)fnval) { /* Go backwards */
9053                     q = s;              /* Point to trim list */
9054                     p2 = *p;
9055                     if (!inpcas[cmdlvl])
9056                       if (islower(p2)) p2 = toupper(p2);
9057                     while (*q) {        /* Is this char in trim list? */
9058                         q2 = *q;
9059                         if (!inpcas[cmdlvl])
9060                           if (islower(q2)) q2 = toupper(q2);
9061                         if (p2 == q2) { /* Yes, null it out */
9062                             *p = NUL;
9063                             break;
9064                         }
9065                         q++;
9066                     }
9067                     if (!*q)            /* Trim list exhausted */
9068                       break;            /* So we're done. */
9069                     p--;                /* Else keep trimming */
9070                 }
9071             } else {                    /* Trim from left */
9072                 char * q, p2, q2;
9073                 p = bp[0];              /* Source */
9074                 while (*p) {
9075                     p2 = *p;
9076                     if (!inpcas[cmdlvl])
9077                       if (islower(p2)) p2 = toupper(p2);
9078                     q = s;
9079                     while (*q) {        /* Is this char in trim list? */
9080                         q2 = *q;
9081                         if (!inpcas[cmdlvl])
9082                           if (islower(q2)) q2 = toupper(q2);
9083                         if (p2 == q2) { /* Yes, point past it */
9084                             p++;        /* and try next source character */
9085                             break;
9086                         }
9087                         q++;            /* No, try next trim character */
9088                     }
9089                     if (!*q)            /* Trim list exhausted */
9090                       break;            /* So we're done. */
9091                 }
9092                 ckstrncpy(fnval,p,FNVALL);
9093             }
9094             p = fnval;
9095         } else p = "";
9096         goto fnend;
9097
9098       case FN_CAP:                      /* \fcapitalize(arg1) */
9099         if (argn < 1)
9100           goto fnend;
9101         s = bp[0];
9102         p = fnval;
9103         x = 0;
9104         while ((c = *s++)) {
9105             if (isalpha(c)) {
9106                 if (x == 0) {
9107                     x = 1;
9108                     if (islower(c))
9109                       c = toupper(c);
9110                 } else if (isupper(c))
9111                   c = tolower(c);
9112             }
9113             *p++ = c;
9114         }
9115         *p = NUL;
9116         p = fnval;
9117         goto fnend;
9118
9119 #ifdef COMMENT
9120       case FN_TOD:                      /* Time of day to secs since midnite */
9121         sprintf(fnval,"%ld",tod2sec(bp[0])); /* SAFE */
9122         goto fnend;
9123 #endif /* COMMENT */
9124
9125       case FN_FFN:                      /* Full pathname of file */
9126         zfnqfp(bp[0],FNVALL,p);
9127         if (!p) p = "";
9128         goto fnend;
9129
9130       case FN_CHK: {                    /* \fchecksum() */
9131           long chk = 0;
9132           p = (argn > 0) ? bp[0] : "";
9133           while (*p) chk += *p++;
9134           sprintf(fnval,"%lu",chk);     /* SAFE */
9135           p = fnval;
9136           goto fnend;
9137       }
9138
9139 #ifndef NOXFER
9140       case FN_CRC:                      /* \fcrc16() */
9141         if (argn > 0)
9142           sprintf(fnval,"%u",           /* SAFE */
9143                   chk3((CHAR *)bp[0],(int)strlen(bp[0])));
9144         else
9145           p = "0";
9146         goto fnend;
9147 #endif /* NOXFER */
9148
9149       case FN_BSN:                      /* \fbasename() */
9150         zstrip(bp[0],&p);
9151         goto fnend;
9152
9153 #ifndef NOLOCAL
9154 #ifdef OS2
9155       case FN_SCRN_CX:                  /* \fscrncurx() */
9156         p = fnval;
9157         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->x); /* SAFE */
9158         goto fnend;
9159
9160       case FN_SCRN_CY:                  /* \fscrncury() */
9161         p = fnval;
9162         sprintf(p,"%d",(int)VscrnGetCurPos(VTERM)->y); /* SAFE */
9163         goto fnend;
9164
9165       case FN_SCRN_STR: {               /* \fscrnstr() */
9166           videoline * line = NULL;
9167           viocell * cells = NULL;
9168           int row = 0, col = 0, len = 0;
9169           /* NOTE: On Unicode systems, the screen contents are stored in */
9170           /* in Unicode.  Therefore, we should really be performing a    */
9171           /* conversion to the local character set.                      */
9172
9173           /* 6/18/2000 - added the translation to lcs */
9174
9175           if (bp[0] == NULL || bp[0][0] == '\0') {
9176               row = 0;
9177           } else {
9178               if (chknum(bp[0])) {
9179                   row = atoi(bp[0]);
9180                   if (row < 0)
9181                     row = 0;
9182               } else {
9183                   failed = 1;
9184                   if (fndiags)
9185                     ckmakmsg(fnval,FNVALL,
9186                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9187                   goto fnend;
9188               }
9189           }
9190           line = VscrnGetLineFromTop( VTERM, (USHORT) row );
9191           if (line != NULL) {
9192               if (bp[1] == NULL || bp[1][0] == '\0')
9193                 col = 0;
9194               else {
9195                   if (chknum(bp[0])) {
9196                       col = atoi(bp[1]);
9197                       if (col < 0 || col >= line->width)
9198                         col = 0;
9199                   } else {
9200                       failed = 1;
9201                       if (fndiags)
9202                         ckmakmsg(fnval,FNVALL,
9203                                  "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9204                       goto fnend;
9205                   }
9206               }
9207               if (bp[2] == NULL || bp[2][0] == '\0') {
9208                   len = line->width - (col+1);
9209               } else {
9210                   if (!chknum(bp[2])) {
9211                       failed = 1;
9212                       if (fndiags)
9213                         ckmakmsg(fnval,FNVALL,
9214                                  "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9215                       goto fnend;
9216                   }
9217                   len = atoi(bp[2]);
9218                   if (len < 0 || len > line->width)
9219                     len = line->width;
9220               }
9221               cells = line->cells;
9222               for (i = 0; i < len; i++) {
9223                   int pos = i + col;
9224                   if (pos < line->width) {
9225                       if (isunicode())
9226                         fnval[i] = (CHAR) utolxlat(cells[pos].c);
9227                       else
9228                         fnval[i] = (CHAR) (cells[pos].c & 0xFF);
9229                       if (fnval[i] == 0)
9230                         fnval[i] = SP;
9231                   } else
9232                     fnval[i] = SP;
9233               }
9234               fnval[i] = '\0';
9235           } else {
9236               fnval[0] = '\0';
9237           }
9238           p = fnval;
9239           goto fnend;
9240       }
9241 #endif /* OS2 */
9242 #endif /* NOLOCAL */
9243
9244 #ifndef NOPUSH
9245       case FN_RAW:                      /* \frawcommand() */
9246       case FN_CMD: {                    /* \fcommand() */
9247           int x, c, n = FNVALL;
9248           x = 0;                        /* Completion flag */
9249 /*
9250   ZIFILE can be safely used because we can't possibly be transferring a file
9251   while executing this function.
9252 */
9253           if (!nopush && zxcmd(ZIFILE,bp[0]) > 0) { /* Open the command */
9254               while (n-- > -1) {        /* Read from it */
9255                   if ((c = zminchar()) < 0) {
9256                       x = 1;             /* EOF - set completion flag */
9257                       if (cx == FN_CMD) { /* If not "rawcommand" */
9258                           p--;           /* remove trailing newlines */
9259                           while (*p == CR || *p == LF)
9260                             p--;
9261                           p++;
9262                       }
9263                       *p = NUL;         /* Terminate the string */
9264                       break;
9265                   } else                /* Command still running */
9266                     *p++ = c;           /* Copy the bytes */
9267               }
9268               zclose(ZIFILE);           /* Close the command */
9269           }
9270           /* Return null string if command's output was too long. */
9271           p = fnval;
9272           if (!x) {
9273               failed = 1;
9274               if (fndiags)
9275                 ckmakmsg(fnval,FNVALL,
9276                          "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
9277           }
9278           goto fnend;
9279       }
9280 #endif /* NOPUSH */
9281     } /* Break up big switch... */
9282
9283     switch (y) {
9284       case FN_STX:                      /* \fstripx(string,c) */
9285         if (!(s = bp[0]))               /* Make sure there is a string */
9286           goto fnend;
9287         c = '.';                        /* Character to strip from */
9288         if (argn > 1) if (*bp[1]) c = *bp[1];
9289         n = ckstrncpy(fnval,bp[0],FNVALL);
9290         while (--n >= 0) {
9291             if (fnval[n] == c) {
9292                 fnval[n] = NUL;
9293                 break;
9294             }
9295         }
9296         p = fnval;
9297         goto fnend;
9298
9299       case FN_STL:                      /* \flop(string,c) */
9300         if (!(s = bp[0]))               /* Make sure there is a string */
9301           goto fnend;
9302         c = '.';                        /* Character to strip to */
9303         if (argn > 1) if (*bp[1]) c = *bp[1];
9304         x = 0;
9305         while (*s++) {
9306             if (*(s-1) == c) {
9307                 x = 1;
9308                 break;
9309             }
9310         }
9311         if (!x) s = bp[0];
9312         ckstrncpy(fnval,s,FNVALL);
9313         p = fnval;
9314         goto fnend;
9315
9316       case FN_STN:                      /* \fstripn(string,n) */
9317         if (argn < 1)                   /* Remove n chars from right */
9318           goto fnend;
9319         val1 = "0";
9320         if (argn > 1)
9321           if (*(bp[1]))
9322             val1 = evalx(bp[1]);
9323         if (!chknum(val1)) {
9324             failed = 1;
9325             evalerr(fn);
9326             goto fnend;
9327         }
9328         n = atoi(val1);
9329         if (n < 0) n = 0;
9330         k = (int)strlen(s = bp[0]) - n;
9331         if (k < 0) k = 0;
9332         p = fnval;
9333         while (k-- > 0)
9334           *p++ = *s++;
9335         *p = NUL;
9336         p = fnval;
9337         goto fnend;
9338
9339       case FN_STB: {                    /* \fstripb(string,c) */
9340           char c2 = NUL;
9341           int i, k = 0;
9342           char * gr_opn = "\"{'([<";    /* Group open brackets */
9343           char * gr_cls = "\"}')]>";    /* Group close brackets */
9344
9345           p = fnval;
9346           *p = NUL;
9347           if (!(s = bp[0]))             /* Make sure there is a string */
9348             goto fnend;
9349           if ((x = strlen(s)) < 1)
9350             goto fnend;
9351           c = NUL;                      /* Brace/bracket kind */
9352           if (argn > 1) {
9353               if (*bp[1]) {
9354                   if (chknum(bp[1])) {
9355                       k = atoi(bp[1]);
9356                       if (k < 0) k = 63;
9357                       for (i = 0; i < 6; i++) {
9358                           if (k & (1<<i)) {
9359                               if (s[0] == gr_opn[i] && s[x-1] == gr_cls[i]) {
9360                                   ckstrncpy(fnval,s+1,FNVALL);
9361                                   fnval[x-2] = NUL;
9362                                   goto fnend;
9363                               }
9364                           }
9365                       }
9366                       ckstrncpy(fnval,s,FNVALL); /* No match */
9367                       goto fnend;
9368                   }
9369               }
9370           }
9371           c = *bp[1];
9372           if (!c) c = s[0];
9373           if (argn > 2) if (*bp[2]) c2 = *bp[2];
9374           if (*s == c) {
9375               if (!c2) {
9376                   switch (c) {
9377                     case '(': c2 = ')'; break;
9378                     case '[': c2 = ']'; break;
9379                     case '{': c2 = '}'; break;
9380                     case '<': c2 = '>'; break;
9381                     case '"': c2 = '"'; break;
9382                     case 39:  c2 = 39;  break;
9383                     case 96:  c2 = 39;  break;
9384                     default:
9385                       if (argn == 2) {
9386                           c2 = c;
9387                       } else {
9388                           strncpy(fnval,s,x); /* Leave it like this */
9389                           fnval[x] = NUL;
9390                           goto fnend;
9391                       }
9392                   }
9393               }
9394               if (s[x-1] == c2) {
9395                   strncpy(fnval,s+1,x-2); /* Leave it like this */
9396                   fnval[x-2] = NUL;
9397                   goto fnend;
9398               }
9399           }
9400           strncpy(fnval,s,x);
9401           fnval[x] = NUL;
9402           goto fnend;
9403       }
9404
9405       case FN_2HEX:                     /* Number to hex */
9406       case FN_2OCT:                     /* Number to octal */
9407         val1 = evalx(bp[0]);
9408         if (!*val1) {
9409             failed = 1;
9410             evalerr(fn);
9411             goto fnend;
9412         }
9413         sprintf(fnval, cx == FN_2HEX ? "%lx" : "%lo", atol(val1)); /* SAFE */
9414         if (cx == FN_2HEX && (int)(strlen(fnval)&1))
9415           sprintf(fnval,"0%lx",atol(val1)); /* SAFE */
9416         p = fnval;
9417         goto fnend;
9418
9419       case FN_DNAM: {                   /* Directory part of file name */
9420           char *s;
9421           zfnqfp(bp[0],FNVALL,p);       /* Get full name */
9422           if (!isdir(p)) {              /* Is it already a directory? */
9423               zstrip(p,&s);             /* No get basename */
9424               if (*s) {
9425                   x = ckindex(s,p,0,0,0); /* Pos of latter in former */
9426                   if (x > 0) p[x-1] = NUL;
9427               }
9428           }
9429           if (!p) p = "";
9430           goto fnend;
9431       }
9432
9433 #ifndef NORANDOM
9434       case FN_RAND:                     /* Random number */
9435 #ifdef CK_SSL
9436         if (RAND_bytes((unsigned char *)&k,sizeof(k)) < 0)
9437 #endif /* CK_SSL */
9438           k = rand();
9439         x = 0;
9440         if (argn > 0) {
9441             if (!chknum(bp[0])) {
9442                 failed = 1;
9443                 if (fndiags)
9444                   ckmakmsg(fnval,FNVALL,
9445                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9446                 goto fnend;
9447             }
9448             x = atoi(bp[0]);
9449         }
9450 #ifdef COMMENT
9451         sprintf(fnval,"%d", (x > 0 && k > 0) || (x < 0 && k < 0) ? k % x : 
9452                 (x == 0 ? 0 : (0 - (k % (-x)))));
9453 #else
9454         debug(F111,"rand",ckitoa(x),k);
9455 #ifdef SUNOS4
9456 /* This is really strange but on SunOS, if we are requesting random numbers */
9457 /* between 0 and 4 or less, they always come out in sequence: 0 1 2 3 0 1 2 */
9458 /* Shifting the result of rand() in this case gives a more random result.   */
9459         if (x < 5)
9460           k = k >> 5;
9461 #endif /* SUNOS4 */
9462         if ((x > 0 && k > 0) || (x < 0 && k < 0))
9463           x = k % x;
9464         else if (x == 0)
9465           x = 0;
9466         else
9467           x = 0 - (k % (-x));
9468         debug(F101,"rand x","",x);
9469         sprintf(fnval,"%d", x);         /* SAFE */
9470 #endif /* COMMENT */
9471         p = fnval;
9472         goto fnend;
9473 #endif /* NORANDOM */
9474     } /* Break up big switch... */
9475
9476     switch (y) {
9477       case FN_SPLIT:                    /* \fsplit(s1,a,s2,s3,mask) */
9478       case FN_WORD: {                   /* \fword(s1,n,s2,s3,mask) */
9479           int wordnum = 0;
9480           int splitting = 0;
9481           int x;
9482           int array = 0;
9483           int grouping = 0;
9484           int nocollapse = 0;
9485           char * sep = "";
9486           char * notsep = "";
9487           char * bp0 = NULL;
9488           char * bp1 = NULL;
9489           char   abuf[16];
9490           struct stringarray * q = NULL;
9491
9492           splitting = (cx == FN_SPLIT); /* Our job */
9493
9494           fnval[0] = splitting ? '0' : NUL; /* Initial return value */
9495           fnval[1] = NUL;
9496           p = fnval;
9497           bp0 = bp[0];                  /* Source string */
9498           if (!bp0) bp0 = "";
9499           debug(F111,"fsplit bp[0]",bp0,argn);
9500           if (argn < 1 || !*bp0)        /* If none, return default value */
9501             goto fnend;
9502
9503           bp1 = bp[1];                  /* Function-dependent arg */
9504           if (!bp1) bp1 = "";           /* (array or number) */
9505           debug(F110,"fsplit bp[1]",bp1,0);
9506           if (bp[5]) {
9507               if (!chknum(bp[5])) {
9508                   failed = 1;
9509                   ckmakmsg(fnval,FNVALL,
9510                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9511                   goto fnend;
9512               }
9513               x = atoi(bp[5]);
9514               nocollapse = x;
9515           }
9516           if (!splitting) {             /* \fword(): n = desired word number */
9517               val1 = "1";               /* Default is first word */
9518               if (argn > 1)             /* Word number supplied */
9519                 if (*bp1)
9520                   val1 = evalx(bp1);
9521               if (!chknum(val1)) {
9522                   failed = 1;
9523                   ckmakmsg(fnval,FNVALL,
9524                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9525                   goto fnend;
9526               }
9527               n = atoi(val1);
9528           } else if (argn > 1 && *bp1) { /* \fsplit(): n = word count */
9529               ckstrncpy(abuf,bp1,16);   /* Get array reference */
9530               debug(F110,"fsplit abuf 1",abuf,0);
9531               failed = 1;               /* Assume it's bad */
9532               if (fndiags)              /* Default is this error message */
9533                 ckmakmsg(fnval,FNVALL,
9534                          "<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
9535               if (abuf[0] != '&')       /* "Address" of array */
9536                 goto fnend;             /* It's bad */
9537               if (abuf[2]) {            /* Check for brackets */
9538                   if (abuf[2] != '[' || abuf[3] != ']') {
9539                       goto fnend;       /* Bad */
9540                   }
9541               }
9542               debug(F110,"fsplit abuf 2",abuf,0);
9543               if (abuf[1] > 64 && abuf[1] < 91) /* Convert upper to lower */
9544                 abuf[1] += 32;
9545               if (abuf[1] < 97 || abuf[1] > 122) { /* Check for a-z */
9546                   goto fnend;
9547               }
9548               debug(F110,"fsplit abuf 3",abuf,0);
9549               array = 1;
9550               fnval[0] = NUL;           /* No error, erase message */
9551               failed = 0;               /* Unset failure flag */
9552               n = 0;                    /* Initialize word counter */
9553           }
9554           if (argn > 2)                 /* Have break set? */
9555             sep = bp[2];
9556           debug(F111,"fsplit sep",sep,argn);
9557           if (argn > 3)                 /* Have include set? */
9558             notsep = bp[3];
9559           debug(F111,"fsplit notsep",notsep,argn);
9560           if (argn > 4) {               /* Have grouping set? */
9561               char * bp4 = bp[4];
9562               debug(F111,"fsplit bp4",bp4,argn);
9563               if (!bp4) bp4 = "0";
9564               if (!*bp4) bp4 = "0";
9565               if (chknum(bp4)) {
9566                   grouping = atoi(bp4);
9567                   if (grouping == -1)
9568                     grouping = 127;
9569               } else {
9570                   failed = 1;
9571                   if (fndiags)
9572                     ckmakmsg(fnval,FNVALL,
9573                              "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9574                   goto fnend;
9575               }
9576           }
9577           /* Args parsed, now do the work */
9578
9579           debug(F111,"fsplit bp0",bp0,n);
9580           q = cksplit(splitting,n,bp0,sep,notsep,grouping,0,nocollapse);
9581
9582           wordnum = q ? q->a_size : -1; /* Check result */
9583           if (wordnum < 0) {
9584               failed = 1;               /* Failure */
9585               if (fndiags)
9586                 ckmakmsg(fnval,FNVALL,
9587                          (wordnum == -1) ?
9588                          "<ERROR:MALLOC_FAILURE:\\f" :
9589                          "<ERROR:TOO_MANY_WORDS:\\f",
9590                          fn,
9591                          "()>",
9592                          NULL
9593                          );
9594               goto fnend;
9595           }
9596           if (splitting) {              /* \fsplit() result */
9597               ckstrncpy(fnval,ckitoa(wordnum),FNVALL);
9598               if (array) {              /* Array was not declared. */
9599                   int i;
9600                   if ((x = dclarray(abuf[1],wordnum)) < 0) { /* Declare it. */
9601                       failed = 1;
9602                       if (fndiags)
9603                         ckmakmsg(fnval,FNVALL,
9604                                  "<ERROR:MALLOC_FAILURE:\\f",fn,"()>",NULL);
9605                       goto fnend;
9606                   }
9607                   for (i = 1; i <= wordnum; i++) { /* Copy results */
9608                       makestr(&(a_ptr[x][i]),q->a_head[i]);
9609                   }
9610                   a_ptr[x][0] = NULL;   /* Array is 1-based */
9611                   makestr(&(a_ptr[x][0]),fnval); /* Element = size */
9612               }
9613           } else {                      /* \fword() result */
9614               char * s;
9615               s = q->a_head[1];
9616               if (!s) s = "";
9617               ckstrncpy(fnval,s,FNVALL);
9618           }
9619           goto fnend;                   /* Done */
9620       }
9621
9622     } /* Break up big switch... */
9623
9624     switch (y) {
9625
9626 #ifdef CK_KERBEROS
9627       case FN_KRB_TK:                   /* Kerberos tickets */
9628       case FN_KRB_NX:                   /* Kerberos next ticket */
9629       case FN_KRB_IV:                   /* Kerberos ticket is valid */
9630       case FN_KRB_FG:                   /* Kerberos Ticket flags */
9631       case FN_KRB_TT: {                 /* Kerberos ticket time */
9632           int kv = 0;                   /* Kerberos version */
9633           int n = 0;
9634           char * s = NULL;
9635           if (rdigits(bp[0])) {
9636               kv = atoi(bp[0]);
9637           } else {
9638               failed = 1;
9639               if (fndiags)
9640                 ckmakmsg(fnval,FNVALL,
9641                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9642               goto fnend;
9643           }
9644           if (kv != 4 && kv != 5) {
9645               failed = 1;
9646               if (fndiags)
9647                 ckmakmsg(fnval,FNVALL,
9648                          "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
9649               goto fnend;
9650           }
9651           if ((cx == FN_KRB_IV || cx == FN_KRB_TT || cx == FN_KRB_FG) &&
9652                argn < 2) {
9653               failed = 1;
9654               if (fndiags)
9655                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
9656               goto fnend;
9657           }
9658           switch (y) {
9659             case FN_KRB_TK:             /* Number of Kerberos tickets */
9660 #ifdef CK_AUTHENTICATION
9661               switch (kv) {
9662                 case 4:
9663                   n = ck_krb4_get_tkts();
9664                   sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
9665                   goto fnend;
9666                 case 5: {
9667                     extern char * krb5_d_cc;
9668                     n = ck_krb5_get_tkts(krb5_d_cc);
9669                     sprintf(fnval, "%d", (n >= 0) ? n : 0); /* SAFE */
9670                     goto fnend;
9671                 }
9672               }
9673 #else
9674               sprintf(fnval,"%d",0);    /* SAFE */
9675 #endif /* CK_AUTHENTICATION */
9676               goto fnend;
9677
9678             case FN_KRB_NX:             /* Kerberos next ticket */
9679 #ifdef CK_AUTHENTICATION
9680               switch (kv) {
9681                 case 4:
9682                   s = ck_krb4_get_next_tkt();
9683                   ckstrncpy(fnval, s ? s : "",FNVALL);
9684                   goto fnend;
9685                 case 5:
9686                   s = ck_krb5_get_next_tkt();
9687                   ckstrncpy(fnval, s ? s : "",FNVALL);
9688                   goto fnend;
9689               }
9690 #else
9691               sprintf(fnval,"k%d next-ticket-string",kv); /* SAFE */
9692 #endif /* CK_AUTHENTICATION */
9693               goto fnend;
9694
9695             case FN_KRB_IV:             /* Kerberos ticket is valid */
9696 #ifdef CK_AUTHENTICATION
9697               /* Return 1 if valid, 0 if not */
9698               switch (kv) {
9699                 case 4:
9700                   n = ck_krb4_tkt_isvalid(bp[1]);
9701                   sprintf(fnval, "%d", n > 0 ? 1 : 0); /* SAVE */
9702                   goto fnend;
9703                 case 5: {
9704                     extern char * krb5_d_cc;
9705                     n = ck_krb5_tkt_isvalid(krb5_d_cc,bp[1]);
9706                     sprintf(fnval,"%d", n > 0 ? 1 : 0); /* SAFE */
9707                     goto fnend;
9708                 }
9709               }
9710 #else
9711               sprintf(fnval,"%d",0);    /* SAFE */
9712 #endif /* CK_AUTHENTICATION */
9713               goto fnend;
9714
9715             case FN_KRB_TT:             /* Kerberos ticket time */
9716 #ifdef CK_AUTHENTICATION
9717               switch (kv) {
9718                 case 4:
9719                   n = ck_krb4_tkt_time(bp[1]);
9720                   sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
9721                   goto fnend;
9722                 case 5: {
9723                     extern char * krb5_d_cc;
9724                     n = ck_krb5_tkt_time(krb5_d_cc,bp[1]);
9725                     sprintf(fnval,"%d", n >= 0 ? n : 0); /* SAFE */
9726                     goto fnend;
9727                 }
9728               }
9729 #else
9730               ckstrncpy(fnval,"600",FNVALL); /* Some time */
9731 #endif /* CK_AUTHENTICATION */
9732               goto fnend;
9733
9734             case FN_KRB_FG:             /* Kerberos ticket flags */
9735 #ifdef CK_AUTHENTICATION
9736               switch (kv) {
9737                 case 4:
9738                   fnval[0] = '\0';
9739                   goto fnend;
9740                 case 5: {
9741                     extern char * krb5_d_cc;
9742                     ckstrncpy(fnval,ck_krb5_tkt_flags(krb5_d_cc,bp[1]),FNVALL);
9743                     goto fnend;
9744                 }
9745               }
9746 #else
9747               fnval[0] = '\0';
9748 #endif /* CK_AUTHENTICATION */
9749               goto fnend;
9750           }
9751           p = fnval;
9752           goto fnend;
9753       }
9754 #endif /* CK_KERBEROS */
9755
9756 #ifdef FN_ERRMSG
9757       case FN_ERRMSG:
9758         if (rdigits(bp[0])) {
9759             k = atoi(bp[0]);
9760         } else {
9761             failed = 1;
9762             if (fndiags)
9763              ckmakmsg(fnval,FNVALL,"<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9764             goto fnend;
9765         }
9766 #ifdef VMS
9767         ckstrncpy(fnval,ckvmserrstr(k),FNVALL);
9768 #else
9769         x = errno;
9770         errno = k;
9771         ckstrncpy(fnval,ck_errstr(),FNVALL);
9772         errno = x;
9773 #endif /* VMS */
9774         p = fnval;
9775         goto fnend;
9776 #endif /* FN_ERRMSG */
9777
9778       case FN_DIM: {
9779           int max;
9780           char abuf[16], *s;
9781           fnval[0] = NUL;               /* Initial return value */
9782           ckstrncpy(abuf,bp[0],16);     /* Get array reference */
9783           s = abuf;
9784           if (*s == CMDQ) s++;
9785           failed = 1;                   /* Assume it's bad */
9786           p = fnval;                    /* Point to result */
9787           if (fndiags)                  /* Default is this error message */
9788             ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
9789           if (s[0] != '&') {            /* "Address" of array */
9790               goto fnend;
9791           }
9792           if (s[2]) {
9793               if (s[2] != '[' || s[3] != ']') {
9794                   goto fnend;
9795               }
9796           }
9797           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
9798             s[1] += 32;
9799           if (s[1] < 95 || s[1] > 122) { /* Check for a-z */
9800               goto fnend;                       /* Bad */
9801           }
9802           if ((max = chkarray(s[1],1)) < 1)
9803             max = 0;
9804           failed = 0;                   /* Unset failure flag */
9805           sprintf(fnval,"%d",max);      /* SAFE */
9806           goto fnend;
9807       }
9808
9809     } /* Break up big switch... */
9810
9811     switch (y) {
9812       case FN_JDATE:
9813         if (argn < 1)                   /* Check number of args */
9814           p = ckdate();                 /* None, get today's date-time */
9815         else                            /* Some */
9816           p = bp[0];                    /* Use first */
9817         p = ckcvtdate(p,0);             /* Convert to standard form */
9818         ckstrncpy(fnval,zjdate(p),FNVALL); /* Convert to Julian */
9819         p = fnval;                      /* Point to result */
9820         failed = 0;
9821         if (*p == '-') {
9822             failed = 1;
9823             if (fndiags)                /* Default is this error message */
9824               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
9825         }
9826         goto fnend;
9827
9828       case FN_DATEJ:
9829         ckstrncpy(fnval,jzdate(bp[0]),FNVALL); /* Convert to yyyy<dayofyear> */
9830         p = fnval;                      /* Point to result */
9831         failed = 0;
9832         if (*p == '-') {
9833             failed = 1;
9834             if (fndiags)                /* Default is this error message */
9835               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
9836         }
9837         goto fnend;
9838
9839       case FN_DTIM:                     /* \fcvtdate() */
9840       case FN_TIME:                     /* Free-format time to hh:mm:ss */
9841       case FN_NTIM:                     /* Time to sec since midnight */
9842         s = (argn > 0) ? bp[0] : "";
9843         if (!s) s = "";
9844         if (!*s)
9845           p = ckdate();                 /* None, get today's date */
9846         else                            /* Some */
9847           p = bp[0];                    /* Use first */
9848         p = ckcvtdate(p,2);             /* Convert to standard form */
9849         if (*p == '<') {
9850             failed = 1;
9851             if (fndiags)                /* Default is this error message */
9852               ckmakmsg(fnval,FNVALL,
9853                        "<ERROR:ARG_BAD_DATE_OR_TIME:\\f",fn,"()>",NULL);
9854             p = fnval;
9855             goto fnend;
9856         }
9857         if (argn > 1) {
9858             s = bp[1];
9859             if (!s) s = "";
9860             if (!*s) s = "0";
9861             if (!chknum(s)) {
9862                 failed = 1;
9863                 if (fndiags)
9864                   ckmakmsg(fnval,FNVALL,
9865                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9866                 p = fnval;
9867                 goto fnend;
9868             }
9869             x = atoi(s);
9870             if (x) p = shuffledate(p,x);
9871         }
9872         if (cx == FN_TIME) {
9873             p += 9;
9874         } else if (cx == FN_NTIM) {
9875             long sec = 0L;
9876             p[11] = NUL;
9877             p[14] = NUL;
9878             sec = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
9879             sprintf(fnval,"%ld",sec);   /* SAFE */
9880             p = fnval;
9881         }
9882         goto fnend;
9883
9884       case FN_MJD:                      /* Modified Julian Date */
9885         if (argn < 1)                   /* Check number of args */
9886           p = zzndate();                /* None, get today's date-time */
9887         else                            /* Some */
9888           p = bp[0];                    /* Use first */
9889         p = ckcvtdate(p,0);             /* Convert to standard form */
9890         if (*p == '-') {
9891             failed = 1;
9892             if (fndiags)                /* Default is this error message */
9893               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
9894             goto fnend;
9895         }
9896         /* Convert to modified Julian date */
9897         sprintf(fnval,"%ld",mjd(p));    /* SAFE */
9898         p = fnval;                      /* Point to result */
9899         goto fnend;
9900
9901       case FN_MJD2: {
9902           long k = 0L;
9903           int n = 0;
9904           p = evalx(bp[0]);
9905           if (*p == '-') {
9906               p++;
9907               n = 1;
9908           }
9909           if (!rdigits(p)) {
9910               failed = 1;
9911               evalerr(fn);
9912               p = fnval;
9913               goto fnend;
9914           } else {
9915               k = atol(p);
9916               if (n) k = -k;
9917           }
9918           ckstrncpy(fnval,mjd2date(k),FNVALL); /* Convert to Date */
9919           p = fnval;                    /* Point to result */
9920           failed = 0;
9921           goto fnend;
9922       }
9923
9924 #ifndef NODIAL
9925       case FN_PNCVT: {                  /* Convert phone number */
9926           extern char * pncvt();
9927           failed = 0;
9928           p = pncvt(bp[0]);
9929           if (!p) p = "";
9930           if (!*p) {
9931             failed = 1;
9932             if (fndiags)                /* Default is this error message */
9933               ckmakmsg(fnval,FNVALL,
9934                        "<ERROR:ARG_BAD_PHONENUM:\\f",fn,"()>",NULL);
9935         }
9936         goto fnend;
9937       }
9938 #endif /* NODIAL */
9939
9940       case FN_DAY:
9941       case FN_NDAY:
9942         if (argn < 1)                   /* Check number of args */
9943           p = zzndate();                /* None, get today's date-time */
9944         else                            /* Some */
9945           p = bp[0];                    /* Use first */
9946         p = ckcvtdate(p,0);             /* Convert to standard form */
9947         if (*p == '-') {
9948             failed = 1;
9949             if (fndiags)                /* Default is this error message */
9950               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_DATE:\\f",fn,"()>",NULL);
9951             goto fnend;
9952         }
9953         failed = 0;
9954         z = mjd(p);                     /* Convert to modified Julian date */
9955         z = z % 7L;
9956         if (z < 0) {
9957             z = 0 - z;
9958             k = 6 - ((int)z + 3) % 7;
9959         } else {
9960             k = ((int)z + 3) % 7;       /* Day of week */
9961         }
9962         p = fnval;                      /* Point to result */
9963         if (cx == FN_NDAY)
9964           sprintf(fnval,"%d",k);        /* SAFE */
9965         else
9966           ckstrncpy(fnval,wkdays[k],FNVALL);
9967         goto fnend;
9968
9969       case FN_N2TIM: {                  /* Sec since midnight to hh:mm:ss */
9970           long k = 0L;
9971           int n = 0, hh, mm, ss;
9972           char * s = bp[0];
9973           if (argn < 1)                 /* If no arg substitute 0 */
9974             s = "0";
9975           p = evalx(s);                 /* Evaluate expression silently */
9976           if (*p == '-') {              /* Check result for minus sign */
9977               p++;
9978               n = 1;
9979           }
9980           if (!rdigits(p)) { /* Check for numeric */
9981               failed = 1;
9982               ckmakmsg(fnval,FNVALL,
9983                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
9984               p = fnval;
9985               goto fnend;
9986           } else {
9987               k = atol(p);
9988               if (n) k = -k;
9989           }
9990           if (k < 0) {                  /* Check for negative */
9991               failed = 1;
9992               if (fndiags)
9993                 ckmakmsg(fnval,FNVALL,
9994                          "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
9995               p = fnval;
9996               goto fnend;
9997           }
9998           hh = k / 3600L;               /* Have positive number */
9999           mm = (k % 3600L) / 60L;       /* break it down... */
10000           ss = ((k % 3600L) % 60L);
10001
10002           sprintf(fnval,"%02d:%02d:%02d",hh,mm,ss); /* SAFE */
10003           p = fnval;
10004           failed = 0;
10005           goto fnend;
10006       }
10007
10008       case FN_PERM: {                   /* File permissions */
10009           p = fnval;
10010           z = zchki(bp[0]);
10011           if (z < 0) {
10012               failed = 1;
10013               if (fndiags) {
10014                   if (z == -1)
10015                     ckmakmsg(fnval,FNVALL,
10016                              "<ERROR:FILE_NOT_FOUND:\\f",fn,"()>",NULL);
10017                   else if (z == -2)
10018                     ckmakmsg(fnval,FNVALL,
10019                              "<ERROR:FILE_NOT_READABLE:\\f",fn,"()>",NULL);
10020                   else if (z == -3)
10021                     ckmakmsg(fnval,FNVALL,
10022                              "<ERROR:FILE_NOT_ACCESSIBLE:\\f",fn,"()>",NULL);
10023                   else
10024                     ckmakmsg(fnval,FNVALL,
10025                              "<ERROR:FILE_ERROR:\\f",fn,"()>",NULL);
10026               }
10027               goto fnend;
10028           }
10029 #ifdef CK_PERMS
10030           ckstrncpy(fnval,ziperm(bp[0]),FNVALL);
10031 #else
10032           ckstrncpy(fnval,"(unknown)",FNVALL);
10033 #endif /* CK_PERMS */
10034           goto fnend;
10035       }
10036       case FN_TLOOK:                    /* tablelook() */
10037       case FN_ALOOK: {                  /* arraylook() */
10038           int i, x, hi, lo, max, cmdlen;
10039           char abuf[16], *s, *pat;
10040           char kwbuf[256];
10041           char delim = ':';
10042           failed = 1;                   /* Assume failure */
10043           ckstrncpy(fnval,"-1",FNVALL);
10044           pat = bp[0];                  /* Point to search pattern */
10045           if (!pat) pat = "";           /* Watch out for NULL pointer */
10046           cmdlen = strlen(pat);         /* Get pattern length */
10047           if (argn < 2 /* || cmdlen < 1 */ ) { /* Need two args */
10048               if (fndiags)
10049                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10050               goto fnend;
10051           }
10052           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
10053           if (argn > 2)
10054             delim = *(bp[2]);
10055           s = abuf;
10056           if ((x = arraybounds(s,&lo,&hi)) < 0) { /* Get index and bounds */
10057               if (fndiags)
10058                ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10059               goto fnend;
10060           }
10061           p = fnval;                    /* Point to result */
10062           max = a_dim[x];               /* Size of array */
10063           if (lo < 0) lo = 0;           /* Use given range if any */
10064           if (lo > max) lo = max;
10065           if (hi < 0) hi = max;
10066           if (hi > max) hi = max;
10067           failed = 0;                   /* Unset failure flag */
10068           if (max < 1)
10069             goto fnend;
10070           kwbuf[255] = NUL;
10071           for (i = lo; i <= hi; i++) {
10072               if (!a_ptr[x][i])
10073                 continue;
10074               if (cx == FN_ALOOK) {
10075                   if (ckmatch(pat,a_ptr[x][i],inpcas[cmdlvl],1+4)) {
10076                       sprintf(fnval,"%d",i); /* SAFE */
10077                       goto fnend;
10078                   }
10079               } else if (cx == FN_TLOOK) {
10080                   char * aa;
10081                   int j = 0, v = 0, len;
10082                   if (i == hi)
10083                     break;
10084                   aa = a_ptr[x][i];     /* Point to this array element */
10085                   if (!aa) aa = "";
10086                   while (j < 254 && *aa) { /* Isolate keyword */
10087                       if (*aa == delim)
10088                         break;
10089                       kwbuf[j++] = *aa++;
10090                   }
10091                   kwbuf[j] = NUL;
10092                   len = j;
10093                   v = 0;
10094                   if ((len == cmdlen && !ckstrcmp(kwbuf,pat,len,0)) ||
10095                       ((v = !ckstrcmp(kwbuf,pat,cmdlen,0)) &&
10096                        ckstrcmp(a_ptr[x][i+1],pat,cmdlen,0))) {
10097                       sprintf(fnval,"%d",i); /* SAFE */
10098                       goto fnend;
10099                   }
10100                   if (v) {              /* Ambiguous */
10101                       ckstrncpy(fnval,"-2",FNVALL);
10102                       goto fnend;
10103                   }
10104               }
10105           }
10106           if (cx == FN_TLOOK) {         /* tablelook() last element */
10107               ckstrncpy(fnval,"-1",FNVALL);
10108               if (!ckstrcmp(a_ptr[x][hi],pat,cmdlen,0))
10109                 sprintf(fnval,"%d",hi); /* SAFE */
10110           }
10111           goto fnend;
10112       }
10113       case FN_TOB64:                    /* Base-64 conversion */
10114       case FN_FMB64:
10115         p = fnval;
10116         *p = NUL;
10117         if (argn < 1)
10118           goto fnend;
10119         if (cx == FN_TOB64) {
10120             x = b8tob64(bp[0],-1,fnval,FNVALL);
10121         } else {
10122             x = strlen(bp[0]);
10123             if (x % 4) {                /* length must be multiple of 4 */
10124                 failed = 1;
10125                 ckmakmsg(fnval,FNVALL,
10126                          "<ERROR:ARG_INCOMPLETE:\\f",fn,"()>",NULL);
10127                 goto fnend;
10128             }
10129             b64tob8(NULL,0,NULL,0);     /* Reset */
10130             x = b64tob8(bp[0],-1,fnval,FNVALL);
10131             b64tob8(NULL,0,NULL,0);     /* Reset again */
10132         }
10133         if (x < 0) {
10134             failed = 1;
10135             if (fndiags) {
10136                 char * m = "INTERNAL_ERROR";
10137                 switch (x) {
10138                   case -1: m = "ARG_TOO_LONG"; break;
10139                   case -2: m = "ARG_OUT_OF_RANGE"; break;
10140                 }
10141                 if (ckmakmsg(fnval,FNVALL,"<ERROR:",m,"\\f",fn) > 0)
10142                   ckstrncat(fnval,"()>",FNVALL);
10143             }
10144         }
10145         goto fnend;
10146
10147       case FN_ABS: {
10148           char * s;
10149           s = bp[0];
10150           if (*s == '-' || *s == '+')
10151             s++;
10152           if (!rdigits(s)) {
10153               if (fndiags)
10154                 ckmakmsg(fnval,FNVALL,
10155                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10156               goto fnend;
10157           }
10158           ckstrncpy(fnval,s,FNVALL);
10159           goto fnend;
10160       }
10161
10162       case FN_AADUMP: {
10163           char abuf[16], *s = NULL, **ap = NULL, **vp = NULL;
10164           char pattern[VNAML];
10165           int slen, i, j, k, first = -1;
10166           extern int xdelmac();
10167           p = fnval;
10168           if (argn < 2) {
10169               if (fndiags)
10170                 ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG2:\\f",fn,"()>",NULL);
10171               goto fnend;
10172           }
10173           debug(F101,"aaconvert argn","",argn);
10174           s = bp[0];
10175           slen = strlen(s);
10176
10177           /* Count elements so we can create the array */
10178
10179           ckmakmsg(pattern,VNAML,s,"<*>",NULL,NULL);
10180           for (k = 0, i = 0; i < nmac; i++) {
10181               if (ckmatch(pattern,mactab[i].kwd,0,1)) {
10182                   if (first < 0)        /* Remember location of first match */
10183                     first = i;
10184                   k++;
10185               }
10186           }
10187           debug(F101,"aaconvert matches","",k);
10188           debug(F101,"aaconvert first","",first);
10189           fnval[0] = NUL;               /* Initial return value */
10190           ckstrncpy(abuf,bp[1],16);     /* Get array reference */
10191           s = abuf;
10192           if (*s == CMDQ) s++;
10193           p = fnval;                    /* Point to result */
10194           if (fndiags)                  /* Default is this error message */
10195             ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10196           if (s[0] != '&')              /* Address of array */
10197             goto fnend;
10198           if (s[2])
10199             if (s[2] != '[' || s[3] != ']')
10200               goto fnend;
10201           if (s[1] >= 64 && s[1] < 91)  /* Convert upper to lower */
10202             s[1] += 32;
10203           if ((x = dclarray(s[1],k)) < 0) /* Declare array to size */
10204             goto fnend;
10205           ap = a_ptr[x];                /* Point to array we just declared */
10206           debug(F111,"aaconvert array 1",abuf,ap);
10207           abuf[0] = NUL;
10208           if (argn > 2) {
10209               ckstrncpy(abuf,bp[2],16); /* Get value array reference */
10210               s = abuf;
10211               if (*s == CMDQ) s++;
10212               if (s[0] != '&')          /* Address of array */
10213                 goto fnend;
10214               if (s[2])
10215                 if (s[2] != '[' || s[3] != ']')
10216                   goto fnend;
10217               if (s[1] >= 64 && s[1] < 91) /* Convert upper to lower */
10218                 s[1] += 32;
10219               if ((x = dclarray(s[1],k)) < 0)
10220                 goto fnend;
10221               vp = a_ptr[x];            /* Point to array we just declared */
10222           }
10223           debug(F111,"aaconvert array 2",abuf,vp);
10224           makestr(&ap[0],ckitoa(k));
10225           if (vp) makestr(&vp[0],ckitoa(k));
10226           if (fndiags)
10227            ckmakmsg(fnval,FNVALL,"<ERROR:ASSOCIATIVE_ARRAY:\\f",fn,"()>",NULL);
10228
10229           /* Copy macro index & value to the arrays and then remove the */
10230           /* macro, so the 'first' pointer keeps indicating the next one. */
10231           /* We could combine the initial counting loop with this one but */
10232           /* then it would be harder to create the array and anyway this */
10233           /* function is plenty fast as it is. */
10234
10235           for (i = 1; i <= k; ) {
10236               if (!ckmatch(pattern,mactab[first].kwd,0,1)) {
10237                   debug(F111,"aaconvert oddball",mactab[first].kwd,first);
10238                   first++;
10239                   continue;
10240               }
10241               ckstrncpy(tmpbuf,mactab[first].kwd,TMPBUFSIZ); /* Macro name */
10242               s = tmpbuf;                       /* Make writeable copy */
10243               s += slen;                        /* Isolate "index" */
10244               j = strlen(s) - 1;
10245               if (*s != '<' || *(s+j) != '>') { /* Check syntax */
10246                   /* This shouldn't happen */
10247                   debug(F111,"aaconvert ERROR",mactab[first].kwd,first);
10248                   goto fnend;
10249               }
10250               *(s+j) = NUL;             /* Remove final '>' */
10251               debug(F111,"aaconvert",s+1,i);
10252               makestr(&(ap[i]),s+1);    /* Set first array to index */
10253               if (vp)
10254                 makestr(&(vp[i]),mactab[first].mval); /* 2nd to value */
10255               if (xdelmac(first) < 0)
10256                 goto fnend;
10257               i++;
10258           }
10259           sprintf(fnval,"%d",k);        /* SAFE */
10260           p = fnval;                    /* Return size of array */
10261           debug(F110,"aaconvert return",p,0);
10262           failed = 0;                   /* Unset failure flag */
10263           goto fnend;
10264       }
10265
10266     } /* End of switch() */
10267
10268 #ifdef FNFLOAT
10269 /*
10270   Floating-point functions.  To be included only if FNFLOAT is defined, which
10271   should happen only if CKFLOAT is also defined, and if the math library is
10272   linked in.  Even then, we might have float-vs-double confusion as well as
10273   confusion about what the final "%f" format effector is supposed to reference
10274   (32 bits, 64 bits, etc).  Expect trouble if CKFLOAT does not match the data
10275   type of math library functions or args.
10276 */
10277     if (cx == FN_FPABS ||               /* Floating-point functions */
10278         cx == FN_FPADD ||
10279         cx == FN_FPDIV ||
10280         cx == FN_FPEXP ||
10281         cx == FN_FPLOG ||
10282         cx == FN_FPLN  ||
10283         cx == FN_FPMOD ||
10284         cx == FN_FPMAX ||
10285         cx == FN_FPMIN ||
10286         cx == FN_FPMUL ||
10287         cx == FN_FPPOW ||
10288         cx == FN_FPSQR ||
10289         cx == FN_FPINT ||
10290         cx == FN_FPSUB ||
10291         cx == FN_FPROU ||
10292         cx == FN_FPSIN ||
10293         cx == FN_FPCOS ||
10294         cx == FN_FPTAN) {
10295         CKFLOAT farg[2], fpresult = 0.0;
10296         char fpbuf[64], * bp0;
10297         double dummy;
10298         /* int sign = 0; */
10299         int i, j, places = 0;
10300         int argcount = 1;
10301
10302         failed = 1;
10303         p = fnval;
10304         bp0 = bp[0];
10305         if (!bp0)
10306           bp0 = "0";
10307         else if (!*bp0)
10308           bp0 = "0";
10309         if (!isfloat(bp0,0)) {
10310             k = mxlook(mactab,bp0,nmac);
10311             bp0 = (k > -1) ? mactab[k].mval : NULL;
10312             if (bp0) {
10313                 if (!isfloat(bp0,0)) {
10314                     if (fndiags)
10315                       ckmakmsg(fnval,FNVALL,
10316                                "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
10317                     goto fnend;
10318                 }
10319             }
10320         }
10321         if (cx == FN_FPINT) {           /* Float to int */
10322             failed = 0;
10323             ckstrncpy(fnval,bp0,FNVALL);
10324             for (i = 0; fnval[i]; i++) {
10325                 if (fnval[i] == '.') {
10326                     fnval[i] = NUL;
10327                     break;
10328                 }
10329             }
10330             goto fnend;
10331         }
10332         switch (y) {                    /* These need 2 args */
10333           case FN_FPADD:
10334           case FN_FPDIV:
10335           case FN_FPMOD:
10336           case FN_FPMAX:
10337           case FN_FPMIN:
10338           case FN_FPMUL:
10339           case FN_FPPOW:
10340           case FN_FPSUB:
10341             argcount = 2;
10342         }
10343         /* Missing arguments are supplied as 0.0 */
10344
10345         debug(F111,fn,"argcount",argcount);
10346         for (i = 0; i < argcount; i++) { /* Get floating-point args */
10347 #ifdef DEBUG
10348             if (deblog) {
10349                 ckmakmsg(fpbuf,
10350                          64,
10351                          "bp[",
10352                          ckitoa(i),
10353                          bp[i] ? bp[i] : "(null)",
10354                          "]"
10355                          );
10356                 debug(F100,fpbuf,"",0);
10357             }
10358 #endif /* DEBUG */
10359             if (!bp[i]) {
10360                 farg[i] = 0.0;
10361             } else if (!*(bp[i])) {
10362                 farg[i] = 0.0;
10363             } else if (!isfloat(bp[i],0)) {
10364                 char * tmp;
10365                 k = mxlook(mactab,bp[i],nmac);
10366                 tmp = (k > -1) ? mactab[k].mval : NULL;
10367                 if (tmp) {
10368                     if (!isfloat(tmp,0)) {
10369                         if (fndiags)
10370                           ckmakmsg(fnval,FNVALL,
10371                                    "<ERROR:ARG_NOT_FLOAT:\\f",fn,"()>",NULL);
10372                         goto fnend;
10373                     }
10374                 }
10375             }
10376             farg[i] = floatval;
10377
10378 #ifdef DEBUG
10379             if (deblog) {
10380                 sprintf(fpbuf,"farg[%d]=%f",i,farg[i]); /* SAFE */
10381                 debug(F100,fpbuf,"",0);
10382             }
10383 #endif /* DEBUG */
10384         }
10385         if (bp[argcount]) {             /* Get decimal places */
10386             char * s;
10387             s = bp[argcount];
10388             if (!s) s = "";
10389             if (!*s) s = "0";
10390             s = evalx(s);
10391             if (!s) s = "";
10392             if (!*s) {
10393                 evalerr(fn);
10394                 goto fnend;
10395             }
10396             places = atoi(s);
10397         }
10398         errno = 0;
10399         failed = 0;
10400         switch (y) {                    /* Now do the requested function */
10401           case FN_FPABS:                /* Floating-point absolute value */
10402 #ifndef COMMENT
10403             fpresult = fabs(farg[0]);
10404 #else
10405             if (farg[0] < 0.0)
10406               fpresult = 0.0 - farg[0];
10407 #endif /* COMMENT */
10408             break;
10409           case FN_FPADD:                /* FP add */
10410             fpresult = farg[0] + farg[1];
10411             break;
10412           case FN_FPDIV:                /* FP divide */
10413           case FN_FPMOD:                /* FP modulus */
10414             if (!farg[1]) {
10415                 failed = 1;
10416                 if (fndiags)
10417                   ckmakmsg(fnval,FNVALL,
10418                            "<ERROR:DIVIDE_BY_ZERO:\\f",fn,"()>",NULL);
10419             } else
10420               fpresult = (cx == FN_FPDIV) ?
10421                 (farg[0] / farg[1]) :
10422                   fmod(farg[0],farg[1]);
10423             break;
10424           case FN_FPEXP:                /* FP e to the x */
10425             fpresult = (CKFLOAT) exp(farg[0]);
10426             break;
10427           case FN_FPLOG:                /* FP base-10 logarithm */
10428           case FN_FPLN:                 /* FP natural logarithm */
10429             if (farg[0] < 0.0) {
10430                 failed = 1;
10431                 if (fndiags)
10432                   ckmakmsg(fnval,FNVALL,
10433                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10434             } else
10435               fpresult = (cx == FN_FPLOG) ? log10(farg[0]) : log(farg[0]);
10436             break;
10437           case FN_FPMUL:                /* FP multiply */
10438             fpresult = farg[0] * farg[1];
10439             break;
10440           case FN_FPPOW:                /* FP raise to a power */
10441             fpresult = modf(farg[1],&dummy);
10442             if ((!farg[0] && farg[1] <= 0.0) ||
10443                 (farg[0] < 0.0 && fpresult)) {
10444                 failed = 1;
10445                 if (fndiags)
10446                   ckmakmsg(fnval,FNVALL,
10447                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10448             } else
10449               fpresult = pow(farg[0],farg[1]);
10450             break;
10451           case FN_FPSQR:                /* FP square root */
10452             if (farg[0] < 0.0) {
10453                 failed = 1;
10454                 if (fndiags)
10455                   ckmakmsg(fnval,FNVALL,
10456                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10457             } else
10458               fpresult = sqrt(farg[0]);
10459             break;
10460           case FN_FPSUB:                /* FP subtract */
10461             fpresult = farg[0] - farg[1];
10462             break;
10463           case FN_FPROU:                /* FP round */
10464             fpresult = farg[0];
10465             break;
10466           case FN_FPSIN:                /* FP sine */
10467             fpresult = (CKFLOAT) sin(farg[0]);
10468             break;
10469           case FN_FPCOS:                /* FP cosine */
10470             fpresult = (CKFLOAT) cos(farg[0]);
10471             break;
10472           case FN_FPTAN:                /* FP tangent */
10473             fpresult = (CKFLOAT) tan(farg[0]);
10474             break;
10475           case FN_FPMAX:
10476             fpresult = (farg[0] > farg[1]) ? farg[0] : farg[1];
10477             break;
10478           case FN_FPMIN:
10479             fpresult = (farg[0] < farg[1]) ? farg[0] : farg[1];
10480             break;
10481         }
10482
10483         /* Get here with fpresult = function result */
10484
10485         if (errno) {                    /* If range or domain error */
10486             failed = 1;
10487             if (fndiags)
10488               ckmakmsg(fnval,FNVALL,
10489                        "<ERROR:FLOATING-POINT-OP:\\f",fn,"()>",NULL);
10490         }
10491         if (failed)                     /* and/or any other kind of error, */
10492           goto fnend;                   /* fail. */
10493 #ifndef COMMENT
10494         /* Call routine containing code that was formerly inline */
10495         ckstrncpy(fnval,fpformat(fpresult,places,cx == FN_FPROU),FNVALL);
10496 #else
10497         {
10498             char fbuf[16];              /* For creating printf format */
10499             if (!fp_rounding &&         /* If printf doesn't round, */
10500                 (places > 0 ||          /* round result to decimal places. */
10501                  (places == 0 && cx == FN_FPROU)))
10502               fpresult += (0.5 / pow(10.0,(CKFLOAT)places));
10503             if (places > 0) {                   /* If places specified */
10504                 /* use specified places to write given number of digits */
10505                 sprintf(fbuf,"%%0.%df",places); /* SAFE */
10506                 sprintf(fnval,fbuf,fpresult);   /* SAFE */
10507             } else {                            /* Otherwise... */
10508 #ifdef COMMENT
10509 /*
10510   Here we want to print exactly fp_digits significant digits, no matter which
10511   side of the decimal point they are on.  That is, we want want the default
10512   format to show the maximum number of non-garbage digits, AND we want the last
10513   such digit to be rounded.  Of course there is no way to do that, since the
10514   digit after the last non-garbage digit is, well, garbage.  So the following
10515   clever ruse does no good.
10516 */
10517                 int sign = 0, m = 0;
10518                 sprintf(fnval,"%f",fpresult);
10519                 if (fnval[0] == '-') sign = 1;
10520                 for (i = sign; i < FNVALL; i++) {
10521                     if (isdigit(fnval[i]))
10522                       m++;
10523                     else
10524                       break;
10525                 }
10526                 if (m > 1) {
10527                     int d = fp_digits - m;
10528                     if (d < 1) d = 1;
10529                     sprintf(fbuf,"%%%d.%df",fp_digits+sign+1,d);
10530                 } else {
10531                     sprintf(fbuf,"%%0.%df",fp_digits);
10532                 }
10533                 sprintf(fnval,fbuf,fpresult);
10534 #else
10535                 /* Go for max precision */
10536                 sprintf(fbuf,"%%0.%df",fp_digits); /* SAFE */
10537                 sprintf(fnval,fbuf,fpresult); /* SAFE */
10538
10539 #endif /* COMMENT */
10540             }
10541             if (fnval[0] == '-') sign = 1;
10542         }
10543         debug(F111,"fpresult 1",fnval,errno); /* Check for over/underflow */
10544         for (i = sign; fnval[i]; i++) { /* Give requested decimal places */
10545             if (fnval[i] == '.')        /* First find the decimal point */
10546               break;
10547             else if (i > fp_digits + sign - 1) /* replacing garbage */
10548               fnval[i] = '0';           /* digits with 0... */
10549         }
10550         if (fnval[i] == '.') {          /* Have decimal point */
10551             int gotend = 0;
10552             /* d < 0 so truncate fraction */
10553             if (places < 0 || (places == 0 && cx == FN_FPROU)) {
10554                 fnval[i] = NUL;
10555             } else if (places > 0) {    /* d > 0 so this many decimal places */
10556                 i++;                           /* First digit after decimal */
10557                 for (j = 0; j < places; j++) { /* Truncate after d decimal */
10558                     if (!fnval[j+i])           /* places or extend to d  */
10559                       gotend = 1;              /* decimal places. */
10560                     if (gotend || j+i+sign > fp_digits)
10561                       fnval[j+i] = '0';
10562                 }
10563                 fnval[j+i] = NUL;
10564             } else {                    /* d == 0 so Do The Right Thing */
10565                 for (j = (int)strlen(fnval) - 1; j > i+1; j--) {
10566                     if ((j - sign) > fp_digits)
10567                       fnval[j] = '0';
10568                     if (fnval[j] == '0')
10569                       fnval[j] = NUL;   /* Strip useless trailing 0's. */
10570                     else
10571                       break;
10572                 }
10573             }
10574         }
10575 #endif /* COMMENT */
10576         debug(F111,"fpresult 2",fnval,errno);
10577         goto fnend;
10578
10579     }
10580 #endif /* FNFLOAT */
10581
10582 #ifdef CKCHANNELIO
10583     if (cx == FN_FSTAT  ||              /* File functions */
10584         cx == FN_FPOS   ||
10585         cx == FN_FEOF   ||
10586         cx == FN_FGCHAR ||
10587         cx == FN_FGLINE ||
10588         cx == FN_FGBLK  ||
10589         cx == FN_FPCHAR ||
10590         cx == FN_FPLINE ||
10591         cx == FN_FPBLK  ||
10592         cx == FN_NLINE  ||
10593         cx == FN_FERMSG ||
10594         cx == FN_FILNO) {
10595         int x = 0, t = 0, channel;
10596         long z;
10597         extern int z_maxchan;
10598
10599         failed = 1;                     /* Assume failure */
10600         p = fnval;                      /* until we validate args */
10601         if (cx == FN_FERMSG) {
10602             extern int z_error;
10603             if (argn < 1) {
10604                 x = z_error;
10605             } else if (chknum(bp[0])) {
10606                 x = atoi(bp[0]);
10607             } else if (fndiags)
10608               ckmakmsg(fnval,FNVALL,
10609                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10610             failed = 0;
10611             ckstrncpy(fnval,ckferror(x),FNVALL);
10612             goto fnend;
10613         }
10614         if (argn < 1) {                 /* All file functions need channel */
10615             if (fndiags)
10616               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10617             goto fnend;
10618         }
10619         if (rdigits(bp[0])) {           /* Channel must be numeric */
10620             channel = atoi(bp[0]);
10621         } else {                        /* Fail if it isn't */
10622             if (fndiags)
10623               ckmakmsg(fnval,FNVALL,
10624                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10625             goto fnend;
10626         }
10627         if (channel < 0 || channel > z_maxchan) { /* Check channel range */
10628             if (fndiags)
10629               ckmakmsg(fnval,FNVALL,
10630                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10631             goto fnend;
10632         }
10633         x = z_getmode(channel);         /* Find out about the channel */
10634
10635         failed = 0;                     /* Assume success from here down */
10636         if (cx == FN_FSTAT) {           /* Status / modes of channel */
10637             if (x > -1)
10638               x &= FM_RWB;              /* Mask out irrelevant bits */
10639             else                        /* In this case not open is OK */
10640               x = 0;                    /* 0 if not open, 1-7 if open */
10641             sprintf(fnval,"%d",x);      /* SAFE */
10642             goto fnend;
10643         } else if (x < 1) {             /* Not \f_status() so must be open */
10644             failed = 1;
10645             if (fndiags)
10646               ckmakmsg(fnval,FNVALL,"<ERROR:FILE_NOT_OPEN:\\f",fn,"()>",NULL);
10647             goto fnend;
10648         }
10649         switch (y) {                    /* Do the requested function */
10650           case FN_FPOS:                 /* Get position */
10651             z = z_getpos(channel);
10652             sprintf(fnval,"%ld",z);     /* SAFE */
10653             goto fnend;
10654
10655           case FN_NLINE:                /* Get line number */
10656             z = z_getline(channel);
10657             sprintf(fnval,"%ld",z);     /* SAFE */
10658             goto fnend;
10659
10660           case FN_FEOF:                 /* Check EOF */
10661             t = 0;
10662             if (x & FM_EOF) t = 1;
10663             sprintf(fnval,"%d",t);      /* SAFE */
10664             goto fnend;
10665
10666           case FN_FILNO:                /* Get file handle */
10667             x = z_getfnum(channel);
10668             sprintf(fnval,"%d",x);      /* SAFE */
10669             goto fnend;
10670
10671           case FN_FPBLK:                /* Read or write block */
10672           case FN_FGBLK:
10673             if (argn < 2) {
10674                 if (fndiags)
10675                   ckmakmsg(fnval,FNVALL,
10676                            "<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10677                 goto fnend;
10678             }
10679             if (rdigits(bp[1])) {
10680                 t = atoi(bp[1]);
10681             } else {
10682                 if (fndiags)
10683                   ckmakmsg(fnval,FNVALL,
10684                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10685                 goto fnend;
10686             }
10687           case FN_FGCHAR:               /* Read or write character or line */
10688           case FN_FPCHAR:
10689           case FN_FGLINE:
10690           case FN_FPLINE:
10691             fnval[0] = NUL;
10692             switch (y) {
10693               case FN_FGCHAR: t = z_in(channel,fnval,FNVALL,1,1); break;
10694               case FN_FGLINE: t = z_in(channel,fnval,FNVALL,FNVALL-1,0); break;
10695               case FN_FGBLK:
10696                 if (t >= FNVALL) t = FNVALL - 1;
10697                 t = z_in(channel,fnval,FNVALL,t,1);
10698                 break;
10699               case FN_FPCHAR: t = z_out(channel,bp[1],1,1);  break;
10700               case FN_FPLINE: t = z_out(channel,bp[1],-1,0); break;
10701               case FN_FPBLK:  t = z_out(channel,bp[1],-1,1); break;
10702             }
10703             if (t < 0) {                /* Handle read/write error */
10704                 failed = 1;
10705                 if (fndiags && t != FX_EOF)
10706                   ckmakmsg(fnval,FNVALL,
10707                            "<ERROR:FILE_ERROR_%d:\\f",fn,"()>",NULL);
10708                 goto fnend;
10709             }
10710             if (cx == FN_FGCHAR)        /* Null terminate char */
10711               fnval[1] = NUL;
10712             /* Write (put) functions return numeric status code */
10713             if (cx == FN_FPCHAR || cx == FN_FPLINE || cx == FN_FPBLK)
10714               sprintf(fnval,"%d",t);    /* SAFE */
10715             goto fnend;
10716         }
10717     }
10718 #endif /* CKCHANNELIO */
10719
10720     if (cx == FN_PATTERN) {             /* \fpattern() */
10721         ispattern = 1;
10722         if (argn > 0) {
10723             p = fnval;
10724             ckstrncpy(fnval,bp[0],FNVALL);
10725         } else p = "";
10726         goto fnend;
10727     }
10728
10729     if (cx == FN_HEX2N || cx == FN_OCT2N) { /* \fhex2n(), \foct2n() */
10730         p = "0";
10731         if (argn < 1)
10732           goto fnend;
10733         p = ckradix(bp[0], ((cx == FN_HEX2N) ? 16 : 8), 10);
10734         if (!p) {
10735             if (fndiags)
10736               ckmakmsg(fnval,FNVALL,
10737                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10738             goto fnend;
10739         }
10740         failed = 0;
10741         ckstrncpy(fnval,p,FNVALL);
10742         p = fnval;
10743         goto fnend;
10744     }
10745
10746     if (cx == FN_HEX2IP) {
10747         int c[2], ip[4], i, k;
10748         p = "0";
10749         if (argn < 1)
10750           goto fnend;
10751         s = bp[0];
10752         if ((int)strlen(s) != 8) {
10753             failed = 1;
10754             if (fndiags)
10755               ckmakmsg(fnval,FNVALL,
10756                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10757             goto fnend;
10758         }
10759         p = fnval;
10760         for (k = 0; k < 8; k += 2) {
10761             for (i = 0; i < 2; i++) {
10762                 c[i] = *s++;
10763                 if (islower(c[i])) c[i] = toupper(c[i]);
10764                 if (c[i] >= '0' && c[i] <= '9') {
10765                     c[i] -= 0x30;
10766                 } else if (c[i] >= 'A' && c[i] <= 'F') {
10767                     c[i] -= 0x37;
10768                 } else {
10769                     failed = 1;
10770                     if (fndiags)
10771                       ckmakmsg(fnval,FNVALL,
10772                                "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10773                     goto fnend;
10774                 }
10775                 ip[k/2] = c[0] << 4 | c[1];
10776             }
10777             sprintf(p,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
10778         }
10779         goto fnend;
10780     }
10781     if (cx == FN_IP2HEX) {
10782         int ip[4], i;
10783         char * q;
10784         p = "00000000";
10785         if (argn < 1)
10786           goto fnend;
10787         s = bp[0];
10788         p = fnval;
10789         for (i = 0; i < 3; i++) {
10790             q = ckstrchr(s,'.');
10791             if (q) {
10792                 *q++ = NUL;
10793                 ip[i] = atoi(s);
10794                 s = q;
10795             } else {
10796                 failed = 1;
10797                 if (fndiags)
10798                   ckmakmsg(fnval,FNVALL,
10799                            "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10800                 goto fnend;
10801             }
10802         }
10803         ip[3] = atoi(s);
10804         sprintf(p,"%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); /* SAFE */
10805         goto fnend;
10806     }
10807     if (cx == FN_RADIX) {
10808         failed = 1;
10809         p = fnval;
10810         if (argn < 3) {
10811             if (fndiags)
10812               ckmakmsg(fnval,FNVALL,"<ERROR:MISSING_ARG:\\f",fn,"()>",NULL);
10813             goto fnend;
10814         }
10815         if (!rdigits(bp[1]) || !rdigits(bp[2])) {
10816             if (fndiags)
10817               ckmakmsg(fnval,FNVALL,
10818                        "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10819             goto fnend;
10820         }
10821         p = ckradix(bp[0],atoi(bp[1]),atoi(bp[2]));
10822         if (!p) {
10823             if (fndiags)
10824               ckmakmsg(fnval,FNVALL,
10825                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
10826             goto fnend;
10827         }
10828         failed = 0;
10829         ckstrncpy(fnval,p,FNVALL);
10830         p = fnval;
10831         goto fnend;
10832     }
10833     if (cx == FN_JOIN) {
10834         int i, x, y, z, flag, hi, lo, max, seplen, grouping = 0;
10835         char abuf[16], c, *s, *q, *sep = NULL;
10836         char * gr_opn = "\"{'([<";      /* Group open brackets */
10837         char * gr_cls = "\"}')]>";      /* Group close brackets */
10838         char lb[2], rb[2];              /* Selected left and right brackets */
10839
10840         failed = 1;                     /* Assume failure */
10841         fnval[0] = NUL;
10842         debug(F101,"FNJOIN ARGN","",argn);
10843
10844         ckstrncpy(abuf,bp[0],16);       /* Get array reference */
10845         s = abuf;
10846         if ((x = arraybounds(s,&lo,&hi)) < 0) {  /* Get index and bounds */
10847             if (fndiags)
10848               ckmakmsg(fnval,FNVALL,"<ERROR:ARG_BAD_ARRAY:\\f",fn,"()>",NULL);
10849             goto fnend;
10850         }
10851         p = fnval;                      /* Point to result */
10852         max = a_dim[x];                 /* Size of array */
10853         if (lo < 0) lo = 1;             /* Use given range if any */
10854         if (lo > max) lo = max;
10855 #ifdef COMMENT
10856         hi = max;
10857 #else
10858 /*
10859   This is a workaround for the problem in which the dimension of the \&_[]
10860   array (but not its contents) grows upon entry to a SWITCH block.  But this
10861   code prevents the dimension from growing.  Go figure.
10862 */
10863         if (hi < 0) {                   /* Bounds not given */
10864             if (x)                      /* Regular array */
10865               hi = max;
10866             else                        /* Argument vector array */
10867               for (hi = max; hi >= lo; hi--) { /* ignore any trailing */
10868                   if (!a_ptr[x][hi]) continue; /* empty elements */
10869                   if (!*(a_ptr[x][hi])) continue;
10870                   break;
10871               }
10872         }
10873 #endif /* COMMENT */
10874         if (hi > max) hi = max;
10875         failed = 0;                     /* Unset failure flag */
10876         if (max < 1)
10877           goto fnend;
10878         sep = " ";                      /* Separator */
10879         if (argn > 1)
10880           if (bp[1])
10881             if (*bp[1])
10882               sep = bp[1];
10883         lb[0] = NUL;
10884         rb[0] = NUL;
10885         lb[1] = NUL;
10886         rb[1] = NUL;
10887         if (argn > 2) {                 /* Grouping? */
10888             char * bp2 = bp[2];
10889             if (!bp2) bp2 = "0";
10890             if (!*bp2) bp2 = "0";
10891             if (chknum(bp2)) {
10892                 grouping = atoi(bp2);
10893                 if (grouping < 0 || grouping > 63)
10894                   grouping = 1;
10895             } else {
10896                 failed = 1;
10897                 if (fndiags)
10898                   ckmakmsg(fnval,FNVALL,
10899                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
10900                 goto fnend;
10901             }
10902             if (grouping) {             /* Take lowest-order one */
10903                 int j, k;               /* and set the others to 0 */
10904                 for (k = 0; k < 6; k++) {
10905                     j = 1 << k;
10906                     if (grouping & j) {
10907                         lb[0] = gr_opn[k];
10908                         rb[0] = gr_cls[k];
10909                         break;
10910                     }
10911                 }
10912             }
10913         }
10914         if (argn > 3)                   /* Nonzero 4th arg for no separator */
10915           if (chknum(bp[3]))
10916             if (atoi(bp[3]) > 0)
10917               sep = NULL;
10918         if (!sep) {
10919             sep = "";
10920             seplen = 0;
10921         } else
10922           seplen = strlen(sep);
10923         for (i = lo; i <= hi; i++) {    /* Loop thru selected array elements */
10924             s = a_ptr[x][i];            /* Get next element */
10925             if (!s)
10926               s = "";
10927             flag = 0;                   /* Buffer overrun flag */
10928             if (grouping) {             /* Does this element need quoting? */
10929                 q = s;                  /* Look for spaces */
10930                 while ((c = *q++)) { if (c == SP) { flag++; break; } }
10931             }
10932             y = strlen(s);              /* Get length of this element */
10933             if (cx == 0 && grouping)    /* If empty it might need quoting */
10934               flag = 1;
10935             if (flag) {                 /* Add grouping if needed */
10936                 char * s2 = NULL;
10937                 y += 2;
10938                 if ((q = (char *)malloc(y+1))) {
10939                     ckmakmsg(q,y+1,(char *)lb,s,(char *)rb,NULL);
10940                     makestr(&s2,q);
10941                     free(q);
10942                     s = s2;
10943                 }
10944             }
10945             z = 0;                      /* Number of chars copied */
10946             flag = 0;                   /* flag is now buffer-overrun flag */
10947             if (y > 0)                  /* If this string is not empty */
10948               z = ckstrncat(fnval,s,FNVALL); /* copy it. */
10949             if (z < y)                  /* Check for buffer overrun. */
10950               flag++;
10951             if (!flag && *sep && i < hi) { /* If buffer still has room */
10952                 z = ckstrncat(fnval,sep,FNVALL); /* copy delimiter */
10953                 if (z < seplen)
10954                   flag++;
10955             }
10956             if (flag) {
10957                 failed = 1;
10958                 if (fndiags)
10959                   ckmakmsg(fnval,FNVALL,
10960                            "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
10961                 goto fnend;
10962             }
10963         }
10964         isjoin = 1;
10965         goto fnend;
10966     }
10967     if (cx == FN_SUBST) {               /* \fsubstitute() */
10968         CHAR c, * s, * r, * tp[2], buf1[256], buf2[256], buf3[256];
10969         int len, i, j, state = 0, lo = 0, hi = 0;
10970
10971         failed = 0;
10972         p = fnval;                      /* Result pointer */
10973         *p = NUL;
10974         if (!bp[0])                     /* No target, no result*/
10975           goto fnend;
10976
10977         len = strlen(bp[0]);            /* Length of source */
10978         if (len == 0)
10979           goto fnend;
10980         if (len > FNVALL) {
10981             failed = 1;
10982             if (fndiags)
10983               ckmakmsg(fnval,FNVALL,
10984                        "<ERROR:RESULT_TOO_LONG:\\f",fn,"()>",NULL);
10985             goto fnend;
10986         }
10987         if (!bp[1]) {
10988             ckstrncpy(bp[0],fnval,FNVALL);
10989             goto fnend;
10990         }
10991         tp[0] = buf1;                   /* For s2-s3 interpretation loop */
10992         tp[1] = buf2;
10993
10994         for (i = 0; i < 256; i++) {     /* Initialize working buffers */
10995             buf1[i] = 0;                /* s2 expansion buffer */
10996             buf2[i] = 0;                /* s3 expansion buffer */
10997             buf3[i] = i;                /* Translation table */
10998         }
10999         for (i = 0; i < 2; i++) {       /* Interpret s2 and s3 */
11000             s = (CHAR *)bp[i+1];        /* Arg pointer */
11001             if (!s) s = (CHAR *)"";
11002             r = tp[i];                  /* To construct interpreted arg */
11003             j = 0;                      /* Output buf pointer */
11004             state = 0;                  /* Initial state */
11005             while (c = *s++) {          /* Loop thru arg chars */
11006                 if (j > 255)            /* Output buf full */
11007                   break;
11008                 switch (state) {
11009                   case 0:               /* Normal state */
11010                     switch (c) {
11011                       case '\\':        /* Have quote */
11012                         state = 1;
11013                         break;
11014                       case '[':         /* Have range starter */
11015                         state = 2;
11016                         break;
11017                       default:          /* Anything else */
11018                         r[j++] = c;
11019                         break;
11020                     }
11021                     continue;
11022                   case 1:               /* Quoted char */
11023                     r[j++] = c;
11024                     state = 0;
11025                     continue;
11026                   case 2:               /* Range bottom */
11027                     lo = c;
11028                     state++;
11029                     continue;
11030                   case 3:               /* Range separater */
11031                     if (c != '-') {
11032                         failed = 1;
11033                         if (fndiags)
11034                           ckmakmsg(fnval,FNVALL,
11035                                    "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
11036                         goto fnend;
11037                     }
11038                     state++;
11039                     continue;
11040                   case 4:               /* Range top */
11041                     hi = c;
11042                     state++;
11043                     continue;
11044                   case 5:               /* Range end */
11045                     if (c != ']') {
11046                         failed = 1;
11047                         if (fndiags)
11048                           ckmakmsg(fnval,FNVALL,
11049                                    "<ERROR:BAD_RANGE:\\f",fn,"()>",NULL);
11050                         goto fnend;
11051                     }
11052                     for (k = lo; k <= hi && j < 255; k++) /* Fill in */
11053                       r[j++] = k;
11054                     lo = 0; hi = 0;     /* Reset */
11055                     state = 0;
11056                     continue;
11057                 }
11058             }
11059         }
11060         for (i = 0; i < 256 && buf1[i]; i++) {  /* Create translation table */
11061             k = (unsigned)buf1[i];
11062             buf3[k] = buf2[i];
11063         }
11064         s = (CHAR *)bp[0];              /* Point to source string */
11065         for (i = 0; i < len; i++) {     /* Translation loop */
11066             k = (unsigned)s[i];         /* Get next char */
11067             if (!buf3[k])               /* Remove this char */
11068               continue;
11069             *p++ = buf3[k];             /* Substitute this char */
11070         }
11071         *p = NUL;
11072         p = fnval;
11073         goto fnend;
11074     }
11075
11076 #ifndef NOSEXP
11077     if (cx == FN_SEXP) {                /* \fsexpression(arg1) */
11078         char * p2;
11079         fsexpflag++;
11080         p = (argn > 0) ? dosexp(bp[0]) : "";
11081         fsexpflag--;
11082         p2 = fnval;
11083         while ((*p2++ = *p++)) ;
11084         p = fnval;
11085         goto fnend;
11086     }
11087 #endif /* NOSEXP */
11088
11089     if (cx == FN_CMDSTK) {              /* \fcmdstack(n1,n2) */
11090         int i, j, k;
11091         char * s;
11092
11093         if (bp[0])
11094           val1 = *(bp[0]) ? evalx(bp[0]) : ckitoa(cmdlvl);
11095         else
11096           val1 = ckitoa(cmdlvl);
11097 #ifdef COMMENT
11098         free(bp[0]);                    /* (evalx() always uses same buffer) */
11099         bp[0] = NULL;                   /* (not any more!) */
11100 #endif /* COMMENT */
11101         failed = 1;
11102         if (argn > 1) {
11103 #ifdef COMMENT
11104             makestr(&(bp[0]),val1);
11105             val1 = bp[0];
11106 #endif /* COMMENT */
11107             val2 = *(bp[1]) ? evalx(bp[1]) : "0";
11108             if (!(chknum(val1) && chknum(val2))) {
11109                 if (fndiags)
11110                   ckmakmsg(fnval,FNVALL,
11111                            "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11112                 goto fnend;
11113             }
11114         } else {
11115             val1 = ckitoa(cmdlvl);
11116             val2 = "0";
11117         }
11118         i = atoi(val1);                 /* Level */
11119         j = atoi(val2);                 /* Flags */
11120         if (i < 0 || i > cmdlvl) {
11121             if (fndiags)
11122               ckmakmsg(fnval,FNVALL,
11123                        "<ERROR:ARG_OUT_OF_RANGE:\\f",fn,"()>",NULL);
11124             goto fnend;
11125         }
11126         failed = 0;
11127         p = fnval;
11128         k = cmdstk[i].src;              /* What (prompt, file, macro) */
11129         if (j) {
11130             ckstrncpy(fnval,ckitoa(k),FNVALL);
11131             goto fnend;
11132         }
11133         switch (k) {
11134           case CMD_KB:
11135             ckstrncpy(fnval,"(prompt)",FNVALL);
11136             break;
11137           case CMD_TF:
11138             s = tfnam[cmdstk[i].lvl];
11139             if (!zfnqfp(s,FNVALL,fnval))
11140               ckstrncpy(fnval,s,FNVALL);
11141             break;
11142           case CMD_MD:
11143             ckstrncpy(fnval,m_arg[cmdstk[i].lvl][0],FNVALL);
11144             break;
11145         }
11146         goto fnend;
11147     }
11148 #ifdef CKFLOAT
11149     if (cx == FN_DIFDATE) {             /* \fdiffdates(d1,d2) */
11150         char * d1, * d2;
11151         d1 = bp[0] ? bp[0] : ckdate();
11152         d2 = bp[1] ? bp[1] : ckdate();
11153         p = (char *)cmdiffdate(d1,d2);
11154         if (!p) {
11155             failed = 1;
11156             if (fndiags) {
11157                 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
11158                 p = fnval;
11159             }
11160         }
11161         goto fnend;
11162     }
11163 #endif /* CKFLOAT */
11164     if (cx == FN_CMPDATE) {             /* \fcmddates(d1,d2) */
11165         int x = 0;
11166         char d1[18], d2[18], * dp;
11167         failed = 0;
11168         d1[0] = NUL;
11169         d2[0] = NUL;
11170         p = fnval;
11171         dp = cmcvtdate(bp[0],1);
11172         if (dp) {
11173             ckstrncpy(d1,dp,18);
11174             if ((dp = cmcvtdate(bp[1],1))) {
11175                 ckstrncpy(d2,dp,18);
11176                 x = 1;
11177             }
11178         }
11179         if (x == 0) {
11180             failed = 1;
11181             if (fndiags)
11182               ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
11183         } else {
11184             x = strcmp(d1,d2);
11185             if (x > 0)
11186               x = 1;
11187             else if (x < 0)
11188               x = -1;
11189             sprintf(fnval,"%d",x);
11190         }
11191         goto fnend;
11192     }
11193     if (cx == FN_TOGMT) {               /* \futcdate(d1) */
11194         char * d1, * dp;
11195         char datebuf[32];
11196         char d2[32];
11197         p = fnval;
11198         failed = 1;
11199         if ((dp = cmcvtdate(bp[0],1))) { /* The given date */
11200             ckstrncpy(datebuf,dp,18);
11201             ckstrncpy(d2,dp,18);        /* local time */
11202             ckstrncat(datebuf,"Z",19);  /* Same time GMT */
11203             if ((dp = cmcvtdate(datebuf,1))) /* converted to local time */
11204               ckstrncpy(datebuf,dp,18);
11205             if ((p = (char *)cmdiffdate(d2,datebuf))) { /* Get offset */
11206                 ckstrncat(d2,p,32);     /* Append offset to local time */
11207                 if ((dp = cmcvtdate(d2,1))) {
11208                     failed = 0;
11209                     ckstrncpy(fnval,dp,FNVALL);
11210                     p = fnval;
11211                 }
11212             }
11213         }
11214         if (failed && fndiags)
11215           ckmakmsg(fnval,FNVALL,"<ERROR:BAD_DATE:\\f",fn,"()>",NULL);
11216         goto fnend;
11217     }
11218     if (cx == FN_DELSEC) {              /* \fdelta2secs(delta-time) */
11219         long secs;
11220         p = fnval;
11221         if ((x = delta2sec(bp[0],&secs)) < 0) {
11222             failed = 1;
11223             if (fndiags)
11224               ckmakmsg(fnval,FNVALL,
11225                        (x == -1) ?
11226                          "<ERROR:BAD_DELTA_TIME:\\f" :
11227                          "<ERROR:OVERFLOW:\\f",
11228                        fn,
11229                        "()>",
11230                        NULL
11231                        );
11232             goto fnend;
11233         }
11234         sprintf(p,"%ld",secs);
11235         goto fnend;
11236     }
11237     if (cx == FN_PC_DU) {
11238         char c, * s = bp[0];
11239         if (!s) s = "";
11240         p = fnval;
11241         while ((c = *s++)) {
11242             if (c == ':') {
11243                 if (*s != '\\')
11244                   *p++ = '/';
11245             } else if (c == '\\') {
11246                 *p++ = '/';
11247             } else {
11248                 *p++ = c;
11249             }
11250         }
11251         *p = NUL;
11252         p = fnval;
11253         goto fnend;
11254     }
11255     if (cx == FN_PC_UD) {               /* Unix to DOS path */
11256         char c, * s = bp[0];
11257         if (!s) s = "";
11258         if (*s == '~') {                /* Skip leading tilde */
11259             s++;
11260             if (*s == '/')
11261               s++;
11262         }
11263         p = fnval;
11264         while ((c = *s++))
11265           *p ++ = (c == '/') ? '\\' : c;
11266         *p = NUL;
11267         p = fnval;
11268         goto fnend;
11269     }
11270     if (cx == FN_KWVAL) {               /* Keyword=Value */
11271         p = dokwval(bp[0],bp[1]?*(bp[1]):'=');
11272         goto fnend;
11273     }
11274 #ifdef COMMENT
11275 /* Cute idea but doesn't work */
11276     if (cx == FN_SLEEP || cx == FN_MSLEEP) {
11277         p = "";
11278         if (chknum(bp[0])) {
11279             x = atoi(bp[0]);
11280         } else {
11281             failed = 1;
11282             if (fndiags) {
11283                 ckmakmsg(fnval,FNVALL,
11284                          "<ERROR:ARG_NOT_NUMERIC:\\f",fn,"()>",NULL);
11285                 p = fnval;
11286             }
11287             goto fnend;
11288         }
11289         if (cx == FN_SLEEP)
11290           x *= 1000;
11291         msleep(x);
11292         goto fnend;
11293     }
11294 #endif /* COMMENT */
11295
11296 #ifdef NT
11297     if (cx == FN_SNAME) {
11298         GetShortPathName(bp[0],fnval,FNVALL);
11299         goto fnend;
11300     }
11301     if (cx == FN_LNAME) {
11302         ckGetLongPathName(bp[0],fnval,FNVALL);
11303         goto fnend;
11304     }
11305 #endif /* NT */
11306
11307 /* Note: when adding new functions remember to update dohfunc in ckuus2.c. */
11308
11309     failed = 1;
11310     if (fndiags)
11311       ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN_FUNCTION:\\f",fn,"()>",NULL);
11312
11313   fnend:
11314     /* Free temporary storage for aguments */
11315     for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
11316     fndepth--;
11317     if (failed) {                       /* Handle failure */
11318         debug(F111,"fnend",fnval,errno);
11319         if (!p) p = "";
11320         if (p[0]) {
11321             /* In case this wasn't caught above... */
11322             k = strlen(p);
11323             if (p[0] != '<' && p[k-1] != '>') {
11324                 ckmakmsg(fnval,FNVALL,"<ERROR:BAD_ARG:\\f",fn,"()>",NULL);
11325                 p = fnval;
11326             }
11327         } else {
11328             ckmakmsg(fnval,FNVALL,"<ERROR:UNKNOWN:\\f",fn,"()>",NULL);
11329             p = fnval;
11330         }
11331         if (fnerror)                    /* SET FUNCTION ERROR ON */
11332           fnsuccess = 0;                /* Make command fail (see ckuus5.c) */
11333         debug(F111,"fneval failed",p,fnsuccess);
11334         if (fndiags)                    /* SET FUNCTION DIAGNOSTICS ON */
11335           printf("?%s\n",p);            /* Print error message now. */
11336         else
11337           return("");                   /* Return nothing. */
11338     }
11339     return(p);
11340 }
11341 #endif /* NOSPL */
11342
11343 static char ckpidbuf[32] = "????";
11344
11345 #ifdef VMS
11346 _PROTOTYP(long zgpid,(void));
11347 #endif /* VMS */
11348
11349 char *
11350 ckgetpid() {                            /* Return pid as string */
11351 #ifdef CK_PID
11352 #ifdef OS2
11353 #define getpid _getpid
11354     unsigned long zz;
11355 #else
11356     long zz;
11357 #endif /* OS2 */
11358 #ifdef VMS
11359     zz = zgpid();
11360 #else
11361     zz = getpid();
11362 #endif /* VMS */
11363     sprintf(ckpidbuf,"%ld",zz);         /* SAFE */
11364 #endif /* CK_PID */
11365     return((char *)ckpidbuf);
11366 }
11367
11368 #ifndef NOSPL
11369 #define EMBUFLEN 128                    /* Error message buffer length */
11370
11371 static char embuf[EMBUFLEN+1];
11372
11373 char *                                  /* Evaluate builtin variable */
11374 nvlook(s) char *s; {
11375     int x, y, cx;
11376     long z;
11377     char *p;
11378 #ifndef NODIAL
11379     MDMINF * m;
11380 #endif /* NODIAL */
11381 #ifndef NOKVERBS                        /* Keyboard macro material */
11382     extern int keymac, keymacx;
11383 #endif /* NOKVERBS */
11384 #ifdef CK_LOGIN
11385     extern int isguest;
11386 #endif /* CK_LOGIN */
11387     if (!s) s = "";
11388     x = strlen(s);
11389     if (fndiags) {                      /* FUNCTION DIAGNOSTIC ON */
11390         if (x + 32 < EMBUFLEN)
11391           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE:\\v(%s)>",s); /* SAFE */
11392         else
11393           sprintf(embuf,"<ERROR:NO_SUCH_VARIABLE>"); /* SAFE */
11394     } else                              /* FUNCTION DIAGNOSTIC OFF */
11395       embuf[0] = NUL;
11396     x = VVBUFL;
11397     p = vvbuf;
11398     if (zzstring(s,&p,&x) < 0) {        /* e.g. for \v(\%a) */
11399         y = -1;
11400     } else {
11401         s = vvbuf;
11402         y = lookup(vartab,s,nvars,&x);
11403     }
11404     cx = y;                             /* y is too generic */
11405 #ifndef NODIAL
11406     m = (mdmtyp > 0) ? modemp[mdmtyp] : NULL; /* For \v(m_xxx) variables */
11407 #endif /* NODIAL */
11408
11409     debug(F101,"nvlook y","",y);
11410
11411     switch (y) {
11412       case VN_ARGC:                     /* ARGC */
11413         sprintf(vvbuf,"%d",maclvl < 0 ? topargc : macargc[maclvl]); /* SAFE */
11414         return(vvbuf);
11415
11416       case VN_ARGS:                     /* ARGS */
11417         sprintf(vvbuf,"%d",xargs);      /* SAFE */
11418         return(vvbuf);
11419
11420       case VN_COUN:                     /* COUNT */
11421         sprintf(vvbuf,"%d",count[cmdlvl]); /* SAFE */
11422         return(vvbuf);
11423
11424       case VN_DATE:                     /* DATE */
11425         ztime(&p);                      /* Get "asctime" string */
11426         if (p == NULL || *p == NUL) return(NULL);
11427         vvbuf[0] = p[8];                /* dd */
11428         vvbuf[1] = p[9];
11429         vvbuf[2] = SP;
11430         vvbuf[3] = p[4];                /* mmm */
11431         vvbuf[4] = p[5];
11432         vvbuf[5] = p[6];
11433         vvbuf[6] = SP;
11434         for (x = 20; x < 24; x++)       /* yyyy */
11435           vvbuf[x - 13] = p[x];
11436         vvbuf[11] = NUL;
11437         return(vvbuf);
11438
11439       case VN_NDAT:                     /* Numeric date */
11440         ckstrncpy(vvbuf,zzndate(),VVBUFL);
11441         return(vvbuf);
11442
11443       case VN_DIRE:                     /* DIRECTORY */
11444         s = zgtdir();                   /* Get current directory */
11445         if (!s)
11446 #ifdef UNIXOROSK
11447           s = "./";
11448 #else
11449 #ifdef VMS
11450           s = "[]";
11451 #else
11452           s = "";
11453 #endif /* VMS */
11454 #endif /* UNIXOROSK */
11455         ckstrncpy(vvbuf,s,VVBUFL);
11456         s = vvbuf;
11457 #ifdef UNIXOROSK
11458         x = strlen(s);
11459         if (x < VVBUFL - 1) {
11460             if (s[x-1] != '/') {
11461                 s[x] = '/';
11462                 s[x+1] = NUL;
11463             }
11464         }
11465 #endif /* UNIXOROSK */
11466         return(s);
11467
11468       case VN_FILE:                     /* filespec */
11469         return(fspec);
11470
11471       case VN_HOST:                     /* host name */
11472         if (*myhost) {                  /* If known */
11473             return(myhost);             /* return it. */
11474         } else {                        /* Otherwise */
11475             ckstrncpy(vvbuf,"unknown",VVBUFL); /* just say "unknown" */
11476             return(vvbuf);
11477         }
11478
11479       case VN_SYST:                     /* System type */
11480 #ifdef UNIX
11481         ckstrncpy(vvbuf,"UNIX",VVBUFL);
11482 #else
11483 #ifdef VMS
11484         ckstrncpy(vvbuf,"VMS",VVBUFL);
11485 #else
11486 #ifdef OSK
11487         ckstrncpy(vvbuf,"OS9/68K",VVBUFL);
11488 #else
11489 #ifdef AMIGA
11490         ckstrncpy(vvbuf,"Amiga",VVBUFL);
11491 #else
11492 #ifdef MAC
11493         ckstrncpy(vvbuf,"Macintosh",VVBUFL);
11494 #else
11495 #ifdef OS2
11496 #ifdef NT
11497         ckstrncpy(vvbuf,"WIN32",VVBUFL) ;
11498 #else /* NT */
11499         ckstrncpy(vvbuf,"OS/2",VVBUFL);
11500 #endif /* NT */
11501 #else
11502 #ifdef datageneral
11503         ckstrncpy(vvbuf,"AOS/VS",VVBUFL);
11504 #else
11505 #ifdef GEMDOS
11506         ckstrncpy(vvbuf,"Atari_ST",VVBUFL);
11507 #else
11508 #ifdef STRATUS
11509         ckstrncpy(vvbuf,"Stratus_VOS",VVBUFL);
11510 #else
11511         ckstrncpy(vvbuf,"unknown",VVBUFL);
11512 #endif /* STRATUS */
11513 #endif /* GEMDOS */
11514 #endif /* datageneral */
11515 #endif /* OS2 */
11516 #endif /* MAC */
11517 #endif /* AMIGA */
11518 #endif /* OSK */
11519 #endif /* VMS */
11520 #endif /* UNIX */
11521         return(vvbuf);
11522
11523       case VN_SYSV:                     /* System herald */
11524 #ifdef IKSD
11525 #ifdef CK_LOGIN
11526         if (inserver && isguest)
11527           return("");
11528 #endif /* CK_LOGIN */
11529 #endif /* IKSD */
11530         for (x = y = 0; x < VVBUFL; x++) {
11531             if (ckxsys[x] == SP && y == 0) continue;
11532             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
11533         }
11534         vvbuf[y] = NUL;
11535         return(vvbuf);
11536     } /* Break up long switch statements... */
11537
11538     switch(y) {
11539       case VN_TIME:                     /* TIME. Assumes that ztime returns */
11540         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
11541         if (p == NULL || *p == NUL)     /* like asctime()! */
11542           return("");
11543         for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
11544           vvbuf[x - 11] = p[x];         /* to vvbuf */
11545         vvbuf[8] = NUL;                 /* terminate */
11546         return(vvbuf);                  /* and return it */
11547
11548       case VN_NTIM:                     /* Numeric time */
11549         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
11550         if (p == NULL || *p == NUL)     /* like asctime()! */
11551           return(NULL);
11552         z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
11553         sprintf(vvbuf,"%ld",z);         /* SAFE */
11554         return(vvbuf);
11555
11556 #ifdef CK_TTYFD
11557       case VN_TTYF:                     /* TTY file descriptor */
11558         sprintf(vvbuf,"%d",             /* SAFE */
11559 #ifdef VMS
11560                 vmsttyfd()
11561 #else
11562                 ttyfd
11563 #endif /* VMS */
11564                 );
11565         return(vvbuf);
11566 #endif /* CK_TTYFD */
11567
11568       case VN_VERS:                     /* Numeric Kermit version number */
11569         sprintf(vvbuf,"%ld",vernum);    /* SAFE */
11570         return(vvbuf);
11571
11572       case VN_XVNUM:                    /* Product-specific version number */
11573         sprintf(vvbuf,"%ld",xvernum);   /* SAFE */
11574         return(vvbuf);
11575
11576       case VN_HOME:                     /* Home directory */
11577         return(homepath());
11578
11579       case VN_IBUF:                     /* INPUT buffer */
11580         return((char *)inpbuf);
11581
11582       case VN_ICHR:                     /* INPUT character */
11583         inchar[1] = NUL;
11584         return((char *)inchar);
11585
11586       case VN_ICNT:                     /* INPUT character count */
11587         sprintf(vvbuf,"%d",incount);    /* SAFE */
11588         return(vvbuf);
11589
11590       case VN_SPEE: {                   /* Transmission SPEED */
11591           long t;
11592           t = ttgspd();
11593           if (t < 0L)
11594             sprintf(vvbuf,"unknown");   /* SAFE */
11595           else
11596             sprintf(vvbuf,"%ld",t);     /* SAFE */
11597           return(vvbuf);
11598       }
11599
11600       case VN_SUCC:                     /* SUCCESS flag */
11601         /* Note inverted sense */
11602         sprintf(vvbuf,"%d",(success == 0) ? 1 : 0); /* SAFE */
11603         return(vvbuf);
11604
11605       case VN_LINE: {                   /* LINE */
11606 #ifdef DEBUG
11607           if (deblog) {
11608               debug(F111,"\\v(line) local",ttname,local);
11609               debug(F111,"\\v(line) inserver","",inserver);
11610 #ifdef TNCODE
11611               debug(F111,"\\v(line) tcp_incoming","",tcp_incoming);
11612 #endif /* TNCODE */
11613 #ifdef CK_TAPI
11614               debug(F111,"\\v(line) tttapi","",tttapi);
11615 #endif /* CK_TAPI */
11616           }
11617 #endif /* DEBUG */
11618
11619 #ifdef CK_TAPI
11620           if (tttapi) {                 /* If I have made a TAPI connection */
11621               int i;                    /* return the TAPI device name */
11622               for (i = 0; i < ntapiline; i++) {
11623                   if (!strcmp(ttname,tapilinetab[i].kwd)) {
11624                       p = _tapilinetab[i].kwd;
11625                       return(p);
11626                   }
11627               }
11628           }
11629 #endif /* CK_TAPI */
11630 #ifndef NOXFER
11631           if (inserver                  /* If I am a TCP server */
11632 #ifdef TNCODE
11633               || tcp_incoming
11634 #endif /* TNCODE */
11635               )
11636 #ifdef TCPSOCKET
11637             p = ckgetpeer();            /* return peer name */
11638           else
11639 #endif /* TCPSOCKET */
11640 #endif /* NOXFER */
11641           if (local)                    /* Otherwise if in local mode */
11642             p = (char *) ttname;        /* return SET LINE / SET HOST name */
11643           else                          /* Otherwise */
11644             p = "";                     /* return empty string */
11645           if (!p)                       /* In case ckgetpeer() returns */
11646             p = "";                     /* null pointer... */
11647           debug(F110,"\\v(line) p",p,0);
11648           if (!*p)
11649             p = (char *) ttname;
11650           return(p);
11651       }
11652       case VN_PROG:                     /* Program name */
11653         return("C-Kermit");
11654
11655     } /* Break up long switch statements... */
11656
11657     switch(y) {
11658       case VN_RET:                      /* Value of most recent RETURN */
11659         debug(F111,"\\v(return)",mrval[maclvl+1],maclvl+1);
11660         p = mrval[maclvl+1];
11661         if (p == NULL) p = "";
11662         return(p);
11663
11664       case VN_FFC:                      /* Size of most recent file */
11665         sprintf(vvbuf, "%ld", ffc);     /* SAFE */
11666         return(vvbuf);
11667
11668       case VN_TFC:                      /* Size of most recent file group */
11669         sprintf(vvbuf, "%ld", tfc);     /* SAFE */
11670         return(vvbuf);
11671
11672       case VN_CPU:                      /* CPU type */
11673 #ifdef IKSD
11674 #ifdef CK_LOGIN
11675         if (inserver && isguest)
11676           return("");
11677 #endif /* CK_LOGIN */
11678 #endif /* IKSD */
11679 #ifdef OS2
11680          {
11681             char * getcpu(void) ;
11682             return getcpu();
11683          }
11684 #else /* OS2 */
11685 #ifdef CKCPU
11686         return(CKCPU);                  /* Traditionally, compile-time value */
11687 #else
11688 #ifdef CK_UTSNAME
11689         {                               /* But if none, try runtime value */
11690             extern char unm_mch[];
11691             return((char *)unm_mch);
11692         }
11693 #else
11694         return("unknown");
11695 #endif /* CK_UTSNAME */
11696 #endif /* CKCPU */
11697 #endif /* OS2 */
11698
11699       case VN_CMDL:                     /* Command level */
11700         sprintf(vvbuf, "%d", cmdlvl);   /* SAFE */
11701         return(vvbuf);
11702
11703       case VN_DAY:                      /* Day of week */
11704         ztime(&p);
11705         if (p != NULL && *p != NUL)     /* ztime() succeeded. */
11706           ckstrncpy(vvbuf,p,4);
11707         else
11708           vvbuf[0] = NUL;               /* ztime() failed. */
11709         return(vvbuf);                  /* Return what we got. */
11710
11711       case VN_NDAY: {                   /* Numeric day of week */
11712           long k;
11713           z = mjd(zzndate());           /* Get modified Julian date */
11714           k = (((int)(z % 7L)) + 3) % 7; /* Get day number */
11715           sprintf(vvbuf,"%ld",k);       /* SAFE */
11716           return(vvbuf);
11717       }
11718
11719       case VN_LCL:                      /* Local (vs remote) mode */
11720         ckstrncpy(vvbuf, local ? "1" : "0",VVBUFL);
11721         return(vvbuf);
11722
11723       case VN_CMDS:                     /* Command source */
11724         if (cmdstk[cmdlvl].src == CMD_KB)
11725           ckstrncpy(vvbuf,"prompt",VVBUFL);
11726         else if (cmdstk[cmdlvl].src == CMD_MD)
11727           ckstrncpy(vvbuf,"macro",VVBUFL);
11728         else if (cmdstk[cmdlvl].src == CMD_TF)
11729           ckstrncpy(vvbuf,"file",VVBUFL);
11730         else
11731           ckstrncpy(vvbuf,"unknown",VVBUFL);
11732         return(vvbuf);
11733
11734       case VN_CMDF:                     /* Current command file name */
11735 #ifdef COMMENT                          /* (see comments above) */
11736         if (tfnam[tlevel]) {            /* (near dblbs declaration) */
11737             dblbs(tfnam[tlevel],vvbuf,VVBUFL);
11738             return(vvbuf);
11739         } else return("");
11740 #else
11741         if (tlevel < 0)
11742           return("");
11743         else
11744           return(tfnam[tlevel] ? tfnam[tlevel] : "");
11745 #endif /* COMMENT */
11746
11747       case VN_MAC:                      /* Current macro name */
11748         return((maclvl > -1) ? m_arg[maclvl][0] : "");
11749
11750       case VN_EXIT:
11751         sprintf(vvbuf,"%d",xitsta);     /* SAFE */
11752         return(vvbuf);
11753
11754     } /* Break up long switch statements... */
11755
11756     switch(y) {
11757       case VN_PRTY: {                   /* Parity */
11758           char *ss;
11759           switch (parity) {
11760             case 0:   ss = "none";  break;
11761             case 'e': ss = "even";  break;
11762             case 'm': ss = "mark";  break;
11763             case 'o': ss = "odd";   break;
11764             case 's': ss = "space"; break;
11765             default:  ss = "unknown"; break;
11766           }
11767           ckstrncpy(vvbuf,ss,VVBUFL);
11768           return(vvbuf);
11769       }
11770
11771       case VN_DIAL:
11772         sprintf(vvbuf,"%d",             /* SAFE */
11773 #ifndef NODIAL
11774                 dialsta
11775 #else
11776                 -1
11777 #endif /* NODIAL */
11778                 );
11779         return(vvbuf);
11780
11781 #ifdef OS2
11782       case VN_KEYB:
11783         ckstrncpy(vvbuf,conkbg(),VVBUFL);
11784         return(vvbuf);
11785       case VN_SELCT: {
11786 #ifndef NOLOCAL
11787           const char * selection = GetSelection();
11788           return( (char *) (selection ? selection : "" )) ;
11789 #else
11790           return("");
11791 #endif /* NOLOCAL */
11792       }
11793 #endif /* OS2 */
11794
11795 #ifndef NOXFER
11796       case VN_CPS:
11797         sprintf(vvbuf,"%ld",tfcps);     /* SAFE */
11798         return(vvbuf);
11799 #endif /* NOXFER */
11800
11801       case VN_MODE:                     /* File transfer mode */
11802         switch (binary) {
11803           case XYFT_T: ckstrncpy(vvbuf,"text",VVBUFL); break;
11804           case XYFT_B:
11805           case XYFT_U: ckstrncpy(vvbuf,"binary",VVBUFL); break;
11806           case XYFT_I: ckstrncpy(vvbuf,"image",VVBUFL); break;
11807           case XYFT_L: ckstrncpy(vvbuf,"labeled",VVBUFL); break;
11808           case XYFT_M: ckstrncpy(vvbuf,"macbinary",VVBUFL); break;
11809           default:     ckstrncpy(vvbuf,"unknown",VVBUFL);
11810         }
11811         return(vvbuf);
11812
11813 #ifdef CK_REXX
11814       case VN_REXX:
11815         return(rexxbuf);
11816 #endif /* CK_REXX */
11817
11818       case VN_NEWL:                     /* System newline char or sequence */
11819 #ifdef UNIX
11820         ckstrncpy(vvbuf,"\n",VVBUFL);
11821 #else
11822 #ifdef datageneral
11823         ckstrncpy(vvbuf,"\n",VVBUFL);
11824 #else
11825 #ifdef OSK
11826         ckstrncpy(vvbuf,"\15",VVBUFL);  /* Remember, these are octal... */
11827 #else
11828 #ifdef MAC
11829         ckstrncpy(vvbuf,"\15",VVBUFL);
11830 #else
11831 #ifdef OS2
11832         ckstrncpy(vvbuf,"\15\12",VVBUFL);
11833 #else
11834 #ifdef STRATUS
11835         ckstrncpy(vvbuf,"\n",VVBUFL);
11836 #else
11837 #ifdef VMS
11838         ckstrncpy(vvbuf,"\15\12",VVBUFL);
11839 #else
11840 #ifdef AMIGA
11841         ckstrncpy(vvbuf,"\n",VVBUFL);
11842 #else
11843 #ifdef GEMDOS
11844         ckstrncpy(vvbuf,"\n",VVBUFL);
11845 #else
11846         ckstrncpy(vvbuf,"\n",VVBUFL);
11847 #endif /* GEMDOS */
11848 #endif /* AMIGA */
11849 #endif /* VMS */
11850 #endif /* STRATUS */
11851 #endif /* OS2 */
11852 #endif /* MAC */
11853 #endif /* OSK */
11854 #endif /* datageneral */
11855 #endif /* UNIX */
11856         return(vvbuf);
11857
11858       case VN_ROWS:                     /* ROWS */
11859       case VN_COLS:                     /* COLS */
11860         ckstrncpy(vvbuf,(cx == VN_ROWS) ? "24" : "80",VVBUFL); /* Default */
11861 #ifdef CK_TTGWSIZ
11862 #ifdef OS2
11863         if (tt_cols[VTERM] < 0 || tt_rows[VTERM] < 0)
11864           ttgwsiz();
11865         sprintf(vvbuf,"%d",             /* SAFE */
11866                 (cx == VN_ROWS) ? tt_rows[VTERM] : tt_cols[VTERM]);
11867 #else /* OS2 */
11868         if (ttgwsiz() > 0)              /* Get window size */
11869           if (tt_cols > 0 && tt_rows > 0) /* sets tt_rows, tt_cols */
11870             sprintf(vvbuf,"%d",         /* SAFE */
11871                     (cx == VN_ROWS) ? tt_rows : tt_cols);
11872 #endif /* OS2 */
11873 #endif /* CK_TTGWSIZ */
11874         return(vvbuf);
11875
11876       case VN_TTYP:
11877 #ifdef NOTERM
11878         ckstrncpy(vvbuf,"unknown",VVBUFL);
11879 #else
11880 #ifdef OS2
11881         sprintf(vvbuf, "%s",            /* SAFE */
11882                 (tt_type >= 0 && tt_type <= max_tt) ?
11883                 tt_info[tt_type].x_name :
11884                 "unknown"
11885                 );
11886 #else
11887 #ifdef MAC
11888         ckstrncpy(vvbuf,"vt320",VVBUFL);
11889 #else
11890         p = getenv("TERM");
11891         ckstrncpy(vvbuf,p ? p : "unknown",VVBUFL+1);
11892 #endif /* MAC */
11893 #endif /* OS2 */
11894 #endif /* NOTERM */
11895         return(vvbuf);
11896
11897       case VN_MINP:                     /* MINPUT */
11898         sprintf(vvbuf, "%d", m_found);  /* SAFE */
11899         return(vvbuf);
11900     } /* Break up long switch statements... */
11901
11902     switch(y) {
11903       case VN_CONN:                     /* CONNECTION */
11904         if (!local) {
11905           ckstrncpy(vvbuf,"remote",VVBUFL);
11906         } else {
11907             if (!network)
11908               ckstrncpy(vvbuf,"serial",VVBUFL);
11909 #ifdef TCPSOCKET
11910             else if (nettype == NET_TCPB || nettype == NET_TCPA) {
11911                 if (ttnproto == NP_TELNET)
11912                   ckstrncpy(vvbuf,"tcp/ip_telnet",VVBUFL);
11913 #ifdef CK_SSL
11914                 else if (ttnproto == NP_SSL)
11915                   ckstrncpy(vvbuf,"tcp/ip_ssl",VVBUFL);
11916                 else if (ttnproto == NP_TLS)
11917                   ckstrncpy(vvbuf,"tcp/ip_tls",VVBUFL);
11918 #endif /* CK_SSL */
11919                 else
11920                   ckstrncpy(vvbuf,"tcp/ip",VVBUFL);
11921             }
11922 #endif /* TCPSOCKET */
11923 #ifdef SSHBUILTIN
11924             else if (nettype == NET_SSH)
11925                   ckstrncpy(vvbuf,"tcp/ip_ssh",VVBUFL);
11926 #endif /* SSHBUILTIN */
11927 #ifdef ANYX25
11928             else if (nettype == NET_SX25 ||
11929                      nettype == NET_VX25 ||
11930                      nettype == NET_IX25
11931                      )
11932               ckstrncpy(vvbuf,"x.25",VVBUFL);
11933 #endif /* ANYX25 */
11934 #ifdef DECNET
11935             else if (nettype == NET_DEC) {
11936                 if (ttnproto == NP_LAT)
11937                   ckstrncpy(vvbuf,"decnet_lat",VVBUFL);
11938                 else if ( ttnproto == NP_CTERM )
11939                   ckstrncpy(vvbuf,"decnet_cterm",VVBUFL);
11940                 else
11941                   ckstrncpy(vvbuf,"decnet",VVBUFL);
11942             }
11943 #endif /* DECNET */
11944 #ifdef SUPERLAT
11945             else if (nettype == NET_SLAT)
11946               ckstrncpy(vvbuf,"superlat",VVBUFL);
11947 #endif /* SUPERLAT */
11948 #ifdef NETFILE
11949             else if (nettype == NET_FILE)
11950               ckstrncpy(vvbuf,"local_file",VVBUFL);
11951 #endif /* NETFILE */
11952 #ifdef NETCMD
11953             else if (nettype == NET_CMD)
11954               ckstrncpy(vvbuf,"pipe",VVBUFL);
11955 #endif /* NETCMD */
11956 #ifdef NETPTY
11957             else if (nettype == NET_PTY)
11958               ckstrncpy(vvbuf,"pseudoterminal",VVBUFL);
11959 #endif /* NETPTY */
11960 #ifdef NETDLL
11961             else if (nettype == NET_DLL)
11962               ckstrncpy(vvbuf,"dynamic_link_library",VVBUFL);
11963 #endif /* NETDLL */
11964
11965 #ifdef NPIPE
11966             else if (nettype == NET_PIPE)
11967               ckstrncpy(vvbuf,"named_pipe",VVBUFL);
11968 #endif /* NPIPE */
11969 #ifdef CK_NETBIOS
11970             else if (nettype == NET_BIOS)
11971               ckstrncpy(vvbuf,"netbios",VVBUFL);
11972 #endif /* CK_NETBIOS */
11973             else
11974               ckstrncpy(vvbuf,"unknown",VVBUFL);
11975         }
11976         return(vvbuf);
11977
11978 #ifndef NOXFER
11979       case VN_SYSI:                     /* System ID, Kermit code */
11980         return((char *)cksysid);
11981 #endif /* NOXFER */
11982
11983 #ifdef OS2
11984       case VN_SPA: {
11985           unsigned long space = zdskspace(0);
11986           if (space > 0 && space < 1024)
11987             sprintf(vvbuf,"-1");
11988           else
11989             sprintf(vvbuf,"%lu",space); /* SAFE */
11990           return(vvbuf);
11991       }
11992 #endif /* OS2 */
11993
11994 #ifndef NOXFER
11995       case VN_QUE: {
11996           extern char querybuf[];
11997           return(querybuf);
11998       }
11999 #endif /* NOXFER */
12000
12001 #ifndef NOCSETS
12002       case VN_CSET:
12003 #ifdef OS2
12004         sprintf(vvbuf,"cp%d",os2getcp()); /* SAFE */
12005 #else
12006         ckstrncpy(vvbuf,fcsinfo[fcharset].keyword,VVBUFL+1);
12007 #endif /* OS2 */
12008         return(vvbuf);
12009 #endif /* NOCSETS */
12010
12011 #ifdef OS2
12012       case VN_EXEDIR:
12013         return(exedir);
12014       case VN_STAR:
12015         return(startupdir);
12016 #else
12017       case VN_EXEDIR:
12018         return(exedir ? exedir : "");
12019 #ifdef VMSORUNIX
12020       case VN_STAR:
12021         return(startupdir);
12022 #endif /* VMSORUNIX */
12023 #endif /* OS2 */
12024
12025       case VN_INI:
12026         return(inidir);
12027
12028       case VN_MDM:
12029         return(gmdmtyp());
12030
12031       case VN_EVAL:
12032         return(evalbuf);
12033
12034 #ifndef NODIAL
12035       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
12036         return(diallcc ? diallcc : "");
12037
12038       case VN_D_AC:                     /* DIAL AREA-CODE */
12039         return(diallac ? diallac : "");
12040
12041       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
12042         return(dialixp ? dialixp : "");
12043
12044       case VN_D_LP:                     /* DIAL LD-PREFIX */
12045         return(dialldp ? dialldp : "");
12046
12047       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
12048         return(diallcp ? diallcp : "");
12049
12050       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE that matched */
12051         return(matchpxx ? matchpxx : "");
12052 #else
12053       case VN_D_CC:                     /* DIAL COUNTRY-CODE */
12054       case VN_D_AC:                     /* DIAL AREA-CODE */
12055       case VN_D_IP:                     /* DIAL INTERNATIONAL-PREFIX */
12056       case VN_D_LP:                     /* DIAL LD-PREFIX */
12057       case VN_D_LCP:                    /* DIAL LOCAL-PREFIX */
12058       case VN_D_PXX:                    /* DIAL PBX-EXCHANGE */
12059         return("");
12060 #endif /* NODIAL */
12061       case VN_UID:
12062 #ifdef UNIX
12063         {
12064             extern char * whoami();     /* From ckufio.c... */
12065 #ifdef IKSD
12066             if (inserver)
12067               return((char *)uidbuf);
12068             else
12069 #endif /* IKSD */
12070               if (uidbuf[0])
12071                 return((char *)uidbuf);
12072               else
12073                 return(whoami());
12074         }
12075 #else
12076         return((char *)uidbuf);
12077 #endif /* UNIX */
12078     } /* Break up long switch statements... */
12079
12080     switch(y) {
12081       case VN_PWD:
12082 #ifdef OS2
12083         if (activecmd == XXOUT || activecmd == XXLNOUT) {
12084             ckstrncpy(vvbuf,pwbuf,VVBUFL);
12085             ck_encrypt((char *)vvbuf);
12086             return((char *)vvbuf);
12087         } else
12088 #endif /* OS2 */
12089           return((char *)pwbuf);
12090
12091       case VN_PRM:
12092         return((char *)prmbuf);
12093
12094       case VN_PROTO:
12095 #ifdef NOXFER
12096         return("none");
12097 #else
12098 #ifdef CK_XYZ
12099         return(ptab[protocol].p_name);
12100 #else
12101         return("kermit");
12102 #endif /* CK_XYZ */
12103 #endif /* NOXFER */
12104
12105 #ifndef NOXFER
12106 #ifdef CK_TMPDIR
12107       case VN_DLDIR:
12108         return(dldir ? dldir : "");
12109 #endif /* CK_TMPDIR */
12110 #endif /* NOXFER */
12111
12112 #ifndef NODIAL
12113       case VN_M_INI:                    /* Modem init string */
12114         return(dialini ? dialini : (m ? m->wake_str : ""));
12115
12116       case VN_M_DCM:                    /* Modem dial command */
12117         return(dialcmd ? dialcmd : (m ? m->dial_str : ""));
12118
12119       case VN_M_DCO:                    /* Modem data compression on */
12120         return(dialdcon ? dialdcon : (m ? m->dc_on_str : ""));
12121
12122       case VN_M_DCX:                    /* Modem data compression off */
12123         return(dialdcoff ? dialdcoff : (m ? m->dc_off_str : ""));
12124
12125       case VN_M_ECO:                    /* Modem error correction on */
12126         return(dialecon ? dialecon : (m ? m->ec_on_str : ""));
12127
12128       case VN_M_ECX:                    /* Modem error correction off */
12129         return(dialecoff ? dialecoff : (m ? m->ec_off_str : ""));
12130
12131       case VN_M_AAO:                    /* Modem autoanswer on */
12132         return(dialaaon ? dialaaon : (m ? m->aa_on_str : ""));
12133
12134       case VN_M_AAX:                    /* Modem autoanswer off */
12135         return(dialaaoff ? dialaaoff : (m ? m->aa_off_str : ""));
12136
12137       case VN_M_HUP:                    /* Modem hangup command */
12138         return(dialhcmd ? dialhcmd : (m ? m->hup_str : ""));
12139
12140       case VN_M_HWF:                    /* Modem hardware flow command */
12141         return(dialhwfc ? dialhwfc : (m ? m->hwfc_str : ""));
12142
12143       case VN_M_SWF:                    /* Modem software flow command */
12144         return(dialswfc ? dialswfc : (m ? m->swfc_str : ""));
12145
12146       case VN_M_NFC:                    /* Modem no flow-control command */
12147         return(dialnofc ? dialnofc : (m ? m->nofc_str : ""));
12148
12149       case VN_M_PDM:                    /* Modem pulse dialing mode */
12150         return(dialpulse ? dialpulse : (m ? m->pulse : ""));
12151
12152       case VN_M_TDM:                    /* Modem tone dialing mode */
12153         return(dialtone ? dialtone : (m ? m->tone : ""));
12154
12155       case VN_M_NAM:                    /* Modem full name */
12156         return(dialname ? dialname : (m ? m->name : ""));
12157 #else
12158       case VN_M_INI:                    /* Modem init string */
12159       case VN_M_DCM:                    /* Modem dial command */
12160       case VN_M_DCO:                    /* Modem data compression on */
12161       case VN_M_DCX:                    /* Modem data compression off */
12162       case VN_M_ECO:                    /* Modem error correction on */
12163       case VN_M_ECX:                    /* Modem error correction off */
12164       case VN_M_AAO:                    /* Modem autoanswer on */
12165       case VN_M_AAX:                    /* Modem autoanswer off */
12166       case VN_M_HUP:                    /* Modem hangup command */
12167       case VN_M_HWF:                    /* Modem hardware flow command */
12168       case VN_M_SWF:                    /* Modem software flow command */
12169       case VN_M_NFC:                    /* Modem no flow-control command */
12170       case VN_M_PDM:                    /* Modem pulse dialing mode */
12171       case VN_M_TDM:                    /* Modem tone dialing mode */
12172       case VN_M_NAM:
12173         return("");
12174 #endif /* NODIAL */
12175
12176       case VN_ISTAT:                    /* INPUT status */
12177         sprintf(vvbuf, "%d", instatus); /* SAFE */
12178         return(vvbuf);
12179
12180       case VN_TEMP:                     /* Temporary directory */
12181         if (tempdir) {
12182             p = tempdir;
12183         } else {
12184 #ifdef OS2
12185 #ifdef NT
12186             p = getenv("K95TMP");
12187 #else
12188             p = getenv("K2TMP");
12189 #endif /* NT */
12190             if ( !p )
12191 #endif /* OS2 */
12192               p = getenv("CK_TMP");
12193             if (!p) p = getenv("TMPDIR");
12194             if (!p) p = getenv("TEMP");
12195             if (!p) p = getenv("TMP");
12196
12197 #ifdef OS2ORUNIX
12198             if (p) {
12199                 int len = strlen(p);
12200                 if (p[len-1] != '/'
12201 #ifdef OS2
12202                     && p[len-1] != '\\'
12203 #endif /* OS2 */
12204                      ) {
12205                     static char foo[CKMAXPATH];
12206                     ckstrncpy(foo,p,CKMAXPATH);
12207                     ckstrncat(foo,"/",CKMAXPATH);
12208                     p = foo;
12209                 }
12210             } else
12211 #else /* OS2ORUNIX */
12212             if (!p)
12213 #endif /* OS2ORUNIX */
12214 #ifdef UNIX                             /* Systems that have a standard */
12215               p = "/tmp/";              /* temporary directory... */
12216 #else
12217 #ifdef datageneral
12218               p = ":TMP:";
12219 #else
12220               p = "";
12221 #endif /* datageneral */
12222 #endif /* UNIX */
12223         }
12224         ckstrncpy(vvbuf,p,VVBUFL);
12225         p = vvbuf;
12226
12227 /* This needs generalizing for VOS, AOS/VS, etc... */
12228
12229         while (*p) {
12230 #ifdef OS2
12231             if (*p == '\\') *p = '/';
12232 #endif /* OS2 */
12233             p++;
12234         }
12235 #ifndef VMS
12236         if (p > vvbuf) {
12237             char c =                    /* Directory termination character */
12238 #ifdef MAC
12239               ':'
12240 #else
12241 #ifdef datageneral
12242               ':'
12243 #else
12244 #ifdef STRATUS
12245               '>'
12246 #else
12247               '/'
12248 #endif /* STRATUS */
12249 #endif /* datageneral */
12250 #endif /* MAC */
12251                 ;
12252
12253             if (*(p-1) != c) {
12254                 *p++ = c;
12255                 *p = NUL;
12256             }
12257         }
12258 #endif /* VMS */
12259         return(vvbuf);
12260     } /* Break up long switch statements... */
12261
12262     switch(y) {
12263       case VN_ERRNO:                    /* Error number */
12264 #ifdef VMS
12265         {
12266             extern int vms_lasterr;
12267             sprintf(vvbuf, "%d", vms_lasterr); /* SAFE */
12268         }
12269 #else
12270         sprintf(vvbuf, "%d", errno);    /* SAFE */
12271 #endif /* VMS */
12272         return(vvbuf);
12273
12274       case VN_ERSTR:                    /* Error string */
12275         ckstrncpy(vvbuf,ck_errstr(),VVBUFL);
12276         return(vvbuf);
12277
12278 #ifndef NOXFER
12279       case VN_RPSIZ:                    /* RECEIVE packet-length */
12280         sprintf(vvbuf,"%d",urpsiz);     /* SAFE */
12281         return(vvbuf);
12282
12283       case VN_WINDO:                    /* WINDOW slots */
12284         sprintf(vvbuf,"%d",wslotr);     /* SAFE */
12285         return(vvbuf);
12286 #endif /* NOXFER */
12287
12288       case VN_TFLN:                     /* TAKE-file line number */
12289         if (tlevel > -1) {
12290             sprintf(vvbuf, "%d", tfline[tlevel]); /* SAFE */
12291             return(vvbuf);
12292         } else
12293           return("0");
12294
12295       case VN_MDMSG:                    /* DIALRESULT */
12296 #ifndef NODIAL
12297         return((char *)modemmsg);
12298 #else
12299         return("");
12300 #endif /* NODIAL */
12301
12302       case VN_DNUM:                     /* DIALNUMBER */
12303 #ifndef NODIAL
12304         return(dialnum ? (char *) dialnum : "");
12305 #else
12306         return("");
12307 #endif /* NODIAL */
12308
12309       case VN_APC:
12310         sprintf(vvbuf, "%d",            /* SAFE */
12311 #ifdef CK_APC
12312                 apcactive
12313 #else
12314                 0
12315 #endif /* CK_APC */
12316                 );
12317         return((char *)vvbuf);
12318
12319 #ifdef OS2
12320 #ifndef NOKVERBS
12321       case VN_TRMK:
12322           sprintf(vvbuf, "%d", keymac); /* SAFE */
12323         return((char *)vvbuf);
12324 #endif /* NOKVERBS */
12325 #endif /* OS2 */
12326
12327       case VN_IPADDR:
12328 #ifdef TCPSOCKET
12329 #ifndef OSK
12330       /* This dumps core on OS-9 for some reason, but only if executed */
12331       /* before we have made a TCP connection.  This is obviously not */
12332       /* the ideal fix. */
12333         if (!myipaddr[0])
12334           getlocalipaddr();
12335 #endif /* OSK */
12336 #endif /* TCPSOCKET */
12337         ckstrncpy(vvbuf,
12338 #ifdef TCPSOCKET
12339                 (char *)myipaddr,
12340 #else
12341                 "",
12342 #endif /* TCPSOCKET */
12343                 VVBUFL);
12344         return((char *)vvbuf);
12345
12346 #ifndef NOXFER
12347       case VN_CRC16:                    /* CRC-16 of most recent transfer */
12348         sprintf(vvbuf,"%d",crc16);      /* SAFE */
12349         return(vvbuf);
12350 #endif /* NOXFER */
12351
12352 #ifdef CK_PID
12353       case VN_PID:
12354 #ifdef IKSD
12355 #ifdef CK_LOGIN
12356         if (inserver && isguest)
12357           return("");
12358 #endif /* CK_LOGIN */
12359 #endif /* IKSD */
12360         return(ckgetpid());
12361 #endif /* CK_PID */
12362
12363 #ifndef NOXFER
12364       case VN_FNAM: {                   /* \v(filename) */
12365           extern char filnam[], ofn1[], *sfspec, *rrfspec;
12366           char * tmp;
12367           switch (what) {               /* File transfer is in progress */
12368 #ifdef NEWFTP
12369             case (W_FTP|W_RECV):
12370             case (W_FTP|W_SEND):
12371               return((char *)filnam);
12372 #endif /* NEWFTP */
12373             case W_RECV:
12374             case W_REMO:
12375               return((char *)ofn1);
12376             default:                    /* Most recent file transferred */
12377               if (filnam[0]) {          /* (if any) */
12378                   return((char *)filnam);
12379               } else if (lastxfer & W_SEND && sfspec) {
12380                   if (fnspath == PATH_OFF)
12381                     zstrip(sfspec,&tmp);
12382                   else
12383                     tmp = sfspec;
12384                   return(tmp);
12385               } else if (lastxfer & W_RECV && rrfspec) {
12386                   if (fnrpath == PATH_OFF)
12387                     zstrip(rrfspec,&tmp);
12388                   else
12389                     tmp = rrfspec;
12390                   return(tmp);
12391               } else
12392                 return("");
12393           }
12394       }
12395       case VN_FNUM:                     /* \v(filenum) */
12396         sprintf(vvbuf,"%ld",filcnt);    /* SAFE */
12397         return((char *)vvbuf);
12398 #endif /* NOXFER */
12399
12400 #ifdef PEXITSTAT
12401       case VN_PEXIT: {
12402           extern int pexitstat;
12403           sprintf(vvbuf,"%d",pexitstat); /* SAFE */
12404           return((char *)vvbuf);
12405       }
12406 #endif /* PEXITSTAT */
12407
12408 #ifndef NOXFER
12409       case VN_P_8BIT:
12410         vvbuf[0] = parity ? ebq : NUL;
12411         vvbuf[1] = NUL;
12412         return((char *)vvbuf);
12413
12414       case VN_P_CTL: {
12415           extern CHAR myctlq;
12416           vvbuf[0] = myctlq;
12417           vvbuf[1] = NUL;
12418           return((char *)vvbuf);
12419       }
12420       case VN_P_RPT: {
12421           extern int rptena;
12422           vvbuf[0] = rptena ? rptq : NUL;
12423           vvbuf[1] = NUL;
12424           return((char *)vvbuf);
12425       }
12426 #endif /* NOXFER */
12427
12428 #ifdef OS2
12429       case VN_REGN:
12430         return(get_reg_name());
12431       case VN_REGO:
12432         return(get_reg_corp());
12433       case VN_REGS:
12434         return(get_reg_sn());
12435 #endif /* OS2 */
12436     } /* Break up long switch statements... */
12437
12438     switch(y) {
12439       case VN_XPROG:
12440 #ifdef OS2
12441 #ifdef NT
12442 #ifdef KUI
12443         return("K-95G");
12444 #else
12445         return("K-95");
12446 #endif /* KUI */
12447 #else
12448         return("K/2");
12449 #endif /* NT */
12450 #else
12451         return("C-Kermit");
12452 #endif /* OS2 */
12453
12454       case VN_EDITOR:
12455 #ifdef NOFRILLS
12456         return("");
12457 #else
12458 #ifdef NOPUSH
12459         return("");
12460 #else
12461         {
12462             extern char editor[];
12463             char *ss;
12464             if (!editor[0]) {
12465                 ss = getenv("EDITOR");
12466                 if (ss) {
12467                     ckstrncpy(editor,ss,CKMAXPATH);
12468                 }
12469             }
12470             debug(F110,"\\v(editor)",editor,0);
12471             return(editor[0] ? (char *)editor : "");
12472         }
12473 #endif /* NOPUSH */
12474 #endif /* NOFRILLS */
12475
12476       case VN_EDOPT:
12477 #ifdef NOFRILLS
12478         return("");
12479 #else
12480 #ifdef NOPUSH
12481         return("");
12482 #else
12483         {
12484             extern char editopts[];
12485             return(editopts[0] ? (char *)editopts : "");
12486         }
12487 #endif /* NOPUSH */
12488 #endif /* NOFRILLS */
12489
12490       case VN_EDFILE:
12491 #ifdef NOFRILLS
12492         return("");
12493 #else
12494 #ifdef NOPUSH
12495         return("");
12496 #else
12497         {
12498             extern char editfile[];
12499             return(editfile[0] ? (char *)editfile : "");
12500         }
12501 #endif /* NOPUSH */
12502 #endif /* NOFRILLS */
12503
12504 #ifdef BROWSER
12505       case VN_BROWSR: {
12506           extern char browser[];
12507           if (!browser[0]) {
12508               s = getenv("BROWSER");
12509               if (s) ckstrncpy(browser,s,CKMAXPATH);
12510           }
12511           return(browser[0] ? (char *)browser : "");
12512       }
12513       case VN_BROPT: {
12514           extern char browsopts[];
12515           return(browsopts[0] ? (char *)browsopts : "");
12516       }
12517       case VN_URL: {
12518           extern char browsurl[];
12519           return(browsurl[0] ? (char *)browsurl : "");
12520       }
12521 #endif /* BROWSER */
12522       case VN_HERALD:
12523         return((char *)versio);
12524
12525       case VN_TEST: {                   /* test */
12526           extern char * ck_s_test, * ck_s_tver;
12527           if (!ck_s_test) ck_s_test = "";
12528           if (!ck_s_tver) ck_s_tver = "";
12529           if (*ck_s_test) {
12530               ckstrncpy(vvbuf,ck_s_test,VVBUFL);
12531               if (*ck_s_tver) {
12532                   ckstrncat(vvbuf,".",VVBUFL);
12533                   ckstrncat(vvbuf,ck_s_tver,VVBUFL);
12534               }
12535           } else
12536             ckstrncpy(vvbuf,"0",VVBUFL);
12537           return((char *)vvbuf);
12538       }
12539
12540 #ifndef NOXFER
12541       case VN_XFSTAT:                   /* xferstatus */
12542         x = xferstat;                   /* Like success */
12543         if (x > -1) x = (x == 0) ? 1 : 0; /* External value is reversed */
12544         sprintf(vvbuf,"%d",x);          /* SAFE */
12545         return((char *)vvbuf);
12546
12547       case VN_XFMSG:                    /* xfermsg */
12548         return((char *)epktmsg);
12549
12550 #ifndef NOMSEND
12551       case VN_SNDL: {                   /* sendlist */
12552           extern int filesinlist;
12553           sprintf(vvbuf,"%d",filesinlist); /* SAFE */
12554           return((char *)vvbuf);
12555       }
12556 #endif /* NOMSEND */
12557 #endif /* NOXFER */
12558
12559 #ifdef CK_TRIGGER
12560       case VN_TRIG: {
12561           extern char * triggerval;
12562           return(triggerval ? triggerval : "");
12563       }
12564 #endif /* CK_TRIGGER */
12565 #ifdef OS2MOUSE
12566 #ifdef OS2
12567       case VN_MOU_X: {
12568           extern int MouseCurX;
12569           sprintf(vvbuf,"%d",MouseCurX); /* SAFE */
12570           return((char *)vvbuf);
12571       }
12572       case VN_MOU_Y: {
12573           extern int MouseCurY;
12574           sprintf(vvbuf,"%d",MouseCurY); /* SAFE */
12575           return((char *)vvbuf);
12576       }
12577 #endif /* OS2 */
12578 #endif /* OS2MOUSE */
12579       case VN_PRINT: {
12580           extern int printpipe;
12581           extern char * printername;
12582 #ifdef PRINTSWI
12583           extern int noprinter;
12584           if (noprinter) return("");
12585 #endif /* PRINTSWI */
12586           ckmakmsg(vvbuf,VVBUFL,
12587                    printpipe ? "|" : "",
12588                    printername ? printername :
12589 #ifdef OS2
12590                    "PRN",
12591 #else
12592                    "(default)",
12593 #endif /* OS2 */
12594                    NULL,
12595                    NULL
12596                    );
12597           return((char *)vvbuf);
12598       }
12599     } /* Break up long switch statements... */
12600
12601     switch(y) {
12602       case VN_ESC:                      /* Escape character */
12603         sprintf(vvbuf,"%d",escape);     /* SAFE */
12604         return((char *)vvbuf);
12605
12606       case VN_INTIME:
12607         sprintf(vvbuf,"%ld",inetime);   /* SAFE */
12608         return((char *)vvbuf);
12609
12610       case VN_INTMO:
12611         sprintf(vvbuf,"%d",inwait);     /* SAFE */
12612         return((char *)vvbuf);
12613
12614       case VN_SECURE:
12615         if (0
12616 #ifdef SSHBUILTIN
12617             || IS_SSH()
12618 #endif /* SSHBUILTIN */
12619 #ifdef CK_ENCRYPTION
12620             || ck_tn_encrypting() && ck_tn_decrypting()
12621 #endif /* CK_ENCRYPTION */
12622 #ifdef CK_SSL
12623             || tls_active_flag || ssl_active_flag
12624 #endif /* CK_SSL */
12625             )
12626           return("1");
12627         else
12628           return("0");
12629
12630       case VN_AUTHN:
12631 #ifdef CK_AUTHENTICATION
12632         {
12633             extern char szUserNameAuthenticated[];
12634             return((char *)szUserNameAuthenticated);
12635         }
12636 #else /* CK_AUTHENTICATION */
12637         return((char *)"");
12638 #endif /* CK_AUTHENTICATION */
12639
12640       case VN_AUTHS:
12641 #ifdef CK_AUTHENTICATION
12642         switch (ck_tn_auth_valid()) {
12643           case AUTH_UNKNOWN:
12644             return((char *)"unknown");
12645           case AUTH_OTHER:
12646             return((char *)"other");
12647           case AUTH_USER:
12648             return((char *)"user");
12649           case AUTH_VALID:
12650             return((char *)"valid");
12651           case AUTH_REJECT:
12652           default:
12653             return((char *)"rejected");
12654         }
12655 #else /* CK_AUTHENTICATION */
12656         return((char *)"rejected");
12657 #endif /* CK_AUTHENTICATION */
12658
12659       case VN_AUTHT:
12660 #ifdef CK_AUTHENTICATION
12661 #ifdef CK_SSL
12662         if ((ssl_active_flag || tls_active_flag) &&
12663             ck_tn_auth_valid() == AUTH_VALID &&
12664             (sstelnet ? (!TELOPT_U(TELOPT_AUTHENTICATION)) :
12665                         (!TELOPT_ME(TELOPT_AUTHENTICATION))) ||
12666              ck_tn_authenticated() == AUTHTYPE_NULL ||
12667              ck_tn_authenticated() == AUTHTYPE_AUTO)
12668           return("X_509_CERTIFICATE");
12669         else
12670 #endif /* CK_SSL */
12671           return(AUTHTYPE_NAME(ck_tn_authenticated()));
12672 #else /* CK_AUTHENTICATION */
12673         return((char *)"NULL");
12674 #endif /* CK_AUTHENTICATION */
12675
12676 #ifdef CK_KERBEROS
12677       case VN_K4PRN: {
12678           extern char * krb4_d_principal;
12679           if (krb4_d_principal)
12680             ckstrncpy(vvbuf,krb4_d_principal,VVBUFL+1);
12681           else
12682             *vvbuf = NUL;
12683           return((char *)vvbuf);
12684       }
12685       case VN_K5PRN: {
12686           extern char * krb5_d_principal;
12687           if (krb5_d_principal)
12688             ckstrncpy(vvbuf,krb5_d_principal,VVBUFL+1);
12689           else
12690             *vvbuf = NUL;
12691           return((char *)vvbuf);
12692       }
12693       case VN_K4RLM: {
12694           extern char * krb4_d_realm;
12695           if (krb4_d_realm) {
12696               ckstrncpy(vvbuf,krb4_d_realm,VVBUFL+1);
12697           } else {
12698               char * s = ck_krb4_getrealm();
12699               ckstrncpy(vvbuf,s ? s : "",VVBUFL+1);
12700           }
12701           return((char *)vvbuf);
12702       }
12703       case VN_K4SRV: {
12704           extern char * krb4_d_srv;
12705           if (krb4_d_srv)
12706             ckstrncpy(vvbuf,krb4_d_srv,VVBUFL+1);
12707           else
12708             ckstrncpy(vvbuf,"rcmd",VVBUFL);
12709           return((char *)vvbuf);
12710       }
12711       case VN_K5RLM: {
12712           extern char * krb5_d_realm;
12713           extern char * krb5_d_cc;
12714           if (krb5_d_realm) {
12715               ckstrncpy(vvbuf,krb5_d_realm,VVBUFL+1);
12716           } else {
12717               char * s = ck_krb5_getrealm(krb5_d_cc);
12718               ckstrncpy(vvbuf,s,VVBUFL+1);
12719           }
12720           return((char *)vvbuf);
12721       }
12722       case VN_K5CC: {
12723           extern char * krb5_d_cc;
12724           if (krb5_d_cc)
12725             ckstrncpy(vvbuf,krb5_d_cc,VVBUFL+1);
12726           else
12727             ckstrncpy(vvbuf,ck_krb5_get_cc_name(),VVBUFL+1);
12728           return((char *)vvbuf);
12729       }
12730       case VN_K5SRV: {
12731           extern char * krb5_d_srv;
12732           if (krb5_d_srv)
12733             ckstrncpy(vvbuf,krb5_d_srv,VVBUFL+1);
12734           else
12735             ckstrncpy(vvbuf,"host",VVBUFL);
12736           return((char *)vvbuf);
12737       }
12738       case VN_K4ENO: {
12739         extern char * krb4_errno;
12740         sprintf(vvbuf,"%d",krb4_errno); /* SAFE */
12741         return((char *)vvbuf);
12742       }
12743       case VN_K5ENO: {
12744         extern char * krb5_errno;
12745         sprintf(vvbuf,"%d",krb5_errno); /* SAFE */
12746         return((char *)vvbuf);
12747       }
12748       case VN_K4EMSG: {
12749         extern char * krb4_errmsg;
12750         ckstrncpy(vvbuf,krb4_errmsg?krb4_errmsg:"",VVBUFL+1);
12751         return((char *)vvbuf);
12752       }
12753       case VN_K5EMSG: {
12754         extern char * krb5_errmsg;
12755         ckstrncpy(vvbuf,krb5_errmsg,VVBUFL+1);
12756         return((char *)vvbuf);
12757       }
12758 #endif /* CK_KERBEROS */
12759 #ifdef CK_SSL
12760       case VN_X509_S:
12761         if (ssl_active_flag)
12762           ckstrncpy(vvbuf,ssl_get_subject_name(ssl_con),VVBUFL+1);
12763         else if (tls_active_flag)
12764           ckstrncpy(vvbuf,ssl_get_subject_name(tls_con),VVBUFL+1);
12765         else
12766           ckstrncpy(vvbuf,"",VVBUFL+1);
12767         return((char *)vvbuf);
12768       case VN_X509_I:
12769         if (ssl_active_flag)
12770           ckstrncpy(vvbuf,ssl_get_issuer_name(ssl_con),VVBUFL+1);
12771         else if (tls_active_flag)
12772           ckstrncpy(vvbuf,ssl_get_issuer_name(tls_con),VVBUFL+1);
12773         else
12774           ckstrncpy(vvbuf,"",VVBUFL+1);
12775         return((char *)vvbuf);
12776 #endif /* CK_SSL */
12777
12778       case VN_OSNAM:
12779 #ifdef IKSD
12780 #ifdef CK_LOGIN
12781         if (inserver && isguest)
12782           return("");
12783 #endif /* CK_LOGIN */
12784 #endif /* IKSD */
12785 #ifdef CK_UTSNAME
12786         {
12787             extern char unm_nam[];
12788             return((char *)unm_nam);
12789         }
12790 #else
12791         for (x = y = 0; x < VVBUFL; x++) {
12792             if (ckxsys[x] == SP && cx == 0) continue;
12793             vvbuf[y++] = (char) ((ckxsys[x] == SP) ? '_' : ckxsys[x]);
12794         }
12795         vvbuf[y] = NUL;
12796         return(vvbuf);
12797 #endif /* CK_UTSNAME */
12798
12799       case VN_OSVER: {
12800 #ifdef CK_UTSNAME
12801           extern char unm_ver[];
12802 #ifdef IKSD
12803 #ifdef CK_LOGIN
12804           if (inserver && isguest)
12805             return("");
12806 #endif /* CK_LOGIN */
12807 #endif /* IKSD */
12808           return((char *)unm_ver);
12809 #else
12810           return("");
12811 #endif /* CK_UTSNAME */
12812       }
12813
12814       case VN_OSREL: {
12815 #ifdef CK_UTSNAME
12816           extern char unm_rel[];
12817 #ifdef IKSD
12818 #ifdef CK_LOGIN
12819           if (inserver && isguest)
12820             return("");
12821 #endif /* CK_LOGIN */
12822 #endif /* IKSD */
12823           return((char *)unm_rel);
12824 #else
12825           return("");
12826 #endif /* CK_UTSNAME */
12827       }
12828     } /* Break up long switch statements... */
12829
12830     switch(y) {
12831       case VN_NAME: {
12832           extern char * myname;
12833           return(myname);
12834       }
12835
12836       case VN_MODL: {
12837 #ifdef CK_UTSNAME
12838           extern char unm_mod[], unm_mch[];
12839           int y = VVBUFL - 1;
12840           char * s = unm_mod;
12841 #endif /* CK_UTSNAME */
12842 #ifdef IKSD
12843 #ifdef CK_LOGIN
12844           if (inserver && isguest)
12845             return("");
12846 #endif /* CK_LOGIN */
12847 #endif /* IKSD */
12848
12849 #ifdef COMMENT                          /* was HPUX */
12850           if (!unm_mod[0] && !nopush)
12851             zzstring("\\fcommand(model)",&s,&y);
12852 /*
12853    Another possibility would be:
12854      "\\fcommand(ksh -c 'whence model 1>&- && model || uname -m')"
12855    But that would depend on having ksh.
12856 */
12857 #else
12858 #ifdef OSF32                            /* Digital UNIX 3.2 and higher... */
12859 /* Note: Ultrix has /etc/sizer, but it is not publicly executable. */
12860 /* sizer -c outputs 'cpu:<tab><tab>"DECxxxx"' */
12861           if (!unm_mod[0]) {
12862               char * p;
12863               int flag = 0;
12864               zzstring("\\fcommand(/usr/sbin/sizer -c)",&s,&y);
12865               debug(F110,"DU model",unm_mod,0);
12866               s = unm_mod;
12867               p = unm_mod;
12868               while (*p) {              /* Extract the part in quotes */
12869                   if (*p == '"') {
12870                       if (flag)
12871                         break;
12872                       flag = 1;
12873                       p++;
12874                       continue;
12875                   }
12876                   if (flag)
12877                     *s++ = *p;
12878                   p++;
12879               }
12880               *s = NUL;
12881           }
12882 #endif /* OSF32 */
12883 #endif /* COMMENT */
12884
12885 #ifdef CK_UTSNAME
12886           if (unm_mod[0])
12887             return((char *)unm_mod);
12888           else
12889             return((char *)unm_mch);
12890 #else
12891           return("");
12892 #endif /* CK_UTSNAME */
12893       }
12894
12895 #ifdef IBMX25
12896       /* X.25 variables (local and remote address) */
12897       case VN_X25LA:
12898         if (!local_nua[0] && !x25local_nua(local_nua))
12899           *vvbuf = NULL;
12900         else
12901           ckstrncpy(vvbuf,local_nua,VVBUFL+1);
12902         return((char *)vvbuf);
12903
12904       case VN_X25RA:
12905         if (!remote_nua[0])
12906           *vvbuf = NULL;
12907         else
12908           ckstrncpy(vvbuf,remote_nua,VVBUFL+1);
12909         return((char *)vvbuf);
12910 #endif /* IBMX25 */
12911
12912 #ifndef NODIAL
12913       case VN_PDSFX: {
12914           extern char pdsfx[];
12915           return((char *)pdsfx);
12916       }
12917       case VN_DTYPE: {
12918           extern int dialtype;
12919           sprintf(vvbuf,"%d",dialtype); /* SAFE */
12920           return((char *)vvbuf);
12921       }
12922 #endif /* NODIAL */
12923
12924 #ifdef UNIX
12925       case VN_LCKPID: {
12926           extern char lockpid[];
12927           return((char *)lockpid);
12928       }
12929 #endif /* UNIX */
12930
12931 #ifndef NOXFER
12932       case VN_BLK:
12933         sprintf(vvbuf,"%d",bctr);       /* SAFE */
12934         return((char *)vvbuf);
12935
12936       case VN_TFTIM:
12937         sprintf(vvbuf,                  /* SAFE */
12938 #ifdef GFTIMER
12939                 "%ld", (long)(fptsecs + 0.5)
12940 #else
12941                 "%d", tsecs
12942 #endif /* GFTIMER */
12943                 );
12944         return((char *)vvbuf);
12945 #endif /* NOXFER */
12946
12947       case VN_HWPAR:
12948       case VN_SERIAL: {
12949           int sb;
12950           char c, * ss;
12951           extern int stopbits;
12952           vvbuf[0] = NUL;
12953           if (hwparity && local && !network)
12954             ss = parnam((char)hwparity);
12955           else
12956             ss = parnam((char)parity);
12957           if (cx == VN_HWPAR) {
12958               ckstrncpy(vvbuf,ss,VVBUFL);
12959               return((char *)vvbuf);
12960           }
12961           c = ss[0];
12962           if (islower(c)) c = toupper(c);
12963           sb = stopbits;
12964           if (sb < 1)
12965             sb = (speed > 0 && speed <= 110L) ? 2 : 1;
12966           if (hwparity)
12967             sprintf(vvbuf," 8%c%d",c,sb); /* SAFE */
12968           else if (parity)
12969             sprintf(vvbuf," 7%c%d",c,sb); /* SAFE */
12970           else
12971             sprintf(vvbuf," 8N%d",sb);  /* SAFE */
12972           return((char *)vvbuf);
12973       }
12974
12975 #ifdef UNIX
12976       case VN_LCKDIR: {
12977 #ifndef NOUUCP
12978           extern char * uucplockdir;
12979           ckstrncpy(vvbuf,uucplockdir,VVBUFL);
12980           x = strlen(vvbuf);
12981           if (x > 0) {
12982               if (vvbuf[x-1] != '/') {
12983                   vvbuf[x] = '/';
12984                   vvbuf[x+1] = NUL;
12985               }
12986           }
12987 #else
12988           vvbuf[0] = NUL;
12989 #endif /* NOUUCP */
12990           return((char *)vvbuf);
12991       }
12992 #endif /* UNIX */
12993     } /* Break up long switch statements... */
12994
12995     switch(y) {
12996 #ifndef NODIAL
12997       case VN_DM_LP:
12998       case VN_DM_SP:
12999       case VN_DM_PD:
13000       case VN_DM_TD:
13001       case VN_DM_WA:
13002       case VN_DM_WD:
13003       case VN_DM_HF:
13004       case VN_DM_WB:
13005       case VN_DM_RC: {
13006           extern char * getdm();
13007           ckstrncpy(vvbuf,getdm(y),VVBUFL);
13008           return((char *)vvbuf);
13009       }
13010 #endif /* NODIAL */
13011
13012       case VN_TY_LN:
13013       case VN_TY_LC: {
13014           extern int typ_lines;
13015           sprintf(vvbuf,"%d",typ_lines); /* SAFE */
13016           return((char *)vvbuf);
13017       }
13018       case VN_TY_LM: {
13019           extern int typ_mtchs;
13020           sprintf(vvbuf,"%d",typ_mtchs); /* SAFE */
13021           return((char *)vvbuf);
13022       }
13023       case VN_MACLVL:
13024         sprintf(vvbuf,"%d",maclvl);     /* SAFE */
13025         return((char *)vvbuf);
13026     } /* Break up long switch statements... */
13027
13028     switch(y) {
13029 #ifndef NOXFER
13030       case VN_XF_BC:
13031         sprintf(vvbuf,"%d",crunched);   /* SAFE */
13032         return((char *)vvbuf);
13033
13034       case VN_XF_TM:
13035         sprintf(vvbuf,"%d",timeouts);   /* SAFE */
13036         return((char *)vvbuf);
13037
13038       case VN_XF_RX:
13039         sprintf(vvbuf,"%d",retrans);    /* SAFE */
13040         return((char *)vvbuf);
13041 #endif /* NOXFER */
13042
13043       case VN_MS_CD:                    /* Modem signals */
13044       case VN_MS_CTS:
13045       case VN_MS_DSR:
13046       case VN_MS_DTR:
13047       case VN_MS_RI:
13048       case VN_MS_RTS: {
13049           int x, z = -1;
13050           x = ttgmdm();                 /* Try to get them */
13051           if (x > -1) {
13052               switch (y) {
13053                 case VN_MS_CD:  z = (x & BM_DCD) ? 1 : 0; break;
13054                 case VN_MS_DSR: z = (x & BM_DSR) ? 1 : 0; break;
13055                 case VN_MS_CTS: z = (x & BM_CTS) ? 1 : 0; break;
13056 #ifdef MAC
13057                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
13058 #else
13059 #ifndef STRATUS
13060                 case VN_MS_RI:  z = (x & BM_RNG) ? 1 : 0; break;
13061 #ifndef NT
13062                 case VN_MS_DTR: z = (x & BM_DTR) ? 1 : 0; break;
13063                 case VN_MS_RTS: z = (x & BM_RTS) ? 1 : 0; break;
13064 #endif /* NT */
13065 #endif /* STRATUS */
13066 #endif /* MAC */
13067               }
13068           }
13069           sprintf(vvbuf,"%d",z);        /* SAFE */
13070           return((char *)vvbuf);
13071       }
13072       case VN_MATCH:                    /* INPUT MATCH */
13073         return(inpmatch ? inpmatch : "");
13074
13075 #ifdef CKFLOAT
13076       case VN_ISCALE:                   /* INPUT SCALE-FACTOR */
13077         return(inpscale ? inpscale : "1.0");
13078 #endif  /* CKFLOAT */
13079
13080       case VN_SLMSG: {                  /* SET LINE / HOST message */
13081           extern char * slmsg;
13082           vvbuf[0] = NUL;
13083           if (slmsg)
13084             ckstrncpy(vvbuf,slmsg,VVBUFL);
13085          return(vvbuf);
13086       }
13087
13088       case VN_TXTDIR:                   /* TEXTDIR */
13089         return(k_info_dir ? k_info_dir : "");
13090
13091 #ifdef FNFLOAT
13092       case VN_MA_PI:
13093         return(math_pi);
13094
13095       case VN_MA_E:
13096         return(math_e);
13097
13098       case VN_MA_PR:
13099         sprintf(vvbuf,"%d",fp_digits);  /* SAFE */
13100         return(vvbuf);
13101 #endif /* FNFLOAT */
13102
13103       case VN_CMDBL:
13104         sprintf(vvbuf,"%d",CMDBL);      /* SAFE */
13105         return(vvbuf);
13106
13107 #ifdef CKCHANNELIO
13108       case VN_FERR: {
13109           extern int z_error;
13110           sprintf(vvbuf,"%d",z_error);  /* SAFE */
13111           return(vvbuf);
13112       }
13113       case VN_FMAX: {
13114           extern int z_maxchan;
13115           sprintf(vvbuf,"%d",z_maxchan); /* SAFE */
13116           return(vvbuf);
13117       }
13118       case VN_FCOU: {
13119           extern int z_filcount;
13120           sprintf(vvbuf,"%d",z_filcount); /* SAFE */
13121           return(vvbuf);
13122       }
13123 #endif /* CKCHANNELIO */
13124
13125 #ifndef NODIAL
13126       case VN_DRTR: {
13127           extern int dialcount;
13128           sprintf(vvbuf,"%d",dialcount); /* SAFE */
13129           return(vvbuf);
13130       }
13131 #endif /* NODIAL */
13132
13133 #ifndef NOLOGDIAL
13134 #ifndef NOLOCAL
13135       case VN_CXTIME:
13136         sprintf(vvbuf,"%ld",dologshow(0)); /* SAFE */
13137         return(vvbuf);
13138 #endif /* NOLOCAL */
13139 #endif /* NOLOGDIAL */
13140
13141       case VN_BYTE:
13142         sprintf(vvbuf,"%d",byteorder);  /* SAFE */
13143         return(vvbuf);
13144
13145       case VN_KBCHAR:
13146         vvbuf[0] = NUL;
13147         vvbuf[1] = NUL;
13148         if (kbchar > 0)
13149           vvbuf[0] = (kbchar & 0xff);
13150         return(vvbuf);
13151
13152       case VN_TTYNAM: {
13153 #ifdef HAVECTTNAM
13154           extern char cttnam[];
13155           return((char *)cttnam);
13156 #else
13157           return(CTTNAM);
13158 #endif /* HAVECTTNAM */
13159       }
13160
13161       case VN_PROMPT:
13162         return(cmgetp());
13163
13164       case VN_BUILD: {
13165           extern char * buildid;
13166           return(buildid);
13167       }
13168
13169 #ifndef NOSEXP
13170       case VN_SEXP: {
13171           extern char * lastsexp;
13172           return(lastsexp ? lastsexp : "");
13173       }
13174       case VN_VSEXP: {
13175           extern char * sexpval;
13176           return(sexpval ? sexpval : "");
13177       }
13178       case VN_LSEXP: {
13179           extern int sexpdep;
13180           ckstrncpy(vvbuf,ckitoa(sexpdep),VVBUFL);
13181           return(vvbuf);
13182       }
13183 #endif /* NOSEXP */
13184
13185 #ifdef GFTIMER
13186       case VN_FTIME: {
13187           CKFLOAT f;
13188           ztime(&p);
13189           if (p == NULL || *p == NUL)
13190             return(NULL);
13191           z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
13192           f = (CKFLOAT)z + ((CKFLOAT)ztusec) / 1000000.0;
13193           sprintf(vvbuf,"%f",f);        /* SAFE */
13194           return(vvbuf);
13195       }
13196 #endif /* GFTIMER */
13197
13198 #ifndef NOHTTP
13199       case VN_HTTP_C: {                 /* HTTP Code */
13200           extern int http_code;
13201           return(ckitoa(http_code));
13202       }
13203       case VN_HTTP_N:                   /* HTTP Connected */
13204         return( http_isconnected() ? "1" : "0");
13205       case VN_HTTP_H:                   /* HTTP Host */
13206         return( (char *)http_host() );
13207       case VN_HTTP_M: {                 /* HTTP Message */
13208           extern char http_reply_str[];
13209           return((char *)http_reply_str);
13210       }
13211       case VN_HTTP_S:                   /* HTTP Security */
13212         return((char *)http_security());
13213 #endif /* NOHTTP */
13214
13215 #ifdef NEWFTP
13216       case VN_FTP_B:
13217         return((char *)ftp_cpl_mode());
13218       case VN_FTP_D:
13219         return((char *)ftp_dpl_mode());
13220       case VN_FTP_Z:
13221         return((char *)ftp_authtype());
13222       case VN_FTP_C: {
13223           extern int ftpcode;
13224           return(ckitoa(ftpcode));
13225       }
13226       case VN_FTP_M: {
13227           extern char ftp_reply_str[];
13228           if (isdigit(ftp_reply_str[0]) &&
13229               isdigit(ftp_reply_str[1]) &&
13230               isdigit(ftp_reply_str[2]) &&
13231               ftp_reply_str[3] == ' ')
13232             return(&ftp_reply_str[4]);
13233           else
13234             return(ftp_reply_str);
13235       }
13236       case VN_FTP_S: {
13237           extern char ftp_srvtyp[];
13238           return((char *)ftp_srvtyp);
13239       }
13240       case VN_FTP_H: {
13241           extern char * ftp_host;
13242           return(ftp_host ? ftp_host : "");
13243       }
13244       case VN_FTP_X: {                  /* FTP Connected */
13245           extern int ftpisconnected();
13246           return(ftpisconnected() ? "1" : "0");
13247       }
13248       case VN_FTP_L: {                  /* FTP Logged in */
13249           extern int ftpisloggedin();
13250           return(ftpisloggedin() ? "1" : "0");
13251       }
13252       case VN_FTP_G: {                  /* FTP GET-PUT-REMOTE */
13253           extern int ftpget;
13254           char * s = "";
13255           switch (ftpget) {
13256             case 0: s = "kermit"; break;
13257             case 1: s = "ftp"; break;
13258             case 2: s = "auto"; break;
13259           }
13260           return(s);
13261       }
13262 #endif /* NEWFTP */
13263
13264 #ifndef NOLOCAL
13265       case VN_CX_STA: {                 /* CONNECT status */
13266           extern int cx_status;
13267           return(ckitoa(cx_status));
13268       }
13269 #endif /* NOLOCAL */
13270       case VN_NOW:                      /* Timestamp */
13271         return(ckcvtdate(p,0));
13272
13273       case VN_HOUR:                     /* Hour of the day */
13274         ztime(&p);                      /* "Thu Feb  8 12:00:00 1990" */
13275         if (!p) p = "";
13276         if (!*p) return(p);
13277         vvbuf[0] = p[11];
13278         vvbuf[1] = p[12];
13279         vvbuf[2] = NUL;
13280         return(vvbuf);                  /* and return it */
13281
13282       case VN_LOG_CON:                  /* \v(...) for log files */
13283 #ifdef CKLOGDIAL
13284         return(diafil);
13285 #else 
13286         return("");
13287 #endif
13288       case VN_LOG_PKT:
13289 #ifndef NOXFER
13290         return(pktfil);
13291 #else
13292         return("");
13293 #endif
13294       case VN_LOG_SES:
13295 #ifndef NOLOCAL
13296         return(sesfil);
13297 #else
13298         return("");
13299 #endif
13300       case VN_LOG_TRA:
13301 #ifdef TLOG
13302         return(trafil);
13303 #else
13304         return("");
13305 #endif
13306       case VN_LOG_DEB:
13307 #ifdef DEBUG
13308         return(debfil);
13309 #else
13310         return("");
13311 #endif
13312     }
13313
13314 #ifndef NODIAL
13315     switch (y) {                        /* Caller ID values */
13316       extern char
13317         * callid_date, * callid_time, * callid_name,
13318         * callid_nmbr, * callid_mesg;
13319
13320       case VN_CI_DA:
13321         return(callid_date ? callid_date : "");
13322
13323       case VN_CI_TI:
13324         return(callid_time ? callid_time : "");
13325
13326       case VN_CI_NA:
13327         return(callid_name ? callid_name : "");
13328
13329       case VN_CI_NU:
13330         return(callid_nmbr ? callid_nmbr : "");
13331
13332       case VN_CI_ME:
13333         return(callid_mesg ? callid_mesg : "");
13334
13335     } /* End of variable-name switches */
13336 #endif /* NODIAL */
13337
13338 #ifdef NT
13339     switch (y) {
13340       case VN_PERSONAL:
13341         p = (char *)GetPersonal();
13342         if (p) {
13343             GetShortPathName(p,vvbuf,VVBUFL);
13344             return(vvbuf);
13345         }
13346         return("");
13347       case VN_DESKTOP:
13348           p = (char *)GetDesktop();
13349           if (p) {
13350               GetShortPathName(p,vvbuf,VVBUFL);
13351               return(vvbuf);
13352           }
13353           return("");
13354       case VN_COMMON:
13355         p = (char *)GetAppData(1);
13356         if (p) {
13357             ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
13358             GetShortPathName(vvbuf,vvbuf,VVBUFL);
13359             return(vvbuf);
13360         }
13361         return("");
13362       case VN_APPDATA:
13363         p = (char *)GetAppData(0);
13364         if (p) {
13365             ckmakmsg(vvbuf,VVBUFL,p,"Kermit 95/",NULL,NULL);
13366             GetShortPathName(vvbuf,vvbuf,VVBUFL);
13367             return(vvbuf);
13368         }
13369         return("");
13370     }
13371 #endif /* NT */
13372
13373 #ifdef TN_COMPORT
13374     switch (y) {
13375       case VN_TNC_SIG: {
13376         p = (char *) tnc_get_signature();
13377         ckstrncpy(vvbuf,p ? p : "",VVBUFL);
13378         return(vvbuf);
13379       }
13380     }
13381 #endif /* TN_COMPORT */
13382
13383 #ifdef KUI
13384     switch (y) {
13385       case VN_GUI_RUN: {
13386           extern HWND getHwndKUI();
13387           if ( IsIconic(getHwndKUI()) )
13388             return("minimized");
13389           if ( IsZoomed(getHwndKUI()) )
13390             return("maximized");
13391           return("restored");
13392       }
13393       case VN_GUI_XP:
13394         sprintf(vvbuf,"%d",get_gui_window_pos_x());  /* SAFE */
13395         return(vvbuf);
13396       case VN_GUI_YP:
13397         sprintf(vvbuf,"%d",get_gui_window_pos_y());  /* SAFE */
13398         return(vvbuf);
13399       case VN_GUI_XR:
13400         sprintf(vvbuf,"%d",GetSystemMetrics(SM_CXSCREEN));  /* SAFE */
13401         return(vvbuf);
13402       case VN_GUI_YR:
13403         sprintf(vvbuf,"%d",GetSystemMetrics(SM_CYSCREEN));  /* SAFE */
13404         return(vvbuf);
13405       case VN_GUI_FNM:
13406           if ( ntermfont > 0 ) {
13407               int i;
13408               for (i = 0; i < ntermfont; i++) {
13409                   if (tt_font == term_font[i].kwval) {
13410                       ckstrncpy(vvbuf,term_font[i].kwd,VVBUFL);
13411                       return(vvbuf);
13412                   }
13413               }
13414           }
13415           return("(unknown)");
13416       case VN_GUI_FSZ:
13417           ckstrncpy(vvbuf,ckitoa(tt_font_size/2),VVBUFL);
13418           if ( tt_font_size % 2 )
13419               ckstrncat(vvbuf,".5",VVBUFL);
13420           return(vvbuf);
13421     }
13422 #endif /* KUI */
13423
13424     fnsuccess = 0;
13425     if (fnerror) {
13426         fnsuccess = 0;
13427     }
13428     if (fndiags) {
13429         if (!embuf)
13430           ckstrncpy(embuf,"<ERROR:NO_SUCH_VARIABLE>",EMBUFLEN);
13431         printf("?%s\n",embuf);
13432         return((char *)embuf);
13433     } else
13434       return("");
13435 }
13436 #endif /* NOSPL */
13437
13438
13439 /*
13440   X X S T R I N G  --  Expand variables and backslash codes.
13441
13442     int xxtstring(s,&s2,&n);
13443
13444   Expands \ escapes via recursive descent.
13445   Argument s is a pointer to string to expand (source).
13446   Argument s2 is the address of where to put result (destination).
13447   Argument n is the length of the destination string (to prevent overruns).
13448   Returns -1 on failure, 0 on success,
13449     with destination string null-terminated and s2 pointing to the
13450     terminating null, so that subsequent characters can be added.
13451 */
13452
13453 #define XXDEPLIM 100                    /* Recursion depth limit */
13454 /*
13455   In Windows the stack is limited to 256K so big character arrays like
13456   vnambuf can't be on the stack in recursive functions like zzstring().
13457   But that's no reason use malloc() in Unix or VMS, which don't have
13458   this kind of restriction.
13459 */
13460 #ifdef DVNAMBUF                         /* Dynamic vnambuf[] */
13461 #undef DVNAMBUF                         /* Clean slate */
13462 #endif /* DVNAMBUF */
13463
13464 #ifndef NOSPL                           /* Only if SPL included */
13465 #ifdef OS2                              /* Only for K95 */
13466 #define DVNAMBUF
13467 #endif /* OS2 */
13468 #endif /* NOSPL */
13469
13470 int
13471 zzstring(s,s2,n) char *s; char **s2; int *n; {
13472     int x,                              /* Current character */
13473         y,                              /* Worker */
13474         pp,                             /* Paren level */
13475         kp,                             /* Brace level */
13476         argn,                           /* Function argument counter */
13477         n2,                             /* Local copy of n */
13478         d,                              /* Array dimension */
13479         vbi,                            /* Variable id (integer form) */
13480         argl,                           /* String argument length */
13481         nx;                             /* Save original length */
13482
13483     char vb,                            /* Variable id (char form) */
13484         *vp,                            /* Pointer to variable definition */
13485         *new,                           /* Local pointer to target string */
13486 #ifdef COMMENT
13487         *old,                           /* Save original target pointer */
13488 #endif /* COMMENT */
13489         *p,                             /* Worker */
13490         *q,                             /* Worker */
13491         *s3;                            /* Worker */
13492     int  x3;                            /* Worker */
13493     char *r  = (char *)0;               /* For holding function args */
13494     char *r2 = (char *)0;
13495     char *r3p;
13496
13497 #ifndef NOSPL
13498 #ifdef DVNAMBUF
13499     char * vnambuf = NULL;              /* Buffer for variable/function name */
13500 #else /* DVNAMBUF */
13501     char vnambuf[VNAML];                /* Buffer for variable/function name */
13502 #endif /* DVNAMBUF */
13503     char *argp[FNARGS];                 /* Pointers to function args */
13504 #endif /* NOSPL */
13505
13506     static int depth = 0;               /* Call depth, avoid overflow */
13507
13508     n2 = *n;                            /* Make local copies of args */
13509     nx = n2;
13510
13511     new = *s2;                          /* for one less level of indirection */
13512 #ifdef COMMENT
13513     old = new;
13514 #endif /* COMMENT */
13515
13516 #ifndef NOSPL
13517     ispattern = 0;                      /* For \fpattern() */
13518     isjoin = 0;                         /* For \fjoin() */
13519 #endif /* NOSPL */
13520     depth++;                            /* Sink to a new depth */
13521     if (depth > XXDEPLIM) {             /* Too deep? */
13522         printf("?definition is circular or too deep\n");
13523         debug(F101,"zzstring fail","",depth);
13524         depth = 0;
13525         *new = NUL;
13526         return(-1);
13527     }
13528     if (!s || !new) {                   /* Watch out for null pointers */
13529         debug(F101,"zzstring fail 2","",depth);
13530         if (new)
13531           *new = NUL;
13532         depth = 0;
13533         return(-1);
13534     }
13535     s3 = s;
13536     argl = 0;
13537     while (*s3++) argl++;              /* Get length of source string */
13538     debug(F010,"zzstring entry",s,0);
13539     if (argl == 0) {                    /* Empty string */
13540         debug(F111,"zzstring empty arg",s,argl);
13541         depth = 0;
13542         *new = NUL;
13543         return(0);
13544     }
13545     if (argl < 0) {                     /* Watch out for garbage */
13546         debug(F101,"zzstring fail 3","",depth);
13547         *new = NUL;
13548         depth = 0;
13549         return(-1);
13550     }
13551 #ifdef DVNAMBUF
13552     debug(F100,"vnambuf malloc...","",0);
13553     vnambuf = malloc(VNAML);
13554     if (vnambuf == NULL) {
13555         printf("?Out of memory");
13556         return(-1);
13557     }
13558     debug(F100,"vnambuf malloc ok","",0);
13559 #endif /* DVNAMBUF */
13560
13561     while ((x = *s)) {                  /* Loop for all characters */
13562         if (x != CMDQ) {                /* Is it the command-quote char? */
13563             *new++ = *s++;              /* No, normal char, just copy */
13564             if (--n2 < 0) {             /* and count it, careful of overflow */
13565                 debug(F101,"zzstring overflow 1","",depth);
13566                 depth = 0;
13567 #ifdef DVNAMBUF
13568                 if (vnambuf) free(vnambuf);
13569 #endif /* DVNAMBUF */
13570                 return(-1);
13571             }
13572             continue;
13573         }
13574
13575 /* We have the command-quote character. */
13576
13577         x = *(s+1);                     /* Get the following character. */
13578         if (isupper(x)) x = tolower(x);
13579         switch (x) {                    /* Act according to variable type */
13580 #ifndef NOSPL
13581           case 0:                       /* It's a lone backslash */
13582             *new++ = *s++;
13583             if (--n2 < 0) {
13584                 debug(F101,"zzstring overflow 2","",0);
13585 #ifdef DVNAMBUF
13586                 if (vnambuf) free(vnambuf);
13587 #endif /* DVNAMBUF */
13588                 return(-1);
13589             }
13590             break;
13591           case '%':                     /* Variable */
13592             s += 2;                     /* Get the letter or digit */
13593             vb = *s++;                  /* and move source pointer past it */
13594             vp = NULL;                  /* Assume definition is empty */
13595             if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
13596                 if (maclvl < 0)         /* Digit variables are global */
13597                   vp = g_var[vb];       /* if no macro is active */
13598                 else                    /* otherwise */
13599                   vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
13600             } else if (vb == '*') {     /* Macro args string */
13601 #ifdef COMMENT
13602                 /* This doesn't take changes into account */
13603                 vp = (maclvl >= 0) ? m_line[maclvl] : topline;
13604                 if (!vp) vp = "";
13605 #else
13606                 char * ss = new;
13607                 if (zzstring("\\fjoin(&_[],,1)",&new,&n2) < 0) {
13608 #ifdef DVNAMBUF
13609                     if (vnambuf) free(vnambuf);
13610 #endif /* DVNAMBUF */
13611                     return(-1);
13612                 }
13613                 debug(F110,"zzstring \\%*",ss,0);
13614                 break;
13615 #endif /* COMMENT */
13616             } else {
13617                 if (isupper(vb)) vb += ('a'-'A');
13618                 vp = g_var[vb];         /* Letter for global variable */
13619             }
13620             if (!vp) vp = "";
13621 #ifdef COMMENT
13622             if (vp) {                   /* If definition not empty */
13623 #endif /* COMMENT */
13624                 debug(F010,"zzstring %n vp",vp,0);
13625                 if (zzstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
13626                     debug(F101,"zzstring fail 6","",depth);
13627 #ifdef DVNAMBUF
13628                     if (vnambuf) free(vnambuf);
13629 #endif /* DVNAMBUF */
13630                     return(-1);         /* Pass along failure */
13631                 }
13632 #ifdef COMMENT
13633             } else {
13634                 debug(F110,"zzstring %n vp","(NULL)",0);
13635                 n2 = nx;
13636                 new = old;
13637                 *new = NUL;
13638             }
13639 #endif /* COMMENT */
13640             break;
13641           case '&':                     /* An array reference */
13642             x = arraynam(s,&vbi,&d);    /* Get name and subscript */
13643             debug(F111,"zzstring arraynam",s,x);
13644             if (x < 0) {
13645                 debug(F101,"zzstring fail 7","",depth);
13646 #ifdef DVNAMBUF
13647                 if (vnambuf) free(vnambuf);
13648 #endif /* DVNAMBUF */
13649                 return(-1);
13650             }
13651             pp = 0;                     /* Bracket counter */
13652             while (*s) {                /* Advance source pointer... */
13653                 if (*s == '[') pp++;
13654                 if (*s == ']' && --pp == 0) break;
13655                 s++;
13656             }
13657             if (*s == ']') s++;         /* ...past the closing bracket. */
13658
13659             x = chkarray(vbi,d);        /* Array is declared? */
13660             debug(F101,"zzstring chkarray","",x);
13661             if (x > 0) {
13662 #ifdef COMMENT
13663                 char * s1 = NULL;
13664 #endif /* COMMENT */
13665                 vbi -= ARRAYBASE;       /* Convert name to index */
13666
13667 #ifdef COMMENT
13668                 if (vbi == 0) {         /* Argument vector array */
13669                     extern char ** toparg, ** m_xarg[];
13670                     extern int n_xarg[];
13671                     if (maclvl < 0) {
13672                         if (topargc >= d) {
13673                             s1 = toparg[d];
13674                         }
13675                     } else {
13676                         if (n_xarg[maclvl] >= d) {
13677                             s1 = m_xarg[maclvl][d];
13678                         }
13679                     }
13680                     if (s1) {
13681                         if (zzstring(s1,&new,&n2) < 0) { /* evaluate */
13682                             debug(F101,"zzstring fail 7.5","",depth);
13683 #ifdef DVNAMBUF
13684                             if (vnambuf) free(vnambuf);
13685 #endif /* DVNAMBUF */
13686                             return(-1); /* Pass along failure */
13687                         }
13688                     } else {
13689                         /* old = new; */
13690                         n2 = nx;
13691                     }
13692                 } else
13693 #endif /* COMMENT */
13694                   if (a_dim[vbi] >= d) { /* If subscript in range */
13695                     char **ap;
13696 #ifndef COMMENT
13697                     debug(F110,"zzstring a_ptr[vbi]",a_ptr[vbi],0);
13698                     debug(F110,"zzstring a_ptr[vbi][d]",a_ptr[vbi][d],0);
13699 #endif /* COMMENT */
13700                     ap = a_ptr[vbi];    /* get data pointer */
13701                     if (ap) {           /* and if there is one */
13702                         if (ap[d]) {    /* If definition not empty */
13703                             debug(F111,"zzstring ap[d]",ap[d],d);
13704                             if (zzstring(ap[d],&new,&n2) < 0) { /* evaluate */
13705                                 debug(F101,"zzstring fail 8","",depth);
13706 #ifdef DVNAMBUF
13707                                 if (vnambuf) free(vnambuf);
13708 #endif /* DVNAMBUF */
13709                                 return(-1); /* Pass along failure */
13710                             }
13711                         }
13712                     } else {
13713                         /* old = new; */
13714                         n2 = nx;
13715                     }
13716                 }
13717             }
13718             break;
13719
13720           case 'f':                     /* A builtin function */
13721             q = vnambuf;                /* Copy the name */
13722             y = 0;                      /* into a separate buffer */
13723             s += 2;                     /* point past 'F' */
13724             while (y++ < VNAML) {
13725                 if (*s == '(') { s++; break; } /* Look for open paren */
13726                 if ((*q = *s) == NUL) break;   /* or end of string */
13727                 s++; q++;
13728             }
13729             *q = NUL;                   /* Terminate function name */
13730             if (y >= VNAML) {           /* Handle pathological case */
13731                 while (*s && (*s != '(')) /* of very long string entered */
13732                   s++;                    /* as function name. */
13733                 if (*s == ')') s++;       /* Skip past it. */
13734             }
13735             r = r2 = malloc(argl+2);    /* And make a place to copy args */
13736             /* debug(F101,"zzstring r2","",r2); */
13737             if (!r2) {                  /* Watch out for malloc failure */
13738                 debug(F101,"zzstring fail 9","",depth);
13739                 *new = NUL;
13740                 depth = 0;
13741 #ifdef DVNAMBUF
13742                 if (vnambuf) free(vnambuf);
13743 #endif /* DVNAMBUF */
13744                 return(-1);
13745             }
13746             if (r3) free(r3); /* And another to copy literal arg string */
13747             r3 = malloc(argl+2);
13748             /* debug(F101,"zzstring r3","",r3); */
13749             if (!r3) {
13750                 debug(F101,"zzstring fail 10","",depth);
13751                 depth = 0;
13752                 *new = NUL;
13753                 if (r2) free(r2);
13754 #ifdef DVNAMBUF
13755                 if (vnambuf) free(vnambuf);
13756 #endif /* DVNAMBUF */
13757                 return(-1);
13758             } else
13759               r3p = r3;
13760             argn = 0;                   /* Argument counter */
13761             argp[argn++] = r;           /* Point to first argument */
13762             y = 0;                      /* Completion flag */
13763             pp = 1;                     /* Paren level (already have one). */
13764             kp = 0;
13765             while (1) {                 /* Copy each argument, char by char. */
13766                 *r3p++ = *s;            /* This is a literal copy for \flit */
13767                 if (!*s) break;
13768
13769                 if (*s == '{') {        /* Left brace */
13770                     kp++;
13771                 }
13772                 if (*s == '}') {        /* Right brace */
13773                     kp--;
13774                 }
13775                 if (*s == '(' && kp <= 0) { /* Open paren not in brace */
13776                     pp++;               /* Count it */
13777                 }
13778                 *r = *s;                /* Now copy resulting byte */
13779                 if (!*r)                /* If NUL, done. */
13780                   break;
13781                 if (*r == ')' && kp <= 0) { /* Closing paren, count it. */
13782                     if (--pp == 0) {    /* Final one? */
13783                         *r = NUL;       /* Make it a terminating null */
13784                         *(r3p - 1) = NUL;
13785                         s++;            /* Point past it in source string */
13786                         y = 1;          /* Flag we've got all the args */
13787                         break;          /* Done with while loop */
13788                     }
13789                 }
13790                 if (*r == ',' && kp <= 0) { /* Comma */
13791                     if (pp == 1) {          /* If not within ()'s, */
13792                         if (argn >= FNARGS) { /* Too many args */
13793                             s++; r++;   /* Keep collecting flit() string */
13794                             continue;
13795                         }
13796                         *r = NUL;           /* New arg, skip past comma */
13797                         argp[argn++] = r+1; /* In range, point to new arg */
13798                     }                   /* Otherwise just skip past  */
13799                 }
13800                 s++; r++;               /* Advance pointers */
13801             }
13802             if (!y)                     /* If we didn't find closing paren */
13803               argn = -1;
13804 #ifdef DEBUG
13805             if (deblog) {
13806                 char buf[24];
13807                 debug(F111,"zzstring function name",vnambuf,y);
13808                 debug(F010,"zzstring function r3",r3,0);
13809                 for (y = 0; y < argn; y++) {
13810                     sprintf(buf,"arg %2d ",y);
13811                     debug(F010,buf,argp[y],0);
13812                 }
13813             }
13814 #endif /* DEBUG */
13815             vp = fneval(vnambuf,argp,argn,r3); /* Evaluate the function. */
13816             if (vp) {                      /* If definition not empty */
13817                 while ((*new++ = *vp++)) { /* copy it to output string */
13818                     if (--n2 < 0) {        /* watch out for overflow */
13819                         debug(F101,"zzstring fail 12","",depth);
13820                         if (r2) { free(r2); r2 = NULL; }
13821                         if (r3) { free(r3); r3 = NULL; }
13822 #ifdef DVNAMBUF
13823                         if (vnambuf) free(vnambuf);
13824 #endif /* DVNAMBUF */
13825                         return(-1);
13826                     }
13827                 }
13828                 new--;                  /* Back up over terminating null */
13829                 n2++;                   /* to allow for further deposits. */
13830             }
13831             if (r2) { free(r2); r2 = NULL; }
13832             if (r3) { free(r3); r3 = NULL; }
13833             break;
13834           case '$':                     /* An environment variable */
13835           case 'v':                     /* Or a named builtin variable. */
13836           case 'm':                     /* Or a macro /long variable */
13837           case 's':                     /* 196 Macro substring */
13838           case ':':                     /* 196 \-variable substring */
13839             pp = 0;
13840             p = s+2;                    /* $/V/M must be followed by (name) */
13841             if (*p != '(') {            /* as in \$(HOME) or \V(count) */
13842                 *new++ = *s++;          /* If not, just copy it */
13843                 if (--n2 < 0) {
13844                     debug(F101,"zzstring overflow 3","",depth);
13845 #ifdef DVNAMBUF
13846                     if (vnambuf) free(vnambuf);
13847 #endif /* DVNAMBUF */
13848                     return(-1);
13849                 }
13850                 break;
13851             }
13852             pp++;
13853             p++;                        /* Point to 1st char of name */
13854             q = vnambuf;                /* Copy the name */
13855             y = 0;                      /* into a separate buffer */
13856             while (y++ < VNAML) {       /* Watch out for name too long */
13857                 if (*p == '(') {        /* Parens can be nested... */
13858                     pp++;
13859                 } else if (*p == ')') { /* Name properly terminated with ')' */
13860                     pp--;
13861                     if (pp == 0) {
13862                         p++;            /* Move source pointer past ')' */
13863                         break;
13864                     }
13865                 }
13866                 if ((*q = *p) == NUL)   /* String ends before ')' */
13867                   break;
13868                 p++; q++;               /* Advance pointers */
13869             }
13870             *q = NUL;                   /* Terminate the variable name */
13871             if (y >= VNAML) {           /* Handle pathological case */
13872                 while (*p && (*p != ')')) /* of very long string entered */
13873                   p++;                    /* as variable name. */
13874                 if (*p == ')') p++;       /* Skip ahead to the end of it. */
13875             }
13876             s = p;                      /* Adjust global source pointer */
13877             s3 = vnambuf;
13878             x3 = 0;
13879             while (*s3++) x3++;
13880             p = malloc(x3 + 1);         /* Make temporary space */
13881             if (p) {                    /* If we got the space */
13882                 vp = vnambuf;           /* Point to original */
13883                 strcpy(p,vp);           /* (safe) Make a copy of it */
13884                 y = VNAML;              /* Length of name buffer */
13885                 zzstring(p,&vp,&y);     /* Evaluate the copy */
13886                 free(p);                /* Free the temporary space */
13887                 p = NULL;
13888             }
13889             debug(F110,"zzstring vname",vnambuf,0);
13890             q = NULL;
13891             if (x == '$') {             /* Look up its value */
13892                 vp = getenv(vnambuf);   /* This way for environment variable */
13893             } else if (x == 'm' || x == 's' || x == ':') { /* Macro / substr */
13894                 int k, x1 = -1, x2 = -1;
13895                 k = strlen(vnambuf);
13896                 /* \s(name[n:m]) -- Compact substring notation */
13897                 if ((x == 's' || x == ':') && (k > 1)) { /* Substring wanted */
13898                     if (vnambuf[k-1] == ']') {
13899                         int i;
13900                         for (i = k-1; i > 0; i--) {
13901                             if (vnambuf[i] == '[') {
13902                                 char * p = NULL;
13903                                 p = (char *)malloc(k - i + 8);
13904                                 if (p) {
13905                                     /* Now this is a dirty trick... */
13906                                     ckmakmsg(p,
13907                                              k-i+8,
13908                                              "\\&a",
13909                                              &vnambuf[i],
13910                                              NULL,
13911                                              NULL
13912                                              );
13913                                     arraybounds(p,&x1,&x2);
13914                                     if (x1 < 1) x1 = 1;
13915                                     x1--; /* Adjust to 0-base */
13916                                     free(p);
13917                                     vnambuf[i] = NUL;
13918                                 }
13919                             }
13920                         }
13921                     }
13922                 }
13923                 if (x == ':') {
13924                     vp = vnambuf;
13925                 } else {
13926                     y = isaarray(vnambuf) ?
13927                         mxxlook(mactab,vnambuf,nmac) :
13928                         mxlook(mactab,vnambuf,nmac);
13929                     if (y > -1) {       /* Got definition */
13930                         vp = mactab[y].mval;
13931                     } else {
13932                         vp = NULL;
13933                     }
13934                 }
13935                 if (vp) {
13936                     if ((x == 's' || x == ':') && (k > 1)) {
13937                         /* Compact substring notation */
13938                         if (x2 == 0) {  /* Length */
13939                             vp = NULL;
13940                         } else if (x1 > -1) { /* Start */
13941                             k = strlen(vp);
13942                             if (x1 > k) {  /* If it's off the end, */
13943                                 vp = NULL; /* result is empty */
13944                             } else if (k > 0) {
13945                                 if ((q = malloc(k+1))) {
13946                                     strcpy(q,vp); /* safe */
13947                                     if ((x2 > -1) && ((x1 + x2) <= k)) {
13948                                         q[x1+x2] = NUL;
13949                                     }
13950                                     vp = q+x1;
13951                                 }  else vp = NULL;
13952                             } else vp = NULL;
13953                         }
13954 #ifdef DEBUG
13955                         if (deblog) {
13956                             if (!vp) {
13957                             } else {
13958                                 k = strlen(vp);
13959                             }
13960                         }
13961 #endif /* DEBUG */
13962                     }
13963                 }
13964             } else {                    /* or */
13965                 vp = nvlook(vnambuf);   /* this way for builtin variable */
13966             }
13967             if (vp) {                   /* If definition not empty */
13968                 while ((*new++ = *vp++)) /* copy it to output string. */
13969                   if (--n2 < 0) {
13970                       if (q) free(q);
13971                       debug(F101,"zzstring overflow 4","",depth);
13972 #ifdef DVNAMBUF
13973                       if (vnambuf) free(vnambuf);
13974 #endif /* DVNAMBUF */
13975                       return(-1);
13976                   }
13977                 new--;                  /* Back up over terminating null */
13978                 n2++;                   /* to allow for further deposits. */
13979             }
13980             if (q) {
13981                 free(q);
13982                 q = NULL;
13983             }
13984             break;
13985 #endif /* NOSPL */                      /* Handle \nnn even if NOSPL. */
13986
13987 #ifndef NOKVERBS
13988         case 'K':
13989         case 'k': {
13990             extern struct keytab kverbs[];
13991             extern int nkverbs;
13992 #define K_BUFLEN 30
13993             char kbuf[K_BUFLEN + 1];    /* Key verb name buffer */
13994             int x, y, z, brace = 0;
13995             s += 2;
13996 /*
13997   We assume that the verb name is {braced}, or it extends to the end of the
13998   string, s, or it ends with a space, control character, or backslash.
13999 */
14000             p = kbuf;                   /* Copy verb name into local buffer */
14001             x = 0;
14002             if (*s == '{')  {
14003                 s++;
14004                 brace++;
14005             }
14006             while ((x++ < K_BUFLEN) && (*s > SP) && (*s != CMDQ)) {
14007                 if (brace && *s == '}') {
14008                     s++;
14009                     break;
14010                 }
14011                 *p++ = *s++;
14012             }
14013             brace = 0;
14014             *p = NUL;                   /* Terminate. */
14015             p = kbuf;                   /* Point back to beginning */
14016             debug(F110,"zzstring kverb",p,0);
14017             y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
14018             debug(F101,"zzstring lookup",0,y);
14019             if (y > -1) {
14020                 dokverb(VCMD,y);
14021 #ifndef NOSPL
14022             } else {                    /* Is it a macro? */
14023                 y = mxlook(mactab,p,nmac);
14024                 if (y > -1) {
14025                     debug(F111,"zzstring mxlook",p,y);
14026                     if ((z = dodo(y,NULL,cmdstk[cmdlvl].ccflgs)) > 0) {
14027                         if (cmpush() > -1) {  /* Push command parser state */
14028                             extern int ifc;
14029                             int ifcsav = ifc; /* Push IF condition on stack */
14030                             y = parser(1);    /* New parser to execute macro */
14031                             cmpop();          /* Pop command parser */
14032                             ifc = ifcsav;     /* Restore IF condition */
14033                             if (y == 0) {     /* No errors, ignore actions */
14034                                 p = mrval[maclvl+1]; /* If OK set return val */
14035                                 if (p == NULL) p = "";
14036                             }
14037                         } else {                /* Can't push any more */
14038                             debug(F101,"zzstring pushed too deep","",depth);
14039                             printf(
14040                                "\n?Internal error: zzstring stack overflow\n"
14041                                    );
14042                             while (cmpop() > -1);
14043                             p = "";
14044                         }
14045                     }
14046                 }
14047 #endif /* NOSPL */
14048             }
14049             break;
14050         }
14051 #endif /* NOKVERBS */
14052
14053         default:                        /* Maybe it's a backslash code */
14054           y = xxesc(&s);                /* Go interpret it */
14055           if (y < 0) {                  /* Upon failure */
14056               *new++ = (char) x;        /* Just quote the next character */
14057               s += 2;                   /* Move past the pair */
14058               n2 -= 2;
14059               if (n2 < 0) {
14060                   debug(F101,"zzstring overflow 5","",depth);
14061 #ifdef DVNAMBUF
14062                   if (vnambuf) free(vnambuf);
14063 #endif /* DVNAMBUF */
14064                   return(-1);
14065               }
14066               continue;                 /* and go back for more */
14067           } else {
14068               *new++ = (char) y;        /* else deposit interpreted value */
14069               if (--n2 < 0) {
14070                   debug(F101,"zzstring overflow 6","",depth);
14071 #ifdef DVNAMBUF
14072                   if (vnambuf) free(vnambuf);
14073 #endif /* DVNAMBUF */
14074                   return(-1);
14075               }
14076           }
14077         }
14078     }
14079     *new = NUL;                         /* Terminate the new string */
14080     debug(F010,"zzstring while exit",*s2,0);
14081
14082     depth--;                            /* Adjust stack depth gauge */
14083     *s2 = new;                          /* Copy results back into */
14084     *n = n2;                            /* the argument addresses */
14085     debug(F101,"zzstring ok","",depth);
14086 #ifdef DVNAMBUF
14087     if (vnambuf) free(vnambuf);
14088 #endif /* DVNAMBUF */
14089     return(0);                          /* and return. */
14090 }
14091 #endif /* NOICP */