home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / tmp9 / ckuus6.c < prev    next >
C/C++ Source or Header  |  2005-12-27  |  369KB  |  10,971 lines

  1. #include "ckcsym.h"
  2. #ifndef NOICP
  3.  
  4. /*  C K U U S 6 --  "User Interface" for Unix Kermit (Part 6)  */
  5.  
  6. /*
  7.   Authors:
  8.     Frank da Cruz <fdc@columbia.edu>,
  9.       The Kermit Project, Columbia University, New York City
  10.     Jeffrey E Altman <jaltman@secure-endpoints.com>
  11.       Secure Endpoints Inc., New York City
  12.  
  13.   Copyright (C) 1985, 2005,
  14.     Trustees of Columbia University in the City of New York.
  15.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  16.     copyright text in the ckcmai.c module for disclaimer and permissions.
  17. */
  18.  
  19. /* Includes */
  20.  
  21. #include "ckcdeb.h"
  22. #include "ckcasc.h"
  23. #include "ckcker.h"
  24. #include "ckuusr.h"
  25. #include "ckcxla.h"
  26. #include "ckcnet.h"                     /* Network symbols */
  27. #include <signal.h>
  28.  
  29. #ifdef VMS
  30. #ifndef TCPSOCKET
  31. #include <errno.h>
  32. #endif /* TCPSOCKET */
  33. #endif /* VMS */
  34.  
  35. #ifdef datageneral
  36. #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
  37. #endif /* datageneral */
  38.  
  39. #ifdef QNX6
  40. #define readblock kreadblock
  41. #endif /* QNX6 */
  42.  
  43. /* External Kermit Variables, see ckmain.c for description. */
  44.  
  45. extern xx_strp xxstring;
  46.  
  47. extern int local, xitsta, binary, parity, escape, flow, cmd_rows, turn,
  48.   turnch, duplex, ckxech, seslog, dfloc, cnflg, tlevel, pflag, msgflg, mdmtyp,
  49.   zincnt, quiet, repars, techo, network, nzxopts, what, filepeek, recursive;
  50.  
  51. extern int xaskmore, tt_rows, tt_cols, cmd_cols, g_matchdot, diractive,
  52.   xcmdsrc, nscanfile, reliable, nolinks;
  53.  
  54. #ifdef VMSORUNIX
  55. extern int zgfs_dir, zgfs_link;
  56. #endif /* VMSORUNIX */
  57.  
  58. #ifdef CK_IFRO
  59.   extern int remonly;
  60. #endif /* CK_IFRO */
  61.  
  62. #ifdef OS2
  63. extern int StartedFromDialer ;
  64. extern int vmode;
  65. extern int k95stdout;
  66. #ifndef NT
  67. #define INCL_NOPM
  68. #define INCL_VIO                        /* Needed for ckocon.h */
  69. #include <os2.h>
  70. #undef COMMENT
  71. #else
  72. #define APIRET ULONG
  73. #include <windows.h>
  74. #include <tapi.h>
  75. #include "ckntap.h"
  76. #endif /* NT */
  77. #include "ckocon.h"
  78. #endif /* OS2 */
  79.  
  80. extern long vernum, speed;
  81. extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
  82. extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
  83. extern char *foz_def[];
  84. extern char *ckxsys, *ckzsys;
  85. #ifndef OS2
  86. extern char *DIRCMD;
  87. #ifndef UNIX
  88. extern char *DELCMD;
  89. #endif /* UNIX */
  90. #endif /* OS2 */
  91. extern char ttname[], filnam[];
  92. extern CHAR sstate, feol;
  93. extern char *zinptr;
  94.  
  95. #ifdef UNIX
  96. extern char ** mtchs;                   /* zxpand() file list */
  97. #endif /* UNIX */
  98.  
  99. #ifndef NOXFER
  100. extern int oopts, omode, oname, opath;  /* O-Packet options */
  101.  
  102. extern int stdinf, sndsrc, size, rpsiz, urpsiz, fncnv, fnrpath, displa,
  103.   stdouf, isguest, pktlog, nfils, keep, maxrps, fblksiz, frecl, frecfm,
  104.   atcapr, atdiso, spsizf, spsiz, spsizr, spmax, wslotr, prefixing,
  105.   fncact, fnspath, nprotos, g_proto, g_urpsiz, g_spsizf,
  106.   g_spsiz, g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact, g_fncnv,
  107.   g_fnspath, g_fnrpath, xfrxla, g_xfrxla;
  108.  
  109. extern char *cmarg, *cmarg2;
  110.  
  111. #ifndef NOMSEND                         /* Multiple SEND */
  112. extern char *msfiles[];
  113. #endif /* NOMSEND */
  114. extern char fspec[];                    /* Most recent filespec */
  115. extern int fspeclen;
  116.  
  117. #ifdef CK_TMPDIR
  118. extern int f_tmpdir;                    /* Directory changed temporarily */
  119. extern char savdir[];                   /* For saving current directory */
  120. #endif /* CK_TMPDIR */
  121.  
  122. extern struct keytab protos[];          /* File transfer protocols */
  123. extern struct ck_p ptab[NPROTOS];
  124. #endif /* NOXFER */
  125.  
  126. #ifdef DCMDBUF                          /* Declarations from cmd package */
  127. extern char *cmdbuf, *atmbuf;           /* Command buffers */
  128. #else
  129. extern char cmdbuf[], atmbuf[];         /* Command buffers */
  130. #endif /* DCMDBUF */
  131.  
  132. extern int nopush;
  133.  
  134. #ifndef NOSPL
  135. int askflag = 0;                        /* ASK-class command active */
  136. int echostars = 0;            /* ASKQ should echo asterisks */
  137. extern char **a_ptr[];
  138. extern int a_dim[];
  139. extern char **m_xarg[];
  140. extern int n_xarg[];
  141. extern struct mtab *mactab;
  142. extern int nmac;
  143. extern long ck_alarm;
  144. extern char alrm_date[], alrm_time[];
  145. extern int x_ifnum;
  146. #endif /* NOSPL */
  147.  
  148. extern int inserver;                    /* I am IKSD */
  149. extern int backgrd;                     /* Kermit executing in background */
  150. extern char psave[];                    /* For saving & restoring prompt */
  151. extern char *tp;                        /* Temporary buffer */
  152.  
  153. int readblock = 4096;                   /* READ buffer size */
  154. CHAR * readbuf = NULL;                  /* Pointer to read buffer */
  155. int readsize = 0;                       /* Number of chars actually read */
  156. int getcmd = 0;                         /* GET-class command was given */
  157.  
  158. extern int zchkod, zchkid;
  159.  
  160. struct keytab deltab[] = {              /* DELETE Command Options */
  161.     { "/all",           DEL_ALL,  CM_INV },
  162.     { "/after",         DEL_AFT,  CM_ARG },
  163.     { "/ask",           DEL_ASK,  0 },
  164.     { "/before",        DEL_BEF,  CM_ARG },
  165.     { "/directories",   DEL_DIR,  0 },
  166.     { "/dotfiles",      DEL_DOT,  0 },
  167.     { "/except",        DEL_EXC,  CM_ARG },
  168.     { "/heading",       DEL_HDG,  0 },
  169.     { "/l",             DEL_LIS,  CM_INV|CM_ABR },
  170.     { "/larger-than",   DEL_LAR,  CM_ARG },
  171.     { "/list",          DEL_LIS,  0 },
  172.     { "/log",           DEL_LIS,  CM_INV },
  173.     { "/noask",         DEL_NAS,  0 },
  174.     { "/nodotfiles",    DEL_NOD,  0 },
  175.     { "/noheading",     DEL_NOH,  0 },
  176.     { "/nol",           DEL_NOL,  CM_INV|CM_ABR },
  177.     { "/nolist",        DEL_NOL,  0 },
  178.     { "/nolog",         DEL_NOL,  CM_INV },
  179.     { "/nopage",        DEL_NOP,  0 },
  180.     { "/not-after",     DEL_NAF,  CM_ARG },
  181.     { "/not-before",    DEL_NBF,  CM_ARG },
  182.     { "/not-since",     DEL_NAF,  CM_INV|CM_ARG },
  183.     { "/page",          DEL_PAG,  0 },
  184.     { "/quiet",         DEL_QUI,  CM_INV },
  185.     { "/recursive",     DEL_REC,  0 },
  186.     { "/simulate",      DEL_SIM,  0 },
  187.     { "/since",         DEL_AFT,  CM_ARG|CM_INV },
  188.     { "/smaller-than",  DEL_SMA,  CM_ARG },
  189.     { "/summary",       DEL_SUM,  0 },
  190.     { "/tree",          DEL_ALL,  0 },
  191.     { "/type",          DEL_TYP,  CM_ARG },
  192.     { "/verbose",       DEL_VRB,  CM_INV }
  193. };
  194. int ndeltab = sizeof(deltab)/sizeof(struct keytab);
  195.  
  196. /* /QUIET-/VERBOSE (/LIST-/NOLIST) (/LOG-/NOLOG) table */
  197.  
  198. struct keytab qvswtab[] = {
  199.     { "/l",           DEL_LIS,  CM_INV|CM_ABR },
  200.     { "/list",        DEL_LIS,  0 },
  201.     { "/log",         DEL_LIS,  CM_INV },
  202.     { "/nol",         DEL_NOL,  CM_INV|CM_ABR },
  203.     { "/nolist",      DEL_NOL,  0 },
  204.     { "/nolog",       DEL_NOL,  CM_INV },
  205.     { "/quiet",       DEL_QUI,  CM_INV },
  206.     { "/verbose",     DEL_VRB,  CM_INV }
  207. };
  208. int nqvswtab = sizeof(qvswtab)/sizeof(struct keytab);
  209.  
  210. struct keytab copytab[] = {
  211.     { "/append",      998,      0 },
  212. #ifndef NOSPL
  213.     { "/fromb64",     997,      0 },
  214. #endif /* NOSPL */
  215.     { "/l",           DEL_LIS,  CM_INV|CM_ABR },
  216.     { "/list",        DEL_LIS,  0 },
  217.     { "/log",         DEL_LIS,  CM_INV },
  218.     { "/nol",         DEL_NOL,  CM_INV|CM_ABR },
  219.     { "/nolist",      DEL_NOL,  0 },
  220.     { "/nolog",       DEL_NOL,  CM_INV },
  221.     { "/quiet",       DEL_QUI,  CM_INV },
  222.     { "/swap-bytes",  999,      0 },
  223. #ifndef NOSPL
  224.     { "/tob64",       996,      0 },
  225. #endif /* NOSPL */
  226.     { "/verbose",     DEL_VRB,  CM_INV }
  227. };
  228. int ncopytab = sizeof(copytab)/sizeof(struct keytab);
  229.  
  230. #ifndef NOXFER
  231. static struct keytab gettab[] = {       /* GET options */
  232.     { "/as-name",         SND_ASN, CM_ARG },
  233.     { "/binary",          SND_BIN, 0 },
  234. #ifdef CALIBRATE
  235.     { "/calibrate",       SND_CAL, CM_INV },
  236. #endif /* CALIBRATE */
  237. #ifdef PIPESEND
  238.     { "/command",         SND_CMD, CM_PSH },
  239. #endif /* PIPESEND */
  240.     { "/delete",          SND_DEL, 0 },
  241.     { "/except",          SND_EXC, CM_ARG },
  242.     { "/filenames",       SND_NAM, CM_ARG },
  243. #ifdef PIPESEND
  244.     { "/filter",          SND_FLT, CM_ARG|CM_PSH },
  245. #endif /* PIPESEND */
  246. #ifdef VMS
  247.     { "/image",           SND_IMG, 0 },
  248.     { "/labeled",         SND_LBL, 0 },
  249. #else
  250.     { "/image",           SND_BIN, CM_INV },
  251. #endif /* VMS */
  252. #ifdef CK_TMPDIR
  253.     { "/move-to",         SND_MOV, CM_ARG },
  254. #endif /* CK_TMPDIR */
  255.     { "/pathnames",       SND_PTH, CM_ARG },
  256.     { "/pipes",           SND_PIP, CM_ARG|CM_PSH },
  257.     { "/quiet",           SND_SHH, 0 },
  258. #ifdef CK_RESEND
  259.     { "/recover",         SND_RES, 0 },
  260. #endif /* CK_RESEND */
  261.     { "/recursive",       SND_REC, 0 },
  262.     { "/rename-to",       SND_REN, CM_ARG },
  263. #ifdef COMMENT
  264.     { "/smaller-than",    SND_SMA, CM_ARG },
  265. #endif /* COMMENT */
  266.     { "/subdirectories",  SND_REC, CM_INV },
  267.     { "/text",            SND_TXT, 0 },
  268.     { "/transparent",     SND_XPA, 0 }
  269. };
  270. #define NGETTAB sizeof(gettab)/sizeof(struct keytab)
  271. static int ngettab = NGETTAB;
  272.  
  273. static struct keytab rcvtab[] = {       /* RECEIVE options */
  274.     { "/as-name",         SND_ASN, CM_ARG },
  275.     { "/binary",          SND_BIN, 0 },
  276. #ifdef CALIBRATE
  277.     { "/calibrate",       SND_CAL, CM_INV },
  278. #endif /* CALIBRATE */
  279. #ifdef PIPESEND
  280.     { "/command",         SND_CMD, CM_PSH },
  281. #endif /* PIPESEND */
  282.     { "/except",          SND_EXC, CM_ARG },
  283.     { "/filenames",       SND_NAM, CM_ARG },
  284. #ifdef PIPESEND
  285.     { "/filter",          SND_FLT, CM_ARG|CM_PSH },
  286. #endif /* PIPESEND */
  287. #ifdef VMS
  288.     { "/image",           SND_IMG, 0 },
  289.     { "/labeled",         SND_LBL, 0 },
  290. #else
  291.     { "/image",           SND_BIN, CM_INV },
  292. #endif /* VMS */
  293. #ifdef CK_TMPDIR
  294.     { "/move-to",         SND_MOV, CM_ARG },
  295. #endif /* CK_TMPDIR */
  296.     { "/pathnames",       SND_PTH, CM_ARG },
  297.     { "/pipes",           SND_PIP, CM_ARG|CM_PSH },
  298. #ifdef CK_XYZ
  299.     { "/protocol",        SND_PRO, CM_ARG },
  300. #else
  301.     { "/protocol",        SND_PRO, CM_ARG|CM_INV },
  302. #endif /* CK_XYZ */
  303.     { "/quiet",           SND_SHH, 0 },
  304.     { "/recursive",       SND_REC, 0 },
  305.     { "/rename-to",       SND_REN, CM_ARG },
  306.     { "/text",            SND_TXT, 0 },
  307.     { "/transparent",     SND_XPA, 0 }
  308. };
  309. #define NRCVTAB sizeof(rcvtab)/sizeof(struct keytab)
  310. static int nrcvtab = NRCVTAB;
  311. #endif /* NOXFER */
  312.  
  313. /* WAIT table */
  314.  
  315. #define WAIT_FIL 997
  316. #define WAIT_MDM 998
  317.  
  318. struct keytab waittab[] = {
  319.     { "cd",            BM_DCD,   CM_INV }, /* (Carrier Detect) */
  320.     { "cts",           BM_CTS,   CM_INV }, /* (Clear To Send)  */
  321.     { "dsr",           BM_DSR,   CM_INV }, /* (Data Set Ready) */
  322.     { "file",          WAIT_FIL, 0 },      /* New category selector keywords */
  323.     { "modem-signals", WAIT_MDM, 0 },      /* ... */
  324.     { "ri",            BM_RNG,   CM_INV }  /* (Ring Indicator) */
  325. };
  326. int nwaittab = (sizeof(waittab) / sizeof(struct keytab));
  327.  
  328. /* Modem signal table */
  329.  
  330. struct keytab mstab[] = {
  331.     { "cd",    BM_DCD, 0 },             /* Carrier Detect */
  332.     { "cts",   BM_CTS, 0 },             /* Clear To Send  */
  333.     { "dsr",   BM_DSR, 0 },             /* Data Set Ready */
  334.     { "ri",    BM_RNG, 0 }              /* Ring Indicator */
  335. };
  336. int nms = (sizeof(mstab) / sizeof(struct keytab));
  337.  
  338. #define WF_MOD 1
  339. #define WF_DEL 2
  340. #define WF_CRE 3
  341.  
  342. struct keytab wfswi[] = {               /* WAIT FILE switches */
  343.     { "creation",     WF_CRE, 0 },      /* Wait for file to be created */
  344.     { "deletion",     WF_DEL, 0 },      /* Wait for file to be deleted */
  345.     { "modification", WF_MOD, 0 }       /* Wait for file to be modified */
  346. };
  347. int nwfswi = (sizeof(wfswi) / sizeof(struct keytab));
  348.  
  349. #ifndef NOSPL
  350. struct keytab asgtab[] = {              /* Assignment operators for "." */
  351.     { "::=", 2, 0 },                    /* ASSIGN and EVALUATE */
  352.     { ":=",  1, 0 },                    /* ASSIGN */
  353.     { "=",   0, 0 }                     /* DEFINE */
  354. };
  355. int nasgtab = (sizeof(asgtab) / sizeof(struct keytab));
  356.  
  357. struct keytab opntab[] = {
  358. #ifndef NOPUSH
  359.     { "!read",  OPN_PI_R, CM_INV },
  360.     { "!write", OPN_PI_W, CM_INV },
  361. #endif /* NOPUSH */
  362.     { "append", OPN_FI_A, 0 },
  363.     { "host",   OPN_NET,  0 },
  364. #ifdef OS2
  365.     { "line",   OPN_SER,  CM_INV },
  366.     { "port",   OPN_SER,  0 },
  367. #else
  368.     { "line",   OPN_SER,  0 },
  369.     { "port",   OPN_SER,  CM_INV },
  370. #endif /* OS2 */
  371.     { "read",   OPN_FI_R, 0 },
  372.     { "write",  OPN_FI_W, 0 }
  373. };
  374. int nopn = (sizeof(opntab) / sizeof(struct keytab));
  375.  
  376. /* IF conditions */
  377.  
  378. #define  XXIFCO 0       /* IF COUNT */
  379. #define  XXIFER 1       /* IF ERRORLEVEL */
  380. #define  XXIFEX 2       /* IF EXIST */
  381. #define  XXIFFA 3       /* IF FAILURE */
  382. #define  XXIFSU 4       /* IF SUCCESS */
  383. #define  XXIFNO 5       /* IF NOT */
  384. #define  XXIFDE 6       /* IF DEFINED */
  385. #define  XXIFEQ 7       /* IF EQUAL (strings) */
  386. #define  XXIFAE 8       /* IF = (numbers) */
  387. #define  XXIFLT 9       /* IF < (numbers) */
  388. #define  XXIFGT 10      /* IF > (numbers) */
  389. #define  XXIFLL 11      /* IF Lexically Less Than (strings) */
  390. #define  XXIFLG 12      /* IF Lexically Greater Than (strings) */
  391. #define  XXIFEO 13      /* IF EOF (READ file) */
  392. #define  XXIFBG 14      /* IF BACKGROUND */
  393. #define  XXIFNU 15      /* IF NUMERIC */
  394. #define  XXIFFG 16      /* IF FOREGROUND */
  395. #define  XXIFDI 17      /* IF DIRECTORY */
  396. #define  XXIFNE 18      /* IF NEWER */
  397. #define  XXIFRO 19      /* IF REMOTE-ONLY */
  398. #define  XXIFAL 20      /* IF ALARM */
  399. #define  XXIFSD 21      /* IF STARTED-FROM-DIALER */
  400. #define  XXIFTR 22      /* IF TRUE */
  401. #define  XXIFNT 23      /* IF FALSE */
  402. #define  XXIFTM 24      /* IF TERMINAL-MACRO */
  403. #define  XXIFEM 25      /* IF EMULATION */
  404. #define  XXIFOP 26      /* IF OPEN */
  405. #define  XXIFLE 27      /* IF <= */
  406. #define  XXIFGE 28      /* IF >= */
  407. #define  XXIFIP 29      /* IF INPATH */
  408. #define  XXIFTA 30      /* IF TAPI */
  409. #define  XXIFMA 31      /* IF MATCH */
  410. #define  XXIFFL 32      /* IF FLAG */
  411. #define  XXIFAB 33      /* IF ABSOLUTE */
  412. #define  XXIFAV 34      /* IF AVAILABLE */
  413. #define  XXIFAT 35      /* IF ASKTIMEOUT */
  414. #define  XXIFRD 36      /* IF READABLE */
  415. #define  XXIFWR 37      /* IF WRITEABLE */
  416. #define  XXIFAN 38      /* IF ... AND ... */
  417. #define  XXIFOR 39      /* IF ... OR ... */
  418. #define  XXIFLP 40      /* IF left parenthesis */
  419. #define  XXIFRP 41      /* IF right parenthesis */
  420. #define  XXIFNQ 42      /* IF != (== "NOT =") */
  421. #define  XXIFQU 43      /* IF QUIET */
  422. #define  XXIFCK 44      /* IF C-KERMIT */
  423. #define  XXIFK9 45      /* IF K-95 */
  424. #define  XXIFMS 46      /* IF MS-KERMIT */
  425. #define  XXIFWI 47      /* IF WILD */
  426. #define  XXIFLO 48      /* IF LOCAL */
  427. #define  XXIFCM 49      /* IF COMMAND */
  428. #define  XXIFFP 50      /* IF FLOAT */
  429. #define  XXIFIK 51      /* IF IKS */
  430. #define  XXIFKB 52      /* IF KBHIT */
  431. #define  XXIFKG 53      /* IF KERBANG */
  432. #define  XXIFVE 54      /* IF VERSION */
  433. #define  XXIFDC 55      /* IF DECLARED */
  434. #define  XXIFGU 56      /* IF GUI */
  435. #define  XXIFLN 57    /* IF LINK */
  436.  
  437. struct keytab iftab[] = {               /* IF commands */
  438.     { "!",          XXIFNO, 0 },
  439.     { "!=",         XXIFNQ, 0 },
  440.     { "&&",         XXIFAN, 0 },
  441.     { "(",          XXIFLP, 0 },
  442.     { ")",          XXIFRP, 0 },
  443.     { "<",          XXIFLT, 0 },
  444.     { "<=",         XXIFLE, 0 },
  445.     { "=",          XXIFAE, 0 },
  446.     { "==",         XXIFAE, CM_INV },
  447.     { ">",          XXIFGT, 0 },
  448.     { ">=",         XXIFGE, 0 },
  449.     { "absolute",   XXIFAB, 0 },
  450.     { "alarm",      XXIFAL, 0 },
  451.     { "and",        XXIFAN, 0 },
  452.     { "asktimeout", XXIFAT, 0 },
  453.     { "available",  XXIFAV, 0 },
  454.     { "background", XXIFBG, 0 },
  455.     { "c-kermit",   XXIFCK, 0 },
  456.     { "command",    XXIFCM, 0 },
  457.     { "count",      XXIFCO, 0 },
  458.     { "dcl",        XXIFDC, CM_INV },
  459.     { "declared",   XXIFDC, 0 },
  460.     { "defined",    XXIFDE, 0 },
  461. #ifdef CK_TMPDIR
  462.     { "directory",  XXIFDI, 0 },
  463. #endif /* CK_TMPDIR */
  464.     { "emulation",  XXIFEM, 0 },
  465. #ifdef COMMENT
  466.     { "eof",        XXIFEO, 0 },
  467. #endif /* COMMENT */
  468.     { "equal",      XXIFEQ, 0 },
  469.     { "error",      XXIFFA, CM_INV },
  470.     { "exist",      XXIFEX, 0 },
  471.     { "failure",    XXIFFA, 0 },
  472.     { "false",      XXIFNT, 0 },
  473.     { "flag",       XXIFFL, 0 },
  474. #ifdef CKFLOAT
  475.     { "float",      XXIFFP, 0 },
  476. #endif /* CKFLOAT */
  477.     { "foreground", XXIFFG, 0 },
  478. #ifdef OS2
  479.     { "gui",        XXIFGU, 0 },
  480. #else
  481.     { "gui",        XXIFGU, CM_INV },
  482. #endif /* OS2 */
  483. #ifdef IKSD
  484.     { "iksd",       XXIFIK, 0 },
  485. #else
  486.     { "iksd",       XXIFIK, CM_INV },
  487. #endif /* IKSD */
  488.     { "integer",    XXIFNU, CM_INV },
  489.     { "k-95",       XXIFK9, 0 },
  490.     { "kbhit",      XXIFKB, 0 },
  491. #ifdef UNIX
  492.     { "kerbang",    XXIFKG, 0 },
  493. #else
  494.     { "kerbang",    XXIFKG, CM_INV },
  495. #endif /* UNIX */
  496.     { "lgt",        XXIFLG, 0 },
  497. #ifdef UNIX
  498.     { "link",       XXIFLN, 0 },
  499. #endif /* UNIX */
  500.     { "llt",        XXIFLL, 0 },
  501.     { "local",      XXIFLO, 0 },
  502.     { "match",      XXIFMA, 0 },
  503.     { "ms-kermit",  XXIFMS, CM_INV },
  504. #ifdef ZFCDAT
  505.     { "newer",      XXIFNE, 0 },
  506. #endif /* ZFCDAT */
  507.     { "not",        XXIFNO, 0 },
  508.     { "numeric",    XXIFNU, 0 },
  509.     { "ok",         XXIFSU, CM_INV },
  510.     { "open",       XXIFOP, 0 },
  511.     { "or",         XXIFOR, 0 },
  512.     { "quiet",      XXIFQU, 0 },
  513.     { "readable",   XXIFRD, 0 },
  514.     { "remote-only",XXIFRO, 0 },
  515.     { "started-from-dialer",XXIFSD, CM_INV },
  516.     { "success",    XXIFSU, 0 },
  517.     { "tapi",       XXIFTA, 0 },
  518. #ifdef OS2
  519.     { "terminal-macro", XXIFTM, 0 },
  520. #else
  521.     { "terminal-macro", XXIFTM, CM_INV },
  522. #endif /* OS2 */
  523.     { "true",       XXIFTR, 0 },
  524.     { "version",    XXIFVE, 0 },
  525.     { "wild",       XXIFWI, 0 },
  526.     { "writeable",  XXIFWR, 0 },
  527.     { "||",         XXIFOR, 0 },
  528.     { "", 0, 0 }
  529. };
  530. int nif = (sizeof(iftab) / sizeof(struct keytab)) - 1;
  531.  
  532. struct keytab iotab[] = {               /* Keywords for IF OPEN */
  533.     { "!read-file",      ZRFILE, CM_INV },
  534.     { "!write-file",     ZWFILE, CM_INV },
  535.     { "append-file",     ZWFILE, CM_INV },
  536.     { "connection",      8888,   0 },
  537. #ifdef CKLOGDIAL
  538.     { "cx-log",          7777,   0 },
  539. #endif /* CKLOGDIAL */
  540.     { "debug-log",       ZDFILE, 0 },
  541.     { "error",           9999,   0 },
  542.     { "packet-log",      ZPFILE, 0 },
  543.     { "read-file",       ZRFILE, 0 },
  544.     { "screen",          ZSTDIO, 0 },
  545.     { "session-log",     ZSFILE, 0 },
  546.     { "transaction-log", ZTFILE, 0 },
  547.     { "write-file",      ZWFILE, 0 }
  548. };
  549. int niot = (sizeof(iotab) / sizeof(struct keytab));
  550. #endif /* NOSPL */
  551.  
  552. /* Variables and prototypes */
  553.  
  554. #ifdef NETCONN
  555. extern int nnetdir;                     /* How many network directories */
  556. #endif /* NETCONN */
  557. #ifdef CK_SECURITY
  558. _PROTOTYP(int ck_krb4_is_installed,(void));
  559. _PROTOTYP(int ck_krb5_is_installed,(void));
  560. _PROTOTYP(int ck_ntlm_is_installed,(void));
  561. _PROTOTYP(int ck_srp_is_installed,(void));
  562. _PROTOTYP(int ck_ssleay_is_installed,(void));
  563. _PROTOTYP(int ck_ssh_is_installed,(void));
  564. _PROTOTYP(int ck_crypt_is_installed,(void));
  565. #else
  566. #define ck_krb4_is_installed() (0)
  567. #define ck_krb5_is_installed() (0)
  568. #define ck_ntlm_is_installed() (0)
  569. #define ck_srp_is_installed() (0)
  570. #define ck_ssleay_is_installed() (0)
  571. #define ck_ssh_is_installed() (0)
  572. #define ck_crypt_is_installed() (0)
  573. #endif /* CK_SECURITY */
  574.  
  575. #define AV_KRB4   1
  576. #define AV_KRB5   2
  577. #define AV_NTLM   3
  578. #define AV_SRP    4
  579. #define AV_SSL    5
  580. #define AV_CRYPTO 6
  581. #define AV_SSH    7
  582.  
  583. struct keytab availtab[] = {             /* Available authentication types */
  584.     { "crypto",     AV_CRYPTO, CM_INV }, /* and encryption */
  585.     { "encryption", AV_CRYPTO, 0 },
  586.     { "k4",         AV_KRB4,   CM_INV },
  587.     { "k5",         AV_KRB5,   CM_INV },
  588.     { "kerberos4",  AV_KRB4,   0 },
  589.     { "kerberos5",  AV_KRB5,   0 },
  590.     { "krb4",       AV_KRB4,   CM_INV },
  591.     { "krb5",       AV_KRB5,   CM_INV },
  592.     { "ntlm",       AV_NTLM,   0 },
  593.     { "srp",        AV_SRP,    0 },
  594.     { "ssh",        AV_SSH,    0 },
  595.     { "ssl",        AV_SSL,    0 },
  596.     { "tls",        AV_SSL,    0 },
  597.     { "",           0,         0 }
  598. };
  599. int availtabn = sizeof(availtab)/sizeof(struct keytab)-1;
  600.  
  601. #ifndef NODIAL
  602. _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
  603. _PROTOTYP(static int dncvt, (int, int, int, int) );
  604. _PROTOTYP(char * getdname, (void) );
  605.  
  606. static int partial  = 0;                /* For partial dial */
  607. static char *dscopy = NULL;
  608. int dialtype = -1;
  609.  
  610. char *dialnum = (char *)0;              /* Remember DIAL number for REDIAL */
  611. int dirline = 0;                        /* Dial directory line number */
  612. extern char * dialdir[];                /* Dial directory file names */
  613. extern int dialdpy;                     /* DIAL DISPLAY on/off */
  614. extern int ndialdir;                    /* How many dial directories */
  615. extern int ntollfree;                   /* Toll-free call info */
  616. extern int ndialpxx;                    /* List of PBX exchanges */
  617. extern char *dialtfc[];
  618. char * matchpxx = NULL;                 /* PBX exchange that matched */
  619. extern int nlocalac;                    /* Local area-code list */
  620. extern char * diallcac[];
  621. extern int tttapi;
  622. #ifdef CK_TAPI
  623. extern int tapiconv;                    /* TAPI Conversions */
  624. extern int tapipass;                    /* TAPI Passthrough */
  625. #endif /* CK_TAPI */
  626. extern int dialatmo;
  627. extern char * dialnpr, * dialsfx;
  628. extern char * dialixp, * dialixs, * dialmac;
  629. extern char * dialldp, * diallds, * dialtfp;
  630. extern char * dialpxi, * dialpxo, * diallac;
  631. extern char * diallcp, * diallcs, * diallcc;
  632. extern char * dialpxx[];
  633.  
  634. extern int dialcnf;                     /* DIAL CONFIRMATION */
  635. int dialfld = 0;                        /* DIAL FORCE-LONG-DISTANCE */
  636. int dialsrt = 1;                        /* DIAL SORT ON */
  637. int dialrstr = 6;                       /* DIAL RESTRICTION */
  638. int dialtest = 0;                       /* DIAL TEST */
  639. int dialcount = 0;                      /* \v(dialcount) */
  640.  
  641. extern int dialsta;                     /* Dial status */
  642. int dialrtr = -1,                       /* Dial retries */
  643.     dialint = 10;                       /* Dial retry interval */
  644. extern long dialcapas;                  /* Modem capabilities */
  645. extern int dialcvt;                     /* DIAL CONVERT-DIRECTORY */
  646. #endif /* NODIAL */
  647.  
  648. #ifndef NOSPL
  649. #define IFCONDLEN 256
  650. int ifc,                                /* IF case */
  651.     not = 0,                            /* Flag for IF NOT */
  652.     ifargs = 0;                         /* Count of IF condition words */
  653. char ifcond[IFCONDLEN];                 /* IF condition text */
  654. char *ifcp;                             /* Pointer to IF condition text */
  655. #ifdef DCMDBUF
  656. extern int
  657.  *ifcmd,  *count,  *iftest, *intime,
  658.  *inpcas, *takerr, *merror, *xquiet;
  659. #else
  660. extern int ifcmd[];                     /* Last command was IF */
  661. extern int iftest[];                    /* Last IF was true */
  662. extern int count[];                     /* For IF COUNT, one for each cmdlvl */
  663. extern int intime[];                    /* Ditto for other stackables... */
  664. extern int inpcas[];
  665. extern int takerr[];
  666. extern int merror[];
  667. extern int xquiet[];
  668. #endif /* DCMDBUF */
  669. #else
  670. extern int takerr[];
  671. #endif /* NOSPL */
  672.  
  673. #ifdef DCMDBUF
  674. extern char *line;                      /* Character buffer for anything */
  675. extern char *tmpbuf;
  676. #else
  677. extern char line[], tmpbuf[];
  678. #endif /* DCMDBUF */
  679. extern char *lp;                        /* Pointer to line buffer */
  680.  
  681. int cwdf = 0;                           /* CWD has been done */
  682.  
  683. /* Flags for ENABLE/DISABLE */
  684. extern int en_cwd, en_cpy, en_del, en_dir, en_fin,
  685.    en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
  686.    en_asg, en_que, en_ret, en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
  687.  
  688. extern FILE *tfile[];                   /* File pointers for TAKE command */
  689. extern char *tfnam[];                   /* Names of TAKE files */
  690. extern int tfline[];                    /* TAKE-file line number */
  691.  
  692. extern int success;                     /* Command success/failure flag */
  693. extern int cmdlvl;                      /* Current position in command stack */
  694.  
  695. #ifndef NOSPL
  696. extern int maclvl;                      /* Macro to execute */
  697. extern char *macx[];                    /* Index of current macro */
  698. extern char *mrval[];                   /* Macro return value */
  699. extern char *macp[];                    /* Pointer to macro */
  700. extern int macargc[];                   /* ARGC from macro invocation */
  701.  
  702. #ifdef COMMENT
  703. extern char *m_line[];
  704. #endif /* COMMENT */
  705.  
  706. extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
  707. extern char *g_var[];                   /* Global variables %a, %b, etc */
  708.  
  709. #ifdef DCMDBUF
  710. extern struct cmdptr *cmdstk;           /* The command stack itself */
  711. #else
  712. extern struct cmdptr cmdstk[];          /* The command stack itself */
  713. #endif /* DCMDBUF */
  714. #endif /* NOSPL */
  715.  
  716. #define xsystem(s) zsyscmd(s)
  717.  
  718. static int x, y, z = 0;
  719. static char *s, *p;
  720.  
  721. #ifdef OS2
  722. _PROTOTYP( int os2settitle, (char *, int) );
  723. #endif /* OS2 */
  724.  
  725. extern struct keytab yesno[], onoff[], fntab[];
  726. extern int nyesno, nfntab;
  727.  
  728. #ifndef NOSPL
  729.  
  730. /* Do the ASK, ASKQ, GETOK, and READ commands */
  731.  
  732. int asktimedout = 0;
  733.  
  734. #define ASK_PUP 1
  735. #define ASK_TMO 2
  736. #define ASK_GUI 3
  737. #define ASK_QUI 4
  738. #define ASK_DEF 5
  739. #define ASK_ECH 6
  740.  
  741. static struct keytab asktab[] = {
  742.     {  "/default", ASK_DEF, CM_ARG },
  743.     {  "/gui",     ASK_GUI,      
  744. #ifdef KUI
  745.            0
  746. #else /* KUI */
  747.            CM_INV
  748. #endif /* KUI */
  749.     },
  750.     { "/popup",    ASK_PUP,   
  751. #ifdef OS2
  752.            0
  753. #else /* OS2 */
  754.            CM_INV
  755. #endif /* OS2 */
  756.     },
  757.     { "/quiet",    ASK_QUI, 0 },
  758.     { "/timeout",  ASK_TMO, CM_ARG },
  759.     { "", 0, 0 }
  760. };
  761. static int nasktab = sizeof(asktab)/sizeof(struct keytab)-1;
  762.  
  763. static struct keytab askqtab[] = {
  764.     { "/default",  ASK_DEF, CM_ARG },
  765.     { "/echo",     ASK_ECH, CM_ARG },
  766.     { "/gui",      ASK_GUI,      
  767. #ifdef KUI
  768.            0
  769. #else /* KUI */
  770.            CM_INV
  771. #endif /* KUI */
  772.     },
  773.     { "/noecho",   ASK_QUI, CM_INV },
  774.     { "/popup",    ASK_PUP,   
  775. #ifdef OS2
  776.            0
  777. #else /* OS2 */
  778.            CM_INV
  779. #endif /* OS2 */
  780.     },
  781.     { "/quiet",    ASK_QUI, 0 },
  782.     { "/timeout",  ASK_TMO, CM_ARG },
  783.     { "", 0, 0 }
  784. };
  785. static int naskqtab = sizeof(askqtab)/sizeof(struct keytab)-1;
  786.  
  787. int
  788. doask(cx) int cx; {
  789.     extern int cmflgs, asktimer, timelimit;
  790. #ifdef CK_RECALL
  791.     extern int on_recall;
  792. #endif /* CK_RECALL */
  793.     int echochar = 0;
  794.     int popupflg = 0;
  795.     int guiflg = 0;
  796.     int nomsg = 0;
  797.     int mytimer = 0;
  798. #ifdef CK_APC
  799.     extern int apcactive, apcstatus;
  800. #endif /* CK_APC */
  801.  
  802.     char dfbuf[1024];            /* Buffer for default answer */
  803.     char * dfanswer = NULL;        /* Pointer to it */
  804.  
  805.     char vnambuf[VNAML+1];              /* Buffer for variable names */
  806.     char *vnp = NULL;                   /* Pointer to same */
  807.     
  808.     dfbuf[0] = NUL;
  809.     vnambuf[0] = NUL;
  810.  
  811. #ifdef CK_APC
  812.     if ( apcactive != APC_INACTIVE && (apcstatus & APC_NOINP) ) {
  813.         return(success = 0);
  814.     }
  815. #endif /* CK_APC */
  816.  
  817.     mytimer = asktimer;                 /* Inherit global ASK timer */
  818.     echostars = 0;            /* For ASKQ */
  819.  
  820.     if (cx == XXASK || cx == XXASKQ) {
  821.         struct FDB sw, fl;
  822.         int getval;
  823.         char c;
  824.         if (cx == XXASKQ)               /* Don't log ASKQ response */
  825.           debok = 0;
  826.         cmfdbi(&sw,                     /* First FDB - command switches */
  827.                _CMKEY,                  /* fcode */
  828.                "Variable name or switch",
  829.                "",                      /* default */
  830.                "",                      /* addtl string data */
  831.            ((cx == XXASK) ? nasktab : naskqtab), /* Table size */
  832.                4,                       /* addtl numeric data 2: 4 = cmswi */
  833.                xxstring,                /* Processing function */
  834.            ((cx == XXASK) ? asktab : askqtab), /* Keyword table */
  835.                &fl                      /* Pointer to next FDB */
  836.                );
  837.         cmfdbi(&fl,                     /* Anything that doesn't match */
  838.                _CMFLD,                  /* fcode */
  839.                "",                      /* hlpmsg */
  840.                "",                      /* default */
  841.                "",                      /* addtl string data */
  842.                0,                       /* addtl numeric data 1 */
  843.                0,                       /* addtl numeric data 2 */
  844.                NULL,
  845.                NULL,
  846.                NULL
  847.                );
  848.         while (1) {                     /* Parse 0 or more switches */
  849.             x = cmfdb(&sw);             /* Parse something */
  850.             if (x < 0)
  851.               return(x);
  852.             if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
  853.               break;
  854.             c = cmgbrk();
  855.             if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  856.                 printf("?This switch does not take an argument\n");
  857.                 return(-9);
  858.             }
  859.             if (!getval && (cmgkwflgs() & CM_ARG)) {
  860.                 printf("?This switch requires an argument\n");
  861.                 return(-9);
  862.             }
  863.             switch (cmresult.nresult) {
  864.           case ASK_QUI:
  865.         nomsg = 1;
  866.         if (cx == XXASKQ)
  867.           echostars = 0;
  868.         break;
  869.               case ASK_PUP:
  870.                 popupflg = 1;
  871.                 break;
  872.           case ASK_GUI:
  873.         guiflg = 1;
  874.         break;
  875.               case ASK_TMO: {
  876.                   if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
  877.                     return(y);
  878.                   if (x < 0)
  879.                     x = 0;
  880.                   mytimer = x;
  881.                   break;
  882.               }
  883.               case ASK_ECH: {
  884.                   if ((y = cmfld("Character to echo","*",&s,xxstring)) < 0)
  885.                     return(y);
  886.           echochar = *s;
  887.                   break;
  888.               }
  889.               case ASK_DEF: {
  890.                   if ((y = cmfld("Text to supply if reply is empty",
  891.                  "",&s,xxstring)) < 0)
  892.                     return(y);
  893.           ckstrncpy(dfbuf,s,1024);
  894.           dfanswer = dfbuf;
  895.                   break;
  896.               }
  897.               default: return(-2);
  898.             }
  899.         }
  900.         /* Have variable name, make copy. */
  901.         ckstrncpy(vnambuf,cmresult.sresult,VNAML);
  902.         vnp = vnambuf;
  903.         if (vnambuf[0] == CMDQ &&
  904.             (vnambuf[1] == '%' || vnambuf[1] == '&'))
  905.           vnp++;
  906.         y = 0;
  907.         if (*vnp == '%' || *vnp == '&') {
  908.             if ((y = parsevar(vnp,&x,&z)) < 0)
  909.           return(y);
  910.         }
  911.     } else if (cx != XXGOK && cx != XXRDBL) { /* Get variable name */
  912.         if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  913.             if (y == -3) {
  914.                 printf("?Variable name required\n");
  915.                 return(-9);
  916.             } else return(y);
  917.         }
  918.         ckstrncpy(vnambuf,s,VNAML);     /* Make a copy. */
  919.         vnp = vnambuf;
  920.         if (vnambuf[0] == CMDQ &&
  921.             (vnambuf[1] == '%' || vnambuf[1] == '&'))
  922.           vnp++;
  923.         y = 0;
  924.         if (*vnp == '%' || *vnp == '&') {
  925.             if ((y = parsevar(vnp,&x,&z)) < 0)
  926.               return(y);
  927.         }
  928.     }
  929.     if (cx == XXREA || cx == XXRDBL) {  /* READ or READBLOCK command */
  930.         if ((y = cmcfm()) < 0)          /* Get confirmation */
  931.           return(y);
  932.         if (chkfn(ZRFILE) < 1) {        /* File open? */
  933.             printf("?Read file not open\n");
  934.             return(success = 0);
  935.         }
  936.         if (!(s = (char *)readbuf)) {           /* Where to read into. */
  937.             printf("?Oops, no READ buffer!\n");
  938.             return(success = 0);
  939.         }
  940.         y = zsinl(ZRFILE, s, readblock); /* Read a line. */
  941.         debug(F111,"read zsinl",s,y);
  942.         if (y < 0) {                    /* On EOF or other error, */
  943.             zclose(ZRFILE);             /* close the file, */
  944.             delmac(vnp,0);              /* delete the variable, */
  945.             return(success = 0);        /* and return failure. */
  946.         } else {                        /* Read was OK. */
  947.             readsize = (int) strlen(s);
  948.             success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
  949.             debug(F111,"read addmac",vnp,success);
  950.             return(success);            /* Return success. */
  951.         }
  952.     }
  953.  
  954.     /* ASK, ASKQ, GETOK, or GETC */
  955.  
  956.     if (cx == XXGOK) {            /* GETOK can take switches */
  957.         struct FDB sw, fl;
  958.         int getval;
  959.         char c;
  960.         cmfdbi(&sw,                     /* First FDB - command switches */
  961.                _CMKEY,                  /* fcode */
  962.                "Variable name or question prompt",
  963.                "",                      /* default */
  964.                "",                      /* addtl string data */
  965.                nasktab,                 /* addtl numeric data 1: tbl size */
  966.                4,                       /* addtl numeric data 2: 4 = cmswi */
  967.                xxstring,                /* Processing function */
  968.                asktab,                  /* Keyword table */
  969.                &fl                      /* Pointer to next FDB */
  970.                );
  971.         cmfdbi(&fl,                     /* Anything that doesn't match */
  972.                _CMTXT,                  /* fcode */
  973.                "",                      /* hlpmsg */
  974.                "",                      /* default */
  975.                "",                      /* addtl string data */
  976.                0,                       /* addtl numeric data 1 */
  977.                0,                       /* addtl numeric data 2 */
  978.                NULL,
  979.                NULL,
  980.                NULL
  981.                );
  982.         while (1) {                     /* Parse 0 or more switches */
  983.             x = cmfdb(&sw);             /* Parse something */
  984.             if (x < 0)
  985.               return(x);
  986.             if (cmresult.fcode != _CMKEY) /* Break out if not a switch */
  987.               break;
  988.             c = cmgbrk();
  989.             if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  990.                 printf("?This switch does not take an argument\n");
  991.                 return(-9);
  992.             }
  993.             if (!getval && (cmgkwflgs() & CM_ARG)) {
  994.                 printf("?This switch requires an argument\n");
  995.                 return(-9);
  996.             }
  997.             switch (cmresult.nresult) {
  998.               case ASK_PUP:
  999.                 popupflg = 1;
  1000.                 break;
  1001.           case ASK_GUI:
  1002.         guiflg = 1;
  1003.         break;
  1004.               case ASK_TMO: {
  1005.                   if ((y = cmnum("seconds","1",10,&x,xxstring)) < 0)
  1006.                     return(y);
  1007.                   if (x < 0)
  1008.                     x = 0;
  1009.                   mytimer = x;
  1010.                   break;
  1011.               }
  1012.               case ASK_DEF: {
  1013.                   if ((y = cmfld("Text to supply if reply is empty",
  1014.                  "",&s,xxstring)) < 0)
  1015.                     return(y);
  1016.           ckstrncpy(dfbuf,s,1024);
  1017.           dfanswer = dfbuf;
  1018.                   break;
  1019.               }
  1020.           case ASK_QUI:
  1021.         nomsg = 1;
  1022.         break;
  1023.               default: return(-2);
  1024.             }
  1025.     }
  1026.     p = cmresult.sresult;
  1027.     } else
  1028.       if ((y = cmtxt(
  1029. "Prompt,\n\
  1030.  enclose in { braces } or \" quotes \" to preserve leading and trailing\n\
  1031.  spaces, precede question mark with backslash (\\).",
  1032.                    "",&p,xxstring)) < 0)
  1033.         return(y);
  1034.  
  1035.     if (!p) p = "";
  1036. #ifndef NOLOCAL
  1037. #ifdef OS2
  1038.     if (popupflg) {                     /* Popup requested */
  1039.         int len = -1;
  1040.         ckstrncpy(tmpbuf,brstrip(p),TMPBUFSIZ);
  1041.         p = tmpbuf;
  1042.         if (cx == XXASK || cx == XXASKQ) {
  1043.             if (cx == XXASK)
  1044.               len = popup_readtext(vmode,NULL,p,line,LINBUFSIZ,mytimer);
  1045.             else
  1046.               len = popup_readpass(vmode,NULL,p,line,LINBUFSIZ,mytimer);
  1047.             asktimedout = ( len < 0 && mytimer );
  1048.         } else if (cx == XXGOK) {
  1049.         printf("?Sorry, GETOK /POPUP not implemented yet\n");
  1050.         timelimit = 0;
  1051.         return(-9);
  1052.     }
  1053.         if (len >= 0) {
  1054.         y = addmac(vnp,(char *)line); /* Add it to the macro table. */
  1055.         } else if ( asktimedout && dfanswer ) {
  1056.             y = addmac(vnp,dfanswer);        /* Add it to the macro table. */
  1057.             asktimedout = 0;
  1058.             len = 0;
  1059.         }
  1060.         timelimit = 0;
  1061.         return(success = ((len >= 0) && (y >= 0)) && !asktimedout);
  1062.     }
  1063. #ifdef KUI
  1064.     if (guiflg) {                       /* GUI requested */
  1065.         int rc, n;
  1066.     char * s1;
  1067.     s1 = tmpbuf;
  1068.     n = TMPBUFSIZ-1;
  1069.     zzstring(brstrip(p),&s1,&n);
  1070.         p = tmpbuf;
  1071.         if (cx == XXASK || cx == XXASKQ) {
  1072.             rc = gui_txt_dialog(NULL,p,(cx == XXASK),
  1073.                                 line,LINBUFSIZ,dfanswer,mytimer);
  1074.             asktimedout = (rc == -1 && mytimer);
  1075.             if (rc == 1) {
  1076.                 y = addmac(vnp,(char *)line); /* Add it to the macro table. */
  1077.             } else if ( asktimedout && dfanswer ) {
  1078.                 y = addmac(vnp,dfanswer); /* Add default to macro table. */
  1079.                 asktimedout = 0;
  1080.                 rc = 1;
  1081.             }
  1082.         timelimit = 0;
  1083.         return(success = (rc == 1 && (y >= 0)) && !asktimedout);
  1084.     } else if (cx == XXGOK) {
  1085.         int x;
  1086.         x = lookup(yesno,dfanswer,nyesno,NULL);
  1087.         if (x != 1) x = 2;
  1088.         rc = uq_ok(NULL, p, 3, NULL, x);
  1089.         return(success = (rc == 1));
  1090.     }
  1091.     }
  1092. #endif /* KUI */
  1093. #endif /* OS2 */
  1094. #endif /* NOLOCAL */
  1095.  
  1096.     concb((char)escape);                /* Enter CBREAK mode */
  1097.     cmsavp(psave,PROMPTL);              /* Save old prompt */
  1098.     cmsetp(brstrip(p));                 /* Make new prompt */
  1099.  
  1100. reprompt:
  1101.     if (cx == XXASKQ) {                 /* For ASKQ, */
  1102.         cmini(0);                       /* no-echo mode. */
  1103.     if (echochar)
  1104.       echostars = echochar;
  1105.     } else {                            /* For others, regular echoing. */
  1106.         cmini(ckxech);
  1107.     echostars = 0;
  1108.     }
  1109.     askflag = 1;
  1110.     x = -1;                             /* This means to reparse. */
  1111.     cmflgs = 0;
  1112.     if (pflag)
  1113.       prompt(xxstring);                 /* Issue prompt. */
  1114.  
  1115.     asktimedout = 0;                    /* Handle timed responses. */
  1116.     timelimit = mytimer;
  1117. reparse:
  1118.     cmres();
  1119.     if (cx == XXGOK) {                  /* GETOK */
  1120. #ifdef CK_RECALL
  1121.         on_recall = 0;
  1122. #endif /* CK_RECALL */
  1123.         askflag = 0;
  1124.     /* GETOK uses keyword table */
  1125.         x = cmkey(yesno,nyesno,"",dfanswer,xxstring);
  1126.         if (x < 0) {                    /* Parse error */
  1127.             if (x == -10) {
  1128.         char * ds;
  1129.         ds = dfanswer ? dfanswer : "No";
  1130.         if (!nomsg)
  1131.           printf("?Timed out, assuming \"%s\"",ds);
  1132.         printf("\n");
  1133.                 asktimedout = 1;
  1134.         x = lookup(yesno,ds,nyesno,NULL);
  1135.         if (x != 1) x = 0;
  1136.                 goto gokdone;
  1137.             } else if (x == -3) {       /* No answer? */
  1138.                 printf("Please respond Yes or No\n"); /* Make them answer */
  1139.                 cmini(ckxech);
  1140.                 goto reprompt;
  1141.             } else if (x == -1) {
  1142.                 goto reparse;
  1143.             } else
  1144.               goto reprompt;
  1145.         }
  1146.         if (cmcfm() < 0)                /* Get confirmation */
  1147.           goto reparse;
  1148.   gokdone:
  1149.         askflag = 0;
  1150.         cmsetp(psave);                  /* Restore prompt */
  1151. #ifdef VMS
  1152.         if (cmdlvl > 0)                 /* In VMS and not at top level, */
  1153.           conres();                     /*  restore console again. */
  1154. #endif /* VMS */
  1155.         timelimit = 0;
  1156.         return(x);                      /* Return success or failure */
  1157.     } else if (cx == XXGETC             /* GETC */
  1158. #ifdef OS2
  1159.                || cx == XXGETK          /* or GETKEYCODE */
  1160. #endif /* OS2 */
  1161.                ) {                      /* GETC */
  1162.         char tmp[16];
  1163.         conbin((char)escape);           /* Put keyboard in raw mode */
  1164. #ifndef NOSETKEY
  1165. #ifdef OS2
  1166.         if (cx == XXGETK) {             /* GETKEYCODE */
  1167.             extern int os2gks;
  1168.             int t;
  1169.             t = os2gks;                 /* Turn off kverb recognition */
  1170.             os2gks = 0;
  1171.             x = congks(timelimit);      /* Read a key event, blocking */
  1172.             os2gks = t;                 /* Put back kverb recognition */
  1173.         } else                          /* GETC */
  1174. #endif /* OS2 */
  1175. #endif /* NOSETKEY */
  1176.         {
  1177.             debug(F101,"GETC conchk","",conchk());
  1178.             x = coninc(timelimit);      /* Just read one character */
  1179.             debug(F101,"GETC coninc","",x);
  1180.         }
  1181.         concb((char)escape);            /* Put keyboard back in cbreak mode */
  1182.         if (x > -1) {
  1183.             if (xcmdsrc == 0)
  1184.               printf("\r\n");
  1185. #ifdef OS2
  1186.             if (cx == XXGETK) {         /* GETKEYCODE */
  1187.                 sprintf(tmp,"%d",x);    /* SAFE */
  1188.             } else {
  1189. #endif /* OS2 */
  1190.                 tmp[0] = (char) (x & 0xff);
  1191.                 tmp[1] = NUL;
  1192. #ifdef OS2
  1193.             }
  1194. #endif /* OS2 */
  1195.             y = addmac(vnp,tmp);        /* Add it to the macro table. */
  1196.             debug(F111,"getc/getk addmac",vnp,y);
  1197.         } else y = -1;
  1198.         cmsetp(psave);                  /* Restore old prompt. */
  1199.         if (x < -1) {
  1200.             asktimedout = 1;
  1201.             if (!quiet && !nomsg)
  1202.               printf("?Timed out");
  1203.         printf("\n");
  1204.         }
  1205.         timelimit = 0;
  1206.         return(success = ((y < 0 ? 0 : 1) && (asktimedout == 0)));
  1207.     } else {                            /* ASK or ASKQ */
  1208. #ifdef CK_RECALL
  1209.         on_recall = 0;            /* Don't put response in recall buf */
  1210. #endif /* CK_RECALL */
  1211.     askflag = 1;            /* ASK[Q] always goes to terminal */
  1212.         y = cmdgquo();                  /* Get current quoting */
  1213.         cmdsquo(0);                     /* Turn off quoting */
  1214.         while (x == -1) {               /* Prompt till they answer */
  1215.             x = cmtxt("Please respond.",dfanswer,&s,NULL);
  1216.             debug(F111,"ASK cmtxt",s,x);
  1217.             cmres();
  1218.         }
  1219.         cmdsquo(y);                     /* Restore previous quoting */
  1220.         if (cx == XXASKQ)               /* ASKQ must echo CRLF here */
  1221.           printf("\r\n");
  1222.     if (x == -10 && dfanswer) {    /* Don't fail on timeout if */
  1223.         s = dfanswer;        /* a default was specified */
  1224.         asktimedout = 0;        /* and don't fail */
  1225.         x = 0;
  1226.     }
  1227.         if (x < 0) {                    /* If cmtxt parse error, */
  1228.             cmsetp(psave);              /* restore original prompt */
  1229. #ifdef VMS
  1230.             if (cmdlvl > 0)             /* In VMS and not at top level, */
  1231.               conres();                 /*  restore console again. */
  1232. #endif /* VMS */
  1233.             if (x == -10) {        /* Timed out with no response */
  1234.         if (!nomsg)
  1235.           printf("?Timed out");
  1236.         printf("\n");
  1237.                 asktimedout = 1;
  1238.         if (dfanswer)        /* Supply default answer if any */
  1239.           s = dfanswer;
  1240.                 success = x = 0;    /* (was "x = -9;") */
  1241.             }
  1242.             timelimit = 0;
  1243.             return(x);                  /* and return cmtxt's error code. */
  1244.         }
  1245.         if (!s || *s == NUL) {        /* If user typed a bare CR, */
  1246.             cmsetp(psave);              /* Restore old prompt, */
  1247.             delmac(vnp,0);              /* delete variable if it exists, */
  1248. #ifdef VMS
  1249.             if (cmdlvl > 0)             /* In VMS and not at top level, */
  1250.               conres();                 /*  restore console again. */
  1251. #endif /* VMS */
  1252.             timelimit = 0;
  1253.             return(success = 1);        /* and return. */
  1254.         }
  1255.         y = addmac(vnp,s);              /* Add it to the macro table. */
  1256.         debug(F111,"ask addmac",vnp,y);
  1257.         cmsetp(psave);                  /* Restore old prompt. */
  1258. #ifdef VMS
  1259.         if (cmdlvl > 0)                 /* In VMS and not at top level, */
  1260.           conres();                     /*  restore console again. */
  1261. #endif /* VMS */
  1262.         timelimit = 0;
  1263.         return(success = (y < 0 ? 0 : 1) && (asktimedout == 0));
  1264.     }
  1265. }
  1266. #endif /* NOSPL */
  1267.  
  1268. #ifndef NOSPL
  1269. int
  1270. doincr(cx) int cx; {                    /* INCREMENT, DECREMENT */
  1271.     char vnambuf[VNAML+1];              /* Buffer for variable names */
  1272.     int eval = 0;
  1273.     CK_OFF_T x;
  1274.     eval = (cx == XX_DECR || cx == XX_INCR);
  1275.  
  1276.     if ((y = cmfld("Variable name","",&s, eval ? xxstring : NULL)) < 0) {
  1277.         if (y == -3) {
  1278.             printf("?Variable name required\n");
  1279.             return(-9);
  1280.         } else return(y);
  1281.     }
  1282.     ckstrncpy(vnambuf,s,VNAML);
  1283.     if ((y = cmnumw("by amount","1",10,&x,xxstring)) < 0)
  1284.       return(y);
  1285.     if ((y = cmcfm()) < 0)
  1286.       return(y);
  1287.  
  1288.     z = (cx == XX_INCR || cx == XXINC) ? 1 : 0; /* Increment or decrement? */
  1289.  
  1290.     if (incvar(vnambuf,x,z) < 0) {
  1291.         printf("?Variable %s not defined or not numeric\n",vnambuf);
  1292.         return(success = 0);
  1293.     }
  1294.     return(success = 1);
  1295. }
  1296.  
  1297. /* Used by doundef() */
  1298. static int
  1299. xxundef(s,verbose,simulate) char * s; int verbose, simulate; {
  1300.     int rc = 0;
  1301.     if (!s) return(0);
  1302.     if (*s == CMDQ && *(s+1) == '%') {
  1303.         char c = *(s+2), * p = NULL;
  1304.         if (c >= '0' && c <= '9') {
  1305.             if (maclvl < 0)
  1306.               p = g_var[c];
  1307.             else
  1308.               p = m_arg[maclvl][c - '0'];
  1309.         } else {
  1310.             if (isupper(c)) c += ('a'-'A');
  1311.             if (c >= 'a' && c <= 'z')
  1312.               p = g_var[c];
  1313.         }
  1314.         if (!p) return(-1);
  1315.     }
  1316.     if (verbose)
  1317.       printf(" %s ",s);
  1318.     if (simulate) {
  1319.         printf("(SELECTED)\n");
  1320.     } else if ((x = delmac(s,1)) > -1) { /* Full name required */
  1321.         rc = 1;
  1322.         if (verbose) printf("(OK)\n");
  1323.     } else if (verbose)
  1324.       printf("(FAILED)\n");
  1325.     return(rc);
  1326. }
  1327.  
  1328. /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
  1329.  
  1330. #define UND_MAT 1
  1331. #define UND_VRB 2
  1332. #define UND_EXC 3
  1333. #define UND_SIM 3
  1334.  
  1335. static struct keytab undefswi[] = {
  1336.     { "/list",     UND_VRB, 0 },
  1337. #ifdef COMMENT
  1338.     { "/except",   UND_EXC, CM_ARG },
  1339. #endif /* COMMENT */
  1340.     { "/matching", UND_MAT, 0 },
  1341.     { "/simulate", UND_SIM, 0 },
  1342.     { "/verbose",  UND_VRB, CM_INV }
  1343. };
  1344. static int nundefswi = sizeof(undefswi) / sizeof(struct keytab);
  1345.  
  1346. #define UNDEFMAX 64
  1347. static char ** undeflist = NULL;
  1348. int
  1349. doundef(cx) int cx; {                   /* UNDEF, _UNDEF */
  1350.     int i, j, n, rc = 0, arraymsg = 0;
  1351.     int domatch = 0, verbose = 0, errors = 0, simulate = 0, flag = 0;
  1352.     char *vnp, vnbuf[4];
  1353. #ifdef COMMENT
  1354.     char *except = NULL;
  1355. #endif /* COMMENT */
  1356.     struct FDB sw, fl;
  1357.     int getval;
  1358.     char c;
  1359.  
  1360.     if (!undeflist) {                   /* Allocate list if necessary */
  1361.         undeflist = (char **)malloc(UNDEFMAX * sizeof(char *));
  1362.         if (!undeflist) {
  1363.             printf("?Memory allocation failure\n");
  1364.             return(-9);
  1365.         }
  1366.         for (i = 0; i < UNDEFMAX; i++)
  1367.           undeflist[i] = NULL;
  1368.     }
  1369.     cmfdbi(&sw,                         /* First FDB - command switches */
  1370.            _CMKEY,                      /* fcode */
  1371.            "Variable name or switch",
  1372.            "",                          /* default */
  1373.            "",                          /* addtl string data */
  1374.            nundefswi,                   /* addtl numeric data 1: tbl size */
  1375.            4,                           /* addtl numeric data 2: 4 = cmswi */
  1376.            xxstring,                    /* Processing function */
  1377.            undefswi,                    /* Keyword table */
  1378.            &fl                          /* Pointer to next FDB */
  1379.            );
  1380.     cmfdbi(&fl,                         /* Anything that doesn't match */
  1381.            _CMFLD,                      /* fcode */
  1382.            "",                          /* hlpmsg */
  1383.            "",                          /* default */
  1384.            "",                          /* addtl string data */
  1385.            0,                           /* addtl numeric data 1 */
  1386.            0,                           /* addtl numeric data 2 */
  1387.            (cx == XXUNDEF) ? NULL : xxstring,
  1388.            NULL,
  1389.            NULL
  1390.            );
  1391.     while (1) {                         /* Parse 0 or more switches */
  1392.         x = cmfdb(&sw);                 /* Parse something */
  1393.         if (x < 0)
  1394.           return(x);
  1395.         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
  1396.           break;
  1397.         c = cmgbrk();
  1398.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  1399.             printf("?This switch does not take an argument\n");
  1400.             return(-9);
  1401.         }
  1402.         switch (cmresult.nresult) {
  1403.           case UND_MAT: domatch  = 1; break;
  1404.           case UND_SIM: simulate = 1; /* fall thru on purpose */
  1405.           case UND_VRB: verbose  = 1; break;
  1406.  
  1407. #ifdef COMMENT
  1408.           case UND_EXC:
  1409.             if (!getval) break;
  1410.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  1411.                 if (x == -3) {
  1412.                     printf("?Pattern required\n");
  1413.                     x = -9;
  1414.                 }
  1415.                 goto xgetx;
  1416.             }
  1417.             makestr(&except,cmresult.sresult);
  1418.             break;
  1419. #endif /* COMMENT */
  1420.  
  1421.           default:
  1422.             return(-2);
  1423.         }
  1424.     }
  1425.     n = 0;
  1426.     makestr(&(undeflist[n++]),cmresult.sresult);
  1427.     for (i = 1; i < UNDEFMAX; i++) {
  1428.         x = cmfld("Macro or variable name","",&s,
  1429.                   ((cx == XXUNDEF) ? NULL : xxstring)
  1430.                   );
  1431.         if (x == -3) {
  1432.             if ((y = cmcfm()) < 0)
  1433.               return(y);
  1434.             break;
  1435.         } else if (y < 0) {
  1436.             return(y);
  1437.         }
  1438.         makestr(&(undeflist[n++]),s);
  1439.     }
  1440.     /* Now we have a list of n variables or patterns to undefine */
  1441.  
  1442.     for (i = 0; i < n; i++) {
  1443.         flag = 0;
  1444.         if (!(vnp = undeflist[i]))
  1445.           continue;
  1446.         if (vnp[0] == CMDQ && (vnp[1] == '%' || vnp[1] == '&')) {
  1447.             flag++;
  1448.             vnp++;
  1449.         }
  1450.         if (!domatch) {                 /* Pattern match not requested */
  1451.             if (flag) {
  1452.                 if ((y = parsevar(vnp,&x,&z)) < 0) {
  1453.                     vnp--;
  1454.                     if (verbose) printf(" %s...error\n",vnp);
  1455.                     continue;
  1456.                 }
  1457.                 vnp--;
  1458.             }
  1459.             x = xxundef(vnp,verbose,simulate);
  1460.             if (x > -1) {
  1461.                 if (!x && !simulate) errors++;
  1462.                 rc += x;
  1463.             }
  1464.             continue;
  1465.         }
  1466.         /* Pattern match requested */
  1467.  
  1468.         if (!flag) {                    /* It's a macro */
  1469.             for (j = 0; j < nmac; j++) {
  1470.                 if (ckmatch(vnp,mactab[j].kwd,0,1)) {
  1471.                     x = xxundef(mactab[j].kwd,verbose,simulate);
  1472.                     if (x > -1) {
  1473.                         rc += x;
  1474.                         if (!x) errors++;
  1475.                     }
  1476.                     if (!simulate)
  1477.                       j--;              /* Because mactab shifted up */
  1478.                 }
  1479.             }
  1480.         } else if (vnp[0] == '%') {     /* It's a \%x variable */
  1481.             vnbuf[0] = CMDQ;
  1482.             vnbuf[1] = '%';
  1483.             vnbuf[3] = NUL;
  1484.             for (j = '0'; j <= 'z'; j++) { /* 0..9 a..z */
  1485.                 vnbuf[2] = j;
  1486.                 if (ckmatch(vnp,&vnbuf[1],0,1)) {
  1487.                     x = xxundef(vnbuf,verbose,simulate);
  1488.                     if (x > -1) {
  1489.                         if (!x) errors++;
  1490.                         rc += x;
  1491.                     }
  1492.                 }
  1493.                 if (j == '9') j = (int)'a' - 1; /* 9 -> a */
  1494.             }
  1495.         } else if (vnp[0] == '&') {
  1496.             if (!arraymsg && !quiet) {
  1497.                 printf("?UNDEFINE /MATCH can't be used with arrays.\n");
  1498.                 printf("(Type HELP ARRAY to see other methods.)\n");
  1499.             }
  1500.             arraymsg++;
  1501.             errors++;
  1502.         }
  1503.     }
  1504.     if (verbose)
  1505.       printf("undefined: %d, errors: %d\n",rc,errors);
  1506.  
  1507.     for (i = 0; i < UNDEFMAX; i++) {    /* Check them all */
  1508.         if (undeflist[i]) {             /* in case we were interrupted */
  1509.             free(undeflist[i]);         /* previously... */
  1510.             undeflist[i] = NULL;
  1511.         }
  1512.     }
  1513.     return(success = (errors == 0) ? 1 : 0);
  1514. }
  1515.  
  1516. int
  1517. dodef(cx) int cx; {
  1518.     extern int xxdot;
  1519.     extern char ppvnambuf[];
  1520.     int doeval = 0;
  1521.     char vnambuf[VNAML+1];              /* Buffer for variable names */
  1522.     char *vnp;                          /* Pointer to same */
  1523.     int k, mydot;
  1524.     mydot = xxdot;                      /* Copy */
  1525.     xxdot = 0;                          /* and reset */
  1526. /*
  1527.   In case we got here from a command that begins like ".\%a", cmkey() has
  1528.   already evaluated \%a, but we don't want that, so we retrieve the variable
  1529.   name from a special pre-evaluation buffer in the command module, and we
  1530.   undo the "unget word" that would be done because of the token, because if
  1531.   the variable was defined, it will unget its value rather than its name.
  1532. */
  1533.     s = NULL;
  1534.  
  1535.     if (mydot && ppvnambuf[0] == '.' && ppvnambuf[1]) {
  1536.         s = ppvnambuf+1;
  1537.         unungw();
  1538.     }
  1539.     if (!s) {
  1540.         if (cx == XXDFX || cx == XXASX)
  1541.           /* Evaluate variable name */
  1542.           y = cmfld("Macro or variable name","",&s,xxstring);
  1543.         else
  1544.           /* Don't evaluate the variable name */
  1545.           y = cmfld("Macro or variable name","",&s,NULL);
  1546.         if (y < 0) {
  1547.             if (y == -3) {
  1548.                 printf("?Variable name required\n");
  1549.                 return(-9);
  1550.             } else return(y);
  1551.         }
  1552.     }
  1553.     k = strlen(s);
  1554.     if (k > VNAML) {
  1555.         printf("?Name too long: \"%s\"\n",s);
  1556.         return(-9);
  1557.     }
  1558.     ckstrncpy(vnambuf,s,VNAML);
  1559.     vnambuf[VNAML] = NUL;
  1560.     vnp = vnambuf;
  1561.     if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
  1562.     if (*vnp == '%' || *vnp == '&') {
  1563.         if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
  1564. #ifdef COMMENT
  1565.         if (cx == XXUNDEF) {            /* Undefine */
  1566.             if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
  1567.             delmac(vnp,0);
  1568.             return(success = 1);
  1569.         }
  1570. #endif /* COMMENT */
  1571.         debug(F101,"dodef parsevar x","",x);
  1572.         if (mydot) {
  1573.             if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
  1574.               return(doeval);
  1575.             if (doeval > 0)             /* Type of assignment */
  1576.               cx = XXASS;
  1577.         }
  1578.         if (y == 1) {                   /* Simple variable */
  1579.             if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
  1580.               return(y);
  1581.             s = brstrip(s);
  1582.             debug(F110,"xxdef var name",vnp,0);
  1583.             debug(F110,"xxdef var def",s,0);
  1584.         } else if (y == 2) {            /* Array element */
  1585.             if ((y = arraynam(vnp,&x,&z)) < 0) return(y);
  1586.             if (x == 96) {
  1587.                 printf("?Argument vector array is read-only\n");
  1588.                 return(-9);
  1589.             }
  1590.             if (chkarray(x,z) < 0) return(-2);
  1591.             if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
  1592.               return(y);
  1593.             debug(F110,"xxdef array ref",vnp,0);
  1594.             debug(F110,"xxdef array def",s,0);
  1595.         }
  1596.     } else {                            /* Macro */
  1597. #ifdef COMMENT
  1598.         if (cx == XXUNDEF) {            /* Undefine */
  1599.             if ((y = cmtxt("Text to be ignored","",&s,NULL)) < 0) return(y);
  1600.             delmac(vnp,0);
  1601.             return(success = 1);
  1602.         }
  1603. #endif /* COMMENT */
  1604.         if (mydot) {
  1605.             if ((doeval = cmkey(asgtab,nasgtab,"operator","=",NULL)) < 0)
  1606.               return(doeval);
  1607.             if (doeval > 0)
  1608.               cx = XXASS;
  1609.         }
  1610.         if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
  1611. #ifdef DEBUG
  1612.         if (deblog) {
  1613.             debug(F110,"xxdef macro name",vnp,0);
  1614.             debug(F010,"xxdef macro def",s,0);
  1615.         }
  1616. #endif /* DEBUG */
  1617.         s = brstrip(s);
  1618.     }
  1619.     if (*s == NUL) {                    /* No arg given, undefine */
  1620.         delmac(vnp,1);                  /* silently... */
  1621.         return(success = 1);            /* even if it doesn't exist... */
  1622.     }
  1623.     /* Defining a new macro or variable */
  1624.  
  1625.     if (cx == XXASS || cx == XXASX) {   /* ASSIGN rather than DEFINE? */
  1626.         int t;
  1627.         t = LINBUFSIZ-1;
  1628.         lp = line;                      /* If so, expand its value now */
  1629.         zzstring(s,&lp,&t);
  1630.         s = line;
  1631.     }
  1632.     if (doeval == 2) {                  /* Arithmetic evaluation wanted too? */
  1633.         ckstrncpy(line,evala(s),LINBUFSIZ);
  1634.         line[LINBUFSIZ] = NUL;
  1635.     }
  1636.     /* debug(F111,"calling addmac",s,(int)strlen(s)); */
  1637.  
  1638.     y = addmac(vnp,s);                  /* Add it to the appropriate table. */
  1639.     if (y < 0) {
  1640.         printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
  1641.                "ASSIGN" : "DEFINE");
  1642.         return(success = 0);
  1643.     } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
  1644.       return(1);                           /* don't change success variable */
  1645.     else
  1646.       return(success = 1);
  1647. }
  1648. #endif /* NOSPL */
  1649.  
  1650.  
  1651. #ifndef NODIAL
  1652. /*
  1653.    L U D I A L  --  Lookup up dialing directory entry.
  1654.  
  1655.    Call with string to look up and file descriptor of open dialing directory
  1656.    file.  On success, returns number of matches found, with numbers stored
  1657.    in an array accessible via getdnum().
  1658. */
  1659. static char *dn_p[MAXDNUMS + 1];        /* Dial Number pointers */
  1660. static char *dn_p2[MAXDNUMS + 1];       /* Converted dial number pointers */
  1661. static int dn_x[MAXDNUMS + 1];          /* Type of call */
  1662. static int dncount = 0;
  1663. char * d_name = NULL;                   /* Dial name pointer */
  1664.  
  1665. char *                                  /* Get dial directory entry name */
  1666. getdname() {
  1667.     return(d_name ? d_name : "");
  1668. }
  1669.  
  1670. char *
  1671. getdnum(n) int n; {                     /* Get dial number n from directory */
  1672.     if (n < 0 || n > dncount || n > MAXDNUMS)
  1673.       return("");
  1674.     else
  1675.       return(dn_p[n]);
  1676. }
  1677.  
  1678. char *                  /* Check area code for spurious leading digit */
  1679. chk_ac(i,buf) int i; char buf[]; {
  1680.     char *p;
  1681.     if (!buf)
  1682.       return("");
  1683.     p = (char *) buf;                   /* Country we are calling: */
  1684.     if (i ==  44 ||                     /* UK */
  1685.         i ==  49 ||                     /* Germany */
  1686.         i ==  39 ||                     /* Italy */
  1687.         i ==  31 ||                     /* Netherlands */
  1688.         i == 351 ||                     /* Portugal */
  1689.         i ==  55 ||                     /* Brazil */
  1690.         i == 972 ||                     /* Israel */
  1691.         i ==  41 ||                     /* Switzerland */
  1692.         i ==  43 ||                     /* Austria */
  1693.         i ==  42 ||                     /* Czech Republic */
  1694.         i ==  36 ||                     /* Hungary */
  1695.         i ==  30 ||                     /* Greece */
  1696.         i == 352 ||                     /* Luxembourg */
  1697.         i ==  48 ||                     /* Poland */
  1698.         i ==  27 ||                     /* South Africa */
  1699.         i ==  33 ||                     /* France (as of 1997) */
  1700.         i ==  358                       /* Finland (ditto) */
  1701.         ) {
  1702.         if (buf[0] == '0')
  1703.           p++;
  1704.     }
  1705.     return(p);
  1706. }
  1707.  
  1708. /* Call Is Long Distance -- Expand this to cover 10-digit local dialing etc */
  1709. /*
  1710.    src  = area code of caller
  1711.    dest = area code of callee
  1712.    Returns:
  1713.      0 if call is local
  1714.      1 if call is long distance
  1715.      2 if call is local but area code must be dialed anyway
  1716. */
  1717. static int
  1718. callisld(src, dest) char * src, * dest; {
  1719.     int i;
  1720.     if (dialfld)                        /* Force long distance? */
  1721.       return(1);
  1722.     if (!strcmp(src,dest)) {            /* Area codes are the same */
  1723.         for (i = 0; i < nlocalac; i++)  /* Is AC in the lc-area-codes list? */
  1724.           if (!strcmp(src,diallcac[i]))
  1725.             return(2);                  /* Yes so must be dialed */
  1726.         return(0);                      /* No so don't dial it. */
  1727.     }
  1728.     for (i = 0; i < nlocalac; i++)      /* ACs not the same so look in list */
  1729.       if (!strcmp(dest,diallcac[i]))    /* Match */
  1730.         return(2);                      /* So local call with area code */
  1731.     return(1);                          /* Not local so long-distance */
  1732. }
  1733.  
  1734. char pdsfx[64] = { NUL, NUL };
  1735.  
  1736. #ifndef NOSPL
  1737. static char *
  1738. xdial(s) char *s; {                     /* Run dial string thru macro */
  1739.     int x, m;
  1740.     char * s2;
  1741.     s2 = NULL;
  1742.     makestr(&s2,s);            /* Copy the argument */
  1743.     if (!dialmac)                       /* Dial macro name given? */
  1744.       return(NULL);
  1745.     if ((x = mxlook(mactab,dialmac,nmac)) < 0) /* Is the macro defined? */
  1746.       return(NULL);
  1747.     m = maclvl;
  1748.     x = dodo(x,s2,0);            /* Set up the macro */
  1749.     if (s2) free(s2);
  1750.     if (x > 0) {
  1751.         while (maclvl > m)              /* Execute the parser */
  1752.           parser(1);
  1753.         return(mrval[maclvl+1]);        /* Return the result */
  1754.     }
  1755.     return(NULL);
  1756. }
  1757. #endif /* NOSPL */
  1758.  
  1759. static int
  1760. dncvt(k,cx, prefix, suffix)
  1761.     int k, cx, prefix, suffix; {        /* Dial Number Convert */
  1762.     int i, j, n, what;                  /* cx is top-level command index */
  1763.     char *ss;                           /* prefix - add prefixes? */
  1764.     char *p, *p2, *pxo;                 /* suffix - add suffixes? */
  1765.     char *lac;
  1766.     char *npr;
  1767.     char *sfx;
  1768.     /* char *psfx; */
  1769.     char ccbuf[128];
  1770.     int cc;
  1771.     char acbuf[24];
  1772.     char *acptr;
  1773.     char outbuf[256];
  1774. /*
  1775.   First pass for strict (punctuation-based) interpretation.
  1776.   If it fails, we try the looser (length-based) one.
  1777. */
  1778.     dialtype = -1;
  1779.     what = 0;                           /* Type of call */
  1780.     s = dn_p[k];                        /* Number to be converted. */
  1781.     debug(F111,"dncvt",s,k);
  1782.     if (dn_p2[k]) {
  1783.         free(dn_p2[k]);
  1784.         dn_p2[k] = NULL;
  1785.     }
  1786.     if (!s) {
  1787.         printf("Error - No phone number to convert\n");
  1788.         return(-1);
  1789.     }
  1790.     if ((int)strlen(s) > 200) {
  1791.         ckstrncpy(outbuf,s,40);
  1792.         printf("?Too long: \"%s...\"\n",outbuf);
  1793.         return(-1);
  1794.     }
  1795.     npr = (prefix && dialnpr) ? dialnpr : "";
  1796.     sfx = (suffix && dialsfx) ? dialsfx : "";
  1797.     /* if (partial) psfx = dialsfx ? dialsfx : ""; */
  1798.     pxo = (prefix && dialpxo) ? dialpxo : "";
  1799.     lac = diallac ? diallac : "";       /* Local area code */
  1800.  
  1801.     outbuf[0] = NUL;                    /* Initialize conversion buffer */
  1802.     ss = s;                             /* Remember original string */
  1803.  
  1804.     if (*s != '+') {                    /* Literal number */
  1805.         dn_x[k] = DN_UNK;               /* Sort key is "unknown". */
  1806.         ckmakmsg(outbuf,256,            /* Sandwich it between */
  1807.                  pxo,npr,s,sfx          /* DIAL PREFIX and SUFFIX */
  1808.                 );
  1809. #ifdef CK_TAPI
  1810.         if (tttapi &&                   /* TAPI does its own conversions */
  1811.             !tapipass &&                /* if not in passthru mode */
  1812.             tapiconv == CK_AUTO ||      /* and TAPI conversions are AUTO */
  1813.             tapiconv == CK_ON           /* OR if TAPI conversions are ON */
  1814.             ) {
  1815.             char * p = NULL;
  1816.             dialtype = -2;
  1817.             if (!cktapiConvertPhoneNumber(dn_p[k], &p))
  1818.               return(-1);
  1819.             makestr(&dn_p2[k], p);
  1820.             if (p) free(p);
  1821.             return(0);
  1822.         } else
  1823. #endif /* CK_TAPI */
  1824.           makestr(&dn_p2[k], outbuf);   /* Not TAPI */
  1825.         dialtype = what;
  1826.         return(0);                      /* Done. */
  1827.     }
  1828.     i = 0;                              /* Portable number */
  1829.     s++;                                /* Tiptoe past the plus sign */
  1830.     ccbuf[0] = NUL;                     /* Do country code first */
  1831.  
  1832.     if (!diallcc) {                     /* Do we know our own? */
  1833.         if (cx != XXLOOK)
  1834.           printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
  1835.         return(-1);
  1836.     }
  1837.  
  1838.     /* Parse the number */
  1839.  
  1840.     while (1) {                         /* Get the country code */
  1841.         while (*s == HT || *s == SP)
  1842.           s++;
  1843.         if (!s)                         /* Not in standard format */
  1844.           break;
  1845.         if (*s == '(') {                /* Beginning of area code  */
  1846.             s++;                        /* Skip past parenthesis   */
  1847.             ccbuf[i] = NUL;             /* End of country code */
  1848.             if (!s) {                   /* Check for end of string */
  1849.                 printf("Error - phone number ends prematurely: \"%s\"\n",ss);
  1850.                 return(-1);
  1851.             }
  1852.             break;
  1853.         } else {                        /* Collect country code */
  1854.             if (isdigit(*s))
  1855.               ccbuf[i++] = *s;          /* copy this character */
  1856.             s++;
  1857.             if (!*s || i > 127)         /* watch out for memory leak */
  1858.               break;
  1859.         }
  1860.     }
  1861.     cc = atoi(ccbuf);                   /* Numeric version of country code */
  1862.  
  1863.     i = 0;                              /* Now get area code */
  1864.     acbuf[0] = NUL;                     /* Initialize area-code buffer */
  1865.     acptr = acbuf;                      /* and pointer. */
  1866.     while (1) {
  1867.         while (*s == HT || *s == SP)    /* Ignore whitespace */
  1868.           s++;
  1869.         if (!s)                         /* String finished */
  1870.           break;
  1871.         if (*s == ')') {                /* End of area code  */
  1872.             s++;                        /* Skip past parenthesis   */
  1873.             acbuf[i] = NUL;             /* Terminate area-code buffer */
  1874.             break;
  1875.         } else {                        /* Part of area code */
  1876.             if (isdigit(*s))            /* If it's a digit, */
  1877.               acbuf[i++] = *s;          /* copy this character */
  1878.             s++;                        /* Point to next */
  1879.             if (!*s || i > 23)          /* Watch out for overflow */
  1880.               break;
  1881.         }
  1882.     }
  1883.  
  1884. /*
  1885.    Here we strip any leading 0 for countries that we know have
  1886.    0 as a long-distance prefix and do not have any area codes that
  1887.    start with 0 (formerly also ditto for "9" in Finland...)
  1888. */
  1889.     i = atoi(ccbuf);
  1890.     acptr = chk_ac(i,acbuf);
  1891.  
  1892.     while (*s == HT || *s == SP)        /* Skip whitespace */
  1893.       s++;
  1894.  
  1895. /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
  1896.  
  1897.     if (*s && *acptr) {                 /* Area code was delimited */
  1898.  
  1899.         while (*s == '-' || *s == '.')  /* Skip past gratuitious punctuation */
  1900.           s++;
  1901.         if (!*s) s--;                   /* But not to end of string */
  1902.  
  1903.         if (strcmp(diallcc,ccbuf)) {    /* Out of country? */
  1904.             if (!dialixp) {             /* Need intl-prefix */
  1905.                 if (cx != XXLOOK)
  1906.                   printf("Error - No international dialing prefix defined\n");
  1907.                 return(-1);
  1908.             }
  1909.             what = dn_x[k] = DN_INTL;
  1910.             p  = (prefix && dialixp) ? dialixp : ""; /* Intl-prefix */
  1911.             p2 = (suffix && dialixs) ? dialixs : ""; /* Intl-suffix */
  1912.  
  1913.             /* Form the final phone number */
  1914. #ifdef COMMENT
  1915.             sprintf(pdsfx,"%s%s",p2,sfx); /* UNSAFE */
  1916.             sprintf(outbuf,
  1917.                     "%s%s%s%s%s%s%s%s",
  1918.                     pxo,npr,p,ccbuf,acptr,s,p2,sfx
  1919.                     );
  1920. #else
  1921.             ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  1922.             ckmakxmsg(outbuf,256,pxo,npr,p,ccbuf,acptr,s,p2,sfx,
  1923.                       NULL,NULL,NULL,NULL);
  1924. #endif /* COMMENT */
  1925.  
  1926.         } else if ((x = callisld(lac,acptr)) >= 1) { /* In-country LD */
  1927.             if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
  1928.                 if (cc == 1)
  1929.                   printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
  1930.             }
  1931.             if (x == 2) {               /* Local call with area code */
  1932.                 what = dn_x[k] = DN_LOCAL;      /* Local-call */
  1933.                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
  1934.                 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
  1935.             } else {
  1936.                 what = dn_x[k] = DN_LONG;       /* Long-distance */
  1937.                 for (i = 0; i < ntollfree; i++) { /* But toll-free too? */
  1938.                     if (!strcmp(acptr,dialtfc[i])) {
  1939.                         what = dn_x[k] = DN_FREE;
  1940.                         break;
  1941.                     }
  1942.                 }
  1943.                 if (what == DN_FREE) {  /* Toll-free call */
  1944.                     p = (prefix && dialtfp) ? dialtfp :
  1945.                         ((prefix && dialldp) ? dialldp : "");
  1946.                     p2 = "";            /* no suffix */
  1947.                 } else {                        /* normal long distance */
  1948.                     p  = (prefix && dialldp) ? dialldp : ""; /* ld-prefix */
  1949.                     p2 = (suffix && diallds) ? diallds : ""; /* ld-suffix */
  1950.                 }
  1951.             }
  1952.             /* Form the number to be dialed */
  1953. #ifdef COMMENT
  1954.             sprintf(outbuf,"%s%s%s%s%s%s%s",
  1955.                     pxo,npr,p,acptr,s,p2,sfx
  1956.                     );
  1957.             sprintf(pdsfx,"%s%s",p2,sfx);
  1958. #else
  1959.             ckmakxmsg(outbuf,256,
  1960.                       pxo,npr,p,acptr,s,p2,sfx,
  1961.                       NULL,NULL,NULL,NULL,NULL);
  1962.             ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  1963. #endif /* COMMENT */
  1964.         } else {                        /* Same country, same area code */
  1965.             what = dn_x[k] = DN_LOCAL;  /* So it's a local call. */
  1966.             if (!prefix || !(dialpxo || ndialpxx)) { /* Not dialing from PBX */
  1967.                 p  = (prefix && diallcp) ? diallcp : ""; /* local-prefix */
  1968.                 p2 = (suffix && diallcs) ? diallcs : ""; /* local-suffix */
  1969. #ifdef COMMENT
  1970.                 if (x == 2)
  1971.                   sprintf(outbuf,"%s%s%s%s%s%s",npr,p,acptr,s,p2,sfx);
  1972.                 else
  1973.                   sprintf(outbuf,"%s%s%s%s%s",npr,p,s,p2,sfx);
  1974.                 sprintf(pdsfx,"%s%s",p2,sfx);
  1975. #else
  1976.                 if (x == 2)
  1977.                   ckmakxmsg(outbuf,256,
  1978.                             npr,p,acptr,s,p2,sfx,
  1979.                             NULL,NULL,NULL,NULL,NULL,NULL);
  1980.                 else
  1981.                   ckmakxmsg(outbuf,256,
  1982.                             npr,p,s,p2,sfx,
  1983.                             NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  1984.                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  1985. #endif /* COMMENT */
  1986.  
  1987.             } else {                    /* Dialing from a PBX and not TAPI */
  1988.                 if (ndialpxx) {         /* Is it internal? */
  1989. #ifdef COMMENT
  1990.                     i = (int) strlen(dialpxx);
  1991.                     j = (int) strlen(s);
  1992.                     x = -1;
  1993.                     if (j > i)
  1994.                       x = ckstrcmp(dialpxx,s,i,0);
  1995. #else
  1996.                     int kx;
  1997.                     x = -1;
  1998.                     j = (int) strlen(s);
  1999.                     for (kx = 0; kx < ndialpxx; kx++) {
  2000.                         i = (int) strlen(dialpxx[kx]);
  2001.                         if (j > i)
  2002.                           if (!(x = ckstrcmp(dialpxx[kx],s,i,0)))
  2003.                             break;
  2004.                     }
  2005. #endif /* COMMENT */
  2006.                     if (!x) {
  2007.                         char * icp, buf[32];
  2008.                         makestr(&matchpxx,dialpxx[kx]);
  2009.                         debug(F111,"dncvt matchpxx",matchpxx,kx);
  2010.                         what = dn_x[kx] = DN_INTERN;   /* Internal call. */
  2011.                         s += i;
  2012.                         /* Internal-call prefix */
  2013.                         icp = dialpxi;
  2014. #ifndef NOSPL
  2015.                         if (icp) {
  2016.                             if (*icp == '\\') {
  2017.                                 char c, *bp;
  2018.                                 int n;
  2019.                                 c = *(icp+1);
  2020.                                 if (isupper(c)) c = tolower(c);
  2021.                                 if (c == 'v' || c == 'f') {
  2022.                                     n = 32;
  2023.                                     bp = buf;
  2024.                                     zzstring(icp,&bp,&n);
  2025.                                     icp = buf;
  2026.                                 }
  2027.                             }
  2028.                         }
  2029. #endif /* NOSPL */
  2030.                         p = (prefix && icp) ? icp : "";
  2031. #ifdef COMMENT
  2032.                         sprintf(outbuf,"%s%s%s%s",npr,p,s,sfx);
  2033. #else
  2034.                         ckmakmsg(outbuf,256,npr,p,s,sfx);
  2035. #endif /* COMMENT */
  2036.                     } else {            /* External local call */
  2037.                         /* local-prefix */
  2038.                         p  = (prefix && diallcp) ? diallcp : "";
  2039.                         /* local-suffix */
  2040.                         p2 = (prefix && diallcs) ? diallcs : "";
  2041. #ifdef COMMENT
  2042.                         if (x == 2)
  2043.                           sprintf(outbuf,"%s%s%s%s%s%s%s",
  2044.                                   dialpxo ? dialpxo : "",
  2045.                                   npr,p,acptr,s,p2,sfx);
  2046.                         else
  2047.                           sprintf(outbuf,
  2048.                                   "%s%s%s%s%s%s",
  2049.                                   dialpxo ? dialpxo : "",
  2050.                                   npr,p,s,p2,sfx
  2051.                                   );
  2052. #else
  2053.                         if (x == 2)
  2054.                           ckmakxmsg(outbuf, 256,
  2055.                                    dialpxo ? dialpxo : "",
  2056.                                    npr,p,acptr,s,p2,sfx,
  2057.                                    NULL,NULL,NULL,NULL,NULL);
  2058.                         else
  2059.                           ckmakxmsg(outbuf, 256,
  2060.                                     dialpxo ? dialpxo : "",
  2061.                                     npr,p,s,p2,sfx,
  2062.                                     NULL,NULL,NULL,NULL,NULL,NULL);
  2063. #endif /* COMMENT */
  2064.                     }
  2065.                 }
  2066.             }
  2067.         }
  2068.  
  2069.     } else {                            /* Area code was not delimited */
  2070.  
  2071.         char xbuf[256];                 /* Comparison based only on length */
  2072.         char ybuf[256];
  2073.         int x, j;
  2074.  
  2075.         s = ss;
  2076.  
  2077.         for (i = 0; i < 255; i++) {
  2078.             if (!*s) break;
  2079.             while (!isdigit(*s)) {      /* Pay attention only to digits */
  2080.                 s++;
  2081.                 if (!*s) break;
  2082.             }
  2083.             xbuf[i] = *s++;
  2084.         }
  2085.         xbuf[i] = NUL;
  2086.  
  2087.         x = 1;                          /* Assume LD */
  2088.         n = 0;
  2089.         if (!dialfld) {                 /* If LD not forced */
  2090.             for (j = 0; j < nlocalac; j++) { /* check local AC list? */
  2091.                 ckmakmsg(ybuf,256,diallcc,diallcac[j],NULL,NULL);
  2092.                 n = (int) strlen(ybuf);
  2093.                 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) {
  2094.                     x = 2;
  2095.                     break;
  2096.                 }
  2097.             }
  2098.             if (x == 1) {               /* Or exact match with local CC+AC? */
  2099.                 ckmakmsg(ybuf,256,diallcc,lac,NULL,NULL);
  2100.                 n = (int) strlen(ybuf);
  2101.                 if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0))
  2102.                   x = 0;
  2103.             }
  2104.         }
  2105.         if (x == 0 || x == 2) {         /* Local call */
  2106.             int xx,kx;                  /* Begin 1 Dec 2001... */
  2107.             /* Account for PBX internal calls */
  2108.             if (ndialpxx) {
  2109.                 xx = -1;
  2110.                 j = (int) strlen(ybuf);
  2111.                 for (kx = 0; kx < ndialpxx; kx++) {
  2112.                     i = (int) strlen(dialpxx[kx]);
  2113.                     if (j >= i)
  2114.                       if (!(xx = ckstrcmp(dialpxx[kx],&xbuf[j],i,0)))
  2115.                         break;
  2116.                 }
  2117.             }
  2118.             if (!xx) {
  2119.                 char * icp, buf[32];
  2120.                 makestr(&matchpxx,dialpxx[kx]);
  2121.                 debug(F111,"dncvt matchpxx",matchpxx,kx);
  2122.                 what = dn_x[kx] = DN_INTERN; /* Internal call. */
  2123.                 s = xbuf + j + i;
  2124.                 icp = dialpxi;          /* Internal-call prefix */
  2125. #ifndef NOSPL
  2126.                 if (icp) {
  2127.                     if (*icp == '\\') {
  2128.                         char c, *bp;
  2129.                         int n;
  2130.                         c = *(icp+1);
  2131.                         if (isupper(c)) c = tolower(c);
  2132.                         if (c == 'v' || c == 'f') {
  2133.                             n = 32;
  2134.                             bp = buf;
  2135.                             zzstring(icp,&bp,&n);
  2136.                             icp = buf;
  2137.                         }
  2138.                     }
  2139.                 }
  2140. #endif /* NOSPL */
  2141.                 p = (prefix && icp) ? icp : "";
  2142.                 ckmakmsg(outbuf,256,npr,p,s,sfx);
  2143.                 /* End 1 Dec 2001... */
  2144.  
  2145.             } else {                    /* Not PBX internal */
  2146.  
  2147.                 dn_x[k] = DN_LOCAL;
  2148.                 p = (prefix && diallcp) ? diallcp : "";
  2149.                 p2 = (suffix && diallcs) ? diallcs : "";
  2150.                 s = (char *) (xbuf + ((x == 0) ? n : (int)strlen(diallcc)));
  2151.                 ckmakxmsg(outbuf,256,
  2152.                           pxo,npr,p,s,p2,sfx,
  2153.                           NULL,NULL,NULL,NULL,NULL,NULL);
  2154.                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  2155.             }
  2156.         } else {                        /* Not local */
  2157.             n = ckstrncpy(ybuf,diallcc,256);
  2158.             if (n > 0 && !ckstrcmp(xbuf,ybuf,n,0)) { /* Long distance */
  2159.                 dn_x[k] = DN_LONG;
  2160.                 p = (prefix && dialldp) ? dialldp : "";
  2161.                 p2 = (suffix && diallds) ? diallds : "";
  2162.                 s = xbuf + n;
  2163.                 while (*s == '-' || *s == '.')
  2164.                   s++;
  2165. #ifdef COMMENT
  2166.                 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
  2167.                 sprintf(pdsfx,"%s%s",p2,sfx);
  2168. #else
  2169.                 ckmakxmsg(outbuf,256,
  2170.                           pxo,npr,p,s,p2,sfx,
  2171.                          NULL,NULL,NULL,NULL,NULL,NULL);
  2172.                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  2173. #endif /* COMMENT */
  2174.             } else {
  2175.                 dn_x[k] = DN_INTL;      /* International */
  2176.                 if (!dialixp) {
  2177.                     if (cx != XXLOOK) {
  2178.                         printf(
  2179.                           "Error - No international dialing prefix defined\n"
  2180.                                );
  2181.                         return(-1);
  2182.                     }
  2183.                 }
  2184.                 p = (prefix && dialixp) ? dialixp : "";
  2185.                 p2 = (suffix && dialixs) ? dialixs : "";
  2186. #ifdef COMMENT
  2187.                 sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
  2188.                 sprintf(pdsfx,"%s%s",p2,sfx);
  2189. #else
  2190.                 ckmakxmsg(outbuf,256,
  2191.                           pxo,npr,p,xbuf,p2,sfx,
  2192.                           NULL,NULL,NULL,NULL,NULL,NULL);
  2193.                 ckmakmsg(pdsfx,64,p2,sfx,NULL,NULL);
  2194. #endif /* COMMENT */
  2195.             }
  2196.         }
  2197.     }
  2198. #ifdef CK_TAPI
  2199.     if (tttapi &&                       /* TAPI performs the conversions */
  2200.         !tapipass &&
  2201.         tapiconv == CK_AUTO ||
  2202.         tapiconv == CK_ON
  2203.         ) {
  2204.         p = NULL;
  2205.         dialtype = -2;
  2206.         if (!cktapiConvertPhoneNumber(dn_p[k],&p))
  2207.           return(-1);
  2208.         makestr(&dn_p2[k], p);
  2209.         if (p) free(p);
  2210.         return(0);
  2211.     } else {
  2212. #endif /* CK_TAPI */
  2213.         makestr(&dn_p2[k], outbuf);
  2214. #ifdef CK_TAPI
  2215.     }
  2216. #endif /* CK_TAPI */
  2217.     dialtype = what;
  2218.     return(0);
  2219. }
  2220.  
  2221. static int
  2222. ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
  2223.     char linebuf[1024], *s2;            /* Buffers and pointers */
  2224. #ifdef VMS
  2225.     char * temp = NULL;
  2226. #endif /* VMS */
  2227.     char *info[8];                      /* Pointers to words from entry */
  2228.     FILE * f2 = NULL;
  2229.     int x, rc;
  2230.     rc = -1;
  2231.  
  2232.     debug(F110,"ddcvt file",s,0);
  2233.  
  2234.     if (!s || !f)                       /* No filename or file */
  2235.       return(-1);
  2236.     if (!*s)
  2237.  
  2238.     fclose(f);
  2239.     znewn(s,&s2);                       /* s2 = address of static buffer */
  2240.     debug(F110,"ddcvt newname",s2,0);
  2241.  
  2242. #ifdef VMS
  2243.     /* In VMS, znewn() returns the same file name with a new version number */
  2244.     makestr(&temp,s);                   /* Swap - otherwise the new */
  2245.     s = s2;                             /* version has the older version */
  2246.     s2 = temp;                          /* number... */
  2247.     debug(F110,"ddcvt after swap s",s,0);
  2248.     debug(F110,"ddcvt after swap s2",s2,0);
  2249.     makestr(&(dialdir[n]),s);           /* New file gets new version number */
  2250.     debug(F110,"ddcvt after makestr s2",s2,0);
  2251.     debug(F111,"ddcvt dialdir[n]",dialdir[n],n);
  2252. #else
  2253.     if (zrename(s,s2) < 0) {            /* Not VMS - rename old file */
  2254.         perror(s2);                     /* to new (wierd) name. */
  2255.         goto ddexit;
  2256.     }
  2257. #endif /* VMS */
  2258.     debug(F110,"ddcvt s2 (old)",s2,0);
  2259.     if ((f = fopen(s2,"r")) == NULL) {  /* Reopen old file with wierd name */
  2260.         debug(F110,"ddcvt s2 open error",ck_errstr(),0);
  2261.         dirline = 0;                    /* (or in VMS, old version) */
  2262.         perror(s2);
  2263.         goto ddexit;
  2264.     }
  2265.     debug(F110,"ddcvt fopen(s2) OK",s2,0);
  2266.  
  2267.     debug(F110,"ddcvt s (new)",s,0);
  2268.     if ((f2 = fopen(s,"w")) == NULL) {  /* Create new file with old name */
  2269.         debug(F110,"ddcvt s open error",ck_errstr(),0);
  2270.         perror(s);                      /* (or in VMS, new version) */
  2271.         goto ddexit;
  2272.     }
  2273.     debug(F110,"ddcvt fopen(s) OK",s,0);
  2274.  
  2275.     printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
  2276.     fprintf(f2,"; %s - Kermit dialing directory\n", s);
  2277.     fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
  2278.                "; Name","Number","Speed","Parity","Comment"
  2279.                );
  2280.  
  2281.     while (1) {
  2282.         linebuf[0] = NUL;               /* Read a line */
  2283.         if (fgets(linebuf,1023,f) == NULL)
  2284.           break;
  2285.         debug(F110,"ddcvt linebuf",linebuf,0);
  2286.         if (!linebuf[0]) {              /* Empty line */
  2287.             fprintf(f2,"\n");
  2288.             continue;
  2289.         }
  2290.         x = (int) strlen(linebuf);      /* Strip line terminator, */
  2291.         while (x-- > 0) {               /* if any. */
  2292.             if (linebuf[x] <= SP)
  2293.               linebuf[x] = NUL;
  2294.             else
  2295.               break;
  2296.         }
  2297.         xwords(linebuf,5,info,1);       /* Parse it the old way */
  2298.         for (x = 1; x < 6; x++)
  2299.           if (!info[x]) info[x] = "";
  2300.         fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
  2301.                info[1],info[2],info[3],info[4],info[5]
  2302.                );
  2303.     }
  2304.     printf(" OK\n\n");
  2305.     rc = 0;                             /* Success */
  2306.   ddexit:
  2307.     if (f) fclose(f);
  2308.     if (f2) fclose(f2);
  2309. #ifdef VMS
  2310.     if (temp) free(temp);
  2311. #endif /* VMS */
  2312.     return(rc);
  2313. }
  2314.  
  2315. int                                     /* s = name to look up   */
  2316. #ifdef CK_ANSIC                         /* cx = index of command */
  2317. ludial(char *s, int cx)                 /* (DIAL, LOOKUP, etc)   */
  2318. #else
  2319. ludial(s, cx) char *s; int cx;
  2320. #endif /* CK_ANSIC */
  2321. /* ludial */ {
  2322.  
  2323.     int dd, n1, n2, n3, i, j, t;        /* Workers */
  2324.     int olddir, newdir, oldentry, newentry;
  2325.     int pass = 0;
  2326.     int oldflg = 0;
  2327.     int ambiguous = 0;                  /* Flag for lookup was ambiguous */
  2328.     char *info[7];                      /* Pointers to words from entry */
  2329.     char *pp;                           /* Pointer to element of array */
  2330.     FILE * f;
  2331.     char *line;                         /* File input buffer */
  2332.  
  2333. /* #define LUDEBUG */
  2334.  
  2335. #ifdef LUDEBUG
  2336. int zz = 1;
  2337. #endif /* LUDEBUG */
  2338.  
  2339.     if (!s || ndialdir < 1)             /* Validate arguments */
  2340.       return(-1);
  2341.  
  2342.     if ((n1 = (int) strlen(s)) < 1)     /* Length of string to look up */
  2343.       return(-1);
  2344.  
  2345.     if (!(line = malloc(1024)))         /* Allocate input buffer */
  2346.       return(-1);
  2347.  
  2348. #ifdef LUDEBUG
  2349. if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
  2350. #endif /* LUDEBUG */
  2351.  
  2352.     pass = 0;
  2353.   lu_again:
  2354.     f = NULL;                           /* Dial directory file descriptor */
  2355.     t = dncount = 0;                    /* Dial-number match count */
  2356.     dd = 0;                             /* Directory counter */
  2357.     olddir = 0;
  2358.     newdir = 0;
  2359. /*
  2360.   We need to recognize both old- and new-style directories.
  2361.   But we can't allow old-style and new-style entries in the same
  2362.   directory because there is no way to tell for sure the difference between
  2363.   an old-style entry like this:
  2364.  
  2365.     foo  5551212  9600
  2366.  
  2367.   and a new-style literal entry like this:
  2368.  
  2369.     foo  555 9600
  2370.  
  2371.   I.e. is the "9600" a speed, or part of the phone number?
  2372. */
  2373.     while (1) {                         /* We make one pass */
  2374.         if (!f) {                       /* Directory not open */
  2375.             if (dd >= ndialdir)         /* No directories left? */
  2376.               break;                    /* Done. */
  2377.             debug(F111,"ludial dialdir[dd]",dialdir[dd],dd);
  2378.             if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
  2379.                 perror(dialdir[dd]);    /* Can't, print message saying why */
  2380.                 if (line) {
  2381.                     free(line);
  2382.                     line = NULL;
  2383.                 }
  2384.                 dd++;                   /* Go on to next one, if any... */
  2385.                 continue;
  2386.             }
  2387.             dirline = 0;                /* Directory file line number */
  2388.             if (dialdpy && !pass)
  2389.               printf("Opening: %s...\n",dialdir[dd]);
  2390.             dd++;
  2391.             if (!oldflg) olddir = 0;
  2392.             newdir = 0;
  2393.         }
  2394.         oldentry = 0;
  2395.         newentry = 0;
  2396.         line[0] = NUL;
  2397.         if (getnct(line,1023,f,1) < 0) { /* Read a line */
  2398.             if (f) {                    /* f can be clobbered! */
  2399.                 fclose(f);              /* Close the file */
  2400.                 f = NULL;               /* Indicate next one needs opening */
  2401.                 oldflg = 0;
  2402.             }
  2403.             continue;
  2404.         }
  2405.         if (!line[0])                   /* Empty line */
  2406.           continue;
  2407. #ifdef LUDEBUG
  2408. if (zz) printf("LUDIAL 2 s[%s]\n",s);
  2409. #endif /* LUDEBUG */
  2410.  
  2411.         /* Make a copy and parse it the old way */
  2412.         /* A copy is needed because xwords() pokes NULs into the string */
  2413.  
  2414.         if ((pp = malloc((int)strlen(line) + 1))) {
  2415.             strcpy(pp,line);            /* safe */
  2416.             xwords(pp,5,info,0);        /* Parse it the old way */
  2417.  
  2418. #ifdef LUDEBUG
  2419. if (zz) printf("LUDIAL 3 s[%s]\n",s);
  2420. #endif /* LUDEBUG */
  2421.  
  2422.             if (!info[1])
  2423.               continue;
  2424.             if (*info[1] == ';') {      /* If full-line comment, */
  2425.                 newdir = 1;             /* (only new directories have them) */
  2426.                 continue;               /* keep reading. */
  2427.             }
  2428.             if (!info[2])
  2429.               continue;
  2430.             if (*info[2] == '+')
  2431.               newentry = 1;
  2432.             if (info[4]) {
  2433.                 if ((*info[4] == '=') ||
  2434.                     !ckstrcmp(info[4],"none", 4,0) ||
  2435.                     !ckstrcmp(info[4],"even", 4,0) ||
  2436.                     !ckstrcmp(info[4],"space",5,0) ||
  2437.                     !ckstrcmp(info[4],"mark", 4,0) ||
  2438.                     !ckstrcmp(info[4],"odd",  3,0)
  2439.                     )
  2440.                   oldentry = 1;
  2441.             }
  2442.         }
  2443.         if (pp) {
  2444.             free(pp);
  2445.             pp = NULL;
  2446.         }
  2447.  
  2448.         /* Check consistency */
  2449.  
  2450.         if ((oldentry || olddir) && (newentry || newdir)) {
  2451.             printf(
  2452. "\nERROR: You seem to have old- and new-format entries mixed in your\n");
  2453.             printf(
  2454. "dialing directory.  You'll have to edit it by hand to convert it to the\n");
  2455. #ifndef NOHELP
  2456.             printf("new format.  Type HELP DIAL for further information.\n\n");
  2457. #else
  2458.             printf("new format.\n\n");
  2459. #endif /* NOHELP */
  2460.             if (line) {
  2461.                 free(line);
  2462.                 line = NULL;
  2463.             }
  2464.             return(-1);
  2465.         }
  2466.         if (!olddir && oldentry) {
  2467.             int convert = 0;
  2468.             olddir = 1;
  2469.             if (dialcvt == 2) {         /* 2 == ASK */
  2470.                 sprintf(tmpbuf,
  2471. "WARNING: Old-style dialing directory detected:\n%s", line);
  2472.         convert = uq_ok(tmpbuf,
  2473.                 "Shall I convert it for you? ",3,NULL,0);
  2474.             } else
  2475.               convert = dialcvt;
  2476.             if (convert) {
  2477.                 debug(F111,"ludial calling ddcvt",dialdir[dd-1],dd);
  2478.                 if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
  2479.                     debug(F111,"ludial ddcvt failed",dialdir[dd-1],dd);
  2480.                     oldflg = 1;
  2481.                     printf(
  2482. "  Sorry, can't convert.");
  2483.                     printf(
  2484. "  Will ignore speed and parity fields, continuing...\n\n");
  2485.                 } else {
  2486.                     olddir = newdir = 0;
  2487.                     debug(F111,"ludial ddcvt ok",dialdir[dd-1],dd);
  2488.                 }
  2489.                 dd--;
  2490.                 f = NULL;
  2491.                 continue;
  2492.             } else {
  2493.                 if (dialcvt == 2)
  2494.                   printf(
  2495. "  OK, will ignore speed and parity fields, continuing...\n\n");
  2496.                 olddir = 1;
  2497.             }
  2498.         }
  2499.  
  2500. #ifdef LUDEBUG
  2501. if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
  2502. #endif /* LUDEBUG */
  2503.  
  2504.         /* Now parse again for real */
  2505.  
  2506.         if (oldentry)                   /* Parse it the old way */
  2507.           xwords(line,5,info,0);
  2508.         else                            /* Parse it the new way */
  2509.           xwords(line,2,info,1);
  2510.  
  2511. #ifdef LUDEBUG
  2512. if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
  2513. if (zz) printf("%s [%s]\n",info[1],info[2]);
  2514. #endif /* LUDEBUG */
  2515.  
  2516.         if (info[1]) {                  /* First word is entry name */
  2517.             if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
  2518.               continue;                 /* If no first word, keep reading. */
  2519.             if (n3 < n1)                /* Search name is longer */
  2520.               continue;                 /* Can't possibly match */
  2521.             if (ambiguous && n3 != n1)
  2522.               continue;
  2523.  
  2524. #ifdef LUDEBUG
  2525. if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
  2526. #endif /* LUDEBUG */
  2527.  
  2528.             if (ckstrcmp(s,info[1],n1,0)) /* Caseless string comparison */
  2529.               continue;
  2530.  
  2531. #ifdef LUDEBUG
  2532. if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
  2533. #endif /* LUDEBUG */
  2534.  
  2535.             if (!info[2])               /* No phone number given */
  2536.               continue;
  2537.             if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
  2538.               continue;                 /* Ignore empty phone numbers */
  2539.  
  2540.             /* Got one */
  2541.  
  2542.             if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
  2543.                 printf("?internal error - ludial malloc 1\n");
  2544.                 if (line) {
  2545.                     free(line);
  2546.                     line = NULL;
  2547.                 }
  2548.                 dncount = 0;
  2549.                 return(-1);
  2550.             }
  2551.             strcpy(pp,info[2]);         /* safe */
  2552.  
  2553.             if (dncount > MAXDNUMS) {
  2554.                 printf("Warning: %d matches found, %d max\n",
  2555.                        dncount,
  2556.                        MAXDNUMS
  2557.                        );
  2558.                 dncount = MAXDNUMS;
  2559.                 break;
  2560.             }
  2561.             dn_p[dncount++] = pp;       /* Add pointer to array. */
  2562.             if (dncount == 1) {         /* First one... */
  2563.                 if (d_name) free(d_name);
  2564.                 if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
  2565.                     printf("?internal error - ludial malloc 2\n");
  2566.                     if (line) {
  2567.                         free(line);
  2568.                         line = NULL;
  2569.                     }
  2570.                     dncount = 0;
  2571.                     return(-1);
  2572.                 }
  2573.                 t = n3;                 /* And its length */
  2574.                 strcpy(d_name,info[1]); /* safe */
  2575.             } else {                    /* Second or subsequent one */
  2576.  
  2577. #ifdef LUDEBUG
  2578.                 if (zz)
  2579.                   printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
  2580. #endif /* LUDEBUG */
  2581.  
  2582.                 if ((int) strlen(info[1]) == t) /* Lengths compare */
  2583.                   if (!ckstrcmp(d_name,info[1],t,0)) /* Caseless compare OK */
  2584.                     continue;
  2585.  
  2586.                 /* Name given by user matches entries with different names */
  2587.  
  2588.                 if (ambiguous)          /* Been here before */
  2589.                   break;
  2590.  
  2591.                 ambiguous = 1;          /* Now an exact match is required */
  2592.                 for (j = 0; j < dncount; j++) { /* Clean out previous list */
  2593.                     if (dn_p[j]) {
  2594.                         free(dn_p[j]);
  2595.                         dn_p[j] = NULL;
  2596.                     }
  2597.                 }
  2598.                 pass++;                 /* Second pass... */
  2599.                 goto lu_again;          /* Do it all over again. */
  2600.             }
  2601.         }
  2602.     }
  2603.     if (line) free(line);
  2604.     if (dncount == 0 && ambiguous) {
  2605.         printf(" Lookup: \"%s\" - ambiguous%s\n",
  2606.                s,
  2607.                cx == XXLOOK ? "" : " - dialing skipped"
  2608.                );
  2609.         return(-2);
  2610.     }
  2611.     return(dncount);
  2612. }
  2613.  
  2614. char *
  2615. pncvt(s) char *s; {                     /* Phone number conversion */
  2616.     char *p = NULL;                     /* (just a wrapper for dncvt() */
  2617.     char *q = NULL;
  2618.     static char pnbuf[128];
  2619.     makestr(&p,dn_p[0]);                /* Save these in case they are */
  2620.     makestr(&q,dn_p2[0]);               /* being used */
  2621.     makestr(&dn_p[0],s);                /* Copy the argument string to here */
  2622.     dncvt(0,XXLOOK,1,1);                /* Convert it */
  2623.     if (!dn_p2[0])                      /* Put result where can return it */
  2624.       pnbuf[0] = NUL;
  2625.     else
  2626.       ckstrncpy(pnbuf,dn_p2[0],127);
  2627.     makestr(&dn_p[0],p);                /* Restore these */
  2628.     makestr(&dn_p2[0],q);
  2629.     makestr(&p,NULL);                   /* Free these */
  2630.     makestr(&q,NULL);
  2631.     return((char *)pnbuf);
  2632. }
  2633.  
  2634. int
  2635. dodial(cx) int cx; {                    /* DIAL or REDIAL */
  2636.     int i = 0, x = 0;                   /* Workers */
  2637.     int sparity = -1;                   /* For saving global parity value */
  2638.     int previous = 0;
  2639.     int len = 0;
  2640.     int literal = 0;
  2641.     int flowsave;
  2642.     int lufound = 0;                    /* Did any lookup succeed? */
  2643.     int prefix = 1;
  2644.     int postfix = 1;
  2645.     int wasalpha = 0;
  2646.     int xredial = 0;
  2647.     int braces = 0;
  2648.  
  2649.     char *p = NULL, *s3 = NULL, * sav = NULL;
  2650.     int j = 0, t = 0, n = 0;
  2651.     int xretries, xlcc;
  2652.  
  2653. #ifdef COMMENT
  2654.     debug(F101,"dodial cx","",cx);
  2655.     debug(F111,"dodial diallcc",diallcc,diallcc);
  2656. #endif    /* COMMENT */
  2657.  
  2658.     xretries = dialrtr;                 /* If retries not set, */
  2659.     if (diallcc) {                      /* choose default based on */
  2660.         xlcc = atoi(diallcc);           /* local country code. */
  2661.         if (xretries < 0) {
  2662.             switch (xlcc) {
  2663.               case 1: xretries = 10; break; /* No restrictions in NANP */
  2664.                 /* Add other country codes here */
  2665.                 /* that are known to have no restrictions on redialing. */
  2666.               default: xretries = 1;
  2667.             }
  2668.         }
  2669.     }
  2670.     if (cx == XXPDIA) {                 /* Shortcut... */
  2671.         cx = XXDIAL;
  2672.         partial = 1;
  2673.         debug(F100,"PDIAL sets partial=1","",0);
  2674.         postfix = 0;                    /* Do not add postfix */
  2675.     } else {
  2676.         partial = 0;
  2677.         debug(F100,"DIAL sets partial=0","",0);
  2678.     }
  2679.     previous = dialsta;                 /* Status of previous call, if any */
  2680.     if (previous == DIA_PART) {
  2681.         prefix = 0;                     /* do not add prefix */
  2682.     }
  2683.     s = NULL;                           /* Initialize user's dial string */
  2684.     if (cx == XXRED) {                  /* REDIAL or... */
  2685.         if ((y = cmcfm()) < 0)
  2686.           return(y);
  2687.     } else if (cx == XXANSW) {          /* ANSWER or ... */
  2688.         if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
  2689.           return(y);
  2690.         dialatmo = x;
  2691.         if ((y = cmcfm()) < 0)
  2692.           return(y);
  2693.     } else {                            /* DIAL or LOOKUP */
  2694.         if (ndialdir > 0)
  2695.           s3 = "Number to dial or entry from dial directory";
  2696.         else
  2697.           s3 = "Number to dial";
  2698.         if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
  2699.           return(x);
  2700.         if (s) {
  2701.             len = (int) strlen(s);
  2702.             ckstrncpy(tmpbuf,s,TMPBUFSIZ); /* Save literal copy */
  2703. #ifdef COMMENT
  2704.             if (len > 1) {              /* Strip outer braces if given */
  2705.                 if (*s == '{') {
  2706.                     if (s[len-1] == '}') {
  2707.                         s[len-1] = NUL;
  2708.                         s++;
  2709.                         len -= 2;
  2710.                     }
  2711.                 }
  2712.             }
  2713. #else
  2714.             s = brstrip(s);             /* Strip outer braces or quotes */
  2715. #endif /* COMMENT */
  2716.         }
  2717.     }
  2718.  
  2719.     if (cx != XXLOOK) {                 /* Not LOOKUP */
  2720. #ifdef IKSD
  2721.         if (inserver) {
  2722.             printf("Sorry, dialing is disabled.\r\n");
  2723.             return(success = 0);
  2724.         }
  2725. #endif /* IKSD */
  2726. #ifdef CK_TAPI
  2727.         if (tttapi && !tapipass) {
  2728.           ;                             /* Skip the modem test if TAPI */
  2729.         } else
  2730. #endif /* CK_TAPI */
  2731.         if (mdmtyp < 1 && !dialtest) {
  2732.             if (network
  2733. #ifdef TN_COMPORT
  2734.                  && !istncomport()
  2735. #endif /* TN_COMPORT */
  2736.                  )
  2737.               printf("Please SET HOST first, and then SET MODEM TYPE\n");
  2738.             else
  2739.               printf("Sorry, you must SET MODEM TYPE first\n");
  2740.             dialsta = DIA_NOMO;
  2741.             return(success = 0);
  2742.         }
  2743.         if (!local && !dialtest) {
  2744.             printf("Sorry, you must SET %s or SET HOST first\n",
  2745. #ifdef OS2
  2746.                    "PORT"
  2747. #else
  2748.                    "LINE"
  2749. #endif /* OS2 */
  2750.                    );
  2751.             dialsta = DIA_NOLI;
  2752.             return(success = 0);
  2753.         }
  2754.         if ((!network 
  2755. #ifdef TN_COMPORT
  2756.               || istncomport()
  2757. #endif /* TN_COMPORT */
  2758.               ) && !dialtest &&
  2759. #ifdef CK_TAPI
  2760.              !tttapi &&
  2761. #endif /* CK_TAPI */
  2762.             (speed < 0L)
  2763. #ifdef UNIX
  2764.             && (strcmp(ttname,"/dev/null"))
  2765. #else
  2766. #ifdef OSK
  2767.             && (strcmp(ttname,"/nil"))
  2768. #endif /* OSK */
  2769. #endif /* UNIX */
  2770.             ) {
  2771.             printf("\nSorry, you must SET SPEED first\n");
  2772.             dialsta = DIA_NOSP;
  2773.             return(success = 0);
  2774.         }
  2775.     }
  2776.     if (cx != XXANSW) {
  2777.         for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
  2778.             if (!dialnum) {             /* First time dialing */
  2779.                 dn_p[j] = NULL;         /* initialize all pointers. */
  2780.                 dn_p2[j] = NULL;
  2781.             } else if (dn_p[j]) {       /* Not the first time, */
  2782.                 free(dn_p[j]);          /* free previous, if any, */
  2783.                 dn_p[j] = NULL;         /* then set to NULL. */
  2784.                 if (dn_p2[j])
  2785.                   free(dn_p2[j]);
  2786.                 dn_p2[j] = NULL;
  2787.             } else break;               /* Already NULL */
  2788.         }
  2789.         if (len == 0)
  2790.           s = NULL;
  2791.         if (!s)
  2792.           s = dialnum;
  2793.         if (!s) {
  2794.             if (cx == XXLOOK)
  2795.               printf("?Lookup what?\n");
  2796.             else
  2797.               printf("%s\n", (cx == XXRED) ?
  2798.                    "?No DIAL command given yet" :
  2799.                    "?You must specify a number to dial"
  2800.                    );
  2801.             return(-9);
  2802.         }
  2803.  
  2804.     /* Now we have the "raw" dial or lookup string and s is not NULL */
  2805.  
  2806.         makestr(&dscopy,s);             /* Put it in a safe place */
  2807.         s = dscopy;
  2808.         n = 0;
  2809.  
  2810.         debug(F111,"dodial",s,ndialdir);
  2811.  
  2812.         wasalpha = 0;
  2813.         if (isalpha(*s)) {
  2814.             wasalpha = 1;
  2815.             if (ndialdir > 0) {         /* Do we have a dialing directory? */
  2816.                 n = ludial(s,cx);       /* Look up what the user typed */
  2817.                 if (n == 0)
  2818.                   printf(" Lookup: \"%s\" - not found%s\n",
  2819.                          s,
  2820.                          cx == XXLOOK ? "" : " - dialing as given\n"
  2821.                          );
  2822.             }
  2823.             debug(F101,"dodial",s,n);
  2824.             if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
  2825.                 if (n == -1)            /* -2 means ludial already gave msg */
  2826.                   printf(" Lookup: fatal error - dialing skipped\n");
  2827.                 dialsta = DIA_DIR;
  2828.                 return(-9);
  2829.             }
  2830.             if (n > 0)                  /* A successful lookup */
  2831.               lufound = 1;
  2832.         } else if (*s == '=') {         /* If number starts with = sign */
  2833.             s++;                        /* strip it */
  2834.             literal = 1;                /* remember this */
  2835.             while (*s == SP) s++;       /* and then also any leading spaces */
  2836.         } else if (tmpbuf[0] == '{' && tmpbuf[1] == '{') {
  2837.             makelist(tmpbuf,dn_p,MAXDNUMS);
  2838.             makestr(&dscopy,tmpbuf);
  2839.             s = tmpbuf;
  2840.             for (n = 0; n < MAXDNUMS; n++) /* (have to count how many) */
  2841.               if (!dn_p[n]) break;
  2842.             braces = 1;
  2843.         }
  2844.         if (cx == XXLOOK && !wasalpha && !braces) {
  2845.             /* We've been told to lookup a number or a quoted name */
  2846.             char *p;
  2847.             n = 0;
  2848.             p = literal ? s : pncvt(dscopy);
  2849.             if (!p) p = "";
  2850.             if (*p) {
  2851.                 printf("%s  => %s\n", dscopy, p);
  2852.                 return(success = 1);
  2853.             } else {
  2854.                 printf("?Bad phone number\n");
  2855.                 return(success = 0);
  2856.             }
  2857.         }
  2858.         /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
  2859.         /* But don't save pieces of partial dial ... */
  2860.  
  2861.         debug(F101,"DIAL save dialnum partial","",partial);
  2862.         debug(F101,"DIAL save dialnum previous","",previous);
  2863.         if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
  2864.             (cx == XXLOOK && n > 0)) {
  2865.             makestr(&dialnum,dscopy);
  2866.             if (!quiet && dscopy && !dialnum)
  2867.               printf("WARNING - memory allocation failure: redial number\n");
  2868.         }
  2869.         if (n > 0) {
  2870.             if (!quiet && !backgrd && !braces /* && dialdpy */ ) {
  2871.                 if (!strcmp(d_name,s))
  2872.                   printf(" Lookup: \"%s\" - exact match\n",s);
  2873.                 else
  2874.                   printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
  2875.                          s,
  2876.                          d_name
  2877.                          );
  2878.             }
  2879.             if ((cx == XXLOOK) ||
  2880.                 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
  2881.                 printf(" %d telephone number%sfound for \"%s\"%s\n",
  2882.                        n,
  2883.                        (n == 1) ? " " : "s ",
  2884.                        s,
  2885.                        (n > 0) ? ":" : "."
  2886.                        );
  2887.                 s3 = getdname();
  2888.             }
  2889.             for (i = 0; i < n; i++) {   /* Convert */
  2890.                 dn_x[i] = -1;
  2891.                 if (dncvt(i,cx,prefix,postfix) < 0) {
  2892.                     if (cx != XXLOOK) {
  2893.                         dialsta = DIA_DIR;
  2894.                         return(-9);
  2895.                     }
  2896.                 }
  2897.             }
  2898.             if (dialsrt && n > 1) {     /* Sort into optimal order */
  2899.                 for (i = 0; i < n-1; i++) {
  2900.                     for (j = i+1; j < n; j++) {
  2901.                         if (dn_x[j] < dn_x[i]) {
  2902.                             t = dn_x[j];
  2903.                             dn_x[j] = dn_x[i];
  2904.                             dn_x[i] = t;
  2905.                             p = dn_p[j];
  2906.                             dn_p[j] = dn_p[i];
  2907.                             dn_p[i] = p;
  2908.                             p = dn_p2[j];
  2909.                             dn_p2[j] = dn_p2[i];
  2910.                             dn_p2[i] = p;
  2911.                         }
  2912.                     }
  2913.                 }
  2914.             }
  2915.             if ((cx == XXLOOK) ||
  2916.                 ((n > 1) && !quiet && !backgrd /* && dialdpy */ )) {
  2917.                 int nn = n;
  2918. #ifndef NOSPL
  2919.                 char * p;
  2920. #endif /* NOSPL */
  2921.                 if (cx != XXLOOK)
  2922.                   if (n > 12) nn = 12;
  2923.                 for (i = 0; i < nn; i++) {
  2924.                     printf("%3d. %-12s  %-20s =>  %-20s  (%d)\n",i+1,
  2925.                            s3, dn_p[i],
  2926.                            dn_p2[i] ? dn_p2[i] : "(processing failed)",
  2927.                            dn_x[i]
  2928.                            );
  2929.                 }
  2930.                 if (cx != XXLOOK && n != nn)
  2931.                   printf("And %d more...\n", n - nn);
  2932.             }
  2933.         } else if (n == 0) {            /* Not found in directory */
  2934.             makestr(&(dn_p[0]),literal ? s : dscopy);
  2935.             makestr(&d_name,literal ? s : dscopy);
  2936.             dncount = 1;
  2937.             n = 1;
  2938.             if (dncvt(0,cx,prefix,postfix) < 0) { /* In case they typed a */
  2939.                 dialsta = DIA_DIR;      /* portable-format number ... */
  2940.                 return(-9);
  2941.             }
  2942.         }
  2943.  
  2944. #ifndef NONET
  2945. #ifdef NETCONN
  2946.         /* It's not good that the networks directory depends on NOT-NODIAL.. */
  2947.         if (cx == XXLOOK && dscopy) {   /* Networks here too... */
  2948.             extern char *nh_p[], *nh_p2[], *n_name;
  2949.             extern char *nh_px[4][MAXDNUMS+1];
  2950.             n = -1;
  2951.             if (nnetdir > 0) {          /* Do we have a network directory? */
  2952.                 dirline = 0;
  2953.                 n = lunet(dscopy);      /* Look up what the user typed */
  2954.             }
  2955.             if (n > -1) {
  2956.                 int k;
  2957.                 if (n > 0)              /* A successful lookup */
  2958.                   lufound = 1;
  2959.                 if (cx == XXLOOK && n == 0)
  2960.                   printf(" Lookup: \"%s\" - not found\n",dscopy);
  2961.                 else
  2962.                   printf("%s %d network entr%s found for \"%s\"%s\n",
  2963.                          cx == XXLOOK ? " Lookup:" : "",
  2964.                          n,
  2965.                          (n == 1) ? "y" : "ies",
  2966.                          dscopy,
  2967.                          (n > 0) ? ":" : "."
  2968.                          );
  2969.  
  2970.                 for (i = 0; i < n; i++) {
  2971.  
  2972.                     printf("%3d. %-12s => %-9s %s",
  2973.                            i+1,n_name,nh_p2[i],nh_p[i]);
  2974.                     for (k = 0; k < 4; k++) {
  2975.                         if (nh_px[k][i]) {
  2976.                             printf(" %s",nh_px[k][i]);
  2977.                         } else
  2978.                           break;
  2979.                     }
  2980.                     printf("\n");
  2981.                 }
  2982.             }
  2983.         }
  2984. #endif /* NETCONN */
  2985. #endif /* NONET */
  2986.         if (cx == XXLOOK)
  2987.           return(success = lufound);
  2988.     } /* cx != XXANSW */
  2989.  
  2990. #ifdef VMS
  2991.     conres();                   /* So Ctrl-C/Y will work */
  2992. #endif /* VMS */
  2993. /*
  2994.   Some modems do not react well to parity.  Also, if we are dialing through a
  2995.   TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
  2996.   negotiations.
  2997.  
  2998.   This should work even if the user interrupts the DIAL command, because the
  2999.   DIAL module has its own interrupt handler.  BUT... if, for some reason, a
  3000.   dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
  3001.   parity should be used), this might prevent successful dialing.  For that
  3002.   reason, we don't do this for V.25bis modems.
  3003. */
  3004.     sparity = parity;                   /* Save current parity */
  3005.     if ((dialcapas & CKD_V25) == 0)     /* If not V.25bis...  */
  3006.       parity = 0;                       /* Set parity to NONE */
  3007.  
  3008.     flowsave = flow;
  3009. /*
  3010.   These modems use some kind of screwy flow control while in command mode,
  3011.   and do not present CTS as they should.  So if RTS/CTS is set (or even if
  3012.   it isn't) disable flow control during dialing.
  3013. */
  3014. #ifndef MINIDIAL
  3015.     if (mdmtyp == n_ATT1910 || mdmtyp == n_ATT1900) {
  3016.         flow = FLO_NONE;                /* This is not enough */
  3017. #ifdef CK_TTSETFLOW
  3018.         ttsetflow(FLO_NONE);            /* Really turn it off */
  3019. #endif /* CK_TTSETFLOW */
  3020.     }
  3021. #endif /* MINIDIAL */
  3022.     if (!network
  3023. #ifdef TN_COMPORT
  3024.         || istncomport()
  3025. #endif /* TN_COMPORT */
  3026.          ) {
  3027.         int x;
  3028.         if ((x = ttgmdm()) > -1) {
  3029.             if (!x && msgflg) {
  3030.                 printf(
  3031. "WARNING - No modem signals detected.  Is your modem turned on?  If not,\n\
  3032. use Ctrl-C to interrupt dialing, turn on your modem, then %s.\n",
  3033.                        cx == XXANSW ?
  3034.                        "ANSWER again" :
  3035.                        "REDIAL"
  3036.                        );
  3037.             }
  3038.             if (flow == FLO_RTSC) {
  3039.                 if (!(x & BM_CTS)) {
  3040.                     if (msgflg)
  3041.                       printf(
  3042. "WARNING - SET FLOW RTS/CTS is in effect but modem's CTS signal is off.\n\
  3043. Disabling flow control temporarily %s...\n",
  3044.                              cx == XXANSW ?
  3045.                              "while waiting for call" :
  3046.                              "during dialing"
  3047.                              );
  3048.                     flow = FLO_NONE;
  3049.                 }
  3050.             }
  3051.         }
  3052.     }
  3053.     if (cx == XXANSW) {                 /* ANSWER */
  3054.         success = ckdial("",0,0,1,0);
  3055.         goto dialfin;
  3056.     }
  3057.  
  3058. /* Edit 192 adds the ability to dial repeatedly. */
  3059.  
  3060.     i = 0;
  3061.     dialcount = 0;
  3062.     do {
  3063.         if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, xretries);
  3064.         dialcount = i+1;
  3065.         success = 0;
  3066.         /* And the ability to dial alternate numbers. */
  3067.         /* Loop to dial each in a list of numbers for the same name... */
  3068.         for (j = 0; j < n && !success; j++) { /* until one answers. */
  3069.             s = dn_p2[j];               /* Next number in list */
  3070.             if (dn_x[j] >= dialrstr) {  /* Dial restriction */
  3071.                 printf("Restricted: %s, skipping...\n",dn_p[j]);
  3072.                 continue;
  3073.             }
  3074.             xredial = (i == 0 && j == 0) ? 0 : 1;
  3075.             if (!s) s = dn_p[j];
  3076.  
  3077. #ifndef NOSPL
  3078.             sav = s;
  3079.             p = xdial(s);               /* Apply DIAL macro now */
  3080.             if (p) if (*p) s = p;
  3081. #endif /* NOSPL */
  3082.  
  3083.         /* Dial confirmation */
  3084.         /* NOTE: the uq_xxx() calls allow for a GUI dialog */
  3085.  
  3086.             if (i == 0 && dialcnf) {
  3087.         char msgbuf[128];
  3088.         ckmakmsg(msgbuf,128,"Dialing ",s,NULL,NULL);
  3089.         x = uq_ok(msgbuf,"Is this number correct? ",3,NULL,0);
  3090.                 if (!x) {
  3091.  
  3092. #ifndef COMMENT
  3093.             x = uq_txt(        /* Allow GUI dialog */
  3094. #ifdef OS2
  3095. " Please enter the correct number,\r\n or press Enter to skip.",
  3096. #else
  3097. " Please enter the correct number,\r\n or press Return to skip.",
  3098. #endif /* OS2 */
  3099.                               "Corrected phone number: ",
  3100.                                1,
  3101.                    NULL,
  3102.                    atmbuf,
  3103.                    ATMBL,
  3104.                                s,
  3105.                                DEFAULT_UQ_TIMEOUT
  3106.                                );
  3107.             if (x && atmbuf[0]) { /* They gave a new one */
  3108.             s = atmbuf;
  3109.             makestr(&(dn_p2[j]), s);
  3110.             }            
  3111.  
  3112. #else  /* COMMENT */
  3113.  
  3114. #ifdef CK_RECALL
  3115.                     extern int on_recall;
  3116. #endif /* CK_RECALL */
  3117.                     cmsavp(psave,PROMPTL);
  3118.                     cmsetp(
  3119. #ifdef OS2
  3120. " Please enter the correct number,\r\n or press Enter to skip: "
  3121. #else
  3122. " Please enter the correct number,\r\n or press Return to skip: "
  3123. #endif /* OS2 */
  3124.                            );
  3125.                     cmini(ckxech);
  3126.                     x = -1;
  3127.                     if (pflag) prompt(NULL);
  3128. #ifdef CK_RECALL
  3129.                     on_recall = 0;
  3130. #endif /* CK_RECALL */
  3131.                     y = cmdgquo();
  3132.                     cmdsquo(0);
  3133.                     while (x < 0) {
  3134.                         x = cmtxt("Corrected phone number","",&s,NULL);
  3135.                         cmres();
  3136.                     }
  3137.                     if ((int) strlen(s) < 1) {
  3138.                         cmsetp(psave);
  3139.                         continue;
  3140.                     }
  3141.                     makestr(&(dn_p2[j]), s);
  3142.                     cmdsquo(y);
  3143.                     cmsetp(psave);
  3144. #endif /* COMMENT */
  3145.                 }
  3146.             }
  3147.             if (dialtest) {             /* Just testing */
  3148.                 if (i + j == 0)
  3149.                   printf("\nTESTING...\n");
  3150.                 if (dialmac)
  3151.                   printf(" Number: \"%s\" => \"%s\"\n",sav,s);
  3152.                 else
  3153.                   printf(" Number: \"%s\"\n",s);
  3154.                 dialsta = DIA_BUSY;
  3155.                 success = 0;
  3156.             } else {
  3157.                 what |= W_DIALING;
  3158.                 success = ckdial(s,i,j,partial ? 3 : 0, xredial); /* Dial it */
  3159.                 what &= ~(W_DIALING);
  3160.                 if (!success) {
  3161.                     if (dialsta < 8 ||  /* Break out if unrecoverable error */
  3162.                         dialsta  == DIA_INTR ||
  3163.                         dialsta  == DIA_ERR  ||
  3164.                         previous == DIA_PART
  3165.                         )
  3166.                       break;
  3167.                 }
  3168.             }
  3169.         }
  3170.         if (success)                    /* Succeeded, leave the outer loop */
  3171.           break;
  3172.         if (dialsta < 8 ||              /* Break out if unrecoverable error */
  3173.             dialsta == DIA_INTR ||      /* Interrupted */
  3174.             dialsta == DIA_NODT ||      /* No dialtone */
  3175.             dialsta == DIA_NOAC ||      /* Access forbidden */
  3176.             dialsta == DIA_BLCK ||      /* Blacklisted */
  3177.             dialsta == DIA_DIR  ||      /* Dialing directory error */
  3178.             dialsta == DIA_ERR  ||      /* Modem command error */
  3179.             previous == DIA_PART)
  3180.           break;
  3181.         if (++i >= xretries)            /* Break out if too many tries */
  3182.           break;
  3183.         if (!backgrd && !quiet) {
  3184.             if (dialint > 5)
  3185.               printf(
  3186. "\nWill redial in %d second%s- press any key to redial immediately.\n",
  3187.                      dialint,
  3188.                      dialint == 1 ? " " : "s "
  3189.                      );
  3190.             printf("Ctrl-C to cancel...\n");
  3191.         }
  3192.         x = dialint;                    /* Redial interval */
  3193.         while (x-- > 0) {
  3194.             if ((y = conchk()) > 0) {   /* Did they type something? */
  3195.                 while (y--) coninc(0);  /* Yes, absorb it */
  3196.                 break;                  /* And wake up */
  3197.             }
  3198.             sleep(1);                   /* No interrupt, sleep a sec */
  3199.         }
  3200.     } while (!success);
  3201.  
  3202.   dialfin:
  3203.  
  3204.     if (cx != XXLOOK) {
  3205.         if (!success)
  3206.           bleep((short) BP_FAIL);
  3207.         else if (!quiet)
  3208.           bleep((short) BP_NOTE);
  3209. #ifdef OS2
  3210.         setint();                       /* Fix OS/2 interrupts */
  3211. #endif /* OS2 */
  3212.         if (sparity > -1)
  3213.           parity = sparity;             /* Restore parity if we saved it */
  3214.         flow = flowsave;
  3215. #ifdef OS2
  3216.         ttres();                        /* Restore DIAL device */
  3217. #endif /* OS2 */
  3218. #ifdef VMS
  3219.         concb((char)escape);            /* Restore console */
  3220. #endif /* VMS */
  3221. #ifdef OS2
  3222.         {                               /* Set session title */
  3223.             char * p, name[72];         /* in window list. */
  3224.             char * q;
  3225.             if (cx == XXANSW) {
  3226.                 q = "Incoming call";
  3227.             } else {
  3228.                 if (d_name)
  3229.                   q = d_name;
  3230.                 else if (dialnum)
  3231.                   q = dialnum;
  3232.                 else if (ttname[0])
  3233.                   q = ttname;
  3234.                 else q = "";
  3235.             }
  3236.             p = name;
  3237.             if (success) {
  3238.                 strncpy(name,q,48);
  3239.                 while (*p) {            /* Uppercase it for emphasis. */
  3240.                     if (islower(*p))
  3241.                       *p = toupper(*p);
  3242.                     p++;
  3243.                 }
  3244.             } else
  3245.               name[0] = NUL ;
  3246.             os2settitle((char *) name, TRUE);
  3247.         }
  3248. #endif /* OS2 */
  3249.     }
  3250.     if (cx != XXLOOK) {
  3251.         if (success) {
  3252.             if (reliable == SET_AUTO) { /* It's not a reliable connection. */
  3253.                 reliable = SET_OFF;
  3254.                 debug(F101,"dodial reliable","",reliable);
  3255.             }
  3256.         } else {
  3257. #ifndef NOHINTS
  3258.             extern int hints;
  3259.             if (hints && !quiet && dialsta != 9) { /* 9 == User interrupted */
  3260.                 extern int dialmhu, dialhng, dialdpy;
  3261.                 extern char * dialmsg[];
  3262.                 printf("\n*************************\n");
  3263.                 printf("DIAL-class command failed.\n");
  3264.                 printf("Modem type:  %s\n", gmdmtyp());
  3265.                 printf("Device:      %s\n", ttname);
  3266.                 printf("Speed:       %ld\n", speed);
  3267.                 printf("Dial status: %d",dialsta);
  3268.                 if (dialsta < 35 && dialmsg[dialsta])
  3269.                   printf(" [%s]",dialmsg[dialsta]);
  3270.                 printf("\n");
  3271.                 if (dialsta == DIA_TIMO ||
  3272.                     dialsta == DIA_NRDY ||
  3273.                    (dialsta > 13 && dialsta != DIA_BUSY && dialsta != DIA_NOAN)
  3274.                     ) {
  3275.                     switch (dialsta) {
  3276.                       case DIA_TIMO:
  3277.                         printf(
  3278. " . SET DIAL TIMEOUT to a greater value and try again.\n"
  3279.                                );
  3280.                         break;
  3281.                       case DIA_NRSP:
  3282.                       case DIA_NRDY:
  3283.                       case DIA_NOIN:
  3284.                         printf(
  3285. " . Is the modem turned on?\n"
  3286.                                );
  3287.                         printf(
  3288. " . Are you using the right communication port?\n"
  3289.                                );
  3290.                         break;
  3291.                       case DIA_NODT:
  3292.                         printf(
  3293. " . Is the modem connected to the telephone line?\n"
  3294.                                );
  3295.                     }
  3296.                     if (mdmtyp == n_GENERIC) {
  3297.                         printf(
  3298. " . Please choose a specific modem type with SET MODEM TYPE and try again.\n"
  3299.                                );
  3300.                         printf(
  3301. "    SET MODEM TYPE ? to see the list of known modem types.\n"
  3302.                                );
  3303.                     } else {
  3304.                         printf(
  3305. " . Are you sure you have chosen the appropriate modem type?\n"
  3306.                                );
  3307.                     }
  3308.                     if (speed > 19200L) {
  3309.                         printf(
  3310. " . Maybe the interface speed (%ld) is too fast:\n", speed
  3311.                                );
  3312.                         printf(
  3313. "    SET SPEED to a lower speed and try again.\n"
  3314.                                );
  3315.                         printf(
  3316. "    SET SPEED ? to see the list of valid speeds.\n"
  3317.                                );
  3318.                     }
  3319.                     if (dialhng) {
  3320.                         if (dialmhu)
  3321.                           printf(
  3322. " . SET MODEM HANGUP-METHOD RS232 and try again.\n"
  3323.                                  );
  3324.                         else
  3325.                           printf(
  3326. " . SET MODEM HANGUP-METHOD MODEM-COMMAND and try again.\n"
  3327.                                  );
  3328.                         printf(
  3329. " . If that doesn't work, try again with SET DIAL HANGUP OFF.\n"
  3330.                                );
  3331.                     } else {
  3332.                         printf(
  3333. " . Give a HANGUP or SET DIAL HANGUP ON command and try again.\n"
  3334.                                );
  3335.                     }
  3336.                     if (!dialdpy)
  3337.                       printf(
  3338. " . Use SET DIAL DISPLAY ON to watch the dialog between Kermit and modem.\n"
  3339.                              );
  3340.                 }
  3341. #ifndef NOSHOW
  3342.                 printf(
  3343. " . SHOW COMMUNICATIONS, SHOW MODEM, SHOW DIAL to see current settings.\n"
  3344.                        );
  3345. #endif /* NOSHOW */
  3346.  
  3347. #ifndef NOHELP
  3348.                 printf(
  3349. " . HELP SET MODEM, HELP SET DIAL, and HELP DIAL for more information.\n"
  3350.                        );
  3351. #endif /* NOHELP */
  3352.                 printf("(Use SET HINTS OFF to suppress future hints.)\n");
  3353.                 printf("*************************\n\n");
  3354.             }
  3355. #endif /* NOHINTS */
  3356.         }
  3357.     }
  3358.     return(success);
  3359. }
  3360. #endif /* NODIAL */
  3361.  
  3362. /*  D O T Y P E  --  Type (display) a file with various options...  */
  3363.  
  3364. #ifdef BIGBUFOK
  3365. #define TYPBUFL 16384
  3366. #else
  3367. #define TYPBUFL 256
  3368. #endif /* BIGBUFOK */
  3369.  
  3370. int typ_lines = 0;                      /* \v(ty_ln) */
  3371. int typ_mtchs = 0;                      /* \v(ty_lm) */
  3372. static int typ_int = 0;                 /* Flag if TYPE interrupted */
  3373.  
  3374. #ifdef UNICODE
  3375. extern int fcharset, fileorder, byteorder, ucsorder;
  3376. #define TYPXBUFL TYPBUFL+TYPBUFL+TYPBUFL+4
  3377. static char * mp = NULL;
  3378. static char * mbuf = NULL;
  3379. static long xn = 0L;
  3380.  
  3381. static int
  3382. #ifdef CK_ANSIC
  3383. storechar(char c)
  3384. #else
  3385. storechar(c) char c;
  3386. #endif /* CK_ANSIC */
  3387. {
  3388.     if (!mp) return(-1);
  3389.     if (++xn > TYPXBUFL)
  3390.       return(-1);
  3391.     debug(F111,"storechar xn",ckitoa((int)c),xn);
  3392.     *mp++ = c;
  3393.     return(0);
  3394. }
  3395. #endif /* UNICODE */
  3396.  
  3397. static FILE * ofp = NULL;               /* For /OUTPUT: file */
  3398.  
  3399. static int
  3400. typeline(buf,len,outcs,ofp) char * buf; int len, outcs; FILE * ofp; {
  3401.     register int i;
  3402.  
  3403.     debug(F011,"typeline buf",buf,len);
  3404.     /* debug(F101,"typeline outcs","",outcs); */
  3405.  
  3406. #ifdef OS2
  3407. #ifndef NOLOCAL
  3408. #ifdef UNICODE
  3409.     /* In K95 only, the buffer is guaranteed to be in UCS-2 if outcs >= 0. */
  3410.     /* Len is its length in bytes.  There is no line terminator. */
  3411.     /* outcs is the file character-set number (FC_xxx) of the target set */
  3412.     /* that was requested by the user. */
  3413.     if (!inserver && !k95stdout) {
  3414.         extern int wherex[], wherey[];
  3415.         extern unsigned char colorcmd;
  3416.  
  3417.         VscrnWrtUCS2StrAtt( VCMD, (unsigned short *)buf, len/2,
  3418.                            wherey[VCMD], wherex[VCMD], &colorcmd);
  3419.         printf("\r\n");
  3420.         return(0);
  3421.     }
  3422. #endif /* UNICODE */
  3423. #endif /* NOLOCAL */
  3424. #endif /* OS2 */
  3425.  
  3426. /* In Unix, VMS, etc, the line has already been converted to the desired  */
  3427. /* character-set, if one was given.  OR... on all platforms, including in */
  3428. /* K95, we don't know the character set.  In either case we dump the line */
  3429. /* byte by byte in case it contains NULs (printf() would truncate). */
  3430.  
  3431. #ifdef COMMENT
  3432.     for (i = 0; i < len; i++)
  3433.       putchar(buf[i]);
  3434. #else
  3435.     for (i = 0; i < len; i++) {
  3436.         if (ofp == stdout) {
  3437.             putchar(buf[i]);
  3438.         } else {
  3439.             putc(buf[i],ofp);
  3440.         }
  3441.     }
  3442. #endif /* COMMENT */
  3443.  
  3444. #ifdef IKSD
  3445.     if (inserver) {
  3446. #ifdef UNICODE
  3447.         if (outcs == FC_UCS2) {
  3448.             if (ofp == stdout) {
  3449.                 putchar(NUL);
  3450.             } else {
  3451.                 putc(NUL,ofp);
  3452.             }
  3453.         }
  3454. #endif /* UNICODE */
  3455.         if (ofp == stdout) {
  3456.             putchar('\r');
  3457.         } else {
  3458.             putc('\r',ofp);
  3459.         }
  3460.     }
  3461. #endif /* IKSD */
  3462. #ifdef UNICODE
  3463.     if (outcs == FC_UCS2) {
  3464.         if (ofp == stdout) {
  3465.             putchar(NUL);
  3466.         } else {
  3467.             putc(NUL,ofp);
  3468.         }
  3469.     }
  3470. #endif /* UNICODE */
  3471.     if (ofp == stdout) {
  3472.         putchar('\n');
  3473.     } else {
  3474.         putc('\n',ofp);
  3475.     }
  3476.     fflush(stdout);
  3477.     return(0);
  3478. }
  3479.  
  3480. static int                              /* Get translated line */
  3481. typegetline(incs, outcs, buf, n) int incs, outcs, n; char * buf; {
  3482.     int x = 0, c0, c1, len = 0, count = 0, eof = 0, xlate = 0;
  3483. #ifdef UNICODE
  3484.     int xxn = -1;
  3485.     int yyn = -9;
  3486.     xn = 0L;
  3487.  
  3488. #ifdef DEBUG
  3489.     if (deblog && typ_lines == 0) {
  3490.         debug(F101,"typegetline incs","",incs);
  3491.         debug(F101,"typegetline outcs","",outcs);
  3492.         debug(F101,"typegetline feol","",feol);
  3493.         debug(F101,"typegetline byteorder","",byteorder);
  3494.         debug(F101,"typegetline ucsorder ","",ucsorder);
  3495.         debug(F111,"typegetline fileorder","1",fileorder);
  3496.     }
  3497. #endif /* DEBUG */
  3498.  
  3499.     if (incs < 0)                       /* Shouldn't happen */
  3500.       return(-2);
  3501.  
  3502.     if (outcs == -1)                    /* Can happen */
  3503.       outcs = incs;
  3504.  
  3505.     if (incs != outcs || incs == FC_UCS2) { /* See if we should translate */
  3506.         xlate = 1;
  3507.         if (!mbuf) {                    /* Allocate buffer if not allocated */
  3508.             mbuf = (char *)malloc(TYPXBUFL+1); /* yet */
  3509.             if (!mbuf) {
  3510.                 printf("WARNING: Translation buffer allocation failure.\n");
  3511.                 printf("Translation will be skipped...\n");
  3512.                 xlate = 0;
  3513.             }
  3514.         }
  3515.     }
  3516.     if (xlate) {                        /* Translating... */
  3517.         mp = mbuf;                      /* Reset working buffer pointer */
  3518. /*
  3519.   Here we call xgnbyte() in a loop, having it return UCS-2 bytes.  In K95, we
  3520.   use UCS-2 directly.  Elsewhere, we feed the UCS-2 bytes into xpnbyte() to
  3521.   convert them to the desired target character set.  But since we are using
  3522.   UCS-2, we have several sources for confusion: (1) xgnbyte() might return in
  3523.   LE or BE byte order, with no explicit indication of what the order is; but
  3524.   (2) xpnbyte() wants BE; but (3) Windows wants LE.
  3525. */
  3526.         while (1) {
  3527.             if (typ_int)                /* Quit if interrupted */
  3528.               return(0);
  3529.             c0 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
  3530.             debug(F000,"typegetline c0","",c0);
  3531.             if (c0 < 0) {               /* EOF */
  3532.                 eof++;
  3533.                 break;
  3534.             }
  3535.             c1 = xgnbyte(FC_UCS2,incs,NULL); /* Convert to UCS-2 */
  3536.             debug(F000,"typegetline c1","",c1);
  3537.             if (c1 < 0) {               /* EOF */
  3538.                 eof++;
  3539.                 break;
  3540.             }
  3541. #ifdef DEBUG
  3542.             if (deblog && typ_lines == 0) {
  3543.                 if (count == 0) /* Check fileorder after BOM */
  3544.                   debug(F111,"typegetline fileorder","2",fileorder);
  3545.             }
  3546. #endif /* DEBUG */
  3547.  
  3548. #ifdef COMMENT
  3549. /* Now we have the two UCS-2 bytes.  Which order are they in? */
  3550.  
  3551.             if (fileorder > 0) {        /* Little Endian */
  3552.                 int t;                  /* So swap them */
  3553.                 debug(F100,"typegetline swapping","",0);
  3554.                 t = c1;
  3555.                 c1 = c0;
  3556.                 c0 = t;
  3557.             }
  3558. #endif /* COMMENT */
  3559.             if (c0 == 0 && c1 == 0x0D)  /* Now see if we have EOL */
  3560.               yyn = xn;
  3561.  
  3562.             if (c0 == 0 && c1 == 0x0A)  /* Now see if we have EOL */
  3563.               xxn = xn;
  3564.  
  3565.             count++;                    /* Count byte */
  3566.  
  3567. /* Give the two bytes to xpnbyte() in BE order */
  3568.  
  3569.             if ((x = xpnbyte(c0,TC_UCS2,outcs,storechar)) < 0) return(-1);
  3570.             if ((x = xpnbyte(c1,TC_UCS2,outcs,storechar)) < 0) return(-1);
  3571.  
  3572.             if (xxn > -1) {             /* Have end of line? */
  3573.                 xn = xxn;
  3574.                 if (yyn == xxn - 2)     /* Adjust for CRLF */
  3575.                   xn = yyn;
  3576.                 break;                  /* And break out of loop. */
  3577.             }
  3578.         }
  3579.         mbuf[xn] = NUL;
  3580.         if (xn > n)                     /* Can truncate here... */
  3581.           xn = n;
  3582.         memcpy(buf,mbuf,xn);
  3583.         debug(F011,"typegetline xlate",buf,xn);
  3584.         return((eof && (xn == 0)) ? -1 : xn);
  3585.     }
  3586. #endif /* UNICODE */
  3587. #ifdef COMMENT
  3588.     /* We can't use this because, stupidly, zsinl() doesn't return a length. */
  3589.     /* It could be changed but then we'd have to change all ck?fio.c modules */
  3590.     x = zsinl(ZIFILE,buf,n);
  3591. #else
  3592.     /* So instead, we copy zsinl() to here... */
  3593.     /* But note: This does not necessarily handle UCS-2 alignment properly;  */
  3594.     /* that's what the code in the first section of this routine is for. */
  3595.     /* But it does tolerate files that contain NULs. */
  3596.     {
  3597.         int a;
  3598.         char *s;
  3599.  
  3600.         s = buf;
  3601.         a = -1;                         /* Current character, none yet. */
  3602.         debug(F101,"typegetline zsinl simulation","",n);
  3603.         while (n--) {                   /* Up to given length */
  3604. #ifdef COMMENT
  3605.             int old = 0;
  3606.             if (feol)                   /* Previous character */
  3607.               old = a;
  3608. #endif /* COMMENT */
  3609.             if (zchin(ZIFILE,&a) < 0) { /* Read a character from the file */
  3610.                 debug(F101,"typegetline zchin fail","",count);
  3611.                 if (count == 0)
  3612.                   x = -1;               /* EOF or other error */
  3613.                 break;
  3614.             } else
  3615.               count++;
  3616.             if (feol) {                 /* Single-character line terminator */
  3617.                 if (a == feol)
  3618.                   break;
  3619.             } else {                    /* CRLF line terminator */
  3620. #ifdef COMMENT
  3621. /* Debug log shows that in Windows, <CR><LF> is returned as <LF>. */
  3622. /* Apparently we're not reading the file in binary mode. */
  3623.  
  3624.                 if (a == '\015')        /* CR, get next character */
  3625.                   continue;
  3626.                 if (old == '\015') {    /* Previous character was CR */
  3627.                     if (a == '\012') {  /* This one is LF, so we have a line */
  3628.                         break;
  3629.                     } else {            /* Not LF, deposit CR */
  3630.                         *s++ = '\015';
  3631.                         n--;
  3632.                         len++;
  3633.                     }
  3634.                 }
  3635. #else
  3636.                 if (a == LF) {
  3637.                     if (s[len] == CR) { /* This probably won't happen */
  3638.                         s[len] = NUL;
  3639.                         s--;
  3640.                         len--;
  3641.                     }
  3642.                     break;
  3643.                 }
  3644. #endif /* COMMENT */
  3645.             }
  3646.             *s = a;                     /* Deposit character */
  3647.             s++;
  3648.             len++;
  3649.         }
  3650.         *s = '\0';                      /* Terminate the string */
  3651.     }
  3652. #endif /* COMMENT */
  3653.     return(x < 0 ? -1 : len);
  3654. }
  3655.  
  3656.  
  3657. #ifndef MAC
  3658. SIGTYP
  3659. #ifdef CK_ANSIC
  3660. tytrap(int foo)                         /* TYPE interrupt trap */
  3661. #else
  3662. tytrap(foo) int foo;
  3663. #endif /* CK_ANSIC */
  3664. /* tytrap */ {
  3665. #ifdef __EMX__
  3666.     signal(SIGINT, SIG_ACK);
  3667. #endif
  3668.     debug(F100,"type tytrap SIGINT","",0);
  3669.     typ_int = 1;                        /* (Need arg for ANSI C) */
  3670.     SIGRETURN;
  3671. }
  3672. #endif /* MAC */
  3673.  
  3674. int
  3675. dotype(file, paging, first, head, pat, width, prefix, incs, outcs, outfile, z)
  3676.     char * file, * pat, * prefix; int paging, first, head, width, incs, outcs;
  3677.     char * outfile; int z;
  3678. /* dotype */ {
  3679.     extern CK_OFF_T ffc;
  3680.     char buf[TYPBUFL+2];
  3681.     char * s = NULL;
  3682.     int rc = 1, lines = 0, ucs2 = 0;
  3683.     char ** tail = NULL;
  3684.     int * tlen = NULL;
  3685.     int tailing = 0, counting = 0;
  3686.     int x, c, n, i, j, k = 0;
  3687.     int number = 0, save, len, pfxlen = 0, evalpfx = 1;
  3688. #ifdef UNICODE
  3689.     int ucsbom_sav;
  3690.     extern int ucsbom;
  3691. #endif /* UNICODE */
  3692. #ifdef NT
  3693.     int gui = 0;
  3694. #endif /* NT */
  3695.  
  3696. #ifndef MAC
  3697. #ifdef OS2
  3698. #ifdef NT
  3699.     SIGTYP (* oldsig)(int);             /* For saving old interrupt trap. */
  3700. #else /* NT */
  3701.     SIGTYP (* volatile oldsig)(int);
  3702. #endif /* NT */
  3703. #else /* OS2 */
  3704.     SIGTYP (* oldsig)();
  3705. #endif /* OS2 */
  3706. #endif /* MAC */
  3707.  
  3708. #ifdef KUI
  3709.     if (outfile == (char *)1) {
  3710.         gui = 1;
  3711.         outfile = "";
  3712.     }
  3713. #endif /* KUI */
  3714.  
  3715.     if (!file) file = "";
  3716.     if (!*file) return(-2);
  3717.  
  3718.     if (ofp != stdout) {                /* In case of previous interruption */
  3719.         if (ofp) fclose(ofp);
  3720.         ofp = stdout;
  3721.     }
  3722.     if (!outfile) outfile = "";
  3723.     if (outfile[0]) {
  3724.         ofp = fopen(outfile,"w");       /* Open output file */
  3725.         if (!ofp) {
  3726.             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
  3727.             ofp = stdout;
  3728.             return(-9);
  3729.         }
  3730.     }
  3731.     number = z;
  3732.     if (number && prefix) prefix = NULL;
  3733.  
  3734. #ifdef UNICODE
  3735.     ucsbom_sav = ucsbom;                /* We are not creating a file */
  3736.     ucsbom = 0;                         /* Do not use BOM bytes */
  3737. #endif /* UNICODE */
  3738.  
  3739.     typ_int = 0;
  3740.  
  3741.     save = binary;                      /* Save file type */
  3742.  
  3743.     debug(F101,"dotype incs","",incs);
  3744.     debug(F101,"dotype outcs","",outcs);
  3745.  
  3746. #ifdef UNICODE
  3747.     debug(F111,"dotype fileorder","A",fileorder);
  3748. #ifdef OS2
  3749.     if (!inserver && !k95stdout)
  3750.       outcs = FC_UCS2;
  3751. #endif /* OS2 */
  3752.  
  3753.     if (outcs == FC_UCS2)               /* Output is UCS-2? */
  3754.       ucs2 = 1;
  3755.     if (fileorder < 0)
  3756.       fileorder = ucsorder;
  3757.     debug(F111,"dotype fileorder","B",fileorder);
  3758. #endif /* UNICODE */
  3759.  
  3760. #ifdef CK_TTGWSIZ
  3761. #ifdef OS2
  3762.     ttgcwsz();
  3763. #else /* OS2 */
  3764.     /* Check whether window size changed */
  3765.     if (ttgwsiz() > 0) {
  3766.         if (tt_rows > 0 && tt_cols > 0) {
  3767.             cmd_rows = tt_rows;
  3768.             cmd_cols = tt_cols;
  3769.             debug(F101,"dotype cmd_rows","",cmd_rows);
  3770.             debug(F101,"dotype cmd_cols","",cmd_cols);
  3771.         }
  3772.     }
  3773. #endif /* OS2 */
  3774. #endif /* CK_TTGWSIZ */
  3775.  
  3776.     if (prefix)
  3777.       pfxlen = strlen(prefix);
  3778.  
  3779.     if (paging < 0) {                   /* Count only, don't print */
  3780.         counting = 1;
  3781.         prefix = NULL;
  3782.         width = 0;
  3783.         paging = 0;
  3784.     }
  3785.     if (ucs2)                           /* Crude... */
  3786.       width *= 2;
  3787.  
  3788. #ifdef OS2
  3789.     if (*file) {
  3790.         ckstrncpy(buf, file, TYPBUFL);  /* Change / to \. */
  3791.         p = buf;
  3792.         while (*p) {
  3793.             if (*p == '/') *p = '\\';
  3794.             p++;
  3795.         }
  3796.         file = buf;
  3797.     } else {
  3798.         rc = 0;
  3799.         goto xdotype;
  3800.     }
  3801. #endif /* OS2 */
  3802.  
  3803.     if (zchki(file) == -2) {            /* It's a directory */
  3804.         debug(F111,"dotype zchki failure",file,-2);
  3805.         if (xcmdsrc == 0) {
  3806.             printf("?Not a regular file: \"%s\"\n",file);
  3807.             rc = -9;
  3808.         } else
  3809.           rc = 0;
  3810.         goto xdotype;
  3811.     }
  3812.     if (!zopeni(ZIFILE, file)) {        /* Not a directory, open it */
  3813.         debug(F111,"dotype zopeni failure",file,0);
  3814.         if (xcmdsrc == 0) {
  3815.             printf("?Can't open file: \"%s\"\n",file);
  3816.             rc = -9;
  3817.         } else
  3818.           rc = 0;
  3819.         goto xdotype;
  3820.     }
  3821.  
  3822. #ifndef AMIGA
  3823. #ifndef MAC
  3824.     errno = 0;
  3825.     oldsig = signal(SIGINT, tytrap);    /* Save current interrupt trap. */
  3826.     /* debug(F111,"type SIGINT trap set",ckitoa(errno),oldsig); */
  3827. #endif /* MAC */
  3828. #endif /* AMIGA */
  3829.  
  3830.     if (paging > -1)                    /* More-prompting */
  3831.       xaskmore = paging;
  3832.  
  3833.     binary = 0;
  3834.  
  3835.     if (head < 0) {                     /* "tail" was requested */
  3836.         tailing = 1;                    /* Set flag */
  3837.         head = 0 - head;                /* Get absolute number of lines */
  3838.         if (!counting) {
  3839.             tail = (char **) malloc(head * sizeof(char *)); /* Allocate list */
  3840.             if (!tail) {
  3841.                 printf("?Memory allocation failure\n");
  3842.                 goto xdotype;
  3843.  
  3844.             }
  3845.             tlen = (int *) malloc(head * sizeof(int));
  3846.             if (!tlen) {
  3847.                 printf("?Memory allocation failure\n");
  3848.                 goto xdotype;
  3849.  
  3850.             }
  3851.             for (i = 0; i < head; i++) { /* Initialize each pointer in list. */
  3852.                 tail[i] = NULL;
  3853.                 tlen[i] = 0;
  3854.             }
  3855.         }
  3856.     }
  3857.     typ_lines = 0;
  3858.     typ_mtchs = 0;
  3859.  
  3860. #ifdef UNICODE
  3861.     if (outcs > -1 && (incs != outcs || incs == FC_UCS2)) { /* Translating? */
  3862.         ffc = (CK_OFF_T)0;
  3863.         initxlate(incs,outcs);          /* Set up translation functions */
  3864.     } else
  3865. #endif /* UNICODE */
  3866.       outcs = -1;                       /* Means we don't know the charset */
  3867.  
  3868.     debug(F101,"dotype ffc","",ffc);
  3869.     debug(F101,"dotype outcs 2","",outcs);
  3870. #ifdef UNICODE
  3871.     debug(F111,"dotype fileorder","C",fileorder);
  3872. #endif /* UNICODE */
  3873.  
  3874.     /* Allow the buffer to contain NULs */
  3875.  
  3876.     for (n = first;
  3877.          (len = typegetline(incs,outcs,buf,TYPBUFL)) > -1;
  3878.          lines++
  3879.          ) {
  3880.         debug(F011,"dotype line",buf,len);
  3881. #ifndef MAC
  3882.         if (typ_int) {                  /* Interrupted? */
  3883.             typ_int = 0;
  3884.             debug(F101,"type interrupted line","",lines);
  3885.             printf("^C...\n");          /* Print message */
  3886.             if (ofp != stdout) {        /* Close any output file */
  3887.                 if (ofp) fclose(ofp);
  3888.                 ofp = stdout;
  3889.             }
  3890.             goto xxdotype;
  3891.         }
  3892. #endif /* MAC */
  3893.         typ_lines++;                    /* For \v(ty_ln) */
  3894.         if (pat)                        /* Matching? */
  3895.           if (!ckmatch(pat,buf,1,1+4))  /* Line matches pattern? */
  3896.             continue;                   /* No, skip it */
  3897.         typ_mtchs++;
  3898.  
  3899.         if (head > 0 && !tailing && lines == head) /* Handle /HEAD:n */
  3900.           break;
  3901.  
  3902.         buf[TYPBUFL+1] = NUL;           /* Just in case... */
  3903.         if (prefix) {                   /* Add specified prefix to each line */
  3904.             char pbuf[64];
  3905.             char * pp;
  3906.             pp = prefix;
  3907. #ifndef NOSPL
  3908.             if (evalpfx) {              /* Prefix is a variable? */
  3909.                 int n = 63;             /* Maybe - evaluate it and see */
  3910.                 char * p = pbuf;
  3911.                 zzstring(prefix,&p,&n); /* If there is no change */
  3912.                 if (!strcmp(prefix,pbuf)) { /* it's not a variable */
  3913.                     evalpfx = 0;        /* So don't do this again. */
  3914.                 } else {                /* It was a variable */
  3915.                     pp = pbuf;          /* So substitute its value */
  3916.                     pfxlen = 63 - n;    /* and get its new length */
  3917.                 }
  3918.             }
  3919. #endif /* NOSPL */
  3920.             if (len + pfxlen + 2 < TYPBUFL) {
  3921.                 /* Shift right to make room for prefix */
  3922.                 memcpy((char *)line+pfxlen,(char *)buf,len);
  3923.                 lset((char *)line,pp,pfxlen,SP);
  3924.                 debug(F110,"dotype prefix",line,pfxlen);
  3925.                 len += pfxlen;
  3926.                 memcpy((char *)buf,(char *)line,len);
  3927.             }
  3928.         } else if (number) {            /* Line numbers */
  3929.             int x;
  3930.             sprintf(line,"%4d. ",typ_lines);
  3931.             x = strlen(line);
  3932.             len += x;
  3933.             if (len < LINBUFSIZ) {
  3934.                 memcpy((char *)&line[x],(char *)buf,len);
  3935.                 memcpy((char *)buf,(char *)line,len);
  3936.             }
  3937.         }
  3938.         if (width > 0 && width <= TYPBUFL) { /* Truncate at given width. */
  3939.             char * obuf = line;         /* But to do that first we must */
  3940.             int i,k,z;                  /* expand tabs; assume every 8 cols. */
  3941.             line[0] = NUL;
  3942.             for (i = 0, k = 0; i < width; k++) { /* Character loop... */
  3943.                 if (!buf[k])            /* No more chars in this line, done. */
  3944.                   break;
  3945.                 if (buf[k] != '\t') {   /* If it's not a tab */
  3946.                     if (i >= LINBUFSIZ) /* Check for overflow */
  3947.                       break;
  3948.                     obuf[i++] = buf[k]; /* and then deposit it. */
  3949.                     obuf[i] = NUL;      /* Keep it null-terminated */
  3950.                     continue;
  3951.                 }
  3952.                 z = 8 - (i % 8);        /* It's a tab, expand it. */
  3953.                 if (z == 0) z = 8;
  3954.                 for (j = 0; j < z && i < LINBUFSIZ; j++) {
  3955. #ifdef UNICODE
  3956.                     if (ucs2 && !ucsorder)
  3957.                       obuf[i++] = NUL;
  3958. #endif /* UNICODE */
  3959.                     obuf[i++] = ' ';
  3960. #ifdef UNICODE
  3961.                     if (ucs2 && ucsorder)
  3962.                       obuf[i++] = NUL;
  3963. #endif /* UNICODE */
  3964.                 }
  3965.                 obuf[i++] = NUL;
  3966.                 obuf[i] = NUL;
  3967.             }
  3968.             obuf[width] = NUL;          /* Now truncate at given width. */
  3969. #ifdef COMMENT
  3970.             /* This doesn't work for UCS-2 because it contains NULs */
  3971.             ckstrncpy(buf,obuf,TYPBUFL); /* and copy it back (again?) */
  3972. #else
  3973.             memcpy((char *)buf,(char *)obuf,i); /* Copy it back */
  3974. #endif /* COMMENT */
  3975.             len = (i > width) ? width : i; /* Spare us another strlen()... */
  3976.         }
  3977.         if (tailing) {                  /* If /TAIL:n... */
  3978.             k = lines % head;           /* save this line in circular buffer */
  3979.             if (!counting) {
  3980.                 if (tail[k]) free(tail[k]);
  3981.                 tail[k] = malloc(len+2);
  3982.                 if (!tail[k]) {
  3983.                     printf("?Memory allocation failure\n");
  3984.                     goto xdotype;
  3985.                 }
  3986.                 memcpy(tail[k],buf,len);
  3987.                 tlen[k] = len;
  3988.                 continue;
  3989.             }
  3990.         }
  3991.         if (counting)                   /* If only counting */
  3992.           continue;                     /* we're done with this line */
  3993.  
  3994.         if (paging) {                   /* Displaying this line... */
  3995.             int u;
  3996.             u = len;                    /* Length in BYTES */
  3997.             if (ucs2)                   /* If outputting in UCS-2 */
  3998.               u /= 2;                   /* convert length to CHARACTERS */
  3999.             x = (u / cmd_cols) + 1;     /* Crudely allow for wrap */
  4000.             if (cmd_rows > 0 && cmd_cols > 0)
  4001.               n += x;                   /* This assumes terminal will wrap */
  4002.         }
  4003. #ifdef KUI
  4004.         if ( gui ) {
  4005.             int i;
  4006.             unsigned short * uch = (unsigned short *)buf;
  4007.             for ( i=0; i<len/2; i++)
  4008.                 gui_text_popup_append(uch[i]);
  4009.             gui_text_popup_append(CR);
  4010.             gui_text_popup_append(LF);
  4011.         } 
  4012.         else
  4013. #endif /* KUI */
  4014.         typeline(buf,len,outcs,ofp);    /* Print line, length based */
  4015. #ifdef CK_TTGWSIZ
  4016.         debug(F101,"dotype n","",n);
  4017.         if (paging > 0 && ofp == stdout) { /* Pause at end of screen */
  4018.             if (cmd_rows > 0 && cmd_cols > 0) {
  4019.                 if (n > cmd_rows - 3) {
  4020.                     if (!askmore())
  4021.                       goto xdotype;
  4022.                     else
  4023.                       n = 0;
  4024.                 }
  4025.             }
  4026.         }
  4027. #endif /* CK_TTGWSIZ */
  4028.     }
  4029.  
  4030.   xdotype:
  4031.     if (counting) {
  4032.         fprintf(ofp,
  4033.                 "%s: %d line%s\n",file,typ_lines,typ_lines == 1 ? "" : "s");
  4034.         if (pat)
  4035.           fprintf(ofp,
  4036.                   "%s: %d match%s\n",pat,typ_mtchs,typ_mtchs == 1 ? "" : "es");
  4037.         goto xxdotype;
  4038.     }
  4039.     if (tailing && tail) {              /* Typing tail of file? */
  4040.         if (lines < head) {             /* Yes, show the lines we saved */
  4041.             k = 0;                      /* Show all lines */
  4042.         } else {                        /* More lines than tail number */
  4043.             lines = k;                  /* Last line to show */
  4044.             k++;                        /* First line to show */
  4045.             if (k >= head)
  4046.               k = 0;
  4047.         }
  4048.         n = first;                      /* Output line counter */
  4049.         for (i = k ;; i++) {            /* Loop thru circular buffer */
  4050. #ifndef MAC
  4051.             if (typ_int) {              /* Interrupted? */
  4052.                 printf("^C...\n");      /* Print message */
  4053.                 goto xxdotype;
  4054.             }
  4055. #endif /* MAC */
  4056.             j = i % head;               /* Index of this line */
  4057.             s = tail[j];                /* Point to line to display */
  4058.             if (!s)                     /* (shouldn't happen...) */
  4059.               break;
  4060.             if (paging) {               /* Crudely allow for line wrap */
  4061.                 x = tlen[j];
  4062.                 if (ucs2) x /= 2;
  4063.                 x = x / cmd_cols + 1;
  4064.                 if (cmd_rows > 0 && cmd_cols > 0)
  4065.                   n += x;
  4066.             }
  4067.             typeline(s,tlen[j],outcs,ofp); /* Display this line */
  4068.             if (paging && ofp == stdout) { /* Pause at end of screen */
  4069.                 if (cmd_rows > 0 && cmd_cols > 0) {
  4070.                     if (n > cmd_rows - 3) {
  4071.                         if (!askmore())
  4072.                           break;
  4073.                         else
  4074.                           n = 0;
  4075.                     }
  4076.                 }
  4077.             }
  4078.             tail[j] = NULL;
  4079.             free(s);                    /* Free the line */
  4080.             if (i % head == lines)      /* When to stop */
  4081.               break;
  4082.         }
  4083.         free((char *)tail);             /* Free the list */
  4084.         tail = NULL;
  4085.         if (tlen) free((char *)tlen);
  4086.         tlen = NULL;
  4087.     }
  4088.  
  4089. /* Come here when finished or on SIGINT */
  4090.  
  4091.   xxdotype:
  4092. #ifndef AMIGA
  4093. #ifndef MAC
  4094.     signal(SIGINT,oldsig);              /* Put old signal action back. */
  4095. #endif /* MAC */
  4096. #endif /* AMIGA */
  4097.     if (tailing && tail) {
  4098.         for (i = 0; i < head; i++) {    /* Free each line. */
  4099.             if (tail[i])
  4100.               free(tail[i]);
  4101.         }
  4102.         free((char *)tail);             /* Free list pointer */
  4103.         if (tlen)
  4104.           free((char *)tlen);
  4105.     }
  4106.     x = zclose(ZIFILE);                 /* Done, close the input file */
  4107.     if (ofp != stdout) {                /* Close any output file */
  4108.         if (ofp) fclose(ofp);
  4109.         ofp = stdout;
  4110.     }
  4111.     binary = save;                      /* Restore text/binary mode */
  4112. #ifdef UNICODE
  4113.     ucsbom = ucsbom_sav;                /* Restore BOM usage */
  4114. #endif /* UNICODE */
  4115.  
  4116. #ifdef KUI
  4117.     if ( gui )
  4118.         gui_text_popup_wait(-1);        /* Wait for user to close the dialog */
  4119. #endif /* KUI */
  4120.     return(rc);
  4121. }
  4122.  
  4123. /* GREP command */
  4124.  
  4125. #define GREP_CASE  0                    /* /CASE */
  4126. #define GREP_COUN  1                    /* /COUNT */
  4127. #define GREP_DOTF  2                    /* /DOTFILES */
  4128. #define GREP_NAME  3                    /* /NAMEONLY */
  4129. #define GREP_NOBK  4                    /* /NOBACKUP */
  4130. #define GREP_NODO  5                    /* /NODOTFILES */
  4131. #define GREP_NOLI  6                    /* /NOLIST */
  4132. #define GREP_NOMA  7                    /* /INVERT = /NOMATCH */
  4133. #define GREP_NOPA  8                    /* /NOPAGE */
  4134. #define GREP_NUMS  9                    /* /LINENUMBERS */
  4135. #define GREP_PAGE 10                    /* /PAGE */
  4136. #define GREP_RECU 11                    /* /RECURSIVE */
  4137. #define GREP_TYPE 12                    /* /TYPE: */
  4138. #define GREP_OUTP 13                    /* /OUTPUTFILE: */
  4139. #define GREP_EXCP 14            /* /EXCEPT: */
  4140.  
  4141. static struct keytab greptab[] = {
  4142.     { "/count",        GREP_COUN, CM_ARG },
  4143.     { "/dotfiles",     GREP_DOTF, 0 },
  4144.     { "/except",       GREP_EXCP, CM_ARG },
  4145.     { "/linenumbers",  GREP_NUMS, 0 },
  4146.     { "/nameonly",     GREP_NAME, 0 },
  4147.     { "/nobackupfiles",GREP_NOBK, 0 },
  4148.     { "/nocase",       GREP_CASE, 0 },
  4149.     { "/nodotfiles",   GREP_NODO, 0 },
  4150.     { "/nolist",       GREP_NOLI, 0 },
  4151.     { "/nomatch",      GREP_NOMA, 0 },
  4152.     { "/nopage",       GREP_NOPA, 0 },
  4153.     { "/output",       GREP_OUTP, CM_ARG },
  4154.     { "/page",         GREP_PAGE, 0 },
  4155.     { "/quiet",        GREP_NOLI, CM_INV },
  4156. #ifdef RECURSIVE
  4157.     { "/recursive",    GREP_RECU, 0 },
  4158. #endif /* RECURSIVE */
  4159.     { "/type",         GREP_TYPE, CM_ARG },
  4160.     { "", 0, 0 }
  4161. };
  4162. static int ngreptab =  sizeof(greptab)/sizeof(struct keytab)-1;
  4163.  
  4164. static char * grep_except = NULL;
  4165.  
  4166. int
  4167. dogrep() {
  4168.     int match, x, y, fc, getval, mc = 0, count = 0, bigcount = 0;
  4169.     int fline = 0, sline = 0, wild = 0, len = 0;
  4170.     int xmode = -1, scan = 0;
  4171.     char c, name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p, *s, *cv = NULL;
  4172.     FILE * fp = NULL;
  4173.  
  4174.     int                                 /* Switch values and defaults */
  4175.       gr_coun = 0,
  4176.       gr_name = 0,
  4177.       gr_nobk = 0,
  4178.       gr_case = 1,
  4179.       gr_noli = 0,
  4180.       gr_noma = 0,
  4181.       gr_nums = 0,
  4182.       gr_excp = 0,
  4183.       gr_page = xaskmore;
  4184.  
  4185.     struct FDB sw, fl;
  4186.  
  4187.     g_matchdot = matchdot;              /* Save global matchdot setting */
  4188.     outfile[0] = NUL;
  4189.     makestr(&grep_except,NULL);
  4190.  
  4191.     if (ofp != stdout) {                /* In case of previous interruption */
  4192.         if (ofp) fclose(ofp);
  4193.         ofp = stdout;
  4194.     }
  4195.     cmfdbi(&sw,                         /* First FDB - command switches */
  4196.            _CMKEY,                      /* fcode */
  4197.            "String or pattern to search for, or switch",
  4198.            "",                          /* default */
  4199.            "",                          /* addtl string data */
  4200.            ngreptab,                    /* addtl numeric data 1: tbl size */
  4201.            4,                           /* addtl numeric data 2: 4 = cmswi */
  4202.            xxstring,                    /* Processing function */
  4203.            greptab,                     /* Keyword table */
  4204.            &fl                          /* Pointer to next FDB */
  4205.            );
  4206.     cmfdbi(&fl,                         /* Anything that doesn't match */
  4207.            _CMFLD,                      /* fcode */
  4208.            "",                          /* hlpmsg */
  4209.            "",                          /* default */
  4210.            "",                          /* addtl string data */
  4211.            0,                           /* addtl numeric data 1 */
  4212.            0,                           /* addtl numeric data 2 */
  4213.            xxstring,            /* xxstring */
  4214.            NULL,
  4215.            NULL
  4216.            );
  4217.     while (1) {                         /* Parse 0 or more switches */
  4218.         x = cmfdb(&sw);                 /* Parse something */
  4219.         if (x < 0)
  4220.           return(x);
  4221.         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
  4222.           break;
  4223.         c = cmgbrk();
  4224.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  4225.             printf("?This switch does not take an argument\n");
  4226.             return(-9);
  4227.         }
  4228.         if ((cmresult.nresult != GREP_COUN) && !getval &&
  4229.             (cmgkwflgs() & CM_ARG)) {
  4230.             printf("?This switch requires an argument\n");
  4231.             return(-9);
  4232.         }
  4233.         switch (cmresult.nresult) {
  4234.           case GREP_COUN: {
  4235.               gr_coun++;
  4236.               if (getval) {
  4237.                   if ((x = cmfld("Variable for result","",&s,NULL)) < 0)
  4238.                     return(x);
  4239.                   makestr(&cv,s);
  4240.               }
  4241.               break;
  4242.           }
  4243.           case GREP_CASE: gr_case=0; break;
  4244.           case GREP_NAME: gr_name++; gr_noli=0; break;
  4245.           case GREP_NOBK: gr_nobk++; break;
  4246.           case GREP_NOLI: gr_noli++; gr_name=0; gr_nums=0; break;
  4247.           case GREP_NOMA: gr_noma++; break;
  4248.           case GREP_NOPA: gr_page=0; break;
  4249.           case GREP_NUMS: gr_nums++; gr_noli=0; break;
  4250.           case GREP_PAGE: gr_page++; gr_noli=0; break;
  4251.           case GREP_NODO:
  4252.             matchdot = 0;
  4253.             break;
  4254.           case GREP_DOTF:
  4255.             matchdot = 1;
  4256.             break;
  4257. #ifdef RECURSIVE
  4258.           case GREP_RECU:
  4259.             recursive = 1;
  4260.             break;
  4261. #endif /* RECURSIVE */
  4262.           case GREP_TYPE: {
  4263.               extern struct keytab txtbin[];
  4264.               if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
  4265.                 return(x);
  4266.               if (x == 2) {             /* ALL */
  4267.                   xmode = -1;
  4268.               } else {                  /* TEXT or BINARY only */
  4269.                   xmode = x;
  4270.                   scan = 1;
  4271.               }
  4272.               break;
  4273.           }
  4274.           case GREP_OUTP:               /* Send output to file */
  4275.             if ((x = cmofi("File for GREP'd lines","",&s,xxstring)) < 0)
  4276.               return(x);
  4277.             ckstrncpy(outfile,s,CKMAXPATH);
  4278.             break;
  4279.       case GREP_EXCP:        /* Exception pattern */
  4280.         if (getval) {
  4281.         if ((x = cmfld("Exception pattern",
  4282.                    "",
  4283.                    &s,
  4284.                    xxstring
  4285.                    )) < 0)
  4286.           return(x);
  4287.         gr_excp++;
  4288.         makestr(&grep_except,s);
  4289.         }
  4290.         }
  4291.     }
  4292.     if (outfile[0]) {
  4293.         ofp = fopen(outfile,"w");       /* Open output file */
  4294.         if (!ofp) {
  4295.             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
  4296.             ofp = stdout;
  4297.             return(-9);
  4298.         }
  4299.         gr_page = 0;
  4300.     }
  4301.     s = cmresult.sresult;
  4302.     s = brstrip(s);                     /* Strip braces from pattern */
  4303.     if (!*s) {
  4304.         printf("?Pattern required\n");
  4305.         return(-9);
  4306.     }
  4307.     ckstrncpy(tmpbuf,s,TMPBUFSIZ);      /* Save pattern */
  4308.     if ((x = cmifi("File(s) to search","",&s,&wild,xxstring)) < 0) {
  4309.         if (x == -3) {
  4310.             printf("?File specification required\n");
  4311.             x = -9;
  4312.         }
  4313.         return(x);
  4314.     }
  4315.     s = brstrip(s);                     /* Strip braces from filename */
  4316. #ifndef ZXREWIND
  4317.     ckstrncpy(line,s,LINBUFSIZ);
  4318. #endif /* ZXREWIND */
  4319.     if ((y = cmcfm()) < 0)
  4320.       return(y);
  4321.  
  4322.     if (gr_page > -1)
  4323.       xaskmore = gr_page;               /* Paging... */
  4324.  
  4325.     p = tmpbuf;                         /* Point to pattern */
  4326. #ifdef COMMENT
  4327. /* Now this is done in ckmatch */
  4328.     if (*p == '^') {                    /* '^' anchors pattern to beginning */
  4329.         p++;
  4330.     } else if (*p != '*') {             /* Otherwise prepend implied '*' */
  4331.         tmpbuf[0] = '*';
  4332.         p = tmpbuf;
  4333.     }
  4334.     x = strlen(p);                      /* Get length of result */
  4335.     if (x > 0 && x < TMPBUFSIZ) {       /* '$' at end anchors pattern to end */
  4336.         if (p[x-1] == '$') {
  4337.             p[x-1] = NUL;
  4338.         } else if (p[x-1] != '*') {
  4339.             p[x] = '*';
  4340.             p[x+1] = NUL;
  4341.         }
  4342.     }
  4343. #endif /* COMMENT */
  4344.     debug(F111,"grep pat",p,x);
  4345.  
  4346. #ifdef ZXREWIND
  4347.     fc = zxrewind();                    /* Rewind the file list */
  4348. #else
  4349.     {
  4350.         int flags = ZX_FILONLY;         /* Expand file list */
  4351.         if (matchdot)  flags |= ZX_MATCHDOT;
  4352.         if (recursive) flags |= ZX_RECURSE;
  4353.         fc = nzxpand(line,flags);
  4354.     }
  4355. #endif /* ZXREWIND */
  4356. #ifdef UNIX
  4357.     sh_sort(mtchs,NULL,fc,0,0,filecase);
  4358. #endif /* UNIX */
  4359.  
  4360.     debug(F101,"grep cmd_rows","",cmd_rows);
  4361.     debug(F101,"grep cmd_cols","",cmd_cols);
  4362.  
  4363.     while (1) {                         /* Loop for each file */
  4364.         znext(name);                    /* Get next file */
  4365.         if (!name[0])                   /* No more, done */
  4366.           break;
  4367.         if (gr_nobk)                    /* Skipping backup files? */
  4368.           if (ckmatch("*.~[1-9]*~",name,1,1)) /* Backup file? */
  4369.             continue;                   /* Yes, skip */
  4370.         if (scan) {                     /* /TYPE: given? */
  4371.             switch (scanfile(name,&y,nscanfile)) { /* Yes, scan the file */
  4372.               case FT_BIN:
  4373.                 if (xmode != 1)
  4374.                   continue;
  4375.                 break;
  4376.               case FT_TEXT:
  4377.               case FT_7BIT:
  4378.               case FT_8BIT:
  4379. #ifdef UNICODE
  4380.               case FT_UTF8:
  4381.               case FT_UCS2:
  4382. #endif /* UNICODE */
  4383.                 if (xmode != 0)
  4384.                   continue;
  4385.             }
  4386.         }
  4387.         fp = fopen(name,"r");           /* Open */
  4388.         if (!fp)                        /* Can't */
  4389.           continue;                     /* Skip */
  4390.         count = 0;                      /* Match count, this file */
  4391.         fline = 0;                      /* Line count, this file */
  4392.         while (1) {                     /* Loop for each line */
  4393.             if (fgets(line,LINBUFSIZ,fp) == NULL) { /* Get next line */
  4394.                 fclose(fp);
  4395.                 fp = NULL;
  4396.         debug(F100,"GREP EOF","",0);
  4397.                 break;
  4398.             }
  4399.             fline++;                    /* Count this line */
  4400.             line[LINBUFSIZ] = NUL;      /* Make sure it's terminated */
  4401.         debug(F111,"GREP",line,fline);
  4402.             len = (int)strlen(line);    /* Get length */
  4403.             while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r'))
  4404.               line[--len] = NUL;        /* Chop off terminators */
  4405.             match = ckmatch(p,line,gr_case,1+4); /* Match against pattern */
  4406.         if (match && gr_excp) {
  4407.         if (ckmatch(grep_except,line,gr_case,1+4))
  4408.             match = 0;
  4409.         }
  4410.             if (gr_noma)                /* Invert match sense if requested */
  4411.               match = !match;
  4412.             if (match) {                /* Have a matching line */
  4413.                 mc++;                   /* Total match count */
  4414.                 count++;                /* Match count this file */
  4415.                 if (gr_name) {          /* Don't care how many lines match */
  4416.                     fclose(fp);         /* Close the file */
  4417.                     fp = NULL;          /* and quit the line-reading loop. */
  4418.                     break;
  4419.                 }
  4420.                 if (gr_coun || gr_noli) /* Not listing each line */
  4421.                   continue;             /* so don't print anything now. */
  4422.                 if (wild) {        /* If searching multiple files */
  4423.                     fprintf(ofp,"%s:",name); /* print filename. */
  4424.                     len += (int)strlen(name) + 1;
  4425.                 }
  4426.                 if (gr_nums) {          /* If line numbers wanted */
  4427.                     char nbuf[32];
  4428.                     len += ckmakmsg(nbuf,32,ckitoa(fline),":",NULL,NULL);
  4429.                     fprintf(ofp,"%s",nbuf);
  4430.                 }
  4431.                 if (cmd_rows > 0 && cmd_cols > 0)
  4432.                   sline += (len / cmd_cols) + 1;
  4433.                 fprintf(ofp,"%s\n",line); /* Print the line. */
  4434.                 if (sline > cmd_rows - 3) {
  4435.                     if (!askmore()) goto xgrep; else sline = 0;
  4436.                 }
  4437.             }
  4438.         }
  4439.         if (!gr_noli) {            /* If not not listing... */
  4440.             x = 0;
  4441.             if (gr_coun) {              /* Show match count only */
  4442.                 fprintf(ofp,"%s:%d\n",name,count);
  4443.                 x++;
  4444.             } else if (gr_name && count > 0) { /* Show name only */
  4445.                 fprintf(ofp,"%s\n",name);
  4446.                 x++;
  4447.             }
  4448.             if (x > 0) {
  4449.                 if (++sline > cmd_rows - 3) {
  4450.                     if (!askmore()) goto xgrep; else sline = 0;
  4451.                 }
  4452.             }
  4453.         }
  4454.         bigcount += count;              /* Overall count */
  4455.     }
  4456.   xgrep:
  4457. #ifndef NOSPL
  4458.     if (gr_coun && cv) {                /* /COUNT:blah */
  4459.         addmac(cv,ckitoa(bigcount));    /* set the variable */
  4460.         makestr(&cv,NULL);              /* free this */
  4461.     }
  4462. #endif /* NOSPL */
  4463.     if (fp) fclose(fp);                 /* close input file if still open */
  4464.     if (ofp != stdout) {                /* Close any output file */
  4465.         if (ofp) fclose(ofp);
  4466.         ofp = stdout;
  4467.     }
  4468.     return(success = mc ? 1 : 0);
  4469. }
  4470.  
  4471. /* System-independent directory */
  4472.  
  4473. static char ** dirlist = NULL;
  4474. static int ndirlist = 0;
  4475.  
  4476. static VOID
  4477. freedirlist() {
  4478.     if (dirlist) {
  4479.         int i;
  4480.         for (i = 0; i < ndirlist; i++) {
  4481.             if (dirlist[i])
  4482.               free(dirlist[i]);
  4483.         }
  4484.         free((char *)dirlist);
  4485.         dirlist = NULL;
  4486.     }
  4487.     ndirlist = 0;
  4488. }
  4489.  
  4490. static struct keytab dirswtab[] = {     /* DIRECTORY command switches */
  4491.     { "/after",       DIR_AFT, CM_ARG },
  4492.     { "/all",         DIR_ALL, 0 },
  4493. #ifndef NOSPL
  4494.     { "/array",       DIR_ARR, CM_ARG },
  4495. #endif /* NOSPL */
  4496.     { "/ascending",   DIR_ASC, 0 },
  4497.     { "/backup",      DIR_BUP, 0 },
  4498.     { "/before",      DIR_BEF, CM_ARG },
  4499.     { "/brief",       DIR_BRF, 0 },
  4500.     { "/descending",  DIR_DSC, CM_INV },
  4501.     { "/directories", DIR_DIR, 0 },
  4502.     { "/dotfiles",    DIR_DOT, 0 },
  4503.     { "/englishdate", DIR_DAT, 0 },
  4504.     { "/except",      DIR_EXC, CM_ARG },
  4505.     { "/files",       DIR_FIL, 0 },
  4506.     { "/heading",     DIR_HDG, 0 },
  4507.     { "/isodate",     DIR_ISO, 0 },
  4508.     { "/larger-than", DIR_LAR, CM_ARG },
  4509. #ifdef CKSYMLINK
  4510.     { "/followlinks", DIR_LNK, 0 },
  4511. #endif /* CKSYMLINK */
  4512.     { "/message",     DIR_MSG, CM_ARG },
  4513.     { "/nobackupfiles",DIR_NOB, 0 },
  4514.     { "/nodotfiles",  DIR_NOD, 0 },
  4515. #ifdef CKSYMLINK
  4516.     { "/nofollowlinks",DIR_NLK, 0 },
  4517. #endif /* CKSYMLINK */
  4518.     { "/noheading",   DIR_NOH, 0 },
  4519.     { "/nomessage",   DIR_NOM, 0 },
  4520. #ifdef CK_TTGWSIZ
  4521.     { "/nopage",      DIR_NOP, 0 },
  4522. #endif /* CK_TTGWSIZ */
  4523. #ifdef RECURSIVE
  4524.     { "/norecursive", DIR_NOR, 0 },
  4525. #else
  4526. #ifdef VMS
  4527.     { "/norecursive", DIR_NOR, 0 },
  4528. #else
  4529. #ifdef datageneral
  4530.     { "/norecursive", DIR_NOR, 0 },
  4531. #endif /* datageneral */
  4532. #endif /* VMS */
  4533. #endif /* RECURSIVE */
  4534.     { "/nosort",      DIR_NOS, 0 },
  4535.     { "/not-after",   DIR_NAF, CM_ARG },
  4536.     { "/not-before",  DIR_NBF, CM_ARG },
  4537.     { "/not-since",   DIR_NAF, CM_INV|CM_ARG },
  4538.     { "/noxfermode",  DIR_NOT, 0 },
  4539.     { "/output",      DIR_OUT, CM_ARG },
  4540. #ifdef CK_TTGWSIZ
  4541.     { "/page",        DIR_PAG, 0 },
  4542. #endif /* CK_TTGWSIZ */
  4543. #ifdef RECURSIVE
  4544.     { "/recursive",   DIR_REC, 0 },
  4545. #else
  4546. #ifdef VMS
  4547.     { "/recursive",   DIR_REC, 0 },
  4548. #else
  4549. #ifdef datageneral
  4550.     { "/recursive",   DIR_REC, 0 },
  4551. #endif /* datageneral */
  4552. #endif /* VMS */
  4553. #endif /* RECURSIVE */
  4554.     { "/reverse",     DIR_DSC, 0 },
  4555.     { "/since",       DIR_AFT, CM_ARG|CM_INV },
  4556.     { "/smaller-than",DIR_SMA, CM_ARG },
  4557.     { "/sort",        DIR_SRT, CM_ARG },
  4558.     { "/summary",     DIR_SUM, 0 },
  4559.     { "/type",        DIR_BIN, CM_ARG },
  4560.     { "/xfermode",    DIR_TYP, 0 },
  4561.     { "/verbose",     DIR_VRB, 0 },
  4562.     { "",0,0 }
  4563. };
  4564. static int ndirswtab = (sizeof(dirswtab) / sizeof(struct keytab)) - 1;
  4565.  
  4566. static struct keytab dirsort[] = {      /* DIRECTORY /SORT: options */
  4567.     { "date",         DIRS_DT, 0 },
  4568.     { "name",         DIRS_NM, 0 },
  4569.     { "size",         DIRS_SZ, 0 }
  4570. };
  4571. static int ndirsort = (sizeof(dirsort) / sizeof(struct keytab));
  4572.  
  4573. static int dir_date = -1;               /* Option defaults (-1 means none) */
  4574. static int dir_page = -1;
  4575. static int dir_verb =  1;
  4576. static int dir_msg  = -1;
  4577. #ifdef VMS
  4578. static int dir_sort = -1;               /* Names are already sorted in VMS */
  4579. static int dir_rvrs = -1;
  4580. #else
  4581. static int dir_sort =  1;               /* Sort by default */
  4582. static int dir_rvrs =  0;               /* Not in reverse */
  4583. #endif /* VMS */
  4584. static int dir_skey = DIRS_NM;          /* By name */
  4585. #ifdef RECURSIVE
  4586. static int dir_recu = -1;
  4587. #endif /* RECURSIVE */
  4588. static int dir_mode = -1;
  4589. static int dir_show = -1;               /* Show all files by default */
  4590. int dir_dots =  -1;            /* Except dot files */
  4591. int dir_back =  1;
  4592. int dir_head =  0;
  4593. static char * dirmsg = NULL;
  4594. static int dirmsglen = 0;
  4595.  
  4596. #ifndef NOSHOW
  4597. VOID
  4598. showdiropts() {
  4599.     int x = 0;
  4600.     extern int optlines;
  4601.     prtopt(&optlines,"DIRECTORY");
  4602.     if (dir_show > 0) {
  4603.         prtopt(&optlines,(dir_show == 1) ? "/FILES" :
  4604.                ((dir_show == 2) ? "/DIRECTORIES" : "/ALL"));
  4605.         x++;
  4606.     } else {
  4607.         prtopt(&optlines,"/ALL");
  4608.         x++;
  4609.     }
  4610.     if (dir_verb > -1) {
  4611.         prtopt(&optlines,dir_verb ? "/VERBOSE" : "/BRIEF");
  4612.         x++;
  4613.     }
  4614.     if (dir_page > -1) {
  4615.         prtopt(&optlines,dir_page ? "/PAGE" : "/NOPAGE");
  4616.         x++;
  4617.     }
  4618.     if (dir_date > -1) {
  4619.         prtopt(&optlines,dir_date ? "/ENGLISHDATE" : "/ISODATE");
  4620.         x++;
  4621.     }
  4622.     if (dir_dots > -1) {
  4623.         prtopt(&optlines,dir_dots ? "/DOTFILES" : "/NODOTFILES");
  4624.         x++;
  4625.     }
  4626.     if (dir_back > -1) {
  4627.         prtopt(&optlines,dir_back ? "/BACKUP" : "/NOBACKUP");
  4628.         x++;
  4629.     }
  4630.     if (dir_head > -1) {
  4631.         prtopt(&optlines,dir_head ? "/HEADING" : "/NOHEADING");
  4632.         x++;
  4633.     }
  4634. #ifdef RECURSIVE
  4635.     if (dir_recu > -1) {
  4636.         prtopt(&optlines,dir_recu ? "/RECURSIVE" : "/NORECURSIVE");
  4637.         x++;
  4638.     }
  4639. #endif /* RECURSIVE */
  4640.     if (dir_mode > -1) {
  4641.         prtopt(&optlines,dir_mode ? "/XFERMODE" : "/NOXFERMODE");
  4642.         x++;
  4643.     }
  4644.     if (dir_sort == 0) {
  4645.         x++;
  4646.         prtopt(&optlines,"/NOSORT ");
  4647.     } else if (dir_sort > 0) {
  4648.         x++;
  4649.         if (dir_skey == DIRS_NM) s = "/SORT:NAME";
  4650.         else if (dir_skey == DIRS_SZ) s = "/SORT:SIZE";
  4651.         else if (dir_skey == DIRS_DT) s = "/SORT:DATE";
  4652.         prtopt(&optlines,s);
  4653.     }
  4654.     if (dir_rvrs > -1) {
  4655.         prtopt(&optlines,dir_rvrs ? "/REVERSE" : "/ASCENDING");
  4656.         x++;
  4657.     }
  4658.     if (dir_msg > -1) {
  4659.         if (dir_msg == 0) {
  4660.             prtopt(&optlines,"/NOMESSAGE");
  4661.         } else {
  4662.             ckmakmsg(tmpbuf,TMPBUFSIZ,"/MESSAGE:{",dirmsg,"}",NULL);
  4663.             prtopt(&optlines,tmpbuf);
  4664.         }
  4665.         x++;
  4666.     }
  4667.     if (!x) prtopt(&optlines,"(no options set)");
  4668.     prtopt(&optlines,"");
  4669. }
  4670. #endif /* NOSHOW */
  4671.  
  4672. int
  4673. setdiropts() {                          /* Set DIRECTORY option defaults */
  4674.     int xb = -1, xv = -1, xp = -1, xd = -1, xh = -1, xf = -1;
  4675.     int xk = -1, xr = -1, xs = -1, xx = -1, xm = -1, xa = -1, xg = -1;
  4676.     int getval;
  4677.     char c;
  4678.     while (1) {
  4679.         if ((y = cmswi(dirswtab,ndirswtab,"Switch","",xxstring)) < 0) {
  4680.             if (y == -3)
  4681.               break;
  4682.             else
  4683.               return(y);
  4684.         }
  4685.         c = cmgbrk();
  4686.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  4687.             printf("?This switch does not take an argument\n");
  4688.             return(-9);
  4689.         }
  4690.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  4691.             printf("?This switch requires an argument\n");
  4692.             return(-9);
  4693.         }
  4694.         switch (y) {
  4695.           case DIR_BRF: xv = 0; break;
  4696.           case DIR_VRB: xv = 1; break;
  4697.           case DIR_PAG: xp = 1; break;
  4698.           case DIR_NOP: xp = 0; break;
  4699.           case DIR_ISO: xd = 0; break;
  4700.           case DIR_DAT: xd = 1; break;
  4701.           case DIR_HDG: xh = 1; break;
  4702.           case DIR_NOH: xh = 0; break;
  4703.           case DIR_DOT: xf = 1; break;
  4704.           case DIR_NOD: xf = 0; break;
  4705.           case DIR_ALL: xa = 3; break;
  4706.           case DIR_DIR: xa = 2; break;
  4707.           case DIR_FIL: xa = 1; break;
  4708.           case DIR_SRT:
  4709.             x = DIRS_NM;
  4710.             if (getval)
  4711.               if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
  4712.                 return(x);
  4713.             xk = x;
  4714.             xs = 1;
  4715.             break;
  4716.           case DIR_NOS: xs = 0; break;
  4717.           case DIR_ASC: xx = 0; break;
  4718.           case DIR_DSC: xx = 1; break;
  4719.           case DIR_REC: xr = 1; break;
  4720.           case DIR_NOR: xr = 0; break;
  4721.           case DIR_TYP: xm = 1; break;
  4722.           case DIR_NOT: xm = 0; break;
  4723.           case DIR_BUP: xb = 1; break;
  4724.           case DIR_NOB: xb = 0; break;
  4725.           case DIR_NOM: xg = 0; break;
  4726.           case DIR_MSG:
  4727.             if (getval)
  4728.               if ((x = cmfld("Message to append to each line",
  4729.                              "",
  4730.                              &s,
  4731.                              xxstring
  4732.                              )) < 0)
  4733.                 return(x);
  4734.             xg = 1;
  4735.             ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  4736.             break;
  4737.           default:
  4738.             printf("?This option can not be set\n");
  4739.             return(-9);
  4740.         }
  4741.     }
  4742.     if ((x = cmcfm()) < 0)              /* Get confirmation */
  4743.       return(x);
  4744.     if (xv > -1) dir_verb = xv;         /* Confirmed, save defaults */
  4745.     if (xp > -1) dir_page = xp;
  4746.     if (xd > -1) dir_date = xd;
  4747.     if (xh > -1) dir_head = xh;
  4748.     if (xs > -1) dir_sort = xs;
  4749.     if (xk > -1) dir_skey = xk;
  4750.     if (xx > -1) dir_rvrs = xx;
  4751.     if (xf > -1) dir_dots = xf;
  4752.     if (xa > -1) dir_show = xa;
  4753.     if (xm > -1) dir_mode = xm;
  4754.     if (xb > -1) dir_back = xb;
  4755. #ifdef RECURSIVE
  4756.     if (xr > -1) dir_recu = xr;
  4757. #endif /* RECURSIVE */
  4758.     if (xg > -1) dir_msg  = xg;
  4759.     if (xg > 0)
  4760.       makestr(&dirmsg,tmpbuf);
  4761.     return(success = 1);
  4762. }
  4763.  
  4764. int
  4765. domydir() {                             /* Internal DIRECTORY command */
  4766.     extern char *months[];
  4767. #ifdef VMS
  4768.     _PROTOTYP( char * zrelname, (char *,char *) );
  4769.     char * cdp = NULL;
  4770. #endif /* VMS */
  4771.  
  4772.     char name[CKMAXPATH+1], outfile[CKMAXPATH+1], *p = NULL, c = NUL;
  4773.     char linebuf[CKMAXPATH+256];
  4774.     char * mstr = NULL, * dstr = NULL, * s2 = NULL;
  4775.     CK_OFF_T len = (CK_OFF_T)0, nbytes = (CK_OFF_T)0;
  4776.     CK_OFF_T minsize = (CK_OFF_T)-1, maxsize = (CK_OFF_T)-1;
  4777.     long ndirs = 0, nfiles = 0, nmatches = 0;
  4778.     int verbose = 0, wild = 0, page = 0, n = 0, engdate = 0, summary = 0;
  4779.     int heading = 0, xsort = 0, reverse = 0, sortby = 0, msg = 0;
  4780.     int k, i = 0, x = 0, nx = 0, skey = 0, dlen = 0, itsadir = 0;
  4781.     int show = 3, xfermod = 0, backup = 1, rc = 0, getval = 0;
  4782.     int fs = 0;
  4783.     int multiple = 0;
  4784.     int cmifn1 = 1, cmifn2 = 0;
  4785.     struct FDB sw, fi, fl;
  4786.     char dbuf[32], xbuf[32];
  4787.  
  4788. #ifndef NOSPL
  4789.     char array = NUL;
  4790.     char ** ap = NULL;
  4791. #endif /* NOSPL */
  4792.     char
  4793.       * dir_aft = NULL,
  4794.       * dir_bef = NULL,
  4795.       * dir_naf = NULL,
  4796.       * dir_nbf = NULL,
  4797.       * dir_exc = NULL;
  4798.     char * xlist[16];
  4799.  
  4800.     g_matchdot = matchdot;              /* Save global matchdot setting */
  4801.     nolinks = 2;                        /* (it should already be 2) */
  4802.     outfile[0] = NUL;                   /* No output file yet */
  4803.  
  4804.     if (ofp != stdout) {                /* In case of previous interruption */
  4805.         if (ofp) fclose(ofp);
  4806.         ofp = stdout;
  4807.     }
  4808.     for (i = 0; i < 16; i++) xlist[i] = NULL;
  4809.  
  4810.     name[0] = NUL;
  4811.     freedirlist();                      /* In case not freed last time */
  4812.     page      = dir_page > -1 ? dir_page : xaskmore; /* Set option defaults */
  4813.     engdate   = dir_date > -1 ? dir_date : 0;
  4814.     verbose   = dir_verb > -1 ? dir_verb : 1;
  4815.     heading   = dir_head > -1 ? dir_head : 0;
  4816.     xsort     = dir_sort > -1 ? dir_sort : 0;
  4817.     sortby    = dir_skey > -1 ? dir_skey : 0;
  4818.     reverse   = dir_rvrs > -1 ? dir_rvrs : 0;
  4819.     msg       = dir_msg  > -1 ? dir_msg  : 0;
  4820. #ifdef UNIXOROSK
  4821.     if (dir_dots > -1) matchdot = dir_dots;
  4822. #endif /* UNIXOROSK */
  4823.     xfermod   = dir_mode > -1 ? dir_mode : 0;
  4824.     backup    = dir_back > -1 ? dir_back : 1;
  4825. #ifdef RECURSIVE
  4826.     recursive = dir_recu > -1 ? dir_recu : 0;
  4827. #endif /* RECURSIVE */
  4828.     show      = dir_show > -1 ? dir_show : 3;
  4829.  
  4830. #ifdef CK_TTGWSIZ
  4831. #ifdef OS2
  4832.     ttgcwsz();                          /* Screen length for more-prompting */
  4833. #else /* OS2 */
  4834.     /* Check whether window size changed */
  4835.     if (ttgwsiz() > 0) {
  4836.         if (tt_rows > 0 && tt_cols > 0) {
  4837.             cmd_rows = tt_rows;
  4838.             cmd_cols = tt_cols;
  4839.         }
  4840.     }
  4841. #endif /* OS2 */
  4842. #endif /* CK_TTGWSIZ */
  4843.  
  4844.     diractive = 1;
  4845.     cmifn1 = nolinks | 1;               /* 1 = files or directories */
  4846.     cmifn2 = 0;                         /* 0 = not directories only */
  4847.  
  4848.   again:
  4849.  
  4850.     cmfdbi(&sw,                         /* First FDB - command switches */
  4851.            _CMKEY,                      /* fcode */
  4852.            "Enter or Return to confirm the command, or\n\
  4853.  file specification, or switch",
  4854.            "",                          /* default */
  4855.            "",                          /* addtl string data */
  4856.            ndirswtab,                   /* addtl numeric data 1: tbl size */
  4857.            4,                           /* addtl numeric data 2: 4 = cmswi */
  4858.            xxstring,                    /* Processing function */
  4859.            dirswtab,                    /* Keyword table */
  4860.            &fi                          /* Pointer to next FDB */
  4861.            );
  4862.     cmfdbi(&fi,                         /* 2nd FDB - filespec to match */
  4863.            _CMIFI,                      /* fcode */
  4864.            "File specification",        /* hlpmsg */
  4865. #ifdef datageneral
  4866.            "+",                         /* Default filespec is wildcard */
  4867. #else                                   /* that matches all files... */
  4868. #ifdef VMS
  4869.            "*.*",
  4870. #else
  4871.            "*",
  4872. #endif /* VMS */
  4873. #endif /* datageneral */
  4874.            "",                          /* addtl string data */
  4875.            cmifn1,
  4876.            cmifn2,                      /* 1 = only dirs; 0 files or dirs */
  4877.            xxstring,
  4878.            NULL,
  4879.            &fl
  4880.            );
  4881.     cmfdbi(&fl,                         /* Anything that doesn't match */
  4882.            _CMFLD,                      /* fcode */
  4883.            "",                          /* hlpmsg */
  4884.            "",                          /* default */
  4885.            "",                          /* addtl string data */
  4886.            0,                           /* addtl numeric data 1 */
  4887.            0,                           /* addtl numeric data 2 */
  4888.            xxstring,
  4889.            NULL,
  4890.            NULL
  4891.            );
  4892.     while (1) {                         /* Parse 0 or more switches */
  4893.         x = cmfdb(&sw);                 /* Parse something */
  4894.         debug(F101,"domydir cmfdb","",x);
  4895.         if (x < 0)
  4896.           return(x);
  4897.         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
  4898.           break;
  4899.         c = cmgbrk();
  4900.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  4901.             printf("?This switch does not take an argument\n");
  4902.             return(-9);
  4903.         }
  4904.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  4905.             printf("?This switch requires an argument\n");
  4906.             return(-9);
  4907.         }
  4908.         switch (k = cmresult.nresult) {
  4909.           case DIR_BRF: verbose = 0; break;
  4910.           case DIR_VRB: verbose = 1; break;
  4911. #ifdef CK_TTGWSIZ
  4912.           case DIR_PAG: page = 1;    break;
  4913.           case DIR_NOP: page = 0;    break;
  4914. #endif /* CK_TTGWSIZ */
  4915.           case DIR_ISO: engdate = 0; break;
  4916.           case DIR_DAT: engdate = 1; break;
  4917.           case DIR_HDG: heading = 1; break;
  4918.           case DIR_NOH: heading = 0; break;
  4919. #ifdef UNIXOROSK
  4920.           case DIR_DOT: matchdot = 1; break;
  4921.           case DIR_NOD: matchdot = 0; break;
  4922. #endif /* UNIXOROSK */
  4923.           case DIR_ALL:
  4924.             show = 3;
  4925.             cmifn1 |= 1;
  4926.             cmifn2 = 0;
  4927.             goto again;
  4928.           case DIR_DIR:
  4929.             show = 2;
  4930.             cmifn1 |= 1;
  4931.             cmifn2 = 1;
  4932.             goto again;
  4933.           case DIR_FIL:
  4934.             show = 1;
  4935.             cmifn1 &= ~(1);
  4936.             cmifn2 = 0;
  4937.             goto again;
  4938.           case DIR_SRT:
  4939.             x = DIRS_NM;
  4940.             if (c == ':' || c == '=')
  4941.               if ((x = cmkey(dirsort,ndirsort,"Sort key","name",xxstring)) < 0)
  4942.                 return(x);
  4943.             xsort = 1;
  4944.             sortby = x;
  4945.             break;
  4946.  
  4947.           case DIR_BUP: backup  = 1; fs++;   break;
  4948.           case DIR_NOB: backup  = 0; fs++;   break;
  4949.  
  4950.           case DIR_NOS: xsort = 0;     break;
  4951.           case DIR_ASC: reverse = 0;   break;
  4952.           case DIR_DSC: reverse = 1;   break;
  4953. #ifdef RECURSIVE
  4954.           case DIR_REC: recursive = 1; diractive = 1; break;
  4955.           case DIR_NOR: recursive = 0; diractive = 0; break;
  4956. #endif /* RECURSIVE */
  4957.           case DIR_TYP: xfermod = 1;   break;
  4958.           case DIR_NOT: xfermod = 0;   break;
  4959.  
  4960. #ifdef CKSYMLINK
  4961.           case DIR_LNK:                 /* Follow links */
  4962.             nolinks = 0;
  4963.             cmifn1 &= ~(2);
  4964.             goto again;
  4965.           case DIR_NLK:                 /* Don't follow links */
  4966.             nolinks = 2;
  4967.             cmifn1 &= ~(2);
  4968.             goto again;
  4969. #endif /* CKSYMLINK */
  4970.  
  4971.           case DIR_NOM: msg     = 0;   break;
  4972.           case DIR_MSG:
  4973.             if (c == ':' || c == '=')
  4974.               if ((x = cmfld("Message to append to each line",
  4975.                              "",
  4976.                              &s,
  4977.                              xxstring
  4978.                              )) < 0)
  4979.                 return(x);
  4980.             msg = 1;
  4981.             ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  4982.             break;
  4983.  
  4984.           case DIR_SMA:
  4985.           case DIR_LAR: {
  4986.           CK_OFF_T y;
  4987.           if (!getval) break;
  4988.           if ((x = cmnumw("File size in bytes","0",10,&y,xxstring)) < 0)
  4989.         return(x);
  4990.           fs++;
  4991.           show = 1;
  4992.           switch (cmresult.nresult) {
  4993.         case DIR_SMA: minsize = y; break;
  4994.         case DIR_LAR: maxsize = y; break;
  4995.           }
  4996.           break;
  4997.       }
  4998.  
  4999. #ifndef NOSPL
  5000.           case DIR_ARR:
  5001.             if (c != ':' && c != '=') {
  5002.                 printf("?Array name required\n");
  5003.                 return(-9);
  5004.             }
  5005.             if ((x = cmfld("Array name (a single letter will do)",
  5006.                            "",
  5007.                            &s,
  5008.                            NULL
  5009.                            )) < 0) {
  5010.                 if (x == -3) {
  5011.                     printf("?Array name required\n");
  5012.                     return(-9);
  5013.                 } else
  5014.                   return(x);
  5015.             }
  5016.             if (!*s) {
  5017.                 printf("?Array name required\n");
  5018.                 return(-9);
  5019.             }
  5020.             s2 = s;
  5021.             if (*s == CMDQ) s++;
  5022.             if (*s == '&') s++;
  5023.             if (!isalpha(*s)) {
  5024.                 printf("?Bad array name - \"%s\"\n",s2);
  5025.                 return(-9);
  5026.             }
  5027.             array = *s++;
  5028.             if (isupper(array)) array = tolower(array);
  5029.             if (*s && (*s != '[' || *(s+1) != ']')) {
  5030.                 printf("?Bad array name - \"%s\"\n",s2);
  5031.                 return(-9);
  5032.             }
  5033.             break;
  5034. #endif /* NOSPL */
  5035.           case DIR_AFT:
  5036.           case DIR_BEF:
  5037.           case DIR_NAF:
  5038.           case DIR_NBF:
  5039.             if (!getval) break;
  5040.             if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
  5041.                 if (x == -3) {
  5042.                     printf("?Date-time required\n");
  5043.                     rc = -9;
  5044.                 } else
  5045.                   rc = x;
  5046.                 goto xdomydir;
  5047.             }
  5048.             fs++;
  5049.             switch (k) {
  5050.               case DIR_AFT: makestr(&dir_aft,s); break;
  5051.               case DIR_BEF: makestr(&dir_bef,s); break;
  5052.               case DIR_NAF: makestr(&dir_naf,s); break;
  5053.               case DIR_NBF: makestr(&dir_nbf,s); break;
  5054.             }
  5055.             break;
  5056.           case DIR_EXC:
  5057.             if (!getval) break;
  5058.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  5059.                 if (x == -3) {
  5060.                     printf("?Pattern required\n");
  5061.                     rc = -9;
  5062.                 } else
  5063.                   rc = x;
  5064.                 goto xdomydir;
  5065.             }
  5066.             fs++;
  5067.             makestr(&dir_exc,s);
  5068.             break;
  5069.  
  5070.           case DIR_SUM:
  5071.             summary = 1; break;
  5072.  
  5073.           case DIR_BIN: {
  5074.               extern struct keytab txtbin[];
  5075.               extern int xfiletype;
  5076.               if (!getval) break;
  5077.               if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0) {
  5078.                   rc = x;
  5079.                   goto xdomydir;
  5080.               }
  5081.               if (x == 2) {
  5082.                   xfiletype = -1;
  5083.               } else {
  5084.                   xfiletype = x;
  5085.                   fs = 1;
  5086.               }
  5087.               break;
  5088.           }
  5089.           case DIR_OUT:
  5090.             if ((x = cmofi("File for directory listing","",&s,xxstring)) < 0)
  5091.               return(x);
  5092.             ckstrncpy(outfile,s,CKMAXPATH+1);
  5093.             break;
  5094.  
  5095.           default:
  5096.             printf("?Sorry, not implemented yet - \"%s\"\n", atmbuf);
  5097.             goto xdomydir;
  5098.         }
  5099.     }
  5100.     ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of filespec */
  5101.  
  5102. /* ^^^ START MULTIPLE */
  5103.     
  5104.     while (1) {
  5105.     x = cmfld("Another filespec or Enter","",&s,xxstring);
  5106.     if (x == -3)
  5107.       break;
  5108.     if (x < 0)
  5109.       return(x);
  5110.     ckstrncat(line,",",LINBUFSIZ);
  5111.     ckstrncat(line,s,LINBUFSIZ);
  5112.     multiple++;
  5113.     }
  5114.     ckmakmsg(tmpbuf,TMPBUFSIZ,"{",line,"}",NULL);
  5115.     ckstrncpy(line,tmpbuf,LINBUFSIZ);
  5116.     cmresult.nresult = 1;
  5117.     cmresult.fcode = _CMIFI;
  5118.  
  5119. /* ^^^ END MULTIPLE */
  5120.  
  5121.     s = line;
  5122.  
  5123.     if ((x = cmcfm()) < 0)              /* Get confirmation */
  5124.       return(x);
  5125.     if (cmresult.fcode != _CMIFI) {     /* Nothing matched */
  5126.         char * m;
  5127.         if (*s == '/')
  5128. #ifdef UNIXOROSK
  5129.           m = "does not match switch or name of accessible file";
  5130. #else
  5131. #ifdef OS2
  5132.           m = "does not match switch or name of accessible file";
  5133. #else
  5134.           m = "no switches match";
  5135. #endif /* OS2 */
  5136. #endif /* UNIXOROSX */
  5137.         else
  5138.           m = "not found or not accessible";
  5139.         printf("\"%s\" - %s\n",s,m);
  5140.         rc = -9;
  5141.         goto xdomydir;
  5142.     }
  5143.     wild = cmresult.nresult;            /* Wildcard was given? */
  5144.     debug(F111,"domydir cmifi2",s,wild);
  5145.  
  5146.     if (outfile[0]) {
  5147.         ofp = fopen(outfile,"w");       /* Open output file */
  5148.         if (!ofp) {
  5149.             printf("?Can't open output file %s: %s\n",outfile,ck_errstr());
  5150.             ofp = stdout;
  5151.             return(-9);
  5152.         }
  5153.         page = 0;
  5154.     }
  5155.  
  5156. #ifdef OS2
  5157.     if (!wild) {
  5158.         if (zchki(s) == -2) {           /* Found a directory */
  5159.             p = s + (int)strlen(s) - 1; /* Yes */
  5160.             if (*p == '\\' || *p == '/')
  5161.               strcat(s, "*");
  5162.             else if (*p == ':')
  5163.               strcat(s, "./*");
  5164.             else
  5165.               strcat(s, "/*");
  5166.             wild = 1;                   /* Now it's wild */
  5167.         }
  5168.     }
  5169. #else
  5170.     if (!wild) if (isdir(s)) {          /* Is it a directory? */
  5171.         p = s + (int)strlen(s) - 1;     /* Yes */
  5172. #ifdef VMS
  5173.         {
  5174.             /* Convert from FOO.DIR;1 to [x.FOO] if necessary */
  5175.             char buf[CKMAXPATH+1];
  5176.             debug(F000,"domydir directory 0",s,*p);
  5177.             if (cvtdir(s,buf,CKMAXPATH) > 0)
  5178.               ckstrncpy(line,buf,LINBUFSIZ);
  5179.         }
  5180. #endif /* VMS */
  5181.         debug(F000,"domydir directory 1",s,*p);
  5182. #ifdef VMS
  5183.         if (*p == ']' || *p == '>' || *p == ':')
  5184.           strcat(s, "*.*");
  5185. #else
  5186. #ifdef datageneral
  5187.         if (*p == ':')
  5188.           strcat(s, "+");
  5189.         else
  5190.           strcat(s, ":+");
  5191. #else
  5192. #ifdef STRATUS
  5193.         if (*p == '>')
  5194.           strcat(s, "*");
  5195.         else
  5196.           strcat(s, ">*");
  5197. #endif /* STRATUS */
  5198. #endif /* datageneral */
  5199. #endif /* VMS */
  5200.         wild = 1;                       /* Now it's wild */
  5201.         debug(F000,"domydir directory 2",s,*p);
  5202.     }
  5203. #endif /* OS2 */
  5204.  
  5205. #ifdef ZXREWIND
  5206. /* cmifi() already called nzxpand so we can just re-use the same list. */
  5207.     if (!multiple) {
  5208.     x = zxrewind();            /* Rewind the list */
  5209.     debug(F111,"domydir zxrewind",s,x);
  5210.     } else {
  5211. #endif /* ZXREWIND */
  5212.     nzxopts = (show == ZX_DIRONLY) ? ZX_DIRONLY :
  5213.       (show == ZX_FILONLY ? ZX_FILONLY : 0);
  5214.     if (matchdot)  nzxopts |= ZX_MATCHDOT;
  5215.     if (recursive) nzxopts |= ZX_RECURSE;
  5216.     x = nzxpand(s,nzxopts);             /* Expand file list */
  5217.     debug(F111,"domydir nzxpand",s,x);
  5218. #ifdef ZXREWIND
  5219.     }
  5220. #endif /* ZXREWIND */
  5221.  
  5222. #ifndef NOSPL
  5223.     if (array) {
  5224.         int n, xx;
  5225.         n = (x < 0) ? 0 : x;
  5226.         if ((xx = dclarray(array,n)) < 0) {
  5227.             printf("?Array declaration failure\n");
  5228.             rc = -9;
  5229.             goto xdomydir;
  5230.         }
  5231.         array = xx;
  5232.         ap = a_ptr[array];
  5233.         if (n < 1) {
  5234.             rc = 0;
  5235.             goto xdomydir;
  5236.         }
  5237.     } else
  5238. #endif /* NOSPL */
  5239.       if (x < 1) {
  5240. #ifdef CKROOT
  5241.           extern int ckrooterr;
  5242.           if (ckrooterr)
  5243.             printf("?Off limits: %s\n",s);
  5244.           else
  5245. #endif /* CKROOT */
  5246.             if (x == 0 && isdir(s))
  5247.               printf("?Empty directory - \"%s\"\n", s);
  5248.             else
  5249.               printf("?%s %s match - \"%s\"\n",
  5250.                      (x == 0) ? "No" : "Too many",
  5251.                      (show == 2) ? "directories" : "files",
  5252.                      brstrip(s)
  5253.                      );
  5254.           rc = -9;
  5255.           goto xdomydir;
  5256.     }
  5257.     nx = x;                             /* Remember how many files */
  5258.  
  5259.     if (msg) {
  5260.         makestr(&dirmsg,tmpbuf);
  5261.         dirmsglen = strlen(tmpbuf);
  5262.     }
  5263.  
  5264. #ifdef VMS
  5265.     cdp = zgtdir();                     /* Get current directory */
  5266.     debug(F110,"domydir VMS zgtdir",cdp,0);
  5267. #endif /* VMS */
  5268.  
  5269.     if (xsort && verbose) {             /* If sorting, allocate space */
  5270.         if (!(dirlist = (char **) malloc((x + 1) * sizeof(char **)))) {
  5271.             if (!quiet) {
  5272.                 printf("* Warning: Failure to allocate memory for sorting.\n");
  5273.                 printf("* Will proceed without sorting...\n");
  5274.             }
  5275.             xsort = 0;
  5276.         }
  5277.         debug(F101,"domydir sort malloc","",xsort);
  5278.     }
  5279.  
  5280.     /* Display the listing */
  5281.  
  5282. #ifndef NOSPL
  5283.     if (array)                          /* Storing instead of printing */
  5284.       heading = 0;
  5285. #endif /* NOSPL */
  5286.  
  5287.     if (heading) {                      /* If /HEADING print heading */
  5288.         zfnqfp(s,TMPBUFSIZ,tmpbuf);
  5289.         fprintf(ofp,"\nDirectory of %s\n\n",tmpbuf);
  5290.         n += 3;
  5291.     }
  5292.     if (page > -1)                      /* Paging */
  5293.       xaskmore = page;
  5294.  
  5295.     if (!verbose) {                     /* /BRIEF */
  5296.         if (outfile[0]) {               /* To file  */
  5297.             int k = 0;
  5298.             znext(name);
  5299.             while (name[0]) {           /* One line per file */
  5300.                 k++;
  5301.                 if (fs) if (fileselect(name,
  5302.                                        dir_aft,dir_bef,dir_naf,dir_nbf,
  5303.                                        minsize,maxsize,!backup,16,xlist) < 1) {
  5304.                     znext(name);
  5305.                     continue;
  5306.                 }
  5307.                 fprintf(ofp,"%s\n",name);
  5308.                 znext(name);
  5309.             }
  5310.             if (heading)
  5311.               fprintf(ofp,"Files: %d\n\n",k);
  5312.             rc = 1;
  5313.             goto xdomydir;
  5314.         } else {
  5315.             rc = filhelp(x,"","",n,0);
  5316.             if (rc < 0)
  5317.               goto xdomydir;
  5318.             if (heading && rc > 0)
  5319.               fprintf(ofp,"Files: %d\n\n",x); /* (Might scroll a line or 2) */
  5320.             rc = 1;
  5321.             goto xdomydir;
  5322.         }
  5323.     }
  5324.     ndirs = nfiles = 0L;        /* Initialize counters */
  5325.     nbytes = (CK_OFF_T)0;
  5326.  
  5327.     if (dir_exc)                        /* Have exception list? */
  5328.       makelist(dir_exc,xlist,16);    /* Yes, convert to array */
  5329.  
  5330.     diractive = 1;
  5331.     znext(name);                        /* Get next file */
  5332.     while (name[0]) {                   /* Loop for each file */
  5333.         if (fs) if (fileselect(name,
  5334.                        dir_aft,dir_bef,dir_naf,dir_nbf,
  5335.                        minsize,maxsize,!backup,16,xlist) < 1) {
  5336.             znext(name);
  5337.             continue;
  5338.         }
  5339.         len = zgetfs(name);             /* Get file length */
  5340.         debug(F111,"domydir zgetfs",name,len);
  5341. #ifdef VMSORUNIX
  5342.         itsadir = zgfs_dir;             /* See if it's a directory */
  5343. #else
  5344.         itsadir = (len == (CK_OFF_T)-2 || isdir(name));
  5345. #endif /* VMSOUNIX */
  5346.         debug(F111,"domydir itsadir",name,itsadir);
  5347.         if ((itsadir && (show == 1)) || (!itsadir && (show == 2))) {
  5348.             znext(name);
  5349.             continue;
  5350.         }
  5351.         /* Get here when we know we have selected this file */
  5352.  
  5353.         nmatches ++;
  5354.         if (itsadir) {                  /* Accumulate totals for summary */
  5355.             ndirs++;
  5356.         } else {
  5357.             nfiles++;
  5358.             nbytes += len;
  5359.         }
  5360.         if (summary) {                  /* Summary only, no detail */
  5361.             znext(name);
  5362.             continue;
  5363.         }
  5364. #ifndef NOSPL
  5365.         if (array) {
  5366.             debug(F111,"domydir array",name,nfiles);
  5367.             if (ap)
  5368.               makestr(&(ap[nmatches]),name);
  5369.             znext(name);
  5370.             continue;
  5371.         }
  5372. #endif /* NOSPL */
  5373.  
  5374. /*
  5375.   NOTE: The sprintf's in this routine should be safe.  They involve
  5376.   permission strings, date/time strings, and filenames, all of which have
  5377.   known maximum lengths; none of these items is input from users.  The
  5378.   destination buffers are large enough to hold maximum sizes for any and
  5379.   all items.
  5380. */
  5381.         dstr = zfcdat(name);            /* Get modification date/time */
  5382.         debug(F111,"domydir zcfdat",dstr,0);
  5383.         if (!dstr) dstr = "";
  5384.         {
  5385. /*
  5386.   Note that zfcdat() always returns "" or yyyymmdd hh:mm:ss, so any warnings
  5387.   about possible out-of-bounds dstr[] array refs do not apply.  This block of
  5388.   code is to stifle the warnings and also allows for any out-of-spec
  5389.   zfcdat() implementations.
  5390. */
  5391.             int x;
  5392.             char * p = "00000000 00:00:00";
  5393.             x = ckstrncpy(xbuf,dstr,32);
  5394.             if (x < 17) ckstrncpy(&xbuf[x],p+x,32-x);
  5395.             dstr = xbuf;
  5396.         }
  5397.         if (engdate) {                  /* English date requested? */
  5398.             short month, day, year, hour, minute, seconds;
  5399.             month = (dstr[4]-48)*10 + (dstr[5]-48);
  5400.             mstr  = (month > 0 && month <= 12) ? months[month-1] : "xxx";
  5401.             day   = (dstr[6]-48)*10 + (dstr[7]-48);
  5402.             year  = (((dstr[0]-48)*10 +
  5403.                       (dstr[1]-48))*10 +
  5404.                       (dstr[2]-48))*10 +
  5405.                       (dstr[3]-48);
  5406.             hour  = (dstr[9]-48)*10 + (dstr[10]-48);
  5407.             minute = (dstr[12]-48)*10 + (dstr[13]-48);
  5408.             seconds = (dstr[15]-48)*10 + (dstr[16]-48);
  5409.             sprintf(dbuf,               /* SAFE */
  5410.                     "%2d-%s-%4d %02d:%02d:%02d",
  5411.                     day,mstr,year,hour,minute,seconds
  5412.                     );
  5413.             dstr = dbuf;
  5414.         } else {                        /* ISO date */
  5415.             dbuf[0] = dstr[0];          /* yyyy */
  5416.             dbuf[1] = dstr[1];
  5417.             dbuf[2] = dstr[2];
  5418.             dbuf[3] = dstr[3];
  5419.             dbuf[4] = '-';
  5420.             dbuf[5] = dstr[4];          /* mm (numeric) */
  5421.             dbuf[6] = dstr[5];
  5422.             dbuf[7] = '-';
  5423.             dbuf[8] = dstr[6];          /* dd */
  5424.             dbuf[9] = dstr[7];
  5425.             strcpy(dbuf+10,dstr+8);     /* hh:mm:ss */
  5426.             dstr = dbuf;
  5427.         }
  5428.         dlen = strlen(dbuf);            /* Length of date */
  5429.         name[CKMAXPATH] = NUL;
  5430. #ifdef CK_PERMS
  5431. #ifdef VMSORUNIX
  5432.         p = ziperm(name);               /* Get permissions */
  5433.         debug(F110,"ziperm perms",p,0);
  5434. #else
  5435.         p = zgperm(name);
  5436.         debug(F110,"zgperm perms",p,0);
  5437. #endif /* VMSORUNIX */
  5438. #else
  5439.         p = NULL;
  5440.         debug(F110,"NULL perms",p,0);
  5441. #endif /* CK_PERMS */
  5442.  
  5443. #ifdef VMS
  5444.         /* Get relative name to save space -- VMS fullnames are long... */
  5445.         ckstrncpy(name,zrelname(name,cdp),CKMAXPATH);
  5446. #endif /* VMS */
  5447.  
  5448.         if (itsadir && len < (CK_OFF_T)0) { /* Directory */
  5449. #ifdef VMS
  5450.             sprintf(linebuf,"%-22s%-10s  %s  %s",p,"<DIR>",dstr,name);
  5451. #else
  5452.             if (p)
  5453.               sprintf(linebuf,"%10s%-10s  %s  %s",p,"<DIR>",dstr,name);
  5454.             else
  5455.               sprintf(linebuf,"%-10s  %s  %s", "<DIR>", dstr, name);
  5456. #endif /* VMS */
  5457.         } else {                        /* Regular file */
  5458. #ifdef VMS
  5459.             sprintf(linebuf,"%-22s%10s  %s  %s", p, ckfstoa(len), dstr, name);
  5460. #else
  5461.             if (p)
  5462.               sprintf(linebuf,"%10s%10s  %s  %s", p, ckfstoa(len), dstr, name);
  5463.             else
  5464.               sprintf(linebuf,"%10s  %s  %s", ckfstoa(len), dstr, name);
  5465. #endif /* VMS */
  5466.         }
  5467. #ifdef UNIX
  5468. #ifdef CKSYMLINK
  5469.         if (zgfs_link) {
  5470.             int n, m;
  5471.             extern char linkname[];
  5472.             n = strlen(linebuf);
  5473.             m = strlen(linkname) + n;
  5474.             if (m < CKMAXPATH + 58)
  5475.               strcpy(linebuf+n, " -> "); /* safe (checked) */
  5476.             if (m + 4 < CKMAXPATH - 58)
  5477.               strcpy(linebuf+n+4, linkname); /* safe (checked) */
  5478.         } else
  5479. #endif /* CKSYMLINK */
  5480. #endif /* UNIX */
  5481.         if (xfermod) {                  /* Show transfer mode */
  5482.             int i, x, y;
  5483.             char * s = "";
  5484.             y = -1;
  5485.             x = scanfile(name,&y,nscanfile);
  5486.             switch (x) {
  5487.               case FT_TEXT: s = " (T)"; break;
  5488.               case FT_7BIT: s = " (T)(7BIT)"; break;
  5489.               case FT_8BIT: s = " (T)(8BIT)"; break;
  5490. #ifdef UNICODE
  5491.               case FT_UTF8: s = " (T)(UTF8)"; break;
  5492.               case FT_UCS2:
  5493.                 s = y ? " (T)(UCS2LE)" : " (T)(UCS2BE)";
  5494.                 break;
  5495. #endif /* UNICODE */
  5496.               case FT_BIN:  s = " (B)"; break;
  5497.             }
  5498.             if (!*s) {
  5499.                 s = binary ? " (B)" : " (T)";
  5500.             }
  5501.             if (*s) {
  5502.                 int n;
  5503.                 n = strlen(linebuf);
  5504.                 if (n + 4 < CKMAXPATH - 58)
  5505.                   strcpy(linebuf+n, s); /* safe (checked) */
  5506.             }
  5507.         }
  5508.         if (msg && dirmsg) {
  5509.             int n;
  5510.             n = strlen(linebuf);
  5511.             if (n + dirmsglen + 2 < CKMAXPATH)
  5512.               sprintf((char *)(linebuf+n)," %s", dirmsg); /* SAFE */
  5513.         }
  5514.         if (xsort) {                    /* Sorting - save line */
  5515.             i = strlen(linebuf);
  5516.             if ((ndirlist >= nx) ||
  5517.                 !(dirlist[ndirlist] = (char *)malloc(i+1))) {
  5518.                 printf("?Memory allocation error - try /NOSORT\n");
  5519.                 rc = -9;
  5520.                 goto xdomydir;
  5521.             }
  5522.             strcpy(dirlist[ndirlist],linebuf); /* safe */
  5523.             ndirlist++;
  5524.         }
  5525.         znext(name);                    /* Peek ahead to next file */
  5526.  
  5527.         if (!xsort) {
  5528.             fprintf(ofp,"%s\n",linebuf);
  5529.             if (page && (name[0] || heading)) { /* If /PAGE */
  5530.                 if (cmd_cols > 0) {
  5531.                     int x = strlen(linebuf);
  5532.                     int y;
  5533.                     y = (x % cmd_cols) ? 1 : 0;
  5534.                     n += x / cmd_cols + y;
  5535.                 } else {
  5536.                     n++;
  5537.                 }
  5538. #ifdef CK_TTGWSIZ
  5539.                 if (n > (cmd_rows - 3)) { /* Do more-prompting */
  5540.                     if (!askmore()) {
  5541.                         rc = 0;
  5542.                         goto xdomydir;
  5543.                     } else
  5544.                       n = 0;
  5545.                 }
  5546. #endif /* CK_TTGWSIZ */
  5547.             }
  5548.         }
  5549.     }
  5550. #ifndef NOSPL
  5551.     if (array) {
  5552.         if (ap)
  5553.           makestr(&(ap[0]),ckitoa(nmatches));
  5554.         rc = 1;
  5555.         goto xdomydir;
  5556.     }
  5557. #endif /* NOSPL */
  5558.     if (xsort) {
  5559.         skey = 0;
  5560. #ifdef VMS
  5561.         switch (sortby) {
  5562.           case DIRS_NM: skey = dlen + 35; break;
  5563.           case DIRS_DT: skey = 33; break;
  5564.           case DIRS_SZ: skey = 21;
  5565.         }
  5566. #else
  5567.         if (p) {
  5568.             switch (sortby) {
  5569.               case DIRS_NM: skey = dlen + 24; break;
  5570.               case DIRS_DT: skey = 22; break;
  5571.               case DIRS_SZ: skey = 10;
  5572.             }
  5573.         } else {
  5574.             switch (sortby) {
  5575.               case DIRS_NM: skey = dlen + 14; break;
  5576.               case DIRS_DT: skey = 12; break;
  5577.               case DIRS_SZ: skey = 0;
  5578.             }
  5579.         }
  5580. #endif /* VMS */
  5581.         sh_sort(dirlist,NULL,ndirlist,skey,reverse,filecase);
  5582.         for (i = 0; i < ndirlist; i++) {
  5583.             fprintf(ofp,"%s\n",dirlist[i]);
  5584.             if (page && (i < ndirlist -1 || heading)) { /* If /PAGE */
  5585.                 if (cmd_cols > 0) {
  5586.                     int x = strlen(dirlist[i]);
  5587.                     int y;
  5588.                     y = (x % cmd_cols) ? 1 : 0;
  5589.                     n += ((int)strlen(dirlist[i]) / cmd_cols) + y;
  5590.                 } else {
  5591.                     n++;
  5592.                 }
  5593. #ifdef CK_TTGWSIZ
  5594.                 if (n > (cmd_rows - 3)) { /* Do more-prompting */
  5595.                     if (!askmore()) {
  5596.                         rc = 0;
  5597.                         goto xdomydir;
  5598.                     } else
  5599.                       n = 0;
  5600.                 }
  5601. #endif /* CK_TTGWSIZ */
  5602.             }
  5603.         }
  5604.     }
  5605.  
  5606.     if (heading || summary) {
  5607. #ifdef CKFLOAT
  5608.         CKFLOAT gm;
  5609. #endif /* CKFLOAT */
  5610.         fprintf(ofp,"\n%ld director%s, %ld file%s, %s byte%s",
  5611.                ndirs,
  5612.                (ndirs == 1) ? "y" : "ies",
  5613.                nfiles,
  5614.                (nfiles == 1) ? "" : "s",
  5615.            ckfstoa(nbytes),
  5616.                (nbytes == 1) ? "" : "s"
  5617.                );
  5618. #ifdef CKFLOAT
  5619.         gm = ((CKFLOAT) nbytes ) / 1000000.0;
  5620.         if (gm > 1000.0)
  5621.           fprintf(ofp," (%0.2fGB)",(gm / 1000.0));
  5622.         else if (gm >= 0.01)
  5623.           fprintf(ofp," (%0.2fMB)",gm);
  5624. #endif /* CKFLOAD */
  5625.         fprintf(ofp,"\n\n");
  5626.     }
  5627.   xdomydir:
  5628.     if (g_matchdot > -1) {
  5629.         matchdot = g_matchdot;          /* Restore these... */
  5630.         g_matchdot = -1;
  5631.     }
  5632.     freedirlist();
  5633.     if (ofp != stdout) {                /* Close any output file */
  5634.         if (ofp) fclose(ofp);
  5635.         ofp = stdout;
  5636.     }
  5637.     if (rc > 0)
  5638.       success = 1;
  5639.     return(rc);
  5640. }
  5641.  
  5642. int
  5643. dodir(cx) int cx; {                     /* Do the DIRECTORY command */
  5644.     char *dc , *msg;
  5645.  
  5646. #ifdef OS2
  5647.     return(domydir());
  5648. #else /* OS2 */
  5649.     if (nopush
  5650. #ifdef DOMYDIR                          /* Builds that domydir() by default */
  5651.         || (cx == XXDIR || cx == XXLDIR)
  5652. #endif /* DOMYDIR */
  5653.         )
  5654.       return(domydir());                /* Built-in directory command */
  5655.  
  5656.     /* Use the system's directory command. */
  5657.  
  5658.     msg = (cx == XXLS) ?
  5659.       "Arguments for ls" :
  5660.         "Directory and/or file specification";
  5661.     if ((x = cmtxt(msg,"",&s,xxstring)) < 0)
  5662.       return(x);
  5663.  
  5664.     ckstrncpy(tmpbuf,s,TMPBUFSIZ);      /* Copy the filespec */
  5665.     s = tmpbuf;
  5666.  
  5667.     if ((y = cmcfm()) < 0) return(y);
  5668.  
  5669.     lp = line;
  5670.     if (!(dc = getenv("CK_DIR")))
  5671.       dc = DIRCMD;
  5672.     ckmakmsg(lp,LINBUFSIZ,dc," ",s,NULL);
  5673.     debug(F110,"DIR",line,0);
  5674. #ifdef VMS
  5675.     conres();
  5676. #endif /* VMS */
  5677.     x = zshcmd(line);
  5678. #ifdef VMS
  5679.     concb((char)escape);
  5680. #endif /* VMS */
  5681.     return(success = (x < 1) ? 0 : 1);
  5682. #endif /* OS2 */
  5683. }
  5684.  
  5685. #ifndef NOSERVER
  5686. #ifndef NOFRILLS
  5687. /* Do the ENABLE and DISABLE commands */
  5688.  
  5689. int
  5690. doenable(y,x) int y, x; {
  5691. #ifdef CK_LOGIN
  5692.     if (isguest)                        /* IKSD: Don't let guests */
  5693.       return(0);                        /* enable anything that's disabled */
  5694. #endif /* CK_LOGIN */
  5695.     switch (x) {
  5696.       case EN_ALL:
  5697.         en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
  5698.         en_ren = en_sen = en_set = en_spa = en_typ = en_ret = y;
  5699.         if (!inserver)
  5700.           en_who = en_mai = en_pri = y;
  5701.         en_mkd = en_rmd = y;
  5702.         en_xit = y;
  5703. #ifndef datageneral
  5704.         en_bye = y;
  5705. #endif /* datageneral */
  5706. #ifndef NOPUSH
  5707.         if (!nopush && !inserver)
  5708.           en_hos = y;
  5709. #endif /* NOPUSH */
  5710. #ifndef NOSPL
  5711.         en_asg = en_que = y;
  5712. #endif /* NOSPL */
  5713.         break;
  5714.  
  5715.       case EN_BYE:
  5716. #ifndef datageneral
  5717. /*
  5718.   In Data General AOS/VS Kermit can't log out its superior process.
  5719. */
  5720.         en_bye = y;
  5721. #endif /* datageneral */
  5722.         break;
  5723.       case EN_CPY:
  5724.         en_cpy = y;
  5725.         break;
  5726.       case EN_CWD:
  5727.         en_cwd = y;
  5728. #ifdef IKSD
  5729.         if (inserver && y == 0) {
  5730.             fnrpath = PATH_OFF;
  5731.             fnspath = PATH_OFF;
  5732.         }
  5733. #endif /* IKSD */
  5734.         break;
  5735.       case EN_DEL:                      /* Deleting of files */
  5736.         en_del = y;
  5737.         break;
  5738.       case EN_DIR:
  5739.         en_dir = y;
  5740.         break;
  5741.       case EN_FIN:
  5742.         en_fin = y;
  5743.         break;
  5744.       case EN_GET:
  5745.         en_get = y;
  5746.         break;
  5747. #ifndef NOPUSH
  5748.       case EN_HOS:
  5749.         if (!nopush)
  5750.          en_hos = y;
  5751.         break;
  5752. #endif /* NOPUSH */
  5753.       case EN_REN:
  5754.         en_ren = y;
  5755.         break;
  5756.       case EN_SEN:
  5757.         en_sen = y;
  5758.         break;
  5759.       case EN_SET:
  5760.         en_set = y;
  5761.         break;
  5762.       case EN_SPA:
  5763.         en_spa = y;
  5764.         break;
  5765.       case EN_TYP:
  5766.         en_typ = y;
  5767.         break;
  5768.       case EN_WHO:
  5769.         en_who = y;
  5770.         break;
  5771. #ifndef NOSPL
  5772.       case EN_ASG:
  5773.         en_asg = y;
  5774.         break;
  5775.       case EN_QUE:
  5776.         en_que = y;
  5777.         break;
  5778. #endif /* NOSPL */
  5779.       case EN_RET:
  5780.         en_del = y;
  5781.         break;
  5782.       case EN_MAI:
  5783. #ifdef CK_LOGIN
  5784.         if (isguest && y) {
  5785.             printf("?Sorry, not valid for guests\n");
  5786.             return(-9);
  5787.         }
  5788. #endif /* CK_LOGIN */
  5789.         en_mai = y;
  5790.         break;
  5791.       case EN_PRI:
  5792. #ifdef CK_LOGIN
  5793.         if (isguest && y) {
  5794.             printf("?Sorry, not valid for guests\n");
  5795.             return(-9);
  5796.         }
  5797. #endif /* CK_LOGIN */
  5798.         en_pri = y;
  5799.         break;
  5800.       case EN_MKD:
  5801.         en_mkd = y;
  5802.         break;
  5803.       case EN_RMD:
  5804.         en_rmd = y;
  5805.         break;
  5806.       case EN_XIT:
  5807.         en_xit = y;
  5808.         break;
  5809.       case EN_ENA:
  5810.         if (((y & 1) && !(en_ena & 1)) ||
  5811.             ((y & 2) && !(en_ena & 2))) {
  5812.             printf("?Sorry, DISABLE ENABLE can not be undone\n");
  5813.             return(-9);
  5814.         } else {
  5815.             en_ena = y;
  5816.             break;
  5817.         }
  5818.       default:
  5819.         return(-2);
  5820.     }
  5821.     return(1);
  5822. }
  5823. #endif /* NOFRILLS */
  5824. #endif /* NOSERVER */
  5825.  
  5826. #ifndef NOFRILLS
  5827.  
  5828. static int del_lis = 0;
  5829. static int del_dot = 0;
  5830. static int del_hdg = 0;
  5831. static int del_pag = -1;
  5832. static int del_ask = 0;
  5833.  
  5834. #ifndef NOSHOW
  5835. VOID
  5836. showdelopts() {
  5837.     int x = 0;
  5838.     extern int optlines;
  5839.     prtopt(&optlines,"");
  5840.     prtopt(&optlines,"DELETE");
  5841.     if (del_ask > -1) {
  5842.         prtopt(&optlines, del_ask ? "/ASK" : "/NOASK");
  5843.         x++;
  5844.     }
  5845. #ifdef UNIXOROSK
  5846.     if (del_dot > -1) {
  5847.         prtopt(&optlines, del_dot ? "/DOTFILES" : "/NODOTFILES");
  5848.         x++;
  5849.     }
  5850. #endif /* UNIXOROSK */
  5851.     if (del_lis > -1) {
  5852.         prtopt(&optlines, del_lis ? "/LIST" : "/NOLIST");
  5853.         x++;
  5854.     }
  5855.     if (del_hdg > -1) {
  5856.         prtopt(&optlines, del_hdg ? "/HEADING" : "/NOHEADING");
  5857.         x++;
  5858.     }
  5859. #ifndef CK_TTGWSIZ
  5860.     if (del_pag > -1) {
  5861.         prtopt(&optlines, del_pag ? "/PAGE" : "/NOPAGE");
  5862.         x++;
  5863.     }
  5864. #endif /* CK_TTGWSIZ */
  5865.     if (!x) prtopt(&optlines,"(no options set)");
  5866.     prtopt(&optlines,"");
  5867. }
  5868. #endif /* NOSHOW */
  5869.  
  5870.  
  5871. int
  5872. setdelopts() {
  5873.     int x_lis = -1, x_pag = -1, x_dot = -1, x_hdg = -1, x_ask = -1;
  5874.     int getval = 0;
  5875.     char c;
  5876.     while (1) {
  5877.         if ((y = cmswi(deltab,ndeltab,"Switch","",xxstring)) < 0) {
  5878.             if (y == -3)
  5879.               break;
  5880.             else
  5881.               return(y);
  5882.         }
  5883.         c = cmgbrk();
  5884.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  5885.             printf("?This switch does not take an argument\n");
  5886.             return(-9);
  5887.         }
  5888.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  5889.             printf("?This switch requires an argument\n");
  5890.             return(-9);
  5891.         }
  5892.         switch (y) {
  5893.           case DEL_DOT:
  5894.             x_dot = 1;
  5895.             break;
  5896.           case DEL_NOD:
  5897.             x_dot = 0;
  5898.             break;
  5899.           case DEL_HDG:
  5900.             x_hdg = 1;
  5901.             break;
  5902.           case DEL_LIS:
  5903.             x_lis = 1;
  5904.             break;
  5905.           case DEL_NOL:
  5906.             x_lis = 0;
  5907.             break;
  5908. #ifndef CK_TTGWSIZ
  5909.           case DEL_PAG:
  5910.             x_pag = 1;
  5911.             break;
  5912.           case DEL_NOP:
  5913.             x_pag = 0;
  5914.             break;
  5915. #endif /* CK_TTGWSIZ */
  5916.           case DEL_QUI:
  5917.             x_lis = 0;
  5918.             break;
  5919.           case DEL_VRB:
  5920.             x_lis = 1;
  5921.             break;
  5922.           case DEL_ASK:
  5923.             x_ask = 1;
  5924.             break;
  5925.           case DEL_NAS:
  5926.             x_ask = 0;
  5927.             break;
  5928.           default:
  5929.             printf("?Sorry, this option can not be set\n");
  5930.             return(-9);
  5931.         }
  5932.     }
  5933.     if ((x = cmcfm()) < 0)              /* Get confirmation */
  5934.       return(x);
  5935.     if (x_pag > -1) del_pag = x_pag;
  5936.     if (x_dot > -1) del_dot = x_dot;
  5937.     if (x_hdg > -1) del_hdg = x_hdg;
  5938.     if (x_lis > -1) del_lis = x_lis;
  5939.     if (x_ask > -1) del_ask = x_ask;
  5940.     return(success = 1);
  5941. }
  5942.  
  5943. #ifdef OS2
  5944. static char ** xmtchs = NULL;
  5945. static int xmtchn = 0;
  5946. #endif /* OS2 */
  5947.  
  5948. int
  5949. dodel() {                               /* DELETE */
  5950.     int i, j, k, x;
  5951.     int fs = 0;                         /* Need to call fileselect() */
  5952.     int len = 0;
  5953.     int bad = 0;
  5954.     int getval = 0, asking = 0;
  5955.     int simulate = 0, rc = 0;
  5956.     CK_OFF_T minsize = -1L, maxsize = -1L;
  5957.     int havename = 0, confirmed = 0;
  5958.     int qflag = 0;
  5959.     int summary = 0;
  5960.     int deldirs = 0;
  5961.     int deltree = 0;
  5962.     int itsadir = 0;
  5963.     int argisdir = 0;
  5964.     int xmode = -1, scan = 0, skip = 0;
  5965. #ifdef COMMENT
  5966.     int pass = 0;
  5967. #endif /* COMMENT */
  5968.     char c;
  5969.     char * deldef = "";
  5970.     char safebuf[CKMAXPATH+1];
  5971.     struct FDB sw, fi, fl;
  5972.     char
  5973.       * del_aft = NULL,
  5974.       * del_bef = NULL,
  5975.       * del_naf = NULL,
  5976.       * del_nbf = NULL,
  5977.       * del_exc = NULL;
  5978.     int
  5979.       x_lis = 0,
  5980.       /* x_dot = -1, */
  5981.       x_hdg = 0;
  5982.  
  5983.     char * dxlist[8];
  5984.  
  5985.     for (i = 0; i < 8; i++) dxlist[i] = NULL;
  5986.  
  5987.     g_matchdot = matchdot;
  5988.  
  5989.     if (del_lis > -1) x_lis    = del_lis;
  5990.     if (del_dot > -1) matchdot = del_dot;
  5991.     if (del_hdg > -1) x_hdg    = del_hdg;
  5992.     if (del_pag > -1) xaskmore = del_pag;
  5993.     if (del_ask > -1) asking   = del_ask;
  5994.  
  5995.     diractive = 1;
  5996.     nolinks = 2;                        /* By default don't follow links */
  5997.  
  5998.     cmfdbi(&sw,                         /* First FDB - command switches */
  5999.            _CMKEY,                      /* fcode */
  6000.            "File specification;\n or switch",
  6001.            "",                          /* default */
  6002.            "",                          /* addtl string data */
  6003.            ndeltab,                     /* addtl numeric data 1: tbl size */
  6004.            4,                           /* addtl numeric data 2: 4 = cmswi */
  6005.            xxstring,                    /* Processing function */
  6006.            deltab,                      /* Keyword table */
  6007.            &fi                          /* Pointer to next FDB */
  6008.            );
  6009.     cmfdbi(&fl,                         /* Anything that doesn't match */
  6010.            _CMFLD,                      /* fcode */
  6011.            "",                          /* hlpmsg */
  6012.            "",                          /* default */
  6013.            "",                          /* addtl string data */
  6014.            0,                           /* addtl numeric data 1 */
  6015.            0,                           /* addtl numeric data 2 */
  6016.            xxstring,
  6017.            NULL,
  6018.            NULL
  6019.            );
  6020.   again:
  6021.     cmfdbi(&fi,                         /* 2nd FDB - file to delete */
  6022.            _CMIFI,                      /* fcode */
  6023.            "File(s) to delete",         /* hlpmsg */
  6024.            deldef,                      /* default */
  6025.            "",                          /* addtl string data */
  6026.            nolinks | deldirs,           /* 0 = files, 1 = files or dirs */
  6027.            0,                           /* 1 = dirs only */
  6028.            xxstring,
  6029.            NULL,
  6030.            &fl
  6031.            );
  6032.     while (!havename && !confirmed) {
  6033.         x = cmfdb(&sw);                 /* Parse something */
  6034.         if (x < 0) {                    /* Error */
  6035.             if (x == -3)
  6036.               break;
  6037.             if (x == -2 || x == -9)
  6038.               printf("?Does not match switch or filename: \"%s\"\n",atmbuf);
  6039.             return(x);
  6040.         }
  6041.         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
  6042.           break;
  6043.         c = cmgbrk();                   /* Get break character */
  6044.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  6045.             printf("?This switch does not take an argument\n");
  6046.             rc = -9;
  6047.             goto xdelete;
  6048.         }
  6049.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  6050.             printf("?This switch requires an argument\n");
  6051.             rc = -9;
  6052.             goto xdelete;
  6053.         }
  6054.         switch (k = cmresult.nresult) {
  6055.           case DEL_AFT:
  6056.           case DEL_BEF:
  6057.           case DEL_NAF:
  6058.           case DEL_NBF:
  6059.             if (!getval) break;
  6060.             if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
  6061.                 if (x == -3) {
  6062.                     printf("?Date-time required\n");
  6063.                     x = -9;
  6064.                 } else
  6065.                   rc = x;
  6066.                 goto xdelete;
  6067.             }
  6068.             fs++;
  6069.             deltree = 0;
  6070.             switch (k) {
  6071.               case DEL_AFT: makestr(&del_aft,s); break;
  6072.               case DEL_BEF: makestr(&del_bef,s); break;
  6073.               case DEL_NAF: makestr(&del_naf,s); break;
  6074.               case DEL_NBF: makestr(&del_nbf,s); break;
  6075.             }
  6076.             break;
  6077.           case DEL_DOT:
  6078.             matchdot = 1;
  6079.             break;
  6080.           case DEL_NOD:
  6081.             matchdot = 0;
  6082.             break;
  6083.           case DEL_ALL:
  6084.             fs = 0;
  6085. #ifdef VMS
  6086.             deldef = "*.*";             /* UNIX, Windows, OS/2 */
  6087. #else
  6088. #ifdef datageneral
  6089.             deldef = "+";               /* AOS/VS */
  6090. #else
  6091.             deldef = "*";               /* UNIX, Windows, OS/2, VMS... */
  6092. #endif /* datageneral */
  6093. #endif /* VMS */
  6094.             deltree = 1;
  6095.             nolinks = 2;
  6096.             matchdot = 1;
  6097.             recursive = 1;              /* Fall through purposely... */
  6098.           case DEL_DIR:
  6099.             deldirs = 1;
  6100.             goto again;
  6101.           case DEL_EXC:
  6102.             if (!getval) break;
  6103.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  6104.                 if (x == -3) {
  6105.                     printf("?Pattern required\n");
  6106.                     x = -9;
  6107.                 } else
  6108.                   rc = x;
  6109.                 goto xdelete;
  6110.             }
  6111.             fs++;
  6112.             deltree = 0;
  6113.             makestr(&del_exc,s);
  6114.             break;
  6115.           case DEL_HDG:
  6116.             x_hdg = 1;
  6117.             break;
  6118. #ifdef RECURSIVE
  6119.           case DEL_REC:
  6120.             recursive = 1;
  6121.             break;
  6122. #endif /* RECURSIVE */
  6123.           case DEL_LIS:
  6124.             x_lis = 1;
  6125.             break;
  6126.           case DEL_SUM:
  6127.             summary = 1;
  6128.             x_lis = 0;
  6129.             x_hdg = 1;
  6130.             break;
  6131.           case DEL_NOL:
  6132.             x_lis = 0;
  6133.             break;
  6134. #ifndef CK_TTGWSIZ
  6135.           case DEL_PAG:
  6136.             xaskmore = 1;
  6137.             break;
  6138.           case DEL_NOP:
  6139.             xaskmore = 0;
  6140.             break;
  6141. #endif /* CK_TTGWSIZ */
  6142.           case DEL_QUI:
  6143.             qflag = 1;
  6144.             x_lis = 0;
  6145.             break;
  6146.           case DEL_VRB:
  6147.             x_lis = 1;
  6148.             break;
  6149.  
  6150.           case DEL_SMA:
  6151.           case DEL_LAR:
  6152.             if (!getval) break;
  6153.             if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0)
  6154.               return(x);
  6155.             fs++;
  6156.             deltree = 0;
  6157.             switch (cmresult.nresult) {
  6158.               case DEL_SMA: minsize = y; break;
  6159.               case DEL_LAR: maxsize = y; break;
  6160.             }
  6161.             break;
  6162.  
  6163.           case DEL_SIM:
  6164.             simulate = 1;
  6165.             x_lis = 1;
  6166.             break;
  6167.           case DEL_ASK:
  6168.             asking = 1;
  6169.             break;
  6170.           case DEL_NAS:
  6171.             asking = 0;
  6172.             break;
  6173.           case DEL_TYP: {
  6174.               extern struct keytab txtbin[];
  6175.               if (!getval) break;
  6176.               if ((x = cmkey(txtbin,3,"","",xxstring)) < 0)
  6177.                 return(x);
  6178.               if (x == 2) {             /* ALL */
  6179.                   xmode = -1;
  6180.               } else {                  /* TEXT or BINARY only */
  6181.                   xmode = x;
  6182.                   scan = 1;
  6183.               }
  6184.               break;
  6185.           }
  6186.           default:
  6187.             printf("?Not implemented yet - \"%s\"\n",atmbuf);
  6188.             return(-9);
  6189.         }
  6190.     }
  6191.     if (qflag && (cmresult.fcode == _CMFLD)) {
  6192.         if ((x = cmcfm()) < 0)
  6193.           return(x);
  6194.         else
  6195.           return(success = 0);
  6196.     }
  6197.     if (cmresult.fcode != _CMIFI) {
  6198.         if (*atmbuf) {
  6199.         int x;
  6200.             if (iswild(atmbuf) && nzxpand(atmbuf,nzxopts) == 0)
  6201.               printf("?No files match: %s\n",brstrip(atmbuf));
  6202.             else if ((x = zchki(atmbuf)) == -1)
  6203.           printf("?File not found: %s\n",brstrip(atmbuf));
  6204.         else if (x == -2)
  6205.           printf("?Not a regular file: %s\n",atmbuf);
  6206.         else
  6207.               /* printf("?Not a deletable file: %s\n",atmbuf); */
  6208.               goto tryanyway;
  6209.         } else {
  6210.             printf("?A file specification is required\n");
  6211.         }
  6212.         return(-9);
  6213.     }
  6214.   tryanyway:
  6215.     ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ); /* Safe copy of filespec */
  6216.     if (deldirs) {
  6217.         ckstrncpy(safebuf,cmresult.sresult,CKMAXPATH);
  6218. #ifdef VMSORUNIX
  6219.         len = zgetfs(tmpbuf);           /* Is it a directory name? */
  6220.         argisdir = zgfs_dir;            /* Then because of how zxpand() */
  6221.         if (argisdir && zgfs_link)      /* works, we have to add it to */
  6222.           argisdir = 0;                 /* the list. */
  6223.         if (itsadir)
  6224.           len = -2;
  6225. #else
  6226.         len = zchki(tmpbuf);
  6227.         if (len < 0)
  6228.           argisdir = isdir(tmpbuf);
  6229. #endif /* VMSORUNIX */
  6230.     }
  6231.     debug(F110,"DELETE file",tmpbuf,0);
  6232.     if ((x = cmcfm()) < 0)
  6233.       return(x);
  6234.  
  6235. #ifdef IKSD
  6236. #ifdef CK_LOGIN
  6237.     if (inserver && isguest) {
  6238.         printf("?Sorry, DELETE unavailable to guests\n");
  6239.         return(-9);
  6240.     }
  6241. #endif /* CK_LOGIN */
  6242. #endif /* IKSD */
  6243.  
  6244. #ifndef OS2ORUNIX
  6245.     if (simulate) {
  6246.         printf("?Sorry, /SIMULATE not implemented on this platform\n");
  6247.         return(-9);
  6248.     }
  6249. #endif /* OS2ORUNIX */
  6250.  
  6251. #ifdef COMMENT
  6252.     /* (not needed) */
  6253.     if (!iswild(tmpbuf)) {
  6254.         char *m;
  6255.         errno = 0;
  6256.         x = zchki(tmpbuf);
  6257.         if (x < 0) {
  6258.             switch (x) {
  6259.               case -2: m = "Not a regular file"; break;
  6260.               case -1: m = "File not found or not accessible"; break;
  6261.               default: m = errno ? ck_errstr() : "Can't delete";
  6262.             }
  6263.             printf("?%s: \"%s\"\n",m,tmpbuf);
  6264.             return(-9);
  6265.         }
  6266.     }
  6267. #endif /* COMMENT */
  6268.  
  6269.     makelist(del_exc,dxlist,8);
  6270.  
  6271. /* tmpbuf[] has the name - now do any needed conversions on it */
  6272.  
  6273. #ifdef OS2
  6274.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  6275.         char *p = tmpbuf;
  6276.         while (*p) {                    /* Change them back to \ */
  6277.             if (*p == '/') *p = '\\';
  6278.             p++;
  6279.         }
  6280.     }
  6281. #endif /* OS2 */
  6282.  
  6283. #ifdef VMS
  6284.     if (iswild(tmpbuf)) {
  6285. #ifdef COMMENT
  6286.         /* Does not handle '.' as version separator */
  6287.         char *p = tmpbuf;
  6288.         x = 0;
  6289.         while (*p) {
  6290.             if (*p == ';') {
  6291.                 x = 1;
  6292.                 break;
  6293.             } else
  6294.               p++;
  6295.         }
  6296.         if (!x) ckstrncat(tmpbuf,";*",TMPBUFSIZ);
  6297. #else
  6298.         j = 0; x = 0;                   /* for end_dot and number of dots */
  6299.         i = strlen(tmpbuf);
  6300.         if (tmpbuf[i] == ';') {
  6301.             ckstrncat(tmpbuf,"0",TMPBUFSIZ);
  6302.         } else {
  6303.             if (tmpbuf[i--] == '.')
  6304.               j++;
  6305.             for (; i >= 0; i--) {
  6306.                 if (tmpbuf[i] == ';' || tmpbuf[i] == ':' ||
  6307.                     tmpbuf[i] == ']' || tmpbuf[i] == '>')
  6308.                   break;
  6309.                 else if (tmpbuf[i] == '.')
  6310.                   x++;
  6311.             }
  6312.             if (tmpbuf[i] != ';') {     /* dot may have been used */
  6313.                 if (j) {                /* last char is dot */
  6314.                   if (x)                /* second is version separator */
  6315.                     ckstrncat(tmpbuf,"0",TMPBUFSIZ);
  6316.                   else                  /* 'foo.' */
  6317.                     ckstrncat(tmpbuf,";0",TMPBUFSIZ);
  6318.                 } else if (x == 1)      /* lacking a version separator */
  6319.                   ckstrncat(tmpbuf,";0",TMPBUFSIZ);
  6320.                 else if (x == 0)        /* x == 2 has a version */
  6321.                   ckstrncat(tmpbuf,".*;0",TMPBUFSIZ);
  6322.             }
  6323.         }
  6324. #endif /* COMMENT */
  6325.     }
  6326. #endif /* VMS */
  6327.  
  6328.     debug(F110,"dodel tmpbuf",tmpbuf,0); /* Filename */
  6329.  
  6330. #ifndef OS2ORUNIX                       /* No built-in DELETE code... */
  6331.     /* Construct system command. */
  6332.     ckmakmsg(line,LINBUFSIZ,DELCMD," ",tmpbuf,NULL);
  6333. #else
  6334. #ifdef VMS
  6335.     if (asking) {                       /* Maybe overwrite in VMS */
  6336.         if (x_lis)                      /* if options are needed... */
  6337.           ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm/log ",tmpbuf,NULL);
  6338.         else
  6339.           ckmakmsg(line,LINBUFSIZ,DELCMD," /confirm ",tmpbuf,NULL);
  6340.     } else if (x_lis)
  6341.       ckmakmsg(line,LINBUFSIZ,DELCMD," /log ",tmpbuf,NULL);
  6342.     conres();
  6343. #endif /* VMS */
  6344.  
  6345.     debug(F110,"dodel line",line,0);
  6346. #endif /* OS2ORUNIX */
  6347.  
  6348. #ifdef MAC
  6349.     success = (zdelet(tmpbuf) == 0);
  6350.  
  6351. #else  /* !MAC ... */
  6352.  
  6353. #ifdef OS2ORUNIX
  6354.     {
  6355.         int filespace = 0;
  6356.         int count = 0;
  6357.         int lines = 0;
  6358.         int n = 0;
  6359.  
  6360.         s = tmpbuf;
  6361.  
  6362. #ifdef CK_TTGWSIZ
  6363. #ifdef OS2
  6364.         ttgcwsz();
  6365. #else /* OS2 */
  6366.         /* Check whether window size changed */
  6367.         if (ttgwsiz() > 0) {
  6368.             if (tt_rows > 0 && tt_cols > 0) {
  6369.                 cmd_rows = tt_rows;
  6370.                 cmd_cols = tt_cols;
  6371.             }
  6372.         }
  6373. #endif /* OS2 */
  6374. #endif /* CK_TTGWSIZ */
  6375.  
  6376.         if (x_hdg > 0 && !summary) {
  6377.             printf("Deleting %s...%s\n", s, simulate ? " (SIMULATION)" : "");
  6378.             n += 2;
  6379.         }
  6380. #ifdef ZXREWIND
  6381.         z = zxrewind();                 /* Rewind file list */
  6382. #else
  6383.         if (!deldirs)
  6384.           nzxopts = ZX_FILONLY;
  6385.         if (recursive) nzxopts |= ZX_RECURSE;
  6386.         if (matchdot)  nzxopts |= ZX_MATCHDOT;
  6387.         errno = 0;
  6388.         z = nzxpand(s,nzxopts);         /* Expand file list */
  6389. #endif /* ZXREWIND */
  6390.         debug(F111,"dodel",s,z);
  6391.  
  6392.         /* If deleting directories, sort in reverse order */
  6393.         /* so we delete the files first, then the directory. */
  6394.  
  6395. #ifdef OS2
  6396.         /* In K95, we have no mtchs array, nor any control over */
  6397.         /* the order in which znext() returns filenames, so we  */
  6398.         /* must copy the array and sort it. */
  6399.         {
  6400.             int i;
  6401.             if (xmtchs) {               /* Free previous list in case */
  6402.                 debug(F101,"dodel freeing previous list","",xmtchn);
  6403.                 for (i = 0; i < xmtchn; i++) /* it wasn't freed last time. */
  6404.                   if (xmtchs[i])
  6405.                     free(xmtchs[i]);
  6406.                 free(xmtchs);
  6407.             }
  6408.             xmtchn = 0;
  6409.             xmtchs = (char **)malloc(z * (sizeof(char **))); /* Make new one */
  6410.             if (!xmtchs) {
  6411.                 printf("?Memory allocation failure\n");
  6412.                 return(-9);
  6413.             }
  6414.             for (i = 0; i < z; i++) {
  6415.                 xmtchs[i] = NULL;
  6416.                 znext(tmpbuf);
  6417.                 if (!*tmpbuf)
  6418.                   break;
  6419.                 makestr(&(xmtchs[i]),tmpbuf);
  6420.                 if (!xmtchs[i]) {
  6421.                     printf("?Memory allocation failure\n");
  6422.                     xmtchn = i - 1;
  6423.                     rc = -9;
  6424.                     goto xdelete;
  6425.                 }
  6426.                 /* debug(F111,"dodel add",xmtchs[i],i); */
  6427.             }
  6428.             xmtchn = i;
  6429.             debug(F101,"dodel xmtchn","",xmtchn);
  6430.             sh_sort(xmtchs,NULL,z,0,deldirs,0);
  6431.         }
  6432. #else
  6433. #ifdef UNIX
  6434.         sh_sort(mtchs,NULL,z,0,deldirs,filecase);
  6435. #endif /* UNIX */
  6436. #endif /* OS2 */
  6437.  
  6438.         if (z > 0) {
  6439.             int i;
  6440. #ifdef OS2
  6441.             int ix = 0;
  6442. #endif /* OS2 */
  6443.             success = 1;
  6444.             if (x_hdg > 0)
  6445.               printf("\n");
  6446.  
  6447.             while (
  6448. #ifdef OS2
  6449.                    ix < xmtchn
  6450. #else
  6451.                    1
  6452. #endif /* OS2 */
  6453.                    ) {                  /* Loop for all files */
  6454. #ifdef OS2
  6455.                 ckstrncpy(tmpbuf,xmtchs[ix++],TMPBUFSIZ);
  6456. #else
  6457.                 znext(tmpbuf);          /* Get next file */
  6458. #endif /* OS2 */
  6459.                 if (!*tmpbuf) {         /* No more */
  6460.                     if (deldirs && recursive && argisdir) {
  6461.                         ckstrncpy(tmpbuf,safebuf,TMPBUFSIZ);
  6462.                         argisdir = 0;   /* (only do this once) */
  6463.                     } else
  6464.                       break;
  6465.                 }
  6466.                 skip = 0;
  6467.                 if (!deltree) {
  6468.                     if (fs)
  6469.                       if (fileselect(tmpbuf,
  6470.                                      del_aft,del_bef,del_naf,del_nbf,
  6471.                                      minsize,maxsize,0,8,dxlist) < 1) {
  6472.                           skip++;
  6473.                       }
  6474.                 }
  6475.                 if (!skip && scan && itsadir) {
  6476.                     skip++;
  6477.                 }
  6478.                 if (!skip && scan) {
  6479.                       switch (scanfile(tmpbuf,&y,nscanfile)) {
  6480.                       case FT_BIN:
  6481.                         if (xmode != 1)
  6482.                           skip++;
  6483.                         break;
  6484.                       case FT_TEXT:
  6485.                       case FT_7BIT:
  6486.                       case FT_8BIT:
  6487. #ifdef UNICODE
  6488.                       case FT_UTF8:
  6489.                       case FT_UCS2:
  6490. #endif /* UNICODE */
  6491.                         if (xmode != 0)
  6492.                           skip++;
  6493.                     }
  6494.                 }
  6495.                 if (!skip && asking) {
  6496.                     int x;
  6497.                     ckmakmsg(line,LINBUFSIZ," Delete ",tmpbuf,"? ",NULL);
  6498.                     x = getyesno(line,3);
  6499.                     switch (x) {
  6500.                       case 0: continue;           /* no */
  6501.                       case 1: break;              /* yes */
  6502.                       case 2: goto xdelete;       /* quit */
  6503.                       case 3: asking = 0; break;  /* go */
  6504.                     }
  6505.                 }
  6506. #ifdef VMSORUNIX
  6507.                 len = zgetfs(tmpbuf);   /* Get length and accessibility */
  6508.                 itsadir = zgfs_dir;
  6509.                 if (itsadir && zgfs_link) { /* Treat links to directories */
  6510.                     itsadir = 0;        /* as regular files */
  6511.                     if (scan)           /* But not if /TYPE: was given */
  6512.                       skip++;
  6513.                 }
  6514.                 if (itsadir)            /* (emulate non-Unix code) */
  6515.                   len = -2;
  6516. #else
  6517.                 len = zchki(tmpbuf);    /* Get accessibility */
  6518.                 if (len < 0)            /* See if it's a directory */
  6519.                   itsadir = isdir(tmpbuf);
  6520. #endif /* VMSORUNIX */
  6521.  
  6522.                 if (skip) {
  6523. #ifdef COMMENT                          /* Too verbose */
  6524.                     if (x_lis > 0) {
  6525.                         lines++;
  6526.                         printf(" %s (SKIPPED)\n",tmpbuf);
  6527. #ifdef CK_TTGWSIZ
  6528.                         if (++n > cmd_rows - 3)
  6529.                           if (!askmore()) goto xdelete; else n = 0;
  6530. #endif /* CK_TTGWSIZ */
  6531.                     }
  6532. #endif /* COMMENT */
  6533.                     continue;
  6534.                 }
  6535.  
  6536.                 debug(F111,"DELETE len",tmpbuf,len);
  6537.                 if (simulate) {
  6538.                     filespace += len;
  6539.                     count++;
  6540.                     if (x_lis > 0) {
  6541.                         lines++;
  6542.                         printf(" %s (SELECTED)\n",tmpbuf);
  6543.                         if (++n > cmd_rows - 3) {
  6544.                             int xx;
  6545.                             xx = askmore();
  6546.                             if (!xx) goto xdelete; else n = 0;
  6547.                         }
  6548.                     }
  6549.                 } else if (len >= 0 || !itsadir) { /* Regular file */
  6550.                     zdelet(tmpbuf);                /* or symlink, etc... */
  6551.                     if (zchki(tmpbuf) < 0) {
  6552.                         filespace += len;
  6553.                         count++;
  6554.                         if (x_lis > 0) {
  6555.                             lines++;
  6556.                             printf(" %s (OK)\n",tmpbuf);
  6557.                             if (++n > cmd_rows - 3)
  6558.                               if (!askmore()) goto xdelete; else n = 0;
  6559.                         }
  6560.                     } else {
  6561.                         bad++;
  6562.                         success = 0;
  6563.                         if (x_lis > 0) {
  6564.                             lines++;
  6565.                             printf(" %s (FAILED: %s)\n",tmpbuf,ck_errstr());
  6566.                             if (++n > cmd_rows - 3)
  6567.                               if (!askmore()) goto xdelete; else n = 0;
  6568.                         }
  6569.                     }
  6570.                 } else if (/* pass > 0 && */ deldirs && itsadir) {
  6571.                     /* It's a directory */
  6572.                     if (zrmdir(tmpbuf) > -1) { /* Only works if empty */
  6573.                         count++;
  6574.                         if (x_lis > 0) {
  6575.                             lines++;
  6576.                             printf(" %s (OK)\n",tmpbuf);
  6577.                             if (++n > cmd_rows - 3)
  6578.                               if (!askmore()) goto xdelete; else n = 0;
  6579.                         }
  6580.                     } else {
  6581.                         success = 0;
  6582.                         if (x_lis > 0) {
  6583.                             lines++;
  6584.                             printf(" %s (FAILED: %s)\n",
  6585.                                    tmpbuf,
  6586.                                    ck_errstr());
  6587.                             if (++n > cmd_rows - 3)
  6588.                               if (!askmore()) goto xdelete; else n = 0;
  6589.                         }
  6590.                     }
  6591.                 } else if (x_lis > 0) {
  6592.                     lines++;
  6593.                     if (isdir(tmpbuf))
  6594.                       printf(" %s (FAILED: directory)\n",tmpbuf);
  6595.                     else
  6596.                       printf(" %s (FAILED: not a regular file)\n",tmpbuf);
  6597.                     if (++n > cmd_rows - 3)
  6598.                       if (!askmore()) goto xdelete; else n = 0;
  6599.                 }
  6600.             }
  6601.             if (x_hdg > 0) {
  6602.                 if (lines > 0)
  6603.                   printf("\n");
  6604.                 if (++n > cmd_rows - 3)
  6605.                   if (!askmore()) goto xdelete; else n = 0;
  6606.                 printf("%d file%s %sdeleted, %d byte%s %sfreed%s\n",
  6607.                        count,
  6608.                        count != 1 ? "s" : "",
  6609.                        simulate ? "would be " : "",
  6610.                        filespace,
  6611.                        filespace != 1 ? "s" : "",
  6612.                        simulate ? "would be " : "",
  6613.                        simulate ? " (maybe)" : ""
  6614.                        );
  6615.             }
  6616.             if (!x_lis && !success && !quiet) {
  6617.                 printf("?DELETE failed for %d file%s \
  6618. (use DELETE /LIST to see details)\n",
  6619.                        bad, bad == 1 ? "" : "s"
  6620.                        );
  6621.             }
  6622.         } else if (x_lis > 0) {
  6623.             if (errno)
  6624.               printf("?%s: %s\n",ck_errstr(), tmpbuf);
  6625.             else
  6626.               printf("?Can't delete: %s\n",tmpbuf);
  6627.         }
  6628.     }
  6629. #else /* OS2ORUNIX */
  6630. #ifndef VMS                             /* Others - let the system do it. */
  6631.     xsystem(line);
  6632.     x = nzxpand(tmpbuf,nzxopts);
  6633.     success = (x > 0) ? 0 : 1;
  6634.     if (x_hdg > 0)
  6635.       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
  6636. #else
  6637.     if (asking)
  6638.       printf("\n");
  6639.     x = xsystem(line);                  /* zshcmd returns 1 for success */
  6640.     success = (x > 0) ? 1 : 0;
  6641.     if (x_hdg > 0 && !asking)
  6642.       printf("%s - %sdeleted\n", tmpbuf, success ? "" : "not ");
  6643.     concb((char)escape);
  6644. #endif /* VMS */
  6645. #endif /* OS2ORUNIX */
  6646. #endif /* MAC */
  6647.   xdelete:
  6648.     if (g_matchdot > -1) {
  6649.         matchdot = g_matchdot;          /* Restore these... */
  6650.         g_matchdot = -1;
  6651.     }
  6652. #ifdef OS2
  6653.     if (xmtchs) {
  6654.         int i;
  6655.         debug(F101,"dodel freeing list","",xmtchn);
  6656.         for (i = 0; i < xmtchn; i++)
  6657.           if (xmtchs[i]) free(xmtchs[i]);
  6658.         free(xmtchs);
  6659.         xmtchs = NULL;
  6660.         xmtchn = 0;
  6661.     }
  6662. #endif /* OS2 */
  6663.     debug(F101,"dodel result","",rc);
  6664.     return((rc < 0) ? rc : success);
  6665. }
  6666. #endif /* NOFRILLS */
  6667.  
  6668. #ifndef NOSPL                           /* The ELSE command */
  6669. _PROTOTYP( VOID pushqcmd, (char *) );
  6670.  
  6671. int
  6672. doelse() {
  6673.     if (!ifcmd[cmdlvl]) {
  6674.         printf("?ELSE doesn't follow IF\n");
  6675.         return(-2);
  6676.     }
  6677. #ifdef COMMENT
  6678. /*
  6679.   Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
  6680.   from working.
  6681. */
  6682.     ifcmd[cmdlvl] = 0;
  6683. #endif /* COMMENT */
  6684.     if (!iftest[cmdlvl]) {              /* If IF was false do ELSE part */
  6685.         if (maclvl > -1 || tlevel > -1) { /* In macro or command file */
  6686.             debug(F100,"doelse pushing","",0);
  6687. #ifndef COMMENT
  6688.             pushcmd(NULL);              /* save rest of command. */
  6689. #else
  6690.             /* This fixes certain obscure problems */
  6691.             /* but breaks many other constructions that must work. */
  6692.             pushqcmd(NULL);
  6693. #endif /* COMMENT */
  6694.         } else {                        /* If interactive, */
  6695.             cmini(ckxech);              /* just start a new command */
  6696.             printf("\n");               /* (like in MS-DOS Kermit) */
  6697.             if (pflag) prompt(xxstring);
  6698.         }
  6699.     } else {                            /* Condition is false */
  6700.         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  6701.           return(y);                    /* Gobble up rest of line */
  6702.     }
  6703.     return(0);
  6704. }
  6705. #endif /* NOSPL */
  6706.  
  6707. #ifndef NOSPL
  6708. int
  6709. doswitch() {
  6710.     char *lp, *ap;                      /* Macro argument pointer */
  6711.     int len = 0, x, y, pp = 0;
  6712.     char brbuf[3];
  6713.  
  6714.     /* Get variable name */
  6715.  
  6716.     tmpbuf[0] = NUL;
  6717.     brbuf[0] = '{';
  6718.     brbuf[1] = '}';
  6719.     brbuf[2] = NUL;
  6720.  
  6721.     y = cmfld("Variable name","",&s,xxstring);
  6722.     debug(F111,"doswitch cmfld",s,y);
  6723.     if (y < 0) {
  6724.         if (y == -3)            /* Because brstrip() writes */
  6725.           s = brbuf;            /* into its argument. */
  6726.         else
  6727.           return(y);
  6728.     }
  6729.     debug(F110,"doswitch A",s,0);
  6730.     if (!strcmp(s,"(")) {
  6731.         pp++;
  6732.         if ((y = cmfld("Variable name","",&s,xxstring)) < 0) {
  6733.             if (y == -3)
  6734.               s = brbuf;
  6735.             else
  6736.               return(y);
  6737.         debug(F110,"doswitch B",s,0);
  6738.         }
  6739.     }
  6740.     len = ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  6741.     if (tmpbuf[0] == CMDQ) {
  6742.         if (chkvar(s) < 1) {
  6743.             printf("?Variable name required\n");
  6744.             return(-9);
  6745.         }
  6746.     }
  6747.     if (pp > 0) {                       /* If open paren given parse closing */
  6748.         if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
  6749.           return(y);
  6750.         if (strcmp(atmbuf,")")) {
  6751.             printf("?Closing parenthesis required\n");
  6752.             return(-9);
  6753.         }
  6754.     }
  6755.     lp = line;
  6756.     x = ckstrncpy(lp,"_switx ",LINBUFSIZ); /* _switx + space */
  6757.     lp += x;
  6758.     ap = lp;
  6759.     debug(F010,"SWITCH a",line,0);
  6760.  
  6761. #ifdef COMMENT
  6762.     x = ckmakmsg(lp,LINBUFSIZ-x,tmpbuf," ",NULL,NULL); /* variable name + SP */
  6763. #else
  6764.     {                                   /* variable name + SP */
  6765.         char * p = tmpbuf;
  6766.     if (len > 0) {
  6767.         if (tmpbuf[0] == '(' && tmpbuf[len-1] == ')') {
  6768.         tmpbuf[len-1] = NUL;
  6769.         p++;
  6770.         }
  6771.         }
  6772.         x = ckmakmsg(lp,LINBUFSIZ-x,"{",brstrip(p),"}"," ");
  6773.     }
  6774. #endif /* COMMENT */
  6775.     debug(F010,"SWITCH b",line,0);
  6776.     lp += x;
  6777.  
  6778.     /* Get body */
  6779.  
  6780.     if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
  6781.     if ((y = (int)strlen(s)) < 1) return(-2);
  6782.     if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
  6783.         ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
  6784.         s = tmpbuf;
  6785.     }
  6786.     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
  6787.         printf("?Unbalanced braces\n");
  6788.         return(0);
  6789.     }
  6790.     debug(F010,"SWITCH c",line,0);
  6791.  
  6792.     x = mlook(mactab,"_switx",nmac);    /* Look up SWITCH macro definition */
  6793.     if (x < 0) {                        /* Not there? */
  6794.         addmmac("_switx",sw_def);       /* Put it back. */
  6795.         if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
  6796.             printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
  6797.             return(success = 0);
  6798.         }
  6799.     }
  6800.     debug(F010,"SWITCH command",line,0); /* Execute the SWITCH macro. */
  6801.     success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC);
  6802.     debug(F101,"SWITCH status","",success);
  6803.     return(success);
  6804. }
  6805.  
  6806. int
  6807. dofor() {                               /* The FOR command. */
  6808.     int i, fx, fy, fz;                  /* loop variables */
  6809.     char *ap, *di;                      /* macro argument pointer */
  6810.     int pp = 0;                         /* Paren level */
  6811.     int mustquote = 0;
  6812.  
  6813.     for (i = 0; i < 2; i++) {
  6814.         if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  6815.             if (y == -3) {
  6816.                 printf("?Variable name required\n");
  6817.                 return(-9);
  6818.             } else
  6819.               return(y);
  6820.         }
  6821.         if (strcmp(s,"("))
  6822.           break;
  6823.         pp++;
  6824.     }
  6825. #ifdef COMMENT
  6826.     if ((y = parsevar(s,&x,&z)) < 0)    /* Check variable. */
  6827.       return(y);
  6828. #else
  6829.     if (*s == CMDQ)                     /* If loop variable starts with */
  6830.       mustquote++;                      /* backslash, mustquote is > 0. */
  6831. #endif /* COMMENT */
  6832.  
  6833.     lp = line;                          /* Build a copy of the command */
  6834.     ckstrncpy(lp,"_forx ",LINBUFSIZ);
  6835.     lp += (int)strlen(line);            /* "_for" macro. */
  6836.     ap = lp;                            /* Save pointer to macro args. */
  6837.  
  6838.     if (*s == CMDQ) s++;                /* Skip past backslash if any. */
  6839.     while ((*lp++ = *s++)) ;            /* copy it */
  6840.     lp--; *lp++ = SP;                   /* add a space */
  6841.  
  6842.     if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
  6843.         if (y == -3) return(-2);
  6844.         else return(y);
  6845.     }
  6846.     debug(F101,"dofor fx","",fx);
  6847.     s = atmbuf;                         /* Copy the atom buffer */
  6848.  
  6849.     if ((int)strlen(s) < 1) goto badfor;
  6850. /*
  6851.   In edit 192, we change the loop variables to be evaluated at loop entry,
  6852.   not each time through the loop.  This was required in order to allow
  6853.   \v(argc) to be used as a loop variable, or in a loop-variable expression.
  6854.   Thus, we can't have FOR loops that modify their own exit conditions by
  6855.   changing the final value or the increment.  The problem with \v(argc) was
  6856.   that it is on the macro stack; after entry into the _forx macro, it is at
  6857.   the wrong place.
  6858. */
  6859.     sprintf(tmpbuf,"%d",fx);            /* (SAFE) Substitute actual value */
  6860.     s = tmpbuf;
  6861.     while ((*lp++ = *s++)) ;            /* (what they actually typed) */
  6862.     lp--; *lp++ = SP;
  6863. #ifdef DEBUG
  6864.     *lp = NUL;
  6865.     debug(F110,"FOR A",line,0);
  6866. #endif /* DEBUG */
  6867.  
  6868.     if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
  6869.         if (y == -3) return(-2);
  6870.         else return(y);
  6871.     }
  6872.     debug(F101,"dofor fy","",fy);
  6873.     s = atmbuf;                         /* Same deal */
  6874.     if ((int)strlen(s) < 1)
  6875.       goto badfor;
  6876.  
  6877.     sprintf(tmpbuf,"%d",fy);            /* SAFE */
  6878.     s = tmpbuf;
  6879.     while ((*lp++ = *s++)) ;
  6880.     lp--;
  6881.     *lp++ = SP;
  6882. #ifdef DEBUG
  6883.     *lp = NUL;
  6884.     debug(F110,"FOR B",line,0);
  6885. #endif /* DEBUG */
  6886.  
  6887.     x_ifnum = 1;                        /* Increment or parenthesis */
  6888.     di = (fx < fy) ? "1" : "-1";        /* Default increment */
  6889.     if ((y = cmnum("increment",di,10,&fz,xxstring)) < 0) {
  6890.         debug(F111,"dofor increment",atmbuf,y);
  6891.         x_ifnum = 0;
  6892.         if (y == -3) {                  /* Premature termination */
  6893.             return(-2);
  6894.         } else if (y == -2) {           /* Maybe closing paren */
  6895.             if (!strcmp(atmbuf,")")) {
  6896.                 pp--;                   /* Count it */
  6897.                 s = di;                 /* supply default interval */
  6898.                 fz = atoi(s);
  6899.             } else                      /* Not closing paren, invalid */
  6900.               return(y);
  6901.         } else                          /* Other error */
  6902.           return(y);
  6903.     } else {                            /* Number */
  6904.         x_ifnum = 0;
  6905.         debug(F101,"dofor fz","",fz);
  6906.         s = atmbuf;                     /* Use it */
  6907.     }
  6908.     if ((int)strlen(s) < 1)
  6909.       goto badfor;
  6910.  
  6911.     sprintf(tmpbuf,"%d",fz);            /* (SAFE) Same deal */
  6912.     s = tmpbuf;
  6913.     while ((*lp++ = *s++)) ;
  6914.     lp--; *lp++ = SP;
  6915.  
  6916. #ifdef DEBUG
  6917.     *lp = NUL;
  6918.     debug(F110,"FOR C",line,0);
  6919. #endif /* DEBUG */
  6920.  
  6921.     /* Insert the appropriate comparison operator */
  6922.     if (fz < 0)
  6923.       *lp++ = '<';
  6924.     else
  6925.       *lp++ = '>';
  6926.     *lp++ = SP;
  6927.  
  6928. #ifdef DEBUG
  6929.     *lp = NUL;
  6930.     debug(F110,"FOR D",line,0);
  6931. #endif /* DEBUG */
  6932.  
  6933.     if (pp > 0) {                       /* If open paren given parse closing */
  6934.         if ((y = cmfld("Closing parenthesis","",&s,NULL)) < 0)
  6935.           return(y);
  6936.         if (strcmp(atmbuf,")")) {
  6937.             printf("?Closing parenthesis required\n");
  6938.             return(-9);
  6939.         }
  6940.     }
  6941.     if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
  6942.     if ((y = (int)strlen(s)) < 1) return(-2);
  6943.     if (s[0] != '{' && s[y-1] != '}') { /* Supply braces if missing */
  6944.         ckmakmsg(tmpbuf,TMPBUFSIZ,"{ ",s," }",NULL);
  6945.         s = tmpbuf;
  6946.     }
  6947.     if (litcmd(&s,&lp,(LINBUFSIZ - (lp - (char *)line) - 2)) < 0) {
  6948.         printf("?Unbalanced braces\n");
  6949.         return(0);
  6950.     }
  6951. #ifdef DEBUG
  6952.     *lp = NUL;
  6953.     debug(F110,"FOR E",line,0);
  6954. #endif /* DEBUG */
  6955.  
  6956. #ifdef COMMENT
  6957. /* Too strict */
  6958.     if (fz == 0) {
  6959.         printf("?Zero increment not allowed\n");
  6960.         return(0);
  6961.     }
  6962. #endif /* COMMENT */
  6963. /*
  6964.   In version 8.0 we decided to allow macro names anyplace a numeric-valed
  6965.   variable could appear.  But this caused trouble for the FOR loops because
  6966.   the quoting in for_def[] assumed a \%i-style loop variable.  We account
  6967.   for this here in the if (mustquote)...else logic by invoking separate
  6968.   FOR macro definitions in the two cases.
  6969. */
  6970.     if (mustquote) {                    /* \%i-style loop variable */
  6971.         x = mlook(mactab,"_forx",nmac); /* Look up FOR macro definition */
  6972.         if (x < 0) {                    /* Not there? */
  6973.             addmmac("_forx",for_def);   /* Put it back. */
  6974.             if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
  6975.                 printf("?FOR macro definition gone!\n");
  6976.                 return(success = 0);
  6977.             }
  6978.         }
  6979.     } else {                            /* Loop variable is a macro */
  6980.         x = mlook(mactab,"_forz",nmac);
  6981.         if (x < 0) {
  6982.             addmmac("_forz",foz_def);
  6983.             if ((x = mlook(mactab,"_forz",nmac)) < 0) {
  6984.                 printf("?FOR macro definition gone!\n");
  6985.                 return(success = 0);
  6986.             }
  6987.         }
  6988.     }
  6989.     debug(F010,"FOR command",line,0);   /* Execute the FOR macro. */
  6990.     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs | CF_IMAC));
  6991.  
  6992. badfor:
  6993.     printf("?Incomplete FOR command\n");
  6994.     return(-2);
  6995. }
  6996. #endif /* NOSPL */
  6997.  
  6998. #ifndef NOFRILLS
  6999. /* Do the BUG command */
  7000.  
  7001. int
  7002. dobug() {
  7003.     int n;
  7004.     char * s = "";
  7005.     extern char * k_info_dir;
  7006.  
  7007.     if (k_info_dir)
  7008.       s = k_info_dir;
  7009.  
  7010. #ifdef COMMENT
  7011.     printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
  7012. #endif /* COMMENT */
  7013.     printf(
  7014. "\nBefore requesting technical support from Columbia U., please consult:\n\n"
  7015.            );
  7016.     n = 7;
  7017. #ifdef OS2
  7018.     printf(" . Your \"Kermit 95\" user manual (use the MANUAL command).\n");
  7019.     printf(" . The technical reference manual, \"Using C-Kermit\".\n");
  7020.     n += 2;
  7021. #else
  7022.     printf(" . The book \"Using C-Kermit\" (type HELP for more info).\n");
  7023.     n += 1;
  7024. #endif /* OS2 */
  7025.  
  7026.     printf(" . Your own organization's support staff, if any.\n");
  7027.     printf(
  7028. " . The comp.protocols.kermit.misc newsgroup.\n");
  7029.     printf(
  7030. " . The Kermit support website, http://www.columbia.edu/kermit/support.html \n"
  7031.            );
  7032.     printf(
  7033.  
  7034. " . The Kermit FAQ, http://www.columbia.edu/kermit/newfaq.html \n");
  7035. #ifdef OS2
  7036.     printf(
  7037. " . The Kermit 95 FAQ, http://www.columbia.edu/kermit/k95faq.html \n");
  7038.     n++;
  7039. #endif /* OS2 */
  7040.  
  7041.     printf(
  7042. " . The C-Kermit FAQ, http://www.columbia.edu/kermit/ckfaq.html \n");
  7043.     n += 4;
  7044.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7045.     printf("\n\
  7046. If you still need help or have a bug to report after consulting these sources,"
  7047.            );
  7048.     printf("\nsend e-mail to:\n\n");
  7049.     n += 2;
  7050.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7051.     printf("  mailto:kermit-support@columbia.edu\n\n");
  7052.     n += 1;
  7053.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7054.     printf("Or contact us by post:\n\n");
  7055.     printf(
  7056. "  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
  7057.            );
  7058.     n += 1;
  7059.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7060.     printf("Or by fax at +1 (212) 662-6442.\n\n");
  7061.     n += 1;
  7062.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7063. #ifdef COMMENT
  7064.     printf("Telephone support is available too:\n\n");
  7065.     n += 1;
  7066.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7067.     printf(
  7068.     "  +1 (212) 854-5126, from anywhere, $25.00 USD per call, MC/Visa\n\n");
  7069.     n += 1;
  7070.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7071. #endif /* COMMENT */
  7072. #ifndef NOSHOW
  7073. #ifndef NOFRILLS
  7074.     printf(
  7075. "Before reporting problems, please use the SHOW FEATURES command\n");
  7076.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  7077.     printf(
  7078. "to get detailed program version and configuration information.\n\n");
  7079. #endif /* NOFRILLS */
  7080. #endif /* NOSHOW */
  7081.     return(1);
  7082. }
  7083. #endif /* NOFRILLS */
  7084.  
  7085. #ifndef NOSPL
  7086.  
  7087. /*  T O D 2 S E C  --  Convert time of day as hh:mm:ss to secs since midnite */
  7088. /*
  7089.   Call with a string hh:mm or hh:mm:ss.
  7090.   Returns a 0 to 86400 on success, or a negative number on failure.
  7091. */
  7092. long
  7093. tod2sec(t) char * t; {
  7094.     long t2;
  7095.     long hh = 0L, mm = 0L, ss = 0L;
  7096.  
  7097.     if (!t) t = "";
  7098.     if (!*t)
  7099.       return(-3L);
  7100.     debug(F110,"tod2sec",t,0);
  7101.  
  7102.     if (isdigit(*t))                    /* Get hours from argument */
  7103.       hh = *t++ - '0';
  7104.     else
  7105.       return(-1L);
  7106.     if (isdigit(*t))
  7107.       hh = hh * 10 + *t++ - '0';
  7108. #ifdef COMMENT
  7109.     if (hh > 24L)
  7110.       return(-1L);
  7111. #endif /* COMMENT */
  7112.     if (*t == ':')
  7113.       t++;
  7114.     else if (!*t)
  7115.       goto xtod2sec;
  7116.     else
  7117.       return(-1L);
  7118.  
  7119.     if (isdigit(*t))                    /* Minutes */
  7120.       mm = *t++ - '0';
  7121.     else
  7122.       return(-1L);
  7123.     if (isdigit(*t))
  7124.       mm = mm * 10 + *t++ - '0';
  7125.     if (mm > 60L)
  7126.       return(-1L);
  7127.     if (*t == ':')
  7128.       t++;
  7129.     else if (!*t)
  7130.       goto xtod2sec;
  7131.     else
  7132.       return(-1L);
  7133.  
  7134.     if (isdigit(*t))                    /* Seconds */
  7135.       ss = *t++ - '0';
  7136.     else
  7137.       return(-1L);
  7138.     if (isdigit(*t))
  7139.       ss = ss * 10 + *t++ - '0';
  7140.     if (ss > 60L)
  7141.       return(-1L);
  7142.  
  7143.     if (*t > 32)                        /* No trailing junk allowed */
  7144.       return(-1L);
  7145.  
  7146.   xtod2sec:
  7147.  
  7148.     t2 = hh * 3600L + mm * 60L + ss;    /* Seconds since midnight from arg */
  7149.     debug(F101,"tod2sec t2","",t2);
  7150.  
  7151.     return(t2);
  7152. }
  7153.  
  7154. int waitinterval = 1;
  7155.  
  7156. #ifdef OLDWAIT
  7157. #undef OLDWAIT
  7158. #endif /* OLDWAIT */
  7159.  
  7160. int kbchar = NUL;
  7161.  
  7162. int
  7163. dopaus(cx) int cx; {
  7164.     long zz;
  7165.     extern int sleepcan;
  7166.  
  7167. #ifdef OLDWAIT
  7168.     zz = -1L;
  7169.     x_ifnum = 1;                        /* Turn off internal complaints */
  7170.     if (cx == XXWAI)
  7171.       y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
  7172.     else if (cx == XXPAU)
  7173.       y = cmnum("seconds to pause, or time of day hh:mm:ss",
  7174.                 "1",10,&x,xxstring);
  7175.     else
  7176.       y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
  7177.                 "100",10,&x,xxstring);
  7178.     x_ifnum = 0;
  7179.     if (y < 0) {
  7180.         if (y == -2) {                  /* Invalid number or expression */
  7181.             char *p = tmpbuf;           /* Retrieve string from atmbuf */
  7182.             int n = TMPBUFSIZ;
  7183.             *p = NUL;
  7184.             zzstring(atmbuf,&p,&n);     /* Evaluate in case it's a variable */
  7185.             zz = tod2sec(tmpbuf);       /* Convert to secs since midnight */
  7186.             if (zz < 0L) {
  7187.                 printf("?Number, expression, or time of day required\n");
  7188.                 return(-9);
  7189.             } else {
  7190.                 char now[32];           /* Current time */
  7191.                 char *p;
  7192.                 long tnow;
  7193.                 p = now;
  7194.                 ztime(&p);
  7195.                 tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  7196.                 if (zz < tnow)          /* User's time before now */
  7197.                   zz += 86400L;         /* So make it tomorrow */
  7198.                 zz -= tnow;             /* Seconds from now. */
  7199.             }
  7200.         } else
  7201.           return(y);
  7202.     }
  7203.     if (x < 0) x = 0;
  7204.     switch (cx) {
  7205.       case XXPAU:                       /* PAUSE */
  7206.       case XXMSL:                       /* MSLEEP */
  7207.         if ((y = cmcfm()) < 0) return(y);
  7208.         break;
  7209.       case XXWAI:                       /* WAIT */
  7210.         z = 0;                          /* Modem signal mask */
  7211.         while (1) {                     /* Read zero or more signal names */
  7212.             y = cmkey(mstab,nms,"modem signal","",xxstring);
  7213.             if (y == -3) break;         /* -3 means they typed CR */
  7214.             if (y < 0) return(y);       /* Other negatives are errors */
  7215.             z |= y;                     /* OR the bit into the signal mask */
  7216.         }
  7217.         if ((y = cmcfm()) < 0) return(y);
  7218.         break;
  7219.  
  7220.       default:                          /* Shouldn't happen */
  7221.         return(-2);
  7222.     }
  7223.  
  7224. /* Command is entered, now do it. */
  7225.  
  7226.     if (zz > -1L) {                     /* Time of day given? */
  7227.         x = zz;
  7228.         if (zz != (long) x) {
  7229.             printf(
  7230. "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
  7231.                    );
  7232.             return(-9);
  7233.         }
  7234.     }
  7235.     if (cx == XXMSL) {                  /* Millisecond sleep */
  7236.         msleep(zz < 0 ? x : x * 1000);
  7237.         return(success = 1);
  7238.     }
  7239.     if (cx == XXPAU && !sleepcan) {     /* SLEEP CANCELLATION is OFF */
  7240.         sleep(x);
  7241.         return(success = 1);
  7242.     }
  7243.  
  7244.     /* WAIT, or else SLEEP with cancellation allowed... */
  7245.  
  7246.     do {                                /* Sleep loop */
  7247.         int mdmsig;
  7248.         if (sleepcan) {                 /* Keyboard cancellation allowed? */
  7249.             if (y = conchk()) {         /* Did they type something? */
  7250. #ifdef COMMENT
  7251.                 while (y--) coninc(0);  /* Yes, gobble it all up */
  7252. #else
  7253.                 /* There is a debate over whether PAUSE should absorb    */
  7254.                 /* its cancelling character(s).  There are several       */
  7255.                 /* reasons why it should gobble at least one character:  */
  7256.                 /* (1) MS-DOS Kermit does it                             */
  7257.                 /* (2) if not, subsequent PAUSE commands will terminate  */
  7258.                 /*     immediately                                       */
  7259.                 /* (3) if not, subsequent ASK commands will use it as    */
  7260.                 /*     valid input.  If \13, then it will get no input   */
  7261.                 /* (4) if not, then the character appears on the command */
  7262.                 /*     line after all enclosing macros are complete.     */
  7263.                 kbchar = coninc(0);     /* Gobble one up */
  7264. #endif /* COMMENT */
  7265.                 break;                  /* And quit PAUSing or WAITing */
  7266.             }
  7267.         }
  7268.         if (cx == XXWAI) {              /* WAIT (z == modem signal mask) */
  7269.             debug(F101,"WAIT x","",x);
  7270.             if (z > 0) {                /* Looking for any modem signals? */
  7271.                 mdmsig = ttgmdm();      /* Yes, get them */
  7272.                 if (mdmsig < 0)         /* Failed */
  7273.                   return(success = 0);
  7274.                 if ((mdmsig & z) == z)  /* Got what we wanted? */
  7275.                   return(success = 1);  /* Succeed */
  7276.             }
  7277.             if (x == 0)                 /* WAIT 0 and didn't get our signals */
  7278.               break;
  7279.         }
  7280.         sleep(1);                       /* No interrupt, sleep one second */
  7281.     } while (--x > 0);
  7282.  
  7283.     if (cx == XXWAI)                    /* If WAIT and loop exhausted */
  7284.       success = (z == 0);               /* Fail. */
  7285.     else                                /*  */
  7286.       success = (x == 0);               /* Set SUCCESS/FAILURE for PAUSE. */
  7287.     return(success);
  7288.  
  7289. #else  /* New code uses chained FDBs and allows FILE waits... */
  7290.  
  7291.     char * m = "";                      /* Help message */
  7292.     struct FDB nu, fl;                  /* Parse function descriptor blocks */
  7293.     int filewait = 0;
  7294.     int mdmsig = 0, fs = 0;
  7295.     char filedate[32];
  7296.  
  7297.     kbchar = 0;
  7298.  
  7299.     switch (cx) {
  7300.       case XXWAI: m = "seconds to wait, or time of day hh:mm:ss"; break;
  7301.       case XXPAU: m = "seconds to pause, or time of day hh:mm:ss"; break;
  7302.       case XXMSL: m = "milliseconds to sleep, or time of day hh:mm:ss"; break;
  7303.     }
  7304.     zz = -1L;
  7305.     cmfdbi(&nu,
  7306.            _CMNUM,                      /* Number */
  7307.            m,                           /* Help message */
  7308.            (cx == XXMSL) ? "100" : "1", /* Default */
  7309.            "",                          /* N/A */
  7310.            0,                           /* N/A */
  7311.            0,                           /* N/A */
  7312.            xxstring,                    /* Processing function */
  7313.            NULL,                        /* N/A */
  7314.            &fl                          /* Next */
  7315.            );
  7316.     cmfdbi(&fl,                         /* Time of day */
  7317.            _CMFLD,                      /* Field */
  7318.            "",                          /* hlpmsg */
  7319.            "",                          /* default */
  7320.            "",                          /* addtl string data */
  7321.            0,                           /* addtl numeric data 1 */
  7322.            0,                           /* addtl numeric data 2 */
  7323.            xxstring,                    /* processing func */
  7324.            NULL,                        /* N/A */
  7325.            NULL                         /* No next */
  7326.            );
  7327.     x = cmfdb(&nu);                     /* Parse a number or a field */
  7328.     if (x < 0) {
  7329.         if (x == -3)
  7330.           x = -2;
  7331.         return(x);
  7332.     }
  7333.     switch (cmresult.fcode) {
  7334.       case _CMNUM:                      /* Number */
  7335.         x = cmresult.nresult;
  7336.         break;
  7337.       case _CMFLD:                      /* Field */
  7338.         zz = tod2sec(cmresult.sresult); /* Convert to secs since midnight */
  7339.         if (zz < 0L) {
  7340.             printf("?Number, expression, or time of day required\n");
  7341.             return(-9);
  7342.         } else {
  7343.             char now[32];               /* Current time */
  7344.             char *p;
  7345.             long tnow;
  7346.             p = now;
  7347.             ztime(&p);
  7348.             tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  7349.             if (zz < tnow)              /* User's time before now */
  7350.               zz += 86400L;             /* So make it tomorrow */
  7351.             zz -= tnow;         /* Seconds from now. */
  7352.         }
  7353.     }
  7354.     debug(F101,"PAUSE/WAIT/MSLEEP zz","",zz);
  7355.     switch (cx) {
  7356.       case XXPAU:                       /* PAUSE */
  7357.       case XXMSL:                       /* MSLEEP */
  7358.         if ((y = cmcfm()) < 0) return(y);
  7359.         break;
  7360.       case XXWAI:                       /* WAIT */
  7361.         z = 0;                          /* Modem signal mask */
  7362.         y = cmkey(waittab,nwaittab,"","",xxstring);
  7363.         if (y < 0) {
  7364.             if (y == -3) {
  7365.                 if ((y = cmcfm()) < 0)
  7366.                   return(y);
  7367.                 break;
  7368.             } else
  7369.               return(y);
  7370.         }
  7371.         if (y == WAIT_FIL) {            /* FILE */
  7372.             int wild = 0;
  7373.             if ((z = cmkey(wfswi,nwfswi,"event","",xxstring)) < 0)
  7374.               return(z);
  7375.             filewait = z;
  7376.             if (filewait == WF_MOD || filewait == WF_DEL)
  7377.               z = cmifi("Filename","",&s,&wild,xxstring);
  7378.             else
  7379.               z = cmfld("Filename","",&s,xxstring);
  7380.             if (z < 0)
  7381.               return(z);
  7382.             if (wild || ((filewait == WF_CRE) && iswild(s))) {
  7383.                 printf("?Wildcards not valid here\n");
  7384.                 return(-9);
  7385.             }
  7386.             ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  7387.             if ((z = cmcfm()) < 0)
  7388.               return(z);
  7389.             break;
  7390.         } else if (y != WAIT_MDM) {     /* A modem signal */
  7391.             z |= y;                     /* OR the bit into the signal mask */
  7392.         }
  7393.         if (!filewait) {                /* Modem signals... */
  7394.             while (1) {                 /* Get zero or more signal names */
  7395.                 y = cmkey(mstab,nms,"modem signal","",xxstring);
  7396.                 if (y == -3) break;     /* -3 means they typed CR */
  7397.                 if (y < 0) return(y);   /* Other negatives are errors */
  7398.                 z |= y;                 /* OR the bit into the signal mask */
  7399.             }
  7400.             if ((y = cmcfm()) < 0) return(y);
  7401.             break;
  7402.         }
  7403.  
  7404.       default:                          /* Shouldn't happen */
  7405.         return(-2);
  7406.     } /* switch (cx) */
  7407.  
  7408. /* Command is entered, now do it. */
  7409.  
  7410.     if (zz > -1L) {                     /* Time of day given? */
  7411.         x = zz;
  7412.         if (zz != (long) x) {
  7413.             printf(
  7414. "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
  7415.                    );
  7416.             return(-9);
  7417.         }
  7418.     }
  7419.     if (sleepcan)
  7420.       concb((char)escape);              /* Ensure single-char wakeup */
  7421.  
  7422.     if (cx == XXMSL) {                  /* Millisecond sleep */
  7423.         msleep(zz < 0 ? x : x * 1000);
  7424.         return(success = 1);
  7425.     }
  7426.     if (cx == XXPAU && !sleepcan) {     /* SLEEP CANCELLATION is OFF */
  7427.         sleep(x);
  7428.         return(success = 1);
  7429.     }
  7430.     if (filewait) {                     /* FILE... */
  7431.         fs = zchki(tmpbuf);             /* Check if file exists */
  7432.         switch (filewait) {
  7433.           case WF_DEL:
  7434.             if (fs == -1)
  7435.               return(success = 1);
  7436.             break;
  7437.           case WF_MOD:
  7438.             if (fs == -1) {
  7439.                 printf("?File does not exit: %s\n",tmpbuf);
  7440.                 return(-9);
  7441.             }
  7442.             s = zfcdat(tmpbuf);         /* Get current modification date */
  7443.             if (!s) s = "";
  7444.             if (ckstrncpy(filedate,s,32) != 17) {
  7445.                 printf("?Can't get modification time: %s\n",tmpbuf);
  7446.                 return(-9);
  7447.             }
  7448.             break;
  7449.           case WF_CRE:
  7450.             if (fs > -1)
  7451.               return(success = 1);
  7452.             break;
  7453.         }
  7454.     }
  7455.     do {                                /* Polling loop */
  7456.         if (sleepcan) {                 /* Keyboard cancellation allowed? */
  7457.             if ((y = conchk()) > 0) {   /* Did they type something? */
  7458.                 kbchar = coninc(0);     /* Yes, get first char they typed */
  7459.                 debug(F000,"WAIT kbchar","",kbchar);
  7460. #ifdef COMMENT
  7461.                 while (--y > 0)         /* Gobble the rest up */
  7462.                   coninc(0);
  7463. #endif /* COMMENT */
  7464.                 return(success = 0);    /* And quit PAUSing or WAITing */
  7465.             }
  7466.         }
  7467.         if (filewait == 0) {
  7468.             if (cx == XXWAI) {          /* WAIT for modem signals */
  7469.                 if (z != 0) {
  7470.                     mdmsig = ttgmdm();  /* Get them. */
  7471.                     debug(F101,"WAIT ttgmdm","",mdmsig);
  7472.                     if (mdmsig < 0)     /* Failure to get them? */
  7473.                       return(success = 0); /* Fail. */
  7474.                     if ((mdmsig & z) == z) /* Got desired ones? */
  7475.                       return(success = 1); /* Succeed. */
  7476.                 } else if (x == 0)
  7477.                   return(success = 0);
  7478.             }
  7479.         } else {                        /* FILE... */
  7480.             fs = zchki(tmpbuf);         /* Get file status */
  7481.             if (filewait == WF_MOD) {   /* Wait for modification */
  7482.                 if (fs == -1)           /* Failure to get status */
  7483.                   return(success = 0);  /* so WAIT fails. */
  7484.                 s = zfcdat(tmpbuf);     /* Get current modification time */
  7485.                 if (!s) s = "";         /* And compare with the time */
  7486.                 if (strcmp(s,filedate)) /* when the WAIT started */
  7487.                   return(success = 1);
  7488.             } else if (filewait == WF_DEL) { /* Wait for deletion */
  7489.                 if (fs == -1)           /* If file doesn't exist, */
  7490.                   return(success = 1);  /* succeed. */
  7491.             } else if (filewait == WF_CRE) { /* Wait for creation */
  7492.                 if (fs != -1)           /* If file exists */
  7493.                   return(success = 1);  /* succeed. */
  7494.             }
  7495.         }
  7496.         if (x < 1)                      /* SLEEP/WAIT/PAUSE 0 */
  7497.           break;
  7498.         sleep(waitinterval);            /* No interrupt, sleep */
  7499.         x -= waitinterval;              /* Deduct sleep time */
  7500.     } while (x > 0);
  7501.  
  7502.     if (cx == XXWAI)                    /* WAIT time expired */
  7503.       success = (z == 0);               /* Succeed if no modem signals */
  7504.     else                                /* For SLEEP or PAUSE, success */
  7505.       success = (x == 0);               /* depends on whether it was */
  7506.     return(success);                    /* interrupted from the keyboard. */
  7507. #endif /* OLDWAIT */
  7508. }
  7509. #endif /* NOSPL */
  7510.  
  7511. #ifdef OS2ORUNIX
  7512. _PROTOTYP(int zcmpfn,(char *, char *));
  7513. #endif /* OS2ORUNIX */
  7514.  
  7515. #ifndef NOFRILLS
  7516. #ifdef NT
  7517. int 
  7518. dolink() {
  7519.     /* Parse a file or a directory name */
  7520.     int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
  7521.     struct FDB sw, fi;
  7522.  
  7523.     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
  7524.            _CMKEY,                      /* fcode */
  7525.            "Filename or switch",        /* hlpmsg */
  7526.            "",                          /* default */
  7527.            "",                          /* addtl string data */
  7528.            nqvswtab,                    /* addtl numeric data 1: tbl size */
  7529.            4,                           /* addtl numeric data 2: 4 = cmswi */
  7530.            xxstring,                    /* Processing function */
  7531.            qvswtab,                     /* Keyword table */
  7532.            &fi                          /* Pointer to next FDB */
  7533.            );
  7534.  
  7535.     cmfdbi(&fi,                         /* 1st FDB - file to type */
  7536.            _CMIFI,                      /* fcode */
  7537.            "",                          /* hlpmsg */
  7538.            "",                          /* default */
  7539.            "",                          /* addtl string data */
  7540.            3,                           /* addtl numeric data 1 */
  7541.            0,                           /* addtl numeric data 2 */
  7542.            xxstring,
  7543.            NULL,
  7544.            NULL
  7545.            );
  7546.  
  7547.     while (!havename) {
  7548.         x = cmfdb(&sw);                 /* Parse something */
  7549.         if (x < 0)                      /* Error */
  7550.           return(x);
  7551.         switch (cmresult.fcode) {
  7552.           case _CMKEY:
  7553.             switch (cmresult.nresult) {
  7554.               case DEL_LIS:
  7555.               case DEL_VRB:
  7556.                 listing = 1;
  7557.                 break;
  7558.               case DEL_NOL:
  7559.               case DEL_QUI:
  7560.                 listing = 0;
  7561.                 break;
  7562.             }
  7563.             break;
  7564.           case _CMIFI:
  7565.             s = cmresult.sresult;
  7566.             havename = 1;
  7567.             break;
  7568.           default:
  7569.             return(-2);
  7570.         }
  7571.     }
  7572.     wild = cmresult.nresult;            /* Source specification wild? */
  7573.  
  7574.     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
  7575.     s = line;
  7576.  
  7577.     if (!wild)
  7578.       wild = iswild(line);
  7579.  
  7580.     p = tmpbuf;                         /* Place for new name */
  7581.     if ((x = cmofi(wild ? "Target directory" : "New name",
  7582.                    "",&s,xxstring)) < 0) { /* Get new name */
  7583.         if (x == -3) {
  7584.             printf("?%s required\n", wild ? "Target directory" : "New name");
  7585.             return(-9);
  7586.         } else return(x);
  7587.     }
  7588.     ckstrncpy(p,s,TMPBUFSIZ);           /* Make a safe copy of the new name */
  7589.     if ((y = cmcfm()) < 0) return(y);
  7590.  
  7591.     if (!wild) {                        /* Just one */
  7592.         if (listing) printf("%s => %s ",line,p);
  7593.         if (zlink(line,p) < 0) {
  7594.             if (listing) printf("(FAILED: %s\n",ck_errstr());
  7595.             rc = 0;
  7596.         } else {
  7597.             if (listing) printf("(OK)\n");
  7598.         }
  7599.         return(success = rc);
  7600.     }
  7601.     if (!isdir(p)) {                    /* Multiple */
  7602.         printf(                         /* if target is not a directory */
  7603. "?Multiple source files not allowed if target is not a directory.\n");
  7604.         return(-9);
  7605.     }
  7606. #ifdef COMMENT
  7607.     else {                              /* Show full path of target */
  7608.         char buf[CKMAXPATH];            /* (too much) */
  7609.         if (zfnqfp(p,CKMAXPATH,buf))
  7610.           ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
  7611.     }
  7612. #endif /* COMMENT */
  7613.  
  7614. #ifdef VMS
  7615.     conres();                           /* Let Ctrl-C work. */
  7616. #endif /* VMS */
  7617.     debug(F110,"dolink line",line,0);
  7618.  
  7619. #ifdef ZXREWIND
  7620.     z = zxrewind();                     /* Rewind file list */
  7621. #else
  7622.     z = nzxpand(s,0);                   /* Expand file list */
  7623. #endif /* ZXREWIND */
  7624.     debug(F111,"dolink p",p,z);
  7625.  
  7626. #ifdef UNIX
  7627.     if (wild && z > 1)
  7628.       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
  7629. #endif /* UNIX */
  7630.  
  7631.     while (z-- > 0) {
  7632.         if (!(z == 0 && !wild))
  7633.           znext(line);
  7634.         if (!line[0])
  7635.           break;
  7636.         if (listing) printf("%s => %s ",line,p);
  7637.         if (zlink(line,p) < 0) {
  7638.             if (listing) printf("(FAILED: %s\n",ck_errstr());
  7639.             rc = 0;
  7640.         } else {
  7641.             if (listing) printf("(OK)\n");
  7642.         }
  7643.     }
  7644. #ifdef VMS
  7645.     concb((char)escape);
  7646. #endif /* VMS */
  7647.     return(success = rc);
  7648. }
  7649. #endif /* NT */
  7650.  
  7651. #ifdef ZCOPY
  7652. int
  7653. docopy() {
  7654.     int i, x, listing = 0, nolist = 0, havename = 0;
  7655.     struct FDB sw, fi;
  7656.     int targetisdir = 0;
  7657.     int targetlen = 0;
  7658.     int swapping = 0;
  7659.     int appending = 0;
  7660.     int fromb64 = 0;
  7661.     int tob64 = 0;
  7662.     int wild = 0;
  7663.     int rc = 1;
  7664.  
  7665.     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
  7666.            _CMKEY,                      /* fcode */
  7667.            "Filename or switch",        /* hlpmsg */
  7668.            "",                          /* default */
  7669.            "",                          /* addtl string data */
  7670.            ncopytab,                    /* addtl numeric data 1: tbl size */
  7671.            4,                           /* addtl numeric data 2: 4 = cmswi */
  7672.            xxstring,                    /* Processing function */
  7673.            copytab,                     /* Keyword table */
  7674.            &fi                          /* Pointer to next FDB */
  7675.            );
  7676.     cmfdbi(&fi,                         /* 1st FDB - file to type */
  7677.            _CMIFI,                      /* fcode */
  7678.            "",                          /* hlpmsg */
  7679.            "",                          /* default */
  7680.            "",                          /* addtl string data */
  7681.            0,                           /* addtl numeric data 1 */
  7682.            0,                           /* addtl numeric data 2 */
  7683.            xxstring,
  7684.            NULL,
  7685.            NULL
  7686.            );
  7687.  
  7688.     while (!havename) {
  7689.         x = cmfdb(&sw);                 /* Parse something */
  7690.         if (x < 0)                      /* Error */
  7691.           return(x);
  7692.         switch (cmresult.fcode) {
  7693.           case _CMKEY:
  7694.             switch (cmresult.nresult) {
  7695.               case DEL_LIS:
  7696.               case DEL_VRB:
  7697.         nolist = 0;
  7698.                 listing = 1;
  7699.                 break;
  7700.               case DEL_NOL:
  7701.               case DEL_QUI:
  7702.         nolist = 1;
  7703.                 listing = 0;
  7704.                 break;
  7705.               case 999:
  7706.                 swapping = 1;
  7707.                 break;
  7708.               case 998:
  7709.                 appending = 1;
  7710.                 break;
  7711. #ifndef NOSPL
  7712.               case 997:
  7713.                 fromb64 = 1;
  7714.                 break;
  7715.               case 996:
  7716.                 tob64 = 1;
  7717.                 break;
  7718. #endif /* NOSPL */
  7719.             }
  7720.             break;
  7721.           case _CMIFI:
  7722.             s = cmresult.sresult;
  7723.             havename = 1;
  7724.             break;
  7725.           default:
  7726.             return(-2);
  7727.         }
  7728.     }
  7729.     wild = cmresult.nresult;
  7730.     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
  7731.     s = line;
  7732.     p = tmpbuf;                         /* Place for new name */
  7733.  
  7734.     /* Get destination name */
  7735.     if ((x = cmofi("destination name and/or directory",
  7736. #ifdef UNIX
  7737.                    "."
  7738. #else
  7739.                    ""
  7740. #endif /* UNIX */
  7741.                    ,&s,xxstring)) < 0) {
  7742.         if (x == -3) {
  7743.             printf("?Name for destination file required\n");
  7744.             return(-9);
  7745.         } else return(x);
  7746.     }
  7747.     ckstrncpy(p,s,TMPBUFSIZ);           /* Safe copy of destination name */
  7748.     if ((y = cmcfm()) < 0) return(y);
  7749.     if (appending && swapping) {
  7750.         printf("?Sorry, /APPEND and /SWAP conflict\n");
  7751.         return(-9);
  7752.     }
  7753. #ifdef COMMENT
  7754. /*
  7755.   This unreasonably prevented "COPY /APPEND *.* bifile" from concatenating
  7756.   a bunch of files into one big file.
  7757. */
  7758.     if (appending && wild) {
  7759.         printf("?Sorry, /APPEND can be used only with single files\n");
  7760.         return(-9);
  7761.     }
  7762. #endif /* COMMENT */
  7763.     targetisdir = isdir(p);
  7764.     x = strlen(p);
  7765.     if (targetisdir) {
  7766. #ifdef UNIXOROSK
  7767.         if (p[x-1] != '/') {
  7768.             ckstrncat(p,"/",TMPBUFSIZ);
  7769.             x++;
  7770.         }
  7771. #else
  7772. #ifdef OS2
  7773.         if (p[x-1] != '/') {
  7774.             ckstrncat(p,"/",TMPBUFSIZ);
  7775.             x++;
  7776.         }
  7777. #else
  7778. #ifdef STRATUS
  7779.         if (p[x-1] != '>') {
  7780.             ckstrncat(p,">",TMPBUFSIZ);
  7781.             x++;
  7782.         }
  7783. #else
  7784. #ifdef datageneral
  7785.         if (p[x-1] != ':') {
  7786.             ckstrncat(p,":",TMPBUFSIZ);
  7787.             x++;
  7788.         }
  7789. #else
  7790.         if (p[x-1] != '/') {
  7791.             ckstrncat(p,"/",TMPBUFSIZ);
  7792.             x++;
  7793.         }
  7794. #endif /* datageneral */
  7795. #endif /* STRATUS */
  7796. #endif /* OS2 */
  7797. #endif /* UNIXOROSK */
  7798.     }
  7799.     targetlen = x;
  7800.  
  7801.     if (!appending) {            /* If /APPEND not given */
  7802.     if (wild && !targetisdir) {    /* No wildcards allowed */
  7803.         printf(            /* if target is not a directory */
  7804. "?Multiple source files not allowed if target is not a directory.\n");
  7805.         return(-9);
  7806.     }
  7807.     }
  7808.  
  7809. #ifdef VMS
  7810.     conres();                           /* Let Ctrl-C work. */
  7811. #endif /* VMS */
  7812.     debug(F110,"docopy line",line,0);
  7813.     debug(F110,"docopy p",p,0);
  7814.  
  7815. #ifdef ZXREWIND
  7816.     z = zxrewind();                     /* Rewind file list */
  7817. #else
  7818.     z = nzxpand(s,0);                   /* Expand file list */
  7819. #endif /* ZXREWIND */
  7820.  
  7821. #ifdef UNIX
  7822.     if (wild)
  7823.       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
  7824. #endif /* UNIX */
  7825.  
  7826. #ifdef IKSD
  7827.     if (!targetisdir && zchki(p) > -1) { /* Destination file exists? */
  7828.         if (inserver && (!ENABLED(en_del)
  7829. #ifdef CK_LOGIN
  7830.                          || isguest
  7831. #endif /* CK_LOGIN */
  7832.                          )) {
  7833.             printf("?Sorry, overwriting existing files is disabled\n");
  7834.             return(-9);
  7835.         }
  7836.     }
  7837. #endif /* IKSD */
  7838.  
  7839.     if (tob64 && fromb64) {             /* To and from B64 = no conversion */
  7840.         tob64 = 0;
  7841.         fromb64 = 0;
  7842.     }
  7843.     debug(F110,"COPY dest",p,0);
  7844.  
  7845.     while (z > 0) {
  7846.  
  7847.         znext(line);
  7848.         if (!line[0])
  7849.           break;
  7850.  
  7851.         errno = 0;                      /* Reset errno */
  7852.  
  7853.         if (listing) printf("%s => %s ",line,p);
  7854.  
  7855.         /* Straight copy */
  7856.         if (!swapping && !appending && !fromb64 && !tob64) {
  7857.             debug(F110,"COPY zcopy",line,0);
  7858.  
  7859.             if ((x = zcopy(line,p)) < 0) { /* Let zcopy() do it. */
  7860.                 switch (x) {
  7861.                   case -2:
  7862.             if (listing)
  7863.               printf("(FAILED: Not a regular file)\n");
  7864.             else if (!nolist)
  7865.               printf("?Not a regular file - %s\n",line);
  7866.                     rc = 0;
  7867.                     break;
  7868.                   case -3:
  7869.             if (listing)
  7870.               printf("(FAILED: Not found or not accessible)\n");
  7871.             else if (!nolist)
  7872.               printf("?Not found or not accessible - %s\n",line);
  7873.                     rc = 0;
  7874.                     break;
  7875.                   case -4:
  7876.             if (listing)
  7877.               printf("(FAILED: Permission denied)\n");
  7878.             else if (!nolist)
  7879.               printf("?Permission denied - %s\n",line);
  7880.                     rc = 0;
  7881.                     break;
  7882.                   case -5:
  7883.             if (listing)
  7884.               printf("(Source and destination are the same file)\n");
  7885.             else if (!nolist)
  7886.               printf(
  7887.               "?Source and destination are the same file - %s\n",
  7888.               line
  7889.               );
  7890.                     break;
  7891.                   case -6:
  7892.             if (listing)
  7893.               printf("(FAILED: Input/Output error)\n");
  7894.             else if (!nolist)
  7895.               printf("?Input/Output error - %s\n",line);
  7896.                     rc = 0;
  7897.                     break;
  7898.                   case -7:
  7899.             if (listing)
  7900.               printf("(FAILED: %s - %s)\n",p,ck_errstr());
  7901.             else if (!nolist)
  7902.               printf("?%s - %s\n",ck_errstr(),p);
  7903.                     rc = 0;
  7904.                     break;
  7905.                   default:
  7906.             if (listing)
  7907.               printf("(FAILED: %s)\n",ck_errstr());
  7908.             else if (!nolist)
  7909.               printf("?%s\n",ck_errstr());
  7910.                     rc = 0;
  7911.                 }
  7912.             } else {
  7913.                 if (listing) printf("(OK)\n");
  7914.             }
  7915.  
  7916.         } else {                        /* Special options */
  7917.  
  7918.             int prev, y, x = 0;         /* Variables needed for them */
  7919.             int i, t;
  7920.             char ibuf[100];
  7921.             char obuf[200];
  7922.             FILE * in = NULL;
  7923.             FILE * out = NULL;
  7924.  
  7925.             if ((in = fopen(line,"r")) == NULL) { /* Open input file */
  7926.                 if (listing)
  7927.           printf("(FAILED: %s)\n",ck_errstr());
  7928.         else if (!nolist)
  7929.           printf("?%s - %s)\n",ck_errstr(),line);
  7930.                 rc = 0;
  7931.                 continue;
  7932.             }
  7933.             if (targetisdir) {          /* Target is directory */
  7934.                 char * buf = NULL;      /* so append this filename to it */
  7935.                 zstrip(line,&buf);
  7936.                 p[targetlen] = NUL;
  7937.                 if (buf)
  7938.                   ckstrncat(p,buf,TMPBUFSIZ);
  7939.             }
  7940. #ifdef OS2ORUNIX
  7941.             if (zcmpfn(line,p)) {       /* Input and output are same file? */
  7942.                 if (listing)
  7943.                   printf("(FAILED: Source and destination identical)\n");
  7944.         else if (!nolist)
  7945.                   printf("?Source and destination identical - %s\n", line); 
  7946.                 rc = 0;
  7947.                 continue;
  7948.             }
  7949. #endif /* OS2ORUNIX */
  7950.             if ((out = fopen(p, (appending ? "a" : "w"))) == NULL) {
  7951.                 fclose(in);
  7952.                 if (listing)
  7953.           printf("(FAILED: %s - %s)\n",p,ck_errstr());
  7954.         else if (!nolist)
  7955.           printf("?%s - %s\n",p,ck_errstr());
  7956.                 rc = 0;
  7957.                 continue;
  7958.             }
  7959. #ifndef NOSPL
  7960.             if (tob64) {                /* Converting to Base-64 */
  7961.  
  7962.                 debug(F110,"COPY tob64",line,0);
  7963.  
  7964.                 while (1) {             /* Loop... */
  7965.                     prev = x;
  7966.                     if ((x = fread(ibuf,1,54,in)) < 1) { /* EOF */
  7967.                         if (listing)
  7968.                           printf("(OK)\n");
  7969.                         break;
  7970.                     }
  7971.                     if (prev % 3) {
  7972.                         if (listing)
  7973.                           printf("(FAILED: Phase error at %d)\n",prev);
  7974.             else if (!nolist)
  7975.                           printf("?Phase error at %d\n",prev);
  7976.                         rc = 0;
  7977.                         break;
  7978.                     }
  7979.                     if (swapping) {
  7980.                         if (x & 1) {
  7981.                             if (listing)
  7982.                               printf("(FAILED: Swap error)\n");
  7983.                 else if (!nolist)
  7984.                   printf("?Swap error\n");
  7985.                             rc = 0;
  7986.                             break;
  7987.                         }
  7988.                         for (i = 0; i < x; i+=2) {
  7989.                             t = ibuf[i];
  7990.                             ibuf[i] = ibuf[i+1];
  7991.                             ibuf[i+1] = t;
  7992.                         }
  7993.                     }
  7994.                     if ((y = b8tob64(ibuf,x,obuf,180)) < 0) {
  7995.                         if (listing)
  7996.                           printf("(FAILED: Encoding error)\n");
  7997.             else if (!nolist)
  7998.               printf("?Encoding error\n");
  7999.                         rc = 0;
  8000.                         break;
  8001.                     }
  8002.                     fprintf(out,"%s\n",obuf);
  8003.                 }
  8004.  
  8005.             } else if (fromb64) {       /* Converting from Base 64 */
  8006.  
  8007.                 debug(F110,"COPY fromb64",line,0);
  8008.  
  8009.                 if ((out = fopen(p,appending ? "a" : "w")) == NULL) {
  8010.                     fclose(in);
  8011.                     if (listing)
  8012.               printf("(FAILED: %s - %s)\n",p,ck_errstr());
  8013.             else if (!nolist)
  8014.               printf("?%s - %s\n",p,ck_errstr());
  8015.                     rc = 0;
  8016.                     continue;
  8017.                 }
  8018.                 x = 1;
  8019.                 while (x) {
  8020.                     x = fread(ibuf,1,80,in);
  8021.                     if ((y = b64tob8(ibuf,x,obuf,80)) < 0) {
  8022.                         if (listing)
  8023.                           printf("(FAILED: Decoding error)\n");
  8024.             else if (!nolist)
  8025.               printf("?Decoding error\n");
  8026.                         rc = 0;
  8027.                         break;
  8028.                     }
  8029.                     if (swapping) {
  8030.                         if (x & 1) {
  8031.                             if (listing)
  8032.                               printf("(FAILED: Swap error)\n");
  8033.                 else if (!nolist)
  8034.                   printf("?Swap error\n");
  8035.                             rc = 0;
  8036.                             break;
  8037.                         }
  8038.                         for (i = 0; i < y; i+=2) {
  8039.                             t = obuf[i];
  8040.                             obuf[i] = obuf[i+1];
  8041.                             obuf[i+1] = t;
  8042.                         }
  8043.                     }
  8044.                     if (y > 0) {
  8045.                         if (fwrite(obuf,1,y,out) < 1) {
  8046.                             if (listing)
  8047.                               printf("(FAILED: %s - %s)\n",p,ck_errstr());
  8048.                 else if (!nolist)
  8049.                   printf("?%s - %s\n",p,ck_errstr());
  8050.                             rc = 0;
  8051.                             break;
  8052.                         }
  8053.                     }
  8054.                 }
  8055.  
  8056.             } else
  8057. #endif /* NOSPL */
  8058.  
  8059.             if (swapping) {             /* Swapping bytes */
  8060.  
  8061.                 CHAR c[3];
  8062.                 c[2] = NUL;
  8063.  
  8064.                 debug(F110,"COPY swapping",line,0);
  8065.  
  8066.                 while (1) {
  8067.                     x = fread((char *)c,1,2,in);
  8068.                     if (x < 1) {
  8069.                         if (listing)
  8070.                           printf("(OK)\n");
  8071.                         break;
  8072.                     } else if (x == 1) {
  8073.                         c[1] = c[0];
  8074.                         c[0] = NUL;
  8075.                         printf(
  8076.                             "(WARNING: Odd byte count)");
  8077.                         if (!listing) printf("\n");
  8078.                     }
  8079.                     if (fprintf(out,"%c%c",c[1],c[0]) == EOF) {
  8080.                         if (listing)
  8081.                           printf("(FAILED: %s - %s)\n",p,ck_errstr());
  8082.             else if (!nolist)
  8083.                           printf("?%s - %s\n",p,ck_errstr());
  8084.                         rc = 0;
  8085.                         break;
  8086.                     }
  8087.                 }
  8088.  
  8089.             } else if (appending) {     /* Appending to target file */
  8090.  
  8091.                 char c;
  8092.  
  8093.                 debug(F110,"COPY appending",line,0);
  8094.  
  8095.                 while (1) {
  8096.                     x = fread(&c,1,1,in);
  8097.                     if (x < 1) {
  8098.                         if (listing)
  8099.                           printf("(OK)\n");
  8100.                         break;
  8101.                     }
  8102.                     if (fwrite(&c,1,1,out) < 1) {
  8103.                         if (listing)
  8104.                           printf("(FAILED: %s - %s)\n",p,ck_errstr());
  8105.             else if (!nolist)
  8106.                           printf("?%s - %s\n",p,ck_errstr());
  8107.                         rc = 0;
  8108.                         break;
  8109.                     }
  8110.                 }
  8111.             }
  8112.             if (out) fclose(out);
  8113.             if (in) fclose(in);
  8114.         }
  8115. #ifdef VMSORUNIX
  8116.         concb((char)escape);
  8117. #endif /* VMSORUNIX */
  8118.     }
  8119.     if (rc > -1) success = rc;
  8120.     return(rc);
  8121. }
  8122. #endif /* ZCOPY */
  8123. #endif /* NOFRILLS */
  8124.  
  8125. #ifndef NORENAME
  8126. #ifndef NOFRILLS
  8127. #ifdef ZRENAME
  8128. int
  8129. dorenam() {
  8130.     /* Parse a file or a directory name */
  8131.     int i, x, z, listing = 0, havename = 0, wild = 0, rc = 1;
  8132.     int nolist = 0;
  8133.     struct FDB sw, fi;
  8134.  
  8135.     cmfdbi(&sw,                         /* 2nd FDB - optional /PAGE switch */
  8136.            _CMKEY,                      /* fcode */
  8137.            "Filename or switch",        /* hlpmsg */
  8138.            "",                          /* default */
  8139.            "",                          /* addtl string data */
  8140.            nqvswtab,                    /* addtl numeric data 1: tbl size */
  8141.            4,                           /* addtl numeric data 2: 4 = cmswi */
  8142.            xxstring,                    /* Processing function */
  8143.            qvswtab,                     /* Keyword table */
  8144.            &fi                          /* Pointer to next FDB */
  8145.            );
  8146.  
  8147.     cmfdbi(&fi,                         /* 1st FDB - file to type */
  8148.            _CMIFI,                      /* fcode */
  8149.            "",                          /* hlpmsg */
  8150.            "",                          /* default */
  8151.            "",                          /* addtl string data */
  8152.            3,                           /* addtl numeric data 1 */
  8153.            0,                           /* addtl numeric data 2 */
  8154.            xxstring,
  8155.            NULL,
  8156.            NULL
  8157.            );
  8158.  
  8159.     while (!havename) {
  8160.         x = cmfdb(&sw);                 /* Parse something */
  8161.         if (x < 0)                      /* Error */
  8162.           return(x);
  8163.         switch (cmresult.fcode) {
  8164.           case _CMKEY:
  8165.             switch (cmresult.nresult) {
  8166.               case DEL_LIS:
  8167.               case DEL_VRB:
  8168.                 listing = 1;
  8169.                 break;
  8170.               case DEL_NOL:
  8171.               case DEL_QUI:
  8172.         nolist = 1;
  8173.                 listing = 0;
  8174.                 break;
  8175.             }
  8176.             break;
  8177.           case _CMIFI:
  8178.             s = cmresult.sresult;
  8179.             havename = 1;
  8180.             break;
  8181.           default:
  8182.             return(-2);
  8183.         }
  8184.     }
  8185.     wild = cmresult.nresult;            /* Source specification wild? */
  8186.  
  8187.     ckstrncpy(line,s,LINBUFSIZ);        /* Make a safe copy of source name */
  8188.     s = line;
  8189.  
  8190.     if (!wild)
  8191.       wild = iswild(line);
  8192.  
  8193.     p = tmpbuf;                         /* Place for new name */
  8194.     if ((x = cmofi(wild ? "Target directory" : "New name",
  8195.                    "",&s,xxstring)) < 0) { /* Get new name */
  8196.         if (x == -3) {
  8197.             printf("?%s required\n", wild ? "Target directory" : "New name");
  8198.             return(-9);
  8199.         } else return(x);
  8200.     }
  8201.     ckstrncpy(p,s,TMPBUFSIZ);           /* Make a safe copy of the new name */
  8202.     if ((y = cmcfm()) < 0) return(y);
  8203.  
  8204.     if (!wild) {                        /* Just one */
  8205.         if (listing) printf("%s => %s ",line,p);
  8206.         if (zrename(line,p) < 0) {
  8207.             if (listing)
  8208.           printf("(FAILED: %s)\n",ck_errstr());
  8209.         else if (!nolist)
  8210.           printf("?%s\n",ck_errstr());
  8211.             rc = 0;
  8212.         } else {
  8213.             if (listing) printf("(OK)\n");
  8214.         }
  8215.         return(success = rc);
  8216.     }
  8217.     if (!isdir(p)) {                    /* Multiple */
  8218.         printf(                         /* if target is not a directory */
  8219. "?Multiple source files not allowed if target is not a directory.\n");
  8220.         return(-9);
  8221.     }
  8222. #ifdef COMMENT
  8223.     else {                              /* Show full path of target */
  8224.         char buf[CKMAXPATH];            /* (too much) */
  8225.         if (zfnqfp(p,CKMAXPATH,buf))
  8226.           ckstrncpy(tmpbuf,buf,TMPBUFSIZ);
  8227.     }
  8228. #endif /* COMMENT */
  8229.  
  8230. #ifdef VMS
  8231.     conres();                           /* Let Ctrl-C work. */
  8232. #endif /* VMS */
  8233.     debug(F110,"dorename line",line,0);
  8234.  
  8235. #ifdef ZXREWIND
  8236.     z = zxrewind();                     /* Rewind file list */
  8237. #else
  8238.     z = nzxpand(s,0);                   /* Expand file list */
  8239. #endif /* ZXREWIND */
  8240.     debug(F111,"dorename p",p,z);
  8241.  
  8242. #ifdef UNIX
  8243.     if (wild && z > 1)
  8244.       sh_sort(mtchs,NULL,z,0,0,filecase); /* Alphabetize the filename list */
  8245. #endif /* UNIX */
  8246.  
  8247. /*
  8248.   Note: COPY, RENAME, DELETE and similar commands should have options to
  8249.   stop or proceed when they are operating on multiple files and the operation
  8250.   fails.
  8251. */
  8252.     while (z-- > 0) {
  8253.         if (!(z == 0 && !wild))
  8254.           znext(line);
  8255.         if (!line[0])
  8256.           break;
  8257.         if (listing) printf("%s => %s ",line,p);
  8258.         if (zrename(line,p) < 0) {
  8259.             if (listing)
  8260.           printf("(FAILED: %s)\n",ck_errstr());
  8261.         else if (!nolist)
  8262.           printf("?%s - %s\n",ck_errstr(),line);
  8263.             rc = 0;
  8264.         } else {
  8265.             if (listing) printf("(OK)\n");
  8266.         }
  8267.     }
  8268. #ifdef VMS
  8269.     concb((char)escape);
  8270. #endif /* VMS */
  8271.     return(success = rc);
  8272. }
  8273. #endif /* ZRENAME */
  8274. #endif /* NOFRILLS */
  8275. #endif /* NORENAME */
  8276.  
  8277. #ifndef NOSPL
  8278.  
  8279. /* Do the RETURN command */
  8280.  
  8281. int
  8282. doreturn(s) char *s; {
  8283.     int x;
  8284.     extern int tra_asg;
  8285.     char * line, * lp;
  8286.  
  8287.     if (cmdlvl < 1) {
  8288.         printf("\n?Can't return from level %d\n",maclvl);
  8289.         return(success = 0);
  8290.     }
  8291.     line = malloc(LINBUFSIZ);
  8292.     if (line == NULL)
  8293.       return(success = 0);
  8294.     lp = line;                          /* Expand return value now */
  8295.     x = LINBUFSIZ-1;
  8296.     if (!s) s = "";
  8297.     debug(F110,"RETURN s",s,0);
  8298.     if (zzstring(s,&lp,&x) > -1) {
  8299.         s = line;
  8300.         debug(F110,"RETURN zzstring",s,0);
  8301.     }
  8302.  
  8303.     /* Pop from all FOR/WHILE/SWITCH/XIFs */
  8304.     while ((maclvl > 0) &&
  8305.            (m_arg[maclvl-1][0]) &&
  8306.            (cmdstk[cmdlvl].src == CMD_MD) &&
  8307.            (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  8308.             !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  8309.             !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
  8310.             !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  8311.         debug(F111,"RETURN IF/FOR/WHI/SWI pop",m_arg[maclvl-1][0],maclvl);
  8312.         dogta(XXPTA);                   /* Put args back */
  8313.         popclvl();                      /* Pop up two levels */
  8314.         popclvl();
  8315.     }
  8316.     if (tra_asg) {                      /* If tracing show return value */
  8317.         if (*s)
  8318.           printf("<<< %s: \"%s\"\n", m_arg[maclvl][0], s);
  8319.         else
  8320.           printf("<<< %s: (null)\n", m_arg[maclvl][0]);
  8321.     }
  8322.     popclvl();                          /* Pop from enclosing TAKE or macro */
  8323.     debug(F111,"RETURN tolevel",s,maclvl);
  8324.     if (!s) s = "";
  8325.     if (!*s) s = NULL;
  8326.     makestr(&(mrval[maclvl+1]),s);      /* Set the RETURN value */
  8327.     free(line);
  8328.     return(success = 1);                /* Macro succeeds if we RETURN */
  8329. }
  8330. #endif /* NOSPL */
  8331.  
  8332. #ifndef NOSPL
  8333. /* Do the OPEN command */
  8334.  
  8335. int
  8336. doopen()  {                             /* OPEN { append, read, write } */
  8337.     int x, y, z = 0; char *s;
  8338.     static struct filinfo fcb;          /* (must be static) */
  8339.     if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
  8340.         if (x == -3) {
  8341.             printf("?Mode required\n");
  8342.             return(-9);
  8343.         } else return(x);
  8344.     }
  8345.     switch (x) {
  8346.       case OPN_FI_R:                    /* Old file (READ) */
  8347.         if (chkfn(ZRFILE) > 0) {
  8348.             printf("?Read file already open\n");
  8349.             return(-2);
  8350.         }
  8351.         if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
  8352.             if (z == -3) {
  8353.                 printf("?Input filename required\n");
  8354.                 return(-9);
  8355.             } else return(z);
  8356.         }
  8357.         if (y) {                                /* No wildcards allowed */
  8358.             printf("\n?Please specify a single file\n");
  8359.             return(-2);
  8360.         }
  8361.         ckstrncpy(line,s,LINBUFSIZ);
  8362.         if ((int)strlen(line) < 1) return(-2);
  8363.         if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
  8364.           return(z);
  8365.         if (y < 1) {
  8366.             printf("?Positive number required\n");
  8367.             return(-9);
  8368.         }
  8369.         if ((z = cmcfm()) < 0) return(z);
  8370.         readblock = y;
  8371.         if (readbuf)
  8372.           free((char *)readbuf);
  8373.         if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  8374.             printf("?Can't allocate read buffer\n");
  8375.             return(-9);
  8376.         }
  8377.         return(success = zopeni(ZRFILE,line));
  8378.  
  8379. #ifndef MAC
  8380. #ifndef NOPUSH
  8381.       case OPN_PI_R:                    /* Pipe/Process (!READ) */
  8382.         if (nopush) {
  8383.             printf("?Read from pipe disabled\n");
  8384.             return(success=0);
  8385.         }
  8386.         if (chkfn(ZRFILE) > 0) {
  8387.             printf("?Read file already open\n");
  8388.             return(-2);
  8389.         }
  8390.         if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
  8391.             if (y == -3) {
  8392.                 printf("?Command name required\n");
  8393.                 return(-9);
  8394.             } else return(y);
  8395.         }
  8396.         ckstrncpy(line,brstrip(s),LINBUFSIZ);
  8397.         if (!line[0]) return(-2);
  8398.         if ((y = cmcfm()) < 0) return(y);
  8399.         if (!readbuf) {
  8400.             if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  8401.                 printf("?Can't allocate read buffer\n");
  8402.                 return(-9);
  8403.             }
  8404.         }
  8405.         return(success = zxcmd(ZRFILE,line));
  8406.  
  8407.       case OPN_PI_W:                    /* Write to pipe */
  8408.         if (nopush) {
  8409.             printf("?Write to pipe disabled\n");
  8410.             return(success=0);
  8411.         }
  8412.         if (chkfn(ZWFILE) > 0) {
  8413.             printf("?Write file already open\n");
  8414.             return(-2);
  8415.         }
  8416.         if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
  8417.             if (y == -3) {
  8418.                 printf("?Command name required\n");
  8419.                 return(-9);
  8420.             } else return(y);
  8421.         }
  8422.         ckstrncpy(line,brstrip(s),LINBUFSIZ);
  8423.         if (!line[0]) return(-2);
  8424.         if ((y = cmcfm()) < 0) return(y);
  8425.         success = zxcmd(ZWFILE,line);
  8426.         if (!success && msgflg)
  8427.           printf("Can't open process for writing: %s\n",line);
  8428.         return(success);
  8429. #endif /* NOPUSH */
  8430. #endif /* MAC */
  8431.  
  8432.       case OPN_FI_W:                    /* New file (WRITE) */
  8433.       case OPN_FI_A:                    /* (APPEND) */
  8434.         if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
  8435.             if (z == -3) {
  8436.                 printf("?Filename required\n");
  8437.                 return(-9);
  8438.             } else return(z);
  8439.         }
  8440.         if (z == 2) {
  8441.             printf("?Sorry, %s is a directory name\n",s);
  8442.             return(-9);
  8443.         }
  8444.         if (chkfn(ZWFILE) > 0) {
  8445.             printf("?Write/Append file already open\n");
  8446.             return(-2);
  8447.         }
  8448.         fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
  8449.         fcb.lblopts = 0;
  8450.         fcb.dsp = (x == OPN_FI_W) ? XYFZ_N : XYFZ_A; /* Create or Append */
  8451.         ckstrncpy(line,s,LINBUFSIZ);
  8452.         if ((int)strlen(line) < 1) return(-2);
  8453.         if ((y = cmcfm()) < 0) return(y);
  8454.         return(success = zopeno(ZWFILE,line,NULL,&fcb));
  8455.  
  8456. #ifndef NOLOCAL
  8457.       case OPN_SER:                     /* OPEN PORT or LINE */
  8458.       case OPN_NET: {                   /* OPEN HOST */
  8459.           extern int didsetlin, ttnproto;
  8460.           if (x == OPN_NET) {
  8461.               z = ttnproto;
  8462.               ttnproto = NP_NONE;
  8463.           }
  8464.           if ((y = setlin((x == OPN_SER) ? XYLINE : XYHOST, 1, 0)) < 0) {
  8465.               if (x == OPN_NET)
  8466.                 ttnproto = z;
  8467.               success = 0;
  8468.           }
  8469.           didsetlin++;
  8470.           return(y);
  8471.       }
  8472. #endif /* NOLOCAL */
  8473.  
  8474.       default:
  8475.         printf("?Not implemented");
  8476.         return(-2);
  8477.     }
  8478. }
  8479. #endif /* NOSPL */
  8480.  
  8481. #ifndef NOXFER
  8482. /*  D O X G E T  --  GET command parser with switches  */
  8483.  
  8484. #ifdef CK_LABELED
  8485. int g_lf_opts = -1;
  8486. extern int lf_opts;
  8487. #endif /* CK_LABELED */
  8488.  
  8489. int
  8490. doxget(cx) int cx; {
  8491.     extern int                          /* External variables we need */
  8492. #ifdef RECURSIVE
  8493.       recursive,
  8494. #endif /* RECURSIVE */
  8495.       xfermode, fdispla, protocol, usepipes,
  8496.       g_binary, g_xfermode, g_displa, g_rpath, g_usepipes;
  8497.     extern char * rcv_move;             /* Directory to move new files to */
  8498.     extern char * rcv_rename;           /* What to rename new files to */
  8499.     extern char * rcvexcept[];          /* RECEIVE / GET exception list */
  8500.     int opkt  =  0;                     /* Flag for O-Packet needed */
  8501.  
  8502. #ifdef PIPESEND
  8503.     extern int pipesend;
  8504.     extern char * rcvfilter;
  8505. #endif /* PIPESEND */
  8506.     extern struct keytab rpathtab[];
  8507.     extern int nrpathtab;
  8508.     extern CK_OFF_T calibrate;
  8509.     int asname = 0;                     /* Flag for have as-name */
  8510.     int konly = 0;                      /* Kermit-only function */
  8511.     int c, i, n, confirmed = 0;         /* Workers */
  8512.     int getval = 0;                     /* Whether to get switch value */
  8513.     int rcvcmd = 0;                     /* Whether it is the RECEIVE command */
  8514.     int mget = 0;                       /* Whether it is the MGET command */
  8515.     struct stringint pv[SND_MAX+1];    /* Temporary array for switch values */
  8516.     struct FDB sw, fl, cm;              /* FDBs for each parse function */
  8517.     char * cmdstr = "this command";
  8518.  
  8519. #ifdef NEWFTP
  8520.     if (cx == XXGET || cx == XXREGET || cx == XXMGET || cx == XXRETR) {
  8521.         extern int ftpget;
  8522.         extern int ftpisopen();
  8523.         if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
  8524.           return(doftpget(cx,0));
  8525.     }
  8526. #endif /* NEWFTP */
  8527.  
  8528.     debug(F101,"xget cx","",cx);
  8529.  
  8530.     oopts = -1;
  8531.     omode = -1;
  8532.  
  8533.     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
  8534.         pv[i].sval = NULL;
  8535.         pv[i].ival = -1;
  8536.         pv[i].wval = (CK_OFF_T)-1;
  8537.     }
  8538.     /* Preset switch values based on top-level command that called us */
  8539.  
  8540.     switch (cx) {
  8541.       case XXREC:                       /* RECEIVE */
  8542.         cmdstr = "RECEIVE";
  8543.         rcvcmd = 1; break;
  8544.       case XXGET:                       /* GET */
  8545.         cmdstr = "GET";
  8546.         konly = 1;
  8547.         break;
  8548. #ifdef CK_RESEND
  8549.       case XXREGET:                     /* REGET */
  8550.         cmdstr = "REGET";
  8551.         konly = 1;
  8552.         pv[SND_BIN].ival = 1;           /* Implies /BINARY */
  8553.         pv[SND_RES].ival = 1; break;
  8554. #endif /* CK_RESEND */
  8555.       case XXRETR:                      /* RETRIEVE */
  8556.         cmdstr = "RETRIEVE";
  8557.         konly = 1;
  8558.         pv[SND_DEL].ival = 1; break;
  8559. #ifdef PIPESEND
  8560.       case XXCREC:                      /* CRECEIVE */
  8561.         cmdstr = "CRECEIVE";
  8562.         konly = 1;
  8563.         rcvcmd = 1;
  8564.         pv[SND_CMD].ival = 1; break;
  8565.       case XXCGET:                      /* CGET */
  8566.         cmdstr = "CGET";
  8567.         konly = 1;
  8568.         pv[SND_CMD].ival = 1; break;
  8569. #endif /* PIPESEND */
  8570. #ifndef NOMGET
  8571.       case XXMGET:                      /* MGET */
  8572.         cmdstr = "MGET";
  8573.         konly = 1;
  8574.         mget = 1; break;
  8575. #endif /* NOMGET */
  8576.     }
  8577.     debug(F111,"xget rcvcmd",cmdstr,rcvcmd);
  8578.     debug(F101,"xget konly","",konly);
  8579.  
  8580. #ifdef CK_XYZ
  8581.     if (!rcvcmd && protocol != PROTO_K) {
  8582.         printf("?Sorry, %s works only with Kermit protocol\n",cmdstr);
  8583.         return(-9);
  8584.     }
  8585. #endif /* CK_XYZ */
  8586.  
  8587.     /* Set up chained parse functions... */
  8588.  
  8589.     cmfdbi(&sw,                         /* First FDB - command switches */
  8590.            _CMKEY,                      /* fcode */
  8591.            rcvcmd ?
  8592.            "Optional name/template to store incoming files under, or switch" :
  8593.            "Remote filename, or switch", /* hlpmsg */
  8594.            "",                          /* default */
  8595.            "",                          /* addtl string data */
  8596.            rcvcmd ? nrcvtab : ngettab,  /* addtl numeric data 1: tbl size */
  8597.            4,                           /* addtl numeric data 2: 4 = cmswi */
  8598.            xxstring,                    /* Processing function */
  8599.            rcvcmd ? rcvtab : gettab,    /* Keyword table */
  8600.            &fl                          /* Pointer to next FDB */
  8601.            );
  8602.     if (rcvcmd || mget)                 /* RECEIVE or MGET */
  8603.       cmfdbi(&fl,
  8604.            _CMTXT,                      /* fcode */
  8605.            rcvcmd ?                     /* hlpmsg */
  8606.              "Output filename or Command" : /* Output filename */
  8607.              "File(s) to GET",              /* Files we are asking for */
  8608.            "",                          /* default */
  8609.            "",                          /* addtl string data */
  8610.            0,                           /* addtl numeric data 1 */
  8611.            0,                           /* addtl numeric data 2 */
  8612. #ifdef CK_XYZ
  8613.            (protocol == PROTO_X || protocol == PROTO_XC) ?
  8614.              xxstring :
  8615.              (rcvcmd ? (xx_strp)0  : xxstring)
  8616. #else
  8617.            rcvcmd ? (xx_strp)0  : xxstring /* Processing function */
  8618. #endif /* CK_XYZ */
  8619.              ,
  8620.            NULL,
  8621.            &cm
  8622.            );
  8623.     else
  8624.       cmfdbi(&fl,                       /* Remote filename or command */
  8625.            _CMFLD,                      /* fcode */
  8626.            "Remote filename",           /* hlpmsg */
  8627.            "",                          /* default */
  8628.            "",                          /* addtl string data */
  8629.            0,                           /* addtl numeric data 1 */
  8630.            0,                           /* addtl numeric data 2 */
  8631.            xxstring,
  8632.            NULL,
  8633.            &cm
  8634.            );
  8635.     cmfdbi(&cm,                         /* Confirmation */
  8636.            _CMCFM,                      /* fcode */
  8637.            "",                          /* hlpmsg */
  8638.            "",                          /* default */
  8639.            "",                          /* addtl string data */
  8640.            0,                           /* addtl numeric data 1 */
  8641.            0,                           /* addtl numeric data 2 */
  8642.            NULL,
  8643.            NULL,
  8644.            NULL
  8645.            );
  8646.  
  8647.     /* (See doxsend() for fuller commentary) */
  8648.  
  8649.     while (1) {                         /* Parse 0 or more switches */
  8650.         x = cmfdb(&sw);                 /* Parse something */
  8651.         debug(F101,"xget cmfdb","",x);
  8652.         if (x < 0)                      /* Error */
  8653.           goto xgetx;                   /* or reparse needed */
  8654.         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
  8655.           break;
  8656.         c = cmgbrk();                   /* Get break character */
  8657.         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
  8658.             printf("?This switch does not take an argument\n");
  8659.             x = -9;
  8660.             goto xgetx;
  8661.         }
  8662.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  8663.             printf("?This switch requires an argument\n");
  8664.             x = -9;
  8665.             goto xgetx;
  8666.         }
  8667.         n = cmresult.nresult;           /* Numeric result = switch value */
  8668.         debug(F101,"xget switch","",n);
  8669.  
  8670.         switch (n) {                    /* Process the switch */
  8671. #ifdef PIPESEND
  8672.           case SND_CMD:                 /* These take no args */
  8673.             if (nopush) {
  8674.                 printf("?Sorry, system command access is disabled\n");
  8675.                 x = -9;
  8676.                 goto xgetx;
  8677.             } else if (rcvfilter) {
  8678.                 printf(
  8679. "?Sorry, no GET /COMMAND when RECEIVE FILTER selected\n");
  8680.                 x = -9;
  8681.                 goto xgetx;
  8682.             }
  8683.             if (rcvcmd)
  8684.               sw.hlpmsg = "Command, or switch"; /* Change help message */
  8685.             /* Fall thru... */
  8686. #endif /* PIPESEND */
  8687.  
  8688.           case SND_REC:                 /* /RECURSIVE */
  8689.             pv[SND_PTH].ival = PATH_REL; /* Implies relative pathnames */
  8690.             pv[n].ival = 1;             /* Set the recursive flag */
  8691.             break;
  8692.  
  8693.           case SND_RES:                 /* /RECOVER */
  8694.             pv[SND_BIN].ival = 1;       /* Implies /BINARY */
  8695.             pv[n].ival = 1;             /* Set the resend flag */
  8696.             break;
  8697.  
  8698.           case SND_DEL:                 /* /DELETE */
  8699.           case SND_SHH:                 /* /QUIET */
  8700.           case SND_CAL:                 /* /CALIBRATE */
  8701.           case SND_XPA:                 /* /TRANSPARENT */
  8702.             pv[n].ival = 1;             /* Just set the appropriate flag */
  8703.             break;
  8704.  
  8705.           case SND_PIP:                 /* /PIPES:{ON,OFF} */
  8706.             if (!getval) {
  8707.                 pv[n].ival = 1;
  8708.                 break;
  8709.             }
  8710.             if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
  8711.               goto xgetx;
  8712.             if (!nopush)
  8713.               pv[n].ival = x;
  8714.             break;
  8715.  
  8716.           /* File transfer modes - each undoes the others */
  8717.  
  8718.           case SND_BIN:                 /* Binary */
  8719.           case SND_TXT:                 /* Text */
  8720.           case SND_IMG:                 /* Image */
  8721.           case SND_LBL:                 /* Labeled */
  8722.             pv[SND_BIN].ival = 0;       /* Unset all */
  8723.             pv[SND_TXT].ival = 0;
  8724.             pv[SND_IMG].ival = 0;
  8725.             pv[SND_LBL].ival = 0;
  8726.             pv[n].ival = 1;             /* Set the requested one */
  8727.             break;
  8728.  
  8729.           case SND_EXC:                 /* Excludes */
  8730.             if (!getval) break;
  8731.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  8732.                 if (x == -3) {
  8733.                     printf("?Pattern required\n");
  8734.                     x = -9;
  8735.                 }
  8736.                 goto xgetx;
  8737.             }
  8738.             if (pv[n].sval) free(pv[n].sval);
  8739.             y = strlen(s);
  8740.             if (y > 256) {
  8741.                 printf("?Pattern too long - 256 max\n");
  8742.                 x = -9;
  8743.                 goto xgetx;
  8744.             }
  8745.             pv[n].sval = malloc(y+1);
  8746.             if (pv[n].sval) {
  8747.                 strcpy(pv[n].sval,s);   /* safe */
  8748.                 pv[n].ival = 1;
  8749.             }
  8750.             break;
  8751.  
  8752. #ifdef COMMENT
  8753.           /* Not implemented */
  8754.           case SND_PRI:                 /* GET to printer */
  8755.             pv[n].ival = 1;
  8756.             if (!getval) break;
  8757.             if ((x = cmfld("Print options","",&s,xxstring)) < 0)
  8758.               goto xgetx;
  8759.             pv[n].sval = malloc((int)strlen(s)+1);
  8760.             if (pv[n].sval)
  8761.               strcpy(pv[n].sval,s);     /* safe */
  8762.             break;
  8763. #endif /* COMMENT */
  8764.  
  8765.           case SND_MOV:                 /* MOVE after */
  8766.           case SND_REN:                 /* RENAME after */
  8767.             if (!getval) break;
  8768.             if ((x = cmfld(n == SND_MOV ?
  8769.            "device and/or directory for source file after sending" :
  8770.            "new name for source file after sending",
  8771.                            "",
  8772.                            &s,
  8773.                            n == SND_MOV ? xxstring : NULL
  8774.                            )) < 0) {
  8775.                 if (x == -3) {
  8776.                     printf("%s\n", n == SND_MOV ?
  8777.                            "?Destination required" :
  8778.                            "?New name required"
  8779.                            );
  8780.                     x = -9;
  8781.                 }
  8782.                 goto xgetx;
  8783.             }
  8784.             if (pv[n].sval) {
  8785.                 free(pv[n].sval);
  8786.                 pv[n].sval = NULL;
  8787.             }
  8788.             s = brstrip(s);
  8789.             y = strlen(s);
  8790.             if (y > 0) {
  8791.                 pv[n].sval = malloc(y+1);
  8792.                 if (pv[n].sval) {
  8793.                     strcpy(pv[n].sval,s); /* safe */
  8794.                     pv[n].ival = 1;
  8795.                 }
  8796.             }
  8797.             break;
  8798.  
  8799.           case SND_ASN:                 /* As-name */
  8800.             if (!getval) break;
  8801.             if (mget) {
  8802.                 printf("?Sorry, as-name not allowed with MGET\n");
  8803.                 x = -9;
  8804.                 goto xgetx;
  8805.             }
  8806.             if ((x = cmfld("Name to store it under","",&s,NULL)) < 0)
  8807.               goto xgetx;
  8808.             s = brstrip(s);
  8809.             if ((y = strlen(s)) > 0) {
  8810.                 if (pv[n].sval) free(pv[n].sval);
  8811.                 pv[n].sval = malloc(y+1);
  8812.                 if (pv[n].sval) {
  8813.                     strcpy(pv[n].sval,s); /* safe */
  8814.                     pv[n].ival = 1;
  8815.                 }
  8816.             }
  8817.             break;
  8818.  
  8819. #ifdef PIPESEND
  8820.           case SND_FLT:                 /* Filter */
  8821.             debug(F101,"xget /filter getval","",getval);
  8822.             if (!getval) break;
  8823.             if ((x = cmfld("Filter program to receive through",
  8824.                            "",&s,NULL)) < 0) {
  8825.                 if (x == -3)
  8826.                   s = "";
  8827.                 else
  8828.                   goto xgetx;
  8829.             }
  8830.             if (*s) s = brstrip(s);
  8831.             y = strlen(s);
  8832.             for (x = 0; x < y; x++) {   /* Make sure they included "\v(...)" */
  8833.                 if (s[x] != '\\') continue;
  8834.                 if (s[x+1] == 'v') break;
  8835.             }
  8836.             if (x == y) {
  8837.                 printf(
  8838.                 "?Filter must contain a replacement variable for filename.\n"
  8839.                        );
  8840.                 x = -9;
  8841.                 goto xgetx;
  8842.             }
  8843.             pv[n].ival = 1;
  8844.             if (pv[n].sval) {
  8845.                 free(pv[n].sval);
  8846.                 pv[n].sval = NULL;
  8847.             }
  8848.             if ((y = strlen(s)) > 0) {
  8849.                 if ((pv[n].sval = malloc(y+1)))
  8850.                   strcpy(pv[n].sval,s); /* safe */
  8851.             }
  8852.             break;
  8853. #endif /* PIPESEND */
  8854.  
  8855.           case SND_PTH:                 /* Pathnames */
  8856.             if (!getval) {
  8857.                 pv[n].ival = PATH_REL;
  8858.                 break;
  8859.             }
  8860.             if ((x = cmkey(rpathtab,nrpathtab,"","on",xxstring)) < 0)
  8861.               goto xgetx;
  8862.             pv[n].ival = x;             /* Ditto */
  8863.             break;
  8864.  
  8865.           case SND_NAM:                 /* Filenames */
  8866.             if (!getval) break;
  8867.             if ((x = cmkey(fntab,nfntab,"","converted",xxstring)) < 0)
  8868.               goto xgetx;
  8869.             pv[n].ival = x;
  8870.             break;
  8871.  
  8872.           case SND_PRO:                 /* Protocol to use */
  8873.             if (!getval) break;
  8874.             if ((x = cmkey(protos,nprotos,"File-transfer protocol","",
  8875.                            xxstring)) < 0) {
  8876.                 if (x == -3)
  8877.                   x = 0;
  8878.                 else
  8879.                   goto xgetx;
  8880.             }
  8881.             debug(F111,"xget /proto",atmbuf,x);
  8882.             pv[n].ival = x;
  8883.             if (konly && x != PROTO_K) {
  8884.                 printf(
  8885. "?Sorry, this command works only with Kermit protocol\n"
  8886.                        );
  8887.                 x = -9;
  8888.                 goto xgetx;
  8889.             }
  8890.             break;
  8891.  
  8892.           default:
  8893.             printf("?Unexpected switch value - %d\n",cmresult.nresult);
  8894.             x = -9;
  8895.             goto xgetx;
  8896.         }
  8897.     }
  8898.     debug(F101,"xget cmresult fcode","",cmresult.fcode);
  8899.  
  8900.     cmarg = line;                       /* Initialize string pointers */
  8901.     cmarg2 = tmpbuf;
  8902.     asname = 0;
  8903.     line[0] = NUL;                      /* and buffers. */
  8904.     tmpbuf[0] = NUL;
  8905.  
  8906.     switch (cmresult.fcode) {           /* How did we get out of switch loop */
  8907.       case _CMFLD:                      /* (3) Remote filespec */
  8908.         ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
  8909.         break;
  8910.       case _CMTXT:                      /* (4) As-name */
  8911.         if (rcvcmd) {
  8912.             ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
  8913.             if ((int)strlen(tmpbuf) > 0)
  8914.               asname = 1;
  8915.         } else {
  8916.             ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
  8917.         }
  8918.       case _CMCFM:                      /* (6) Confirmation */
  8919.         confirmed = 1;
  8920.         break;
  8921.       default:
  8922.         printf("?Unexpected function code: %d\n",cmresult.fcode);
  8923.         x = -9;
  8924.         goto xgetx;
  8925.     }
  8926.     debug(F110,"xget string",cmarg,0);
  8927.     debug(F101,"xget confirmed","",confirmed);
  8928.  
  8929.     cmarg = brstrip(cmarg);             /* Strip any braces */
  8930.  
  8931.     if (!confirmed) {                   /* CR not typed yet, get more fields */
  8932.         if (pv[SND_CMD].ival > 0) {
  8933.             debug(F100,"xget calling cmtxt","",0);
  8934.             x = cmtxt("Local command to pipe into","",&s,NULL);
  8935.             if (x < 0 && x != -3) goto xgetx;
  8936.             if (x != -3) {
  8937.                 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  8938.                 asname = 1;
  8939.             }
  8940.         } else if (!rcvcmd) {
  8941. #ifdef VMS
  8942.             /* cmofi() fails if you give it a directory name */
  8943.             x = cmfld("Name or directory for incoming file","",&s,NULL);
  8944.             debug(F111,"xget cmfld",s,x);
  8945. #else
  8946.             x = cmofi("Name or directory for incoming file","",&s,NULL);
  8947.             debug(F111,"xget cmofi",s,x);
  8948. #endif /* VMS */
  8949.             if (x < 0 && x != -3) goto xgetx;
  8950.             if (x != -3) {
  8951.                 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  8952.                 if ((x = cmcfm()) < 0) goto xgetx;
  8953.                 asname = 1;
  8954.             }
  8955.         }
  8956.     }
  8957.     /* Arrive here with cmarg and cmarg2 all set */
  8958.  
  8959.     debug(F111,"xget asname",cmarg2,asname);
  8960.     if (!asname) {
  8961.         if (pv[SND_ASN].sval)
  8962.           ckstrncpy(tmpbuf,pv[SND_ASN].sval,TMPBUFSIZ);
  8963.         else
  8964.           tmpbuf[0] = NUL;
  8965.     }
  8966.     cmarg2 = brstrip(cmarg2);           /* Strip outer braces if any. */
  8967.     debug(F110,"xget cmarg",cmarg,0);
  8968.     debug(F110,"xget cmarg2",cmarg2,0);
  8969.  
  8970.     if (!*cmarg &&
  8971.         (cx == XXGET || cx == XXREGET || cx == XXCGET || cx == XXMGET)) {
  8972.         printf("?A remote file specification is required\n");
  8973.         x = -9;
  8974.         goto xgetx;
  8975.     }
  8976. #ifdef PIPESEND
  8977.     if (pv[SND_CMD].ival > 0) {         /* /COMMAND sets pipesend flag */
  8978.         x = -9;
  8979.         if (!*cmarg2) {
  8980.             printf("?Command required\n");
  8981.             goto xgetx;
  8982.         } else if (nopush) {
  8983.             printf("?Sorry, system command access is disabled\n");
  8984.             goto xgetx;
  8985.         } else if (rcvfilter) {
  8986.             printf("?Sorry, no GET /COMMAND while RECEIVE FILTER selected\n");
  8987.             goto xgetx;
  8988.         } else
  8989.           pipesend = 1;
  8990.     }
  8991.     debug(F101,"xget /COMMAND pipesend","",pipesend);
  8992. #endif /* PIPESEND */
  8993.  
  8994. #ifdef CK_RESEND
  8995.     if (pv[SND_RES].ival > 0) {         /* REGET or GET /RECOVER */
  8996. #ifdef RECURSIVE
  8997.         if (pv[SND_REC].ival > 0) {     /* RECURSIVE */
  8998. #ifdef COMMENT
  8999.             printf("?Unsupported option combination: /RECOVER /RECURSIVE\n");
  9000.             x = -9;
  9001.             goto xgetx;
  9002. #else
  9003.             opkt = 1;
  9004. #endif /* COMMENT */
  9005.         }
  9006. #endif /* RECURSIVE */
  9007.         if (pv[SND_DEL].ival > 0) {     /* /DELETE */
  9008. #ifdef COMMENT
  9009.             printf("?Unsupported option combination: /RECOVER /DELETE\n");
  9010.             x = -9;
  9011.             goto xgetx;
  9012. #else
  9013.             opkt = 1;
  9014. #endif /* COMMENT */
  9015.         }
  9016.     }
  9017. #endif /* CK_RESEND */
  9018.  
  9019.     if (pv[SND_EXC].ival > 0)           /* /EXCEPT */
  9020.       makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
  9021.  
  9022. #ifdef IKS_OPTION
  9023.     if (!rcvcmd
  9024. #ifdef CK_XYZ
  9025.          && protocol == PROTO_K
  9026. #endif /* CK_XYZ */
  9027.          ) {
  9028.         if (!iks_wait(KERMIT_REQ_START,1)) {
  9029.             printf(
  9030.               "?A Kermit Server is not available to process this command\n");
  9031.             x = -9;                     /* correct the return code */
  9032.             goto xgetx;
  9033.         }
  9034.     }
  9035. #endif /* IKS_OPTION */
  9036.  
  9037. #ifdef CK_XYZ
  9038.     {
  9039.         int po, pg;                     /* (for clarity) */
  9040.         po = pv[SND_PRO].ival;          /* /PROTOCOL option */
  9041.         pg = protocol;                  /* Protocol global  */
  9042.         if ((rcvcmd && !*cmarg2) &&     /* If no as-name was given */
  9043.             /* and /PROTOCOL is XMODEM or global protocol is XMODEM... */
  9044.             ((po <  0 && (pg == PROTO_X || pg == PROTO_XC)) ||
  9045.              (po > -1 && (po == PROTO_X || po == PROTO_XC)))
  9046.             ) {
  9047.             printf(
  9048. "Sorry, you must specify a name when receiving a file with XMODEM protocol\n"
  9049.                    );
  9050.             x = -9;
  9051.             goto xgetx;
  9052.         }
  9053.     }
  9054. #endif /* CK_XYZ */
  9055.  
  9056. #ifdef RECURSIVE
  9057.     if (pv[SND_REC].ival > 0) {         /* RECURSIVE */
  9058.         recursive = 1;
  9059.         pv[SND_PTH].ival = PATH_REL;    /* Implies relative pathnames too */
  9060.     }
  9061. #endif /* RECURSIVE */
  9062.  
  9063.     if (pv[SND_PIP].ival > -1) {
  9064.         g_usepipes = usepipes;
  9065.         usepipes = pv[SND_PIP].ival;
  9066.     }
  9067.  
  9068.     /* Save global protocol parameters */
  9069.  
  9070.     g_proto = protocol;
  9071. #ifdef CK_LABELED
  9072.     g_lf_opts = lf_opts;                /* Save labeled transfer options */
  9073. #endif /* CK_LABELED */
  9074.     g_urpsiz = urpsiz;                  /* Receive packet length */
  9075.     g_spsizf = spsizf;                  /* Send packet length flag */
  9076.     g_spsiz = spsiz;                    /* Send packet length */
  9077.     g_spsizr = spsizr;                  /* etc etc */
  9078.     g_spmax = spmax;
  9079.     g_wslotr = wslotr;
  9080.     g_prefixing = prefixing;
  9081.     g_fncact = fncact;
  9082.     g_fncnv = fncnv;
  9083.     g_fnspath = fnspath;
  9084.     g_fnrpath = fnrpath;
  9085.     g_xfrxla = xfrxla;
  9086.  
  9087.     if (pv[SND_PRO].ival > -1) {        /* Change according to switch */
  9088.         protocol = pv[SND_PRO].ival;
  9089.         if (ptab[protocol].rpktlen > -1)   /* copied from initproto() */
  9090.             urpsiz = ptab[protocol].rpktlen;
  9091.         if (ptab[protocol].spktflg > -1)
  9092.             spsizf = ptab[protocol].spktflg;
  9093.         if (ptab[protocol].spktlen > -1) {
  9094.             spsiz = ptab[protocol].spktlen;
  9095.             if (spsizf)
  9096.                 spsizr = spmax = spsiz;
  9097.         }
  9098.         if (ptab[protocol].winsize > -1)
  9099.             wslotr = ptab[protocol].winsize;
  9100.         if (ptab[protocol].prefix > -1)
  9101.             prefixing = ptab[protocol].prefix;
  9102.         if (ptab[protocol].fnca > -1)
  9103.             fncact  = ptab[protocol].fnca;
  9104.         if (ptab[protocol].fncn > -1)
  9105.             fncnv   = ptab[protocol].fncn;
  9106.         if (ptab[protocol].fnsp > -1)
  9107.             fnspath = ptab[protocol].fnsp;
  9108.         if (ptab[protocol].fnrp > -1)
  9109.             fnrpath = ptab[protocol].fnrp;
  9110.     }
  9111.     debug(F101,"xget protocol","",protocol);
  9112.     debug(F111,"xget cmarg2",cmarg2,xfermode);
  9113.  
  9114.     g_xfermode = xfermode;
  9115.     g_binary = binary;
  9116.     if (pv[SND_BIN].ival > 0) {         /* Change according to switch */
  9117.         xfermode = XMODE_M;
  9118.         binary = XYFT_B;                /* FILE TYPE BINARY */
  9119.         omode = GMOD_BIN;               /* O-Packet mode */
  9120.         debug(F101,"doxget /BINARY xfermode","",xfermode);
  9121.     } else if (pv[SND_TXT].ival > 0) {  /* Ditto for /TEXT */
  9122.         xfermode = XMODE_M;
  9123.         binary = XYFT_T;
  9124.         omode = GMOD_TXT;
  9125.         debug(F101,"doxget /TEXT xfermode","",xfermode);
  9126.     } else if (pv[SND_IMG].ival > 0) {
  9127.         xfermode = XMODE_M;
  9128. #ifdef VMS
  9129.         binary = XYFT_I;
  9130. #else
  9131.         binary = XYFT_B;
  9132. #endif /* VMS */
  9133.         omode = GMOD_TXT;
  9134.         debug(F101,"doxget /IMAGE xfermode","",xfermode);
  9135.     }
  9136. #ifdef CK_LABELED
  9137.     else if (pv[SND_LBL].ival > 0) {
  9138.         xfermode = XMODE_M;
  9139.         binary = XYFT_L;
  9140.         omode = GMOD_LBL;
  9141.         debug(F101,"doxget /LABELED xfermode","",xfermode);
  9142.     }
  9143. #endif /* CK_LABELED */
  9144.     debug(F101,"xget binary","",binary);
  9145.     debug(F101,"xget omode","",omode);
  9146.  
  9147.     if (pv[SND_XPA].ival > 0)           /* /TRANSPARENT */
  9148.       xfrxla = 0;                       /* Don't translate character sets */
  9149.  
  9150. #ifdef PIPESEND
  9151.     if (pv[SND_FLT].ival > 0)
  9152.       makestr(&rcvfilter,pv[SND_FLT].sval);
  9153. #endif /* PIPESEND */
  9154.  
  9155. #ifdef CK_TMPDIR
  9156.     if (pv[SND_MOV].ival > 0) {
  9157.         int len;
  9158.         char * p = pv[SND_MOV].sval;
  9159. #ifdef CK_LOGIN
  9160.         if (isguest) {
  9161.             printf("?Sorry, /MOVE-TO not available to guests\n");
  9162.             x = -9;
  9163.             goto xgetx;
  9164.         }
  9165. #endif /* CK_LOGIN */
  9166.         len = strlen(p);
  9167.         if (!isdir(p)) {                /* Check directory */
  9168. #ifdef CK_MKDIR
  9169.             char * s = NULL;
  9170.             s = (char *)malloc(len + 4);
  9171.             if (s) {
  9172.                 strcpy(s,p);            /* safe */
  9173. #ifdef datageneral
  9174.                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
  9175. #else
  9176.                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
  9177. #endif /* datageneral */
  9178.                 s[len++] = 'X';
  9179.                 s[len] = NUL;
  9180.                 x = zmkdir(s);
  9181.                 free(s);
  9182.                 if (x < 0) {
  9183.                     printf("?Can't create \"%s\"\n",p);
  9184.                     x = -9;
  9185.                     goto xgetx;
  9186.                 }
  9187.             }
  9188. #else
  9189.             printf("?Directory \"%s\" not found\n",p);
  9190.             x = -9;
  9191.             goto xgetx;
  9192. #endif /* CK_MKDIR */
  9193.         }
  9194.         zfnqfp(p,LINBUFSIZ,line);
  9195.         makestr(&rcv_move,line);
  9196.     }
  9197. #endif /* CK_TMPDIR */
  9198.  
  9199.     if (pv[SND_REN].ival > 0) {         /* /RENAME-TO:name */
  9200.         char * p = pv[SND_REN].sval;
  9201. #ifdef CK_LOGIN
  9202.         if (isguest) {
  9203.             printf("?Sorry, /RENAME-TO not available to guests\n");
  9204.             x = -9;
  9205.             goto xgetx;
  9206.         }
  9207. #endif /* CK_LOGIN */
  9208.         if (!p) p = "";
  9209.         if (!*p) {
  9210.             printf("?New name required for /RENAME\n");
  9211.             x = -9;
  9212.             goto xgetx;
  9213.         }
  9214.         p = brstrip(p);
  9215.         makestr(&rcv_rename,p);
  9216.         debug(F110,"xget rcv_rename","",0);
  9217.     }
  9218.  
  9219. #ifdef CALIBRATE
  9220.     if (pv[SND_CAL].ival > 0)
  9221.       calibrate = (CK_OFF_T)1;
  9222. #endif /* CALIBRATE */
  9223.     g_displa = fdispla;
  9224.     if (pv[SND_SHH].ival > 0)
  9225.       fdispla = 0;
  9226.     debug(F101,"xget display","",fdispla);
  9227.  
  9228.     if (pv[SND_NAM].ival > -1) {        /* /FILENAMES */
  9229.         g_fncnv = fncnv;                /* Save global value */
  9230.         fncnv = pv[SND_NAM].ival;
  9231.         debug(F101,"xsend fncnv","",fncnv);
  9232.         /* We should also handle O packet filename option here */
  9233.         /* but we don't really need to since WHATAMI already handles it */
  9234.     }
  9235.     if (pv[SND_PTH].ival > -1) {        /* PATHNAMES */
  9236.         g_rpath = fnrpath;              /* Save global values */
  9237.         fnrpath = pv[SND_PTH].ival;
  9238.         debug(F101,"xsend fnrpath","",fnrpath);
  9239. #ifndef NZLTOR
  9240.         if (fnrpath != PATH_OFF) {
  9241.             g_fncnv = fncnv;
  9242.             fncnv = XYFN_L;
  9243.             debug(F101,"xsend fncnv","",fncnv);
  9244.         }
  9245.         /* We should also handle O packet pathname option here */
  9246.         /* but we don't really need to since WHATAMI already handles it */
  9247. #endif /* NZLTOR */
  9248.     }
  9249.  
  9250.     /* Set protocol start state */
  9251.  
  9252.     if (opkt) {                         /* Extended GET Options*/
  9253.         sstate = (CHAR) 'o';
  9254.         oopts = 0;
  9255.         if (pv[SND_DEL].ival > 0) oopts |= GOPT_DEL; /* GET /DELETE */
  9256.         if (pv[SND_RES].ival > 0) oopts |= GOPT_RES; /* GET /RECOVER */
  9257.         if (pv[SND_REC].ival > 0) oopts |= GOPT_REC; /* GET /RECURSIVE */
  9258.     } else if (rcvcmd)
  9259.       sstate = (CHAR) 'v';              /* RECEIVE or CRECEIVE */
  9260.     else if (pv[SND_DEL].ival > 0)
  9261.       sstate = (CHAR) 'h';              /* GET /DELETE (= RETRIEVE) */
  9262.     else if (pv[SND_RES].ival > 0)
  9263.       sstate = (CHAR) 'j';              /* GET /RECOVER (= REGET) */
  9264.     else
  9265.       sstate = (CHAR) 'r';              /* Regular GET */
  9266.     getcmd = 1;
  9267.     debug(F000,"xget sstate","",sstate);
  9268. #ifdef MAC
  9269.     what = W_RECV;
  9270.     scrcreate();
  9271. #endif /* MAC */
  9272.     if (local) {
  9273.         if (pv[SND_SHH].ival != 0)
  9274.           displa = 1;
  9275.         ttflui();
  9276.     }
  9277.     x = 0;
  9278. #ifdef PIPESEND
  9279.     if (pipesend)
  9280.       goto xgetx;
  9281. #endif /* PIPESEND */
  9282.  
  9283. #ifdef CK_TMPDIR
  9284. /*
  9285.   cmarg2 is also allowed to be a device or directory name;
  9286.   even the name of a directory that doesn't exist.
  9287. */
  9288.     y = strlen(cmarg2);
  9289.     debug(F111,"xget strlen(cmarg2)",cmarg2,y);
  9290.     if ((y > 0) &&
  9291. #ifdef OS2
  9292.         ((isalpha(cmarg2[0]) &&
  9293.          cmarg2[1] == ':' &&
  9294.          cmarg2[2] == NUL) ||
  9295.         (cmarg[y-1] == '/' || cmarg[y-1] == '\\') ||
  9296.         isdir(cmarg2))
  9297. #else
  9298. #ifdef UNIXOROSK
  9299.         (cmarg2[y-1] == '/' || isdir(cmarg2))
  9300. #else
  9301. #ifdef VMS
  9302.         (cmarg2[y-1] == ']' || cmarg2[y-1] == '>' || isdir(cmarg2))
  9303. #else
  9304. #ifdef STRATUS
  9305.         (cmarg2[y-1] == '>' || isdir(cmarg2))
  9306. #else
  9307. #ifdef datageneral
  9308.         (cmarg2[y-1] == ':' || cmarg[0] == ':' || isdir(cmarg2))
  9309. #else
  9310.         isdir(cmarg2)
  9311. #endif /* datageneral */
  9312. #endif /* STRATUS */
  9313. #endif /* VMS */
  9314. #endif /* UNIXOROSK */
  9315. #endif /* OS2 */
  9316.         ) {
  9317.         debug(F110,"doxget RECEIVE cmarg2 disk or dir",cmarg2,0);
  9318.         if (!f_tmpdir) {
  9319.             int x;
  9320.             s = zgtdir();
  9321.             if (s) {
  9322.                 ckstrncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
  9323.                 f_tmpdir = 1;   /* and that we did this */
  9324.             } else {
  9325.                 printf("?Can't get current directory\n");
  9326.                 cmarg2 = "";
  9327.                 f_tmpdir = 0;
  9328.                 x = -9;
  9329.                 goto xgetx;
  9330.             }
  9331. #ifdef CK_MKDIR
  9332.             x = zchki(cmarg2);          /* Does as-name exist? */
  9333.             if (x == -1) {              /* Doesn't exist */
  9334.                 char * p = NULL;        /* Try to create it */
  9335.                 x = strlen(cmarg2);
  9336.                 if ((p = (char *)malloc(x+4))) {
  9337.                     sprintf(p,"%s%s",cmarg2,"x.x"); /* SAFE (prechecked) */
  9338.                     x = zmkdir(p);
  9339.                     free(p);
  9340.                     if (x < 0) {
  9341.                         printf("?Can't create %s\n",cmarg2);
  9342.                         x = -9;
  9343.                         goto xgetx;
  9344.                     }
  9345.                 }
  9346.             }
  9347. #endif /* CK_MKDIR */
  9348.             if (!zchdir(cmarg2)) {      /* change to given disk/directory, */
  9349.                 printf("?Can't access %s\n",cmarg2);
  9350.                 x = -9;
  9351.                 goto xgetx;
  9352.             }
  9353.             cmarg2 = "";
  9354.         }
  9355.     }
  9356. #endif /* CK_TMPDIR */
  9357.  
  9358.     ckstrncpy(fspec,cmarg,CKMAXPATH);   /* Note - this is a REMOTE filespec */
  9359.     debug(F111,"xget fspec",fspec,fspeclen);
  9360.     debug(F110,"xget cmarg2",cmarg2,0);
  9361.  
  9362.   xgetx:
  9363.     for (i = 0; i < SND_MAX; i++)
  9364.       if (pv[i].sval)
  9365.         free(pv[i].sval);
  9366.     return(x);
  9367. }
  9368. #endif /* NOXFER */
  9369.  
  9370. #ifndef NOSPL
  9371.  
  9372. /*
  9373.   D O G T A  --  Do _GETARGS or _PUTARGS Command.
  9374.  
  9375.   Used by XIF, FOR, WHILE, and SWITCH, each of which are implemented as
  9376.   2-level macros; the first level defines the macro, the second runs it.
  9377.   This routine hides the fact that they are macros by importing the
  9378.   macro arguments (if any) from two levels up, to make them available
  9379.   in the IF, FOR, SWITCH, and WHILE commands themselves; for example as
  9380.   loop indices, etc, and within the IF/FOR/WHILE/SWITCH body itself.
  9381.   _PUTARGS is in case we changed any of these variables or used SHIFT
  9382.   on them, so the new values won't be lost as we pop up the stack.
  9383. */
  9384. int
  9385. dogta(cx) int cx; {
  9386.     int i, n;
  9387.     char c, *p,  mbuf[4];
  9388.     extern int topargc, cmdint;
  9389.     extern char ** topxarg;
  9390.  
  9391.     if ((y = cmcfm()) < 0)
  9392.       return(y);
  9393.     debug(F101,"dogta cx","",cx);
  9394.     debug(F101,"dogta maclvl","",maclvl);
  9395.     if (cx == XXGTA) {
  9396.         debug(F101,"dogta _GETARGS maclvl","",maclvl);
  9397.     } else if (cx == XXPTA) {
  9398.         debug(F101,"dogta _PUTARGS maclvl","",maclvl);
  9399.     } else {
  9400.         return(-2);
  9401.     }
  9402.     if (maclvl < 1)
  9403.       return(success = 0);
  9404.  
  9405.     /* Make new copies of macro arguments /%0..9 */
  9406.  
  9407.     mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = NUL; /* Argument name buf */
  9408.  
  9409.     if (cx == XXPTA) {                  /* Go NOINT because _PUTARGS */
  9410.         if (cmdint)                     /* temporarily changes maclvl. */
  9411.           connoi();                     /* Interrupts OFF. */
  9412.     }
  9413.     for (i = 0; i < 10; i++) {          /* For all args */
  9414.         c = (char) (i + '0');           /* Make name */
  9415.         mbuf[1] = (char) c;             /* Insert digit */
  9416.         if (cx == XXGTA) {              /* Get arg from level-minus-2 */
  9417.             if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
  9418.             else p = m_arg[maclvl-2][i];   /* Otherwise they're on the stack */
  9419.             addmac(mbuf,p);
  9420. #ifdef COMMENT
  9421.             if (maclvl > 1)
  9422.               makestr(&(m_line[maclvl]),m_line[maclvl-2]);
  9423. #endif /* COMMENT */
  9424.         } else if (cx == XXPTA) {       /* Put args level+2 */
  9425.             maclvl -= 2;                /* This is gross, it's because we're */
  9426.             addmac(mbuf,m_arg[maclvl+2][i]); /* adding macros two levels up */
  9427.             maclvl += 2;                     /* and addmac() uses maclvl. */
  9428.             count[cmdlvl - 2]  = count[cmdlvl];
  9429.             intime[cmdlvl - 2] = intime[cmdlvl];
  9430.             inpcas[cmdlvl - 2] = inpcas[cmdlvl];
  9431.             takerr[cmdlvl - 2] = takerr[cmdlvl];
  9432.             merror[cmdlvl - 2] = merror[cmdlvl];
  9433.             xquiet[cmdlvl - 2] = xquiet[cmdlvl];
  9434.         } else return(success = 0);     /* Bad call to this routine */
  9435.     }
  9436.     if (cx == XXPTA) {                  /* Restore interrupts if we */
  9437.         if (cmdint)                     /* turned them off above. */
  9438.           conint(trap,stptrap);
  9439.     }
  9440.     /* Now take care of the argument vector array \&_[], \v(return), */
  9441.     /* and \v(argc) by just copying the pointers. */
  9442.  
  9443.     if (cx == XXGTA) {                  /* GETARGS from 2 levels up */
  9444.         if (maclvl == 1) {
  9445.             a_ptr[0] = topxarg;         /* \&_[] array */
  9446.             a_dim[0] = topargc - 1;     /* Dimension doesn't include [0] */
  9447.             m_xarg[maclvl] = topxarg;
  9448.             n_xarg[maclvl] = topargc;   /* But \v(argc) does include \%0 */
  9449.             macargc[maclvl] = topargc;
  9450.             makestr(&(mrval[maclvl+1]),mrval[0]); /* (see vnlook()) */
  9451.         } else {
  9452.             a_ptr[0] = m_xarg[maclvl-2];
  9453.             a_dim[0] = n_xarg[maclvl-2];
  9454.             m_xarg[maclvl] = m_xarg[maclvl-2];
  9455.             n_xarg[maclvl] = n_xarg[maclvl-2];
  9456.             macargc[maclvl] = n_xarg[maclvl-2];
  9457.             makestr(&(mrval[maclvl+1]),mrval[maclvl-1]); /* (see vnlook()) */
  9458.  
  9459.         }
  9460.     } else {                            /* PUTARGS 2 levels up */
  9461.         if (maclvl > 1) {
  9462.             a_ptr[0] = m_xarg[maclvl];
  9463.             m_xarg[maclvl-2] = m_xarg[maclvl];
  9464.             a_dim[0] = n_xarg[maclvl];
  9465.             n_xarg[maclvl-2] = n_xarg[maclvl];
  9466.             macargc[maclvl-2] = n_xarg[maclvl];
  9467.         }
  9468.     }
  9469.     return(1);                  /* Internal command - don't change success */
  9470. }
  9471. #endif /* NOSPL */
  9472.  
  9473. #ifndef NOSPL
  9474. /*
  9475.   Do the GOTO and [_]FORWARD commands.
  9476.   s = Label to search for, cx = function code: XXGOTO, XXFWD, or XXXFWD.
  9477. */
  9478.  
  9479. int
  9480. dogoto(s, cx) char *s; int cx; {
  9481.     int i, j, x, y, z, bc;
  9482.     int empty = 0, stopflg = 0;
  9483.     char * cmd;                         /* Name of this command */
  9484.     char tmplbl[LBLSIZ+1], *lp;            /* Current label from command stream */
  9485.     char tmp2[LBLSIZ+1];        /* SWITCH label conversion buffer */
  9486.     char tmp3[LBLSIZ+1];        /* Target label */
  9487.  
  9488.     stopflg = (cx == XXXFWD);           /* _FORWARD (used in SWITCH) */
  9489.     bc = 0;                             /* Brace counter */
  9490.  
  9491.     cmd = (cx == XXGOTO) ? "GOTO" : ((cx == XXFWD) ? "FORWARD" : "_FORWARD");
  9492.     if (!s) s = "";
  9493.     if (!*s) empty = 1;
  9494.  
  9495. #ifdef DEBUG
  9496.     if (deblog) {
  9497.         debug(F111,"GOTO command",cmd,cx);
  9498.         debug(F101,"GOTO cmdlvl","",cmdlvl);
  9499.         debug(F101,"GOTO maclvl","",maclvl);
  9500.         debug(F101,"GOTO tlevel","",tlevel);
  9501.         debug(F111,"GOTO target",s,empty);
  9502.     }
  9503. #endif /* DEBUG */
  9504.     debug(F110,cmd,s,0);
  9505.     x = ckstrncpy(tmp3+1,s,LBLSIZ);
  9506.     debug(F101,"GOTO target len","",x);
  9507.     debug(F101,"GOTO target at x","",s[x]);
  9508.     if (s[x]) {
  9509.     debug(F100,"GOTO target overflow","",0);
  9510.     printf("?GOTO target or SWITCH case label too long\n");
  9511.     if (stopflg) dostop();        /* If in SWITCH return to prompt */
  9512.     return(success = 0);
  9513.     }
  9514.     s = tmp3+1;
  9515.     if (*s != ':') {                    /* Make copy of label */
  9516.         tmp3[0] = ':';                  /* guaranteed to start with ":" */
  9517.         s--;
  9518.     }
  9519.     if (!stopflg && !empty) {
  9520.         if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
  9521.             printf("?Bad label syntax - '%s'\n",s);
  9522.         if (stopflg) dostop();    /* If in SWITCH return to prompt */
  9523.             return(success = 0);
  9524.         }
  9525.     }
  9526.     if (cmdlvl == 0) {
  9527.         printf("?Sorry, %s only works in a command file or macro\n",cmd);
  9528.         return(success = 0);
  9529.     }
  9530.     y = strlen(s);                      /* y = length of target label */
  9531.     debug(F111,cmd,s,y);
  9532.  
  9533.     while (cmdlvl > 0) {                /* As long as not at top level... */
  9534.         if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
  9535.             int i, m, flag;
  9536.             char *xp, *tp;
  9537.  
  9538.             /* GOTO: rewind the macro; FORWARD: start at current position */
  9539.  
  9540.             lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
  9541.             m = (int)strlen(lp);
  9542.             debug(F111,"GOTO in macro",lp,m);
  9543.  
  9544.             flag = 1;                   /* flag for valid label position */
  9545.             for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
  9546.                 if (*lp == '{')         /* But only at this level */
  9547.                   bc++;                 /* Anything inside braces is off */
  9548.                 else if (*lp == '}')    /* limits. */
  9549.                   bc--;
  9550.                 if (stopflg && bc > 0)  /* This is good for SWITCH */
  9551.                   continue;             /* but interferes with WHILE, etc. */
  9552.                 if (*lp == ',') {
  9553.                     flag = 1;
  9554.                     continue;
  9555.                 }
  9556.                 if (flag) {             /* If in valid label position */
  9557.                     if (*lp == SP)      /* eat leading spaces */
  9558.                       continue;
  9559.                     if (*lp != ':') {   /* Look for label introducer */
  9560.                         flag = 0;       /* this isn't it */
  9561.                         continue;       /* keep looking */
  9562.                     }
  9563.                 }
  9564.                 if (!flag)              /* We don't have a label */
  9565.                   continue;             /*  so keep looking... */
  9566.                 xp = lp; tp = tmplbl;   /* Copy the label from the macro */
  9567.                 j = 0;                  /* to make it null-terminated */
  9568.                 while ((*tp = *xp)) {
  9569.                     if (j++ > LBLSIZ-1) { /* j = length of word from macro */
  9570.             printf("?GOTO target or SWITCH case label too long\n");
  9571.             if (stopflg) dostop(); /* Return to prompt */
  9572.             return(success = 0);
  9573.             }
  9574.                     if (!*tp || *tp == ',') /* Look for end of word */
  9575.                       break;
  9576.                     else tp++, xp++;    /* Next character */
  9577.                 }
  9578.                 *tp = NUL;              /* In case we stopped early */
  9579.                 /* Now do caseless string comparison, using longest length */
  9580.                 debug(F111,"macro GOTO label",s,y);
  9581.                 debug(F111,"macro target label",tmplbl,j);
  9582.                 if (stopflg) {          /* Allow variables as SWITCH labels */
  9583.                     int n = LBLSIZ - 1;
  9584.                     char * p = tmp2;
  9585.                     zzstring(tmplbl,&p,&n);
  9586.             if (n < 0) {
  9587.             printf("?GOTO target or SWITCH case label too long\n");
  9588.             if (stopflg) dostop(); /* Return to prompt */
  9589.             return(0);
  9590.             }
  9591.                     ckstrncpy(tmplbl,tmp2,LBLSIZ);
  9592.                 }
  9593.                 debug(F111,"GOTO s",s,y);
  9594.                 debug(F111,"GOTO tmplbl",tmplbl,j);
  9595.                 debug(F111,"GOTO empty",ckitoa(stopflg),empty);
  9596.  
  9597.                 if (empty) {           /* Empty target */
  9598.             z = (!strcmp(s,":") && /* String is empty */
  9599.              /* and Label is ":" or ":*"... */
  9600.              (!strcmp(tmplbl,":") || !strcmp(tmplbl,":*")))
  9601.             ? 0 : 1;
  9602.             debug(F111,"GOTO","A",z);
  9603.                 } else if (stopflg) {
  9604.                     z = ckmatch(tmplbl,s,inpcas[cmdlvl],1) ? 0 : 1;
  9605.             debug(F111,"GOTO","B",z);
  9606.                 } else {
  9607.                     z = (stopflg && inpcas[cmdlvl]) ?
  9608.                       strcmp(s,tmplbl) :
  9609.                         ckstrcmp(s,tmplbl,(y > j) ? y : j, 0);
  9610.             debug(F111,"GOTO","C",z);
  9611.                 }
  9612.                 if (!z) {
  9613.                     break;
  9614.                 } else if (stopflg &&
  9615.                          !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j, 0)) {
  9616.                     debug(F100,"GOTO DEFAULT","",0);
  9617.                     break;
  9618.                 } else {
  9619.                     flag = 0;
  9620.                 }
  9621.             }
  9622.             debug(F111,"GOTO macro i",cmd,i);
  9623.             debug(F111,"GOTO macro m",cmd,m);
  9624.             if (i >= m) {               /* Didn't find the label */
  9625.                 debug(F101,"GOTO failed cmdlvl","",cmdlvl);
  9626. #ifdef COMMENT
  9627.         /* MOVED TO AFTER POPCLVL ABOUT 20 LINES DOWN 5 AUG 2002 */
  9628.            if (stopflg)
  9629.                   return(0);
  9630. #endif /* COMMENT */
  9631.                 if ((maclvl > 0) &&
  9632.                        (m_arg[maclvl-1][0]) &&
  9633.                        (cmdstk[cmdlvl].src == CMD_MD) &&
  9634.                        (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  9635.                         !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  9636.                         !strncmp(m_arg[maclvl-1][0],"_swi",4) ||
  9637.                         !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  9638.                     dogta(XXPTA);       /* Restore args */
  9639.                     debug(F101,"GOTO in XIF/FOR/WHI/SWI popping","",cmdlvl);
  9640.                     popclvl();          /* Pop an extra level */
  9641.                 }
  9642.                 debug(F101,"GOTO popping","",cmdlvl);
  9643.                 if (!popclvl()) {       /* pop up to next higher level */
  9644.                     printf("?Label '%s' not found\n",s); /* if none */
  9645.                     return(0);          /* Quit */
  9646.                 } else if (stopflg) {    /* SWITCH no case label match */
  9647.             return(0);        /* and no DEFAULT lable. */
  9648.         } else {
  9649.             continue;        /* otherwise look again */
  9650.         }
  9651.             }
  9652.             debug(F110,"GOTO found macro label",tmplbl,0);
  9653.             macp[maclvl] = lp;          /* set macro buffer pointer */
  9654.             return(1);
  9655.         } else if (cmdstk[cmdlvl].src == CMD_TF) {
  9656.             x = 0;                      /* GOTO issued in take file */
  9657.             debug(F111,"GOTO in TAKE file",cmd,cx);
  9658.             if (cx == XXGOTO) {         /* If GOTO, but not FORWARD, */
  9659.                 rewind(tfile[tlevel]);  /* search file from beginning */
  9660.                 tfline[tlevel] = 0;
  9661.             }
  9662.             while (! feof(tfile[tlevel])) {
  9663. #ifdef COMMENT
  9664. /* This is wrong - it lets us jump to labels inside inferior blocks */
  9665.                 tfline[tlevel]++;
  9666.                 if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
  9667. #else
  9668.                 if (getnct(line,LINBUFSIZ,tfile[tlevel],0) < 0)
  9669. #endif /* COMMENT */
  9670.                   break;                /* If no more, done, label not found */
  9671.                 lp = line;              /* Got line */
  9672.                 while (*lp == SP || *lp == HT)
  9673.                   lp++;                 /* Strip leading whitespace */
  9674.                 if (*lp != ':') continue; /* Check for label introducer */
  9675.                 while (*(lp+1) == SP) { /* Remove space between : and name */
  9676.                     *(lp+1) = ':';
  9677.                     lp++;               /* Strip leading whitespace */
  9678.                 }
  9679.                 tp = lp;                /* Get end of word */
  9680.                 j = 0;
  9681.                 while (*tp) {           /* And null-terminate it */
  9682.                     if (*tp < 33) {
  9683.                         *tp = NUL;
  9684.                         break;
  9685.                     } else tp++, j++;
  9686.                 }
  9687.                 if (!ckstrcmp(lp,s,(y > j) ? y : j,0)) { /* Caseless compare */
  9688.                     x = 1;              /* Got it */
  9689.                     break;              /* done. */
  9690.                 } else if (stopflg &&
  9691.                            !ckstrcmp(":default",tmplbl,(8 > j) ? 8 : j,0)) {
  9692.                     x = 1;
  9693.                     break;
  9694.                 }
  9695.             }
  9696.             if (x == 0) {               /* If not found, print message */
  9697.                 debug(F101,"GOTO failed at cmdlvl","",cmdlvl);
  9698.                 if (stopflg)
  9699.                   return(0);
  9700.                 if (!popclvl()) {       /* pop up to next higher level */
  9701.                     printf("?Label '%s' not found\n",s); /* if none */
  9702.                     return(0);          /* quit */
  9703.                 } else continue;        /* otherwise look again */
  9704.             }
  9705.             return(x);                  /* Send back return code */
  9706.         }
  9707.     }
  9708.     printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
  9709.     return(0);
  9710. }
  9711. #endif /* NOSPL */
  9712.  
  9713. /* Finish parsing and do the IF, XIF, and WHILE commands */
  9714.  
  9715. #ifndef NOSPL
  9716.  
  9717. /*  C H K V A R  --  Check (if it's a) Variable  */
  9718.  
  9719.  
  9720. #ifdef OLDCHKVAR
  9721. /*
  9722.   Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
  9723.   have backslashes in them.  How do we know if a backslash in a filename is a
  9724.   directory separator, or if it's a Kermit backslash?  This routine does a
  9725.   rough syntax check of the next few characters and if it looks like it MIGHT
  9726.   be a variable, then it tries to evaluate it, and if the result is not empty,
  9727.   we say it's a variable, although sometimes it might not be -- some cases are
  9728.   truly ambiguous.  For example there might a DOS directory called \%a, and
  9729.   we also have a variable with the same name.  This is all for the sake of not
  9730.   having to tell PC users that they have to double all backslashes in file
  9731.   and directory names.
  9732. */
  9733. #else
  9734. /*
  9735.   Somewhat less crude & disgusting.  The previous method was nondeterministic
  9736.   and (worse) it interfered with macro argument passing.  So now we only
  9737.   check the syntax of backslash-items to see if they are variables, but we
  9738.   do NOT check their values.
  9739. */
  9740. #endif /* OLDCHKVAR */
  9741. /*
  9742.   Call with a string pointer pointing at the backslash of the purported
  9743.   variable.  Returns 1 if it has the syntax of a variable, 0 if not.
  9744. */
  9745. int
  9746. chkvar(s) char *s; {
  9747.     int z = 0;                          /* Return code - assume failure. */
  9748.     if (!s) s = "";                     /* Watch our for null pointers. */
  9749.     if (!*s) return(0);                 /* Empty arg so not a variable. */
  9750.     if (*s == CMDQ) {                   /* Object begins with backslash. */
  9751.         char c;
  9752.         c = s[1];                       /* Character following backslash. */
  9753.         if (c) {
  9754.             int t = 0;
  9755.             if (c == CMDQ)              /* Quoted backslash */
  9756.               return(1);
  9757.             c = (char) (islower(c) ? toupper(c) : c); /* Otherwise... */
  9758.             if (c == '%') {             /* Simple variable */
  9759. #ifdef OLDCHKVAR
  9760.                 t = 1;
  9761. #else
  9762.                 return(1);
  9763. #endif /* OLDCHKVAR */
  9764.             } else if (c == '&') {      /* Array */
  9765.                 if (!s[2]) return(0);
  9766.                 if (s[3] == '[')
  9767.                   t = ckindex("]",s,4,0,1);
  9768. #ifndef OLDCHKVAR
  9769.                 return((t > 0) ? 1 : 0);
  9770. #endif /* OLDCHKVAR */
  9771.             } else if (c == '$' ||      /* Environment variable */
  9772.                        c == 'V' ||      /* Built-in variable */
  9773.                        c == 'M') {      /* Macro name */
  9774.                 t = (s[2] == '(');
  9775. #ifndef OLDCHKVAR
  9776.                 return((t > 0) ? 1 : 0);
  9777. #endif /* OLDCHKVAR */
  9778.             } else if (c == 'F') {      /* Function reference */
  9779.                 /* Don't actually call it - it might have side effects */
  9780.                 int x;
  9781.                 if ((x = ckindex("(",s,3,0,1))) /* Just check syntax */
  9782.                   if ((x = ckindex(")",s,x,0,1)))
  9783.                     z = 1;
  9784.                 /* Insert a better syntax check here if necessary */
  9785.             }
  9786. #ifdef OLDCHKVAR
  9787.             if (t) {
  9788.                 t = 255;                /* This lets us test \v(xxx) */
  9789.                 lp = line;              /* and even \f...(xxx) */
  9790.                 zzstring(s,&lp,&t);     /* Evaluate it, whatever it is. */
  9791.                 t = strlen(line);       /* Get its length. */
  9792.                 debug(F111,"chkvar",line,t);
  9793.                 z = t > 0;              /* If length > 0, it's defined */
  9794.             }
  9795. #endif /* OLDCHKVAR */
  9796.         }
  9797.     }
  9798.     return(z);
  9799. }
  9800.  
  9801. /*  B O O L E X P  --  Evaluate a Boolean expression  */
  9802.  
  9803. #define BOOLLEN 1024
  9804. static char boolval[BOOLLEN];
  9805.  
  9806. int
  9807. boolexp(cx) int cx; {
  9808.     int x, y, z; char *s, *p;
  9809.     int parens = 0, pcount = 0, ecount = 0;
  9810.     char *q, *bx;
  9811.     struct FDB kw, nu;
  9812. #ifdef FNFLOAT
  9813.     struct FDB fl;
  9814.     CKFLOAT f1 = 0.0, f2 = 0.0;
  9815.     int f1flag = 0, f2flag = 0;
  9816. #endif /* FNFLOAT */
  9817. #ifdef OS2
  9818.     extern int keymac;
  9819. #endif /* OS2 */
  9820.  
  9821.     not = 0;                            /* Flag for whether "NOT" was seen */
  9822.     z = 0;                              /* Initial IF condition */
  9823.     ifargs = 0;                         /* Count of IF condition words */
  9824.     bx = boolval;                       /* Initialize boolean value */
  9825.     *bx = NUL;
  9826.  
  9827.   ifagain:
  9828.     cmfdbi(&kw,                         /* First FDB - command switches */
  9829.            _CMKEY,                      /* fcode */
  9830.            "Number, numeric-valued variable, Boolean expression, or keyword",
  9831.            "",                          /* default */
  9832.            "",                          /* addtl string data */
  9833.            nif,                         /* addtl numeric data 1: tbl size */
  9834.            0,                           /* addtl numeric data 2: 4 = silent */
  9835.            xxstring,                    /* Processing function */
  9836.            iftab,                       /* Keyword table */
  9837.            &nu                          /* Pointer to next FDB */
  9838.            );
  9839.     cmfdbi(&nu,                         /* 2nd FDB - An integer */
  9840.            _CMNUM,                      /* fcode */
  9841.            "",                          /* hlpmsg */
  9842.            "",                          /* Default */
  9843.            "",                          /* addtl string data */
  9844.            0,
  9845.            0,
  9846.            xxstring,
  9847.            NULL,
  9848. #ifdef FNFLOAT
  9849.            &fl
  9850. #else
  9851.            NULL
  9852. #endif /* FNFLOAT */
  9853.            );
  9854. #ifdef FNFLOAT
  9855.     cmfdbi(&fl,                         /* A floating-point number */
  9856.            _CMFLD,                      /* fcode */
  9857.            "",                          /* hlpmsg */
  9858.            "",                          /* default */
  9859.            "",                          /* addtl string data */
  9860.            0,                           /* addtl numeric data 1 */
  9861.            0,                           /* addtl numeric data 2 */
  9862.            xxstring,
  9863.            NULL,
  9864.            NULL
  9865.            );
  9866. #endif /* FNFLOAT */
  9867.     x = cmfdb(&kw);                     /* Parse a keyword or a number */
  9868.     debug(F111,"boolval cmfdb","",x);
  9869.     if (x < 0) {
  9870.         if (x == -3)
  9871.           x = -2;
  9872.         return(x);
  9873.     }
  9874.     debug(F111,"boolval switch","",cmresult.fcode);
  9875.     switch (cmresult.fcode) {           /* What did we get? */
  9876. #ifdef FNFLOAT
  9877.       case _CMFLD:                      /* A "field" */
  9878.         if (isfloat(cmresult.sresult,0)) { /* A floating-point number? */
  9879.             f1 = floatval;              /* Yes, get its value */
  9880.             f1flag = 1;                 /* remember we did this */
  9881.             ifc = 9999;                 /* Set special "if-code" */
  9882.         } else
  9883.           return(-2);
  9884. #endif /* FNFLOAT */
  9885.       case _CMNUM:                      /* A number... */
  9886.         ifc = 9999;                     /* Set special "if-code" */
  9887.         break;
  9888.       case _CMKEY:                      /* A keyword */
  9889.         ifc = cmresult.nresult;         /* Get if-code */
  9890.         break;
  9891.       default:
  9892.         return(-2);
  9893.     }
  9894.     switch (ifc) {                      /* set z = 1 for true, 0 for false */
  9895.       case 9999:                        /* Number */
  9896. #ifdef FNFLOAT
  9897.         if (f1flag) {
  9898.             z = (f1 == 0.0) ? 0 : 1;
  9899.         } else
  9900. #endif /* FNFLOAT */
  9901.         z = (cmresult.nresult == 0) ? 0 : 1;
  9902.         break;
  9903.       case XXIFLP:                      /* Left paren */
  9904.         if (pcount == 0 && ifargs > 0)
  9905.           return(-2);
  9906.         parens = 1;
  9907.         pcount++;
  9908.         ifargs++;
  9909.         *bx++ = '(';
  9910.         goto ifagain;
  9911.       case XXIFRP:                      /* Right paren */
  9912.         if (!parens)
  9913.           return(-2);
  9914.         if (--pcount < 0)
  9915.           return(-2);
  9916.         ifargs++;
  9917.         *bx++ = ')';
  9918.         *bx = NUL;
  9919.         if (pcount == 0)
  9920.           goto ifend;
  9921.         goto ifagain;
  9922.       case XXIFAN:                      /* AND (&&) */
  9923.         ifargs++;
  9924.         if (!ecount)
  9925.           return(-2);
  9926.         *bx++ = '&';
  9927.         goto ifagain;
  9928.       case XXIFOR:                      /* OR (||) */
  9929.         ifargs++;
  9930.         if (!ecount)
  9931.           return(-2);
  9932.         *bx++ = '|';
  9933.         goto ifagain;
  9934.       case XXIFNO:                      /* IF NOT [ NOT [ NOT ... ] ] */
  9935.         if (bx > boolval) {             /* evala() doesn't like cascaded */
  9936.             if (*(bx-1) == '!') {       /* unary operators... */
  9937.                 *(bx-1) = NUL;          /* So here, two wrongs make a right. */
  9938.                 bx--;
  9939.             } else {
  9940.                 *bx++ = '!';
  9941.             }
  9942.         } else {
  9943.             *bx++ = '!';
  9944.         }
  9945.         ifargs++;
  9946.         goto ifagain;
  9947.       case XXIFTR:                      /* IF TRUE */
  9948.         z = 1;
  9949.         debug(F101,"if true","",z);
  9950.         ifargs += 1;
  9951.         break;
  9952.       case XXIFNT:                      /* IF FALSE */
  9953.         z = 0;
  9954.         debug(F101,"if true","",z);
  9955.         ifargs += 1;
  9956.         break;
  9957.       case XXIFSU:                      /* IF SUCCESS */
  9958.         z = ( success != 0 ) ? 1 : 0;
  9959.         debug(F101,"if success","",z);
  9960.         ifargs += 1;
  9961.         break;
  9962.       case XXIFFA:                      /* IF FAILURE */
  9963.         z = ( success == 0 ) ? 1 : 0;
  9964.         debug(F101,"if failure","",z);
  9965.         ifargs += 1;
  9966.         break;
  9967.  
  9968.       case XXIFDE:                      /* IF DEFINED */
  9969.         if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0)
  9970.           return((x == -3) ? -2 : x);
  9971.  
  9972.         if (*s == CMDQ) {
  9973.             char * lp;
  9974.             char line[256];
  9975.             int t, x;
  9976.             if (*(s+1) == 'f' || *(s+1) == 'F') { /* Built-in function */
  9977.                 extern struct keytab fnctab[];
  9978.                 extern int nfuncs;
  9979.                 ckstrncpy(line,s+2,256);
  9980.                 if (line[0]) {
  9981.                     lp = ckstrchr(line,'(');
  9982.                     if (lp) *lp = NUL;
  9983.                     x = lookup(fnctab,line,nfuncs,&t);
  9984.                     z = x > -1;
  9985.                 }
  9986.                 debug(F111,"if defined function",line,z);
  9987.             } else if (*(s+1) == 'v' || *(s+1) == 'V') { /* 8.0.200 */
  9988.                 extern struct keytab vartab[];
  9989.                 extern int nvars;
  9990.                 z = 0;
  9991.                 if (*(s+2) == '(') {
  9992.                     ckstrncpy(line,s+3,256);
  9993.                     if (line[0]) {
  9994.                         lp = ckstrchr(line,')');
  9995.                         if (lp) *lp = NUL;
  9996.                         x = lookup(vartab,line,nvars,&t);
  9997.                         z = x > -1;
  9998.             if (z) {    /* 8.0.203 */
  9999.                 int t;    /* It must have a value to succeed */
  10000.                 t = 255;    /* as in C-Kermit 6.0 and 7.0 */
  10001.                 lp = line;    /* (this was broken in 8.0.200-201) */
  10002.                 zzstring(s,&lp,&t);
  10003.                 t = strlen(line);
  10004.                 z = line[0] ? 1 : 0;
  10005.             }
  10006.                     }
  10007.                 }
  10008.                 debug(F111,"if defined variable",line,z);
  10009.             } else {
  10010.                 z = chkvar(s);          /* Starts with backslash */
  10011.                 if (z > 0) {            /* Yes... */
  10012.                     t = 255;            /* than buffer so if zzstring fails  */
  10013.                     lp = line;          /* check for that -- overflow means */
  10014.                     line[0] = NUL;      /* the quantity is defined. */
  10015.                     x = zzstring(s,&lp,&t);
  10016.                     if ((x < 0 && t != 255) || !line[0])
  10017.                       z = 0;
  10018.                     debug(F111,"if defined zzstring",line,z);
  10019.                     debug(F101,"if defined zzstring t","",t);
  10020.                 }
  10021.             }
  10022.         } else {
  10023.             z = (mxlook(mactab,s,nmac) > -1); /* Look for exact match */
  10024.         }
  10025.         debug(F111,"if defined final",s,z);
  10026.         ifargs += 2;
  10027.         break;
  10028.  
  10029.       case XXIFDC: {                    /* IF DECLARED */
  10030.           char * lp;
  10031.           char line[32];
  10032.           int j, k, t, x;
  10033.           if ((x = cmfld("Array name","",&s,NULL)) < 0)
  10034.             return((x == -3) ? -2 : x);
  10035.           if (*s == CMDQ) {
  10036.               if (*(s+1) != '&') {
  10037.                   t = 31;
  10038.                   lp = line;
  10039.                   line[0] = NUL;
  10040.                   x = zzstring(s,&lp,&t);
  10041.                   s = line;
  10042.               }
  10043.           }
  10044.           z = 0;
  10045.           if ((x = arraybounds(s,&j,&k)) > -1) {
  10046.               if (a_ptr[x]) {
  10047.                   if (j < 1)
  10048.                     z = 1;
  10049.                   else if (j <= a_dim[x])
  10050.                     z = 1;
  10051.                   if (z == 1 && k > a_dim[x])
  10052.                     z = 0;
  10053.               }
  10054.           }
  10055.           break;
  10056.       }
  10057.       case XXIFBG:                      /* IF BACKGROUND */
  10058.       case XXIFFG:                      /* IF FOREGROUND */
  10059.         bgchk();                        /* Check background status */
  10060.         if (ifc == XXIFFG)              /* Foreground */
  10061.           z = pflag ? 1 : 0;
  10062.         else z = pflag ? 0 : 1;         /* Background */
  10063.         ifargs += 1;
  10064.         break;
  10065.  
  10066.       case XXIFCO:                      /* IF COUNT */
  10067.         z = ( --count[cmdlvl] > 0 );
  10068.         if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
  10069.         debug(F101,"if count","",z);
  10070.         ifargs += 1;
  10071.         break;
  10072.  
  10073.       case XXIFEX:                      /* IF EXIST */
  10074. #ifdef CK_TMPDIR
  10075.       case XXIFDI:                      /* IF DIRECTORY */
  10076. #endif /* CK_TMPDIR */
  10077.       case XXIFAB:                      /* IF ABSOLUTE */
  10078.       case XXIFLN:            /* IF LINK */
  10079.         if ((x = cmfld(
  10080.                        ((ifc == XXIFDI) ? "Directory name" : "File"),
  10081.                        "",&s,
  10082. #ifdef OS2
  10083.                        NULL             /* This allows \'s in filenames */
  10084. #else
  10085.                        xxstring
  10086. #endif /* OS2 */
  10087.                        )) < 0) {
  10088.             if (x == -3) {
  10089.                 extern int cmflgs;
  10090.                 if (cmflgs == 1) {
  10091.                     printf("?File or directory name required\n");
  10092.                     return(-9);
  10093.                 }
  10094.             } else return(x);
  10095.         }
  10096.         s = brstrip(s);
  10097. #ifdef UNIX
  10098.     if (ifc == XXIFLN) {
  10099.         z = islink(s);
  10100.     } else
  10101. #endif    /* UNIX */
  10102.         if (ifc == XXIFAB) {
  10103.             z = isabsolute(s);
  10104.         } else if (ifc == XXIFEX) {
  10105.             z = (zgetfs(s) > -1L);
  10106.             debug(F101,"if exist 1","",z);
  10107. #ifdef OS2
  10108.             if (!z) {                   /* File not found. */
  10109.                 int t;                  /* Try expanding variables */
  10110.                 t = LINBUFSIZ-1;        /* and looking again. */
  10111.                 lp = line;
  10112.                 zzstring(s,&lp,&t);
  10113.                 s = line;
  10114.                 z = ( zchki(s) > -1L );
  10115.                 debug(F101,"if exist 2","",z);
  10116.             }
  10117. #endif /* OS2 */
  10118. #ifdef CK_TMPDIR
  10119.         } else {
  10120. #ifdef VMS
  10121.             z = (zchki(s) == -2)
  10122. #else
  10123. /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
  10124.             z = isdir(s)
  10125. #ifdef OS2
  10126.               || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
  10127. #endif /* OS2 */
  10128. #endif /* VMS */
  10129.               ;
  10130.             debug(F101,"if directory 1","",z);
  10131.  
  10132.             if (!z) {            /* File not found. */
  10133.                 int t;                  /* Try expanding variables */
  10134.                 t = LINBUFSIZ-1;        /* and looking again. */
  10135.                 lp = line;
  10136.                 zzstring(s,&lp,&t);
  10137.                 s = line;
  10138.                 z = isdir(s)
  10139. #ifdef OS2
  10140.                   || (isalpha(s[0]) && s[1] == ':' && s[2] == NUL)
  10141. #endif /* OS2 */
  10142.                     ;
  10143.                 debug(F101,"if directory 2","",z);
  10144.             }
  10145. #endif /* CK_TMPDIR */
  10146.         }
  10147.         ifargs += 2;
  10148.         break;
  10149.  
  10150.       case XXIFEQ:                      /* IF EQUAL (string comparison) */
  10151.       case XXIFLL:                      /* IF Lexically Less Than */
  10152.       case XXIFLG:                      /* If Lexically Greater Than */
  10153.         if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
  10154.             if (x == -3) {
  10155.                 printf("?Text required\n");
  10156.                 return(-9);
  10157.             } else return(x);
  10158.         }
  10159.         s = brstrip(s);                 /* Strip braces */
  10160.         x = (int)strlen(s);
  10161.         if (x > LINBUFSIZ-1) {
  10162.             printf("?IF: strings too long\n");
  10163.             return(-2);
  10164.         }
  10165.         lp = line;                      /* lp points to first string */
  10166.         ckstrncpy(line,s,LINBUFSIZ);
  10167.         if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
  10168.             if (y == -3) {
  10169.                 printf("?Text required\n");
  10170.                 return(-9);
  10171.             } else return(y);
  10172.         }
  10173.         s = brstrip(s);
  10174.         y = (int)strlen(s);
  10175.         if (x + y + 2 > LINBUFSIZ) {
  10176.             printf("?IF: strings too long\n");
  10177.             return(-2);
  10178.         }
  10179.         tp = lp + x + 2;                /* tp points to second string */
  10180.         strcpy(tp,s);                   /* safe (checked) */
  10181.         x = ckstrcmp(lp,tp,-1,inpcas[cmdlvl]); /* Use longest length */
  10182.         switch (ifc) {
  10183.           case XXIFEQ:                  /* IF EQUAL (string comparison) */
  10184.             z = (x == 0);
  10185.             break;
  10186.           case XXIFLL:                  /* IF Lexically Less Than */
  10187.             z = (x < 0);
  10188.             break;
  10189.           case XXIFLG:                  /* If Lexically Greater Than */
  10190.             z = (x > 0);
  10191.             break;
  10192.         }
  10193.         debug(F101,"IF EQ result","",z);
  10194.         ifargs += 3;
  10195.         break;
  10196.  
  10197.       case XXIFVE:                      /* IF VERSION */
  10198.       case XXIFAE:                      /* IF (arithmetically) = */
  10199.       case XXIFNQ:                      /* IF != (not arithmetically equal) */
  10200.       case XXIFLT:                      /* IF <  */
  10201.       case XXIFLE:                      /* IF <= */
  10202.       case XXIFGE:                      /* IF >= */
  10203.       case XXIFGT: {                    /* IF >  */
  10204.  
  10205.         /* Really should use longs here... */
  10206.         /* But cmnum parses ints. */
  10207.         int xx, n1 = 0, n2 = 0;
  10208.         if (ifc == XXIFVE) {
  10209.             n1 = (int) vernum;
  10210.         } else {
  10211.             x = cmfld("first number or variable name","",&s,xxstring);
  10212.             if (x == -3) {
  10213.                 printf("?Quantity required\n");
  10214.                 return(-9);
  10215.             }
  10216.             if (x < 0) return(x);
  10217.             debug(F101,"xxifgt cmfld","",x);
  10218.             ckstrncpy(line,s,LINBUFSIZ);
  10219.             lp = brstrip(line);
  10220.             debug(F110,"xxifgt exp1",lp,0);
  10221.  
  10222. /* The following bit is for compatibility with old versions of MS-DOS Kermit */
  10223.  
  10224.             if (!ckstrcmp(lp,"count",5,0)) {
  10225.                 n1 = count[cmdlvl];
  10226.             } else if (!ckstrcmp(lp,"version",7,0)) {
  10227.                 n1 = (int) vernum;
  10228.             } else if (!ckstrcmp(lp,"argc",4,0)) {
  10229.                 n1 = (int) macargc[maclvl];
  10230.             } else {
  10231.  
  10232. /* End of compatibility bit */
  10233.  
  10234. #ifdef FNFLOAT
  10235.                 if (isfloat(lp,0) > 1) { /* Allow floating-point comparisons */
  10236.                     f1 = floatval;
  10237.                     f1flag = 1;
  10238.                 } else
  10239. #endif /* FNFLOAT */
  10240.                   if (chknum(lp)) {
  10241.                       n1 = atoi(lp);
  10242.                   } else {              /* Check for arithmetic expression */
  10243.                       q = evala(lp);    /* cmnum() does this but ... */
  10244.                       if (chknum(q)) {    /* we're not using cmnum(). */
  10245.               n1 = atoi(q);
  10246.               } else {
  10247.               printf("?Value not numeric - %s", lp);
  10248.               return(-9);
  10249.               }
  10250.                   }
  10251.             }
  10252.         }
  10253.         y = cmfld("number or variable name","",&s,xxstring);
  10254.         if (y == -3) {
  10255.             printf("?Quantity required\n");
  10256.             return(-9);
  10257.         }
  10258.         if (y < 0) return(y);
  10259.         s = brstrip(s);
  10260.         if (!*s) return(-2);
  10261.         if (ifc == XXIFVE) {
  10262.             tp = line;
  10263.         } else {
  10264.             x = (int)strlen(lp);
  10265.             tp = line + x + 2;
  10266.         }
  10267.         ckstrncpy(tp,s,LINBUFSIZ-x-2);
  10268.         debug(F110,"xxifgt exp2",tp,0);
  10269.         if (!ckstrcmp(tp,"count",5,0)) {
  10270.             n2 = count[cmdlvl];
  10271.         } else if (!ckstrcmp(tp,"version",7,0)) {
  10272.             n2 = (int) vernum;
  10273.         } else if (!ckstrcmp(tp,"argc",4,0)) {
  10274.             n2 = (int) macargc[maclvl];
  10275.         } else {
  10276. #ifdef FNFLOAT
  10277.             if (isfloat(tp,0) > 1) {
  10278.                 f2 = floatval;
  10279.                 f2flag = 1;
  10280.             } else
  10281. #endif /* FNFLOAT */
  10282.             if (chknum(tp)) {
  10283.                 n2 = atoi(tp);
  10284.             } else {
  10285.                 q = evala(tp);
  10286.         if (chknum(q)) {    /* we're not using cmnum(). */
  10287.             n2 = atoi(q);
  10288.         } else {
  10289.             printf("?Value not numeric - %s", tp);
  10290.             return(-9);
  10291.         }
  10292.             }
  10293.         }
  10294.         xx = (ifc == XXIFVE) ? XXIFGE : ifc;
  10295.  
  10296. #ifdef FNFLOAT
  10297.         if (f1flag && !f2flag) {
  10298.             f2 = (CKFLOAT)n2;
  10299.             f2flag = 1;
  10300.         }
  10301.         if (f2flag && !f1flag)
  10302.           f1 = (CKFLOAT)n1;
  10303.         if (f1flag)
  10304.           z = ((f1 <  f2 && xx == XXIFLT)
  10305.                || (f1 != f2 && xx == XXIFNQ)
  10306.                || (f1 <= f2 && xx == XXIFLE)
  10307.                || (f1 == f2 && xx == XXIFAE)
  10308.                || (f1 >= f2 && xx == XXIFGE)
  10309.                || (f1 >  f2 && xx == XXIFGT));
  10310.         else
  10311. #endif /* FNFLOAT */
  10312.           z = ((n1 <  n2 && xx == XXIFLT)
  10313.                || (n1 != n2 && xx == XXIFNQ)
  10314.                || (n1 <= n2 && xx == XXIFLE)
  10315.                || (n1 == n2 && xx == XXIFAE)
  10316.                || (n1 >= n2 && xx == XXIFGE)
  10317.                || (n1 >  n2 && xx == XXIFGT));
  10318.         debug(F101,"xxifge z","",z);
  10319.         if (ifc == XXIFVE)
  10320.           ifargs += 2;
  10321.         else
  10322.           ifargs += 3;
  10323.         break;
  10324.       }
  10325.  
  10326.       case XXIFNU:                      /* IF NUMERIC */
  10327.         x = cmfld("variable name or constant","",&s,NULL);
  10328.         if (x == -3) {
  10329.             extern int cmflgs;
  10330.             if (cmflgs == 1) {
  10331.                 printf("?Quantity required\n");
  10332.                 return(-9);
  10333.             }
  10334.         } else if (x < 0)
  10335.           return(x);
  10336.         x = LINBUFSIZ-1;
  10337.         lp = line;
  10338.         zzstring(s,&lp,&x);
  10339.         lp = line;
  10340.         debug(F110,"xxifnu quantity",lp,0);
  10341.         z = chknum(lp);
  10342. #ifdef COMMENT
  10343. /*
  10344.   This works, but it's not wise -- IF NUMERIC is mostly used to see if a
  10345.   string really does contain only numeric characters.  If they want to force
  10346.   evaluation, they can use \feval() on the argument string.
  10347. */
  10348.         if (!z) {                       /* Not a number */
  10349.             x_ifnum = 1;                /* Avoid "eval" error messages */
  10350.             q = evala(lp);              /* Maybe it's an expression */
  10351.             z = chknum(q);              /* that evaluates to a number */
  10352.             x_ifnum = 0;                /* Put eval messages back to normal */
  10353.             if (z) debug(F110,"xxifnu exp",lp,0);
  10354.         }
  10355. #endif /* COMMENT */
  10356.         debug(F101,"xxifnu chknum","",z);
  10357.         ifargs += 2;
  10358.         break;
  10359.  
  10360. #ifdef ZFCDAT
  10361.       case XXIFNE: {                    /* IF NEWER */
  10362.         char d1[20], * d2;              /* Buffers for 2 dates */
  10363.         if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
  10364.           return(z);
  10365.         ckstrncpy(d1,zfcdat(s),20);
  10366.         if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
  10367.           return(z);
  10368.         d2 = zfcdat(s);
  10369.         if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
  10370.             printf("?Failure to get file date\n");
  10371.             return(-9);
  10372.         }
  10373.         debug(F110,"xxifnewer d1",d1,0);
  10374.         debug(F110,"xxifnewer d2",d2,0);
  10375.         z = (strcmp(d1,d2) > 0) ? 1 : 0;
  10376.         debug(F101,"xxifnewer","",z);
  10377.         ifargs += 2;
  10378.         break;
  10379.       }
  10380. #endif /* ZFCDAT */
  10381.  
  10382. #ifdef CK_IFRO
  10383.       case XXIFRO:                      /* REMOTE-ONLY advisory */
  10384.         ifargs++;
  10385. #ifdef NOLOCAL
  10386.         z = 1;
  10387. #else
  10388.         z = remonly;
  10389. #endif /* NOLOCAL */
  10390.         break;
  10391. #endif /* CK_IFRO */
  10392.  
  10393.       case XXIFAL:                      /* ALARM */
  10394.         ifargs++;
  10395.         debug(F101,"IF ALARM ck_alarm","",ck_alarm);
  10396.         debug(F110,"IF ALARM alrm_date",alrm_date,0);
  10397.         debug(F110,"IF ALARM alrm_time",alrm_time,0);
  10398.  
  10399.         if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
  10400.             z = 0;                      /* ALARM not SET */
  10401.             break;                      /* so IF ALARM fails */
  10402.         }
  10403.         /* Get current date and time */
  10404.         ckstrncpy(tmpbuf,ckcvtdate("",1),TMPBUFSIZ);
  10405.         s = tmpbuf;
  10406.         s[8] = NUL;
  10407.         z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
  10408.         debug(F101,"IF ALARM date z","",z);
  10409.         if (z == 0) {                   /* Dates are the same */
  10410.             /* Compare times */
  10411.             z = (tod2sec(tmpbuf+9) >= atol(alrm_time)) ? 1 : -1;
  10412.             debug(F101,"IF ALARM time z","",z);
  10413.         }
  10414.         tmpbuf[0] = NUL;                /* z >= 0 if alarm is passed */
  10415.         z = ((z >= 0) ? 1 : 0);         /* z <  0 otherwise */
  10416.         debug(F101,"IF ALARM final z","",z);
  10417.         break;
  10418.  
  10419.       case XXIFOP:                      /* IF OPEN */
  10420.         if ((x = cmkey(iotab,niot,"file or log","",xxstring)) < 0)
  10421.           return(x);
  10422.         if (x == 9999 || x == ZSTDIO) {
  10423.             bgchk();                    /* Check background status */
  10424.             z = pflag ? 1 : 0;
  10425.         } else if (x == 8888) {
  10426.             z = local ? ttchk() > -1 : 0;
  10427. #ifdef CKLOGDIAL
  10428.         } else if (x == 7777) {
  10429.             extern int dialog;
  10430.             z = dialog ? 1 : 0;
  10431. #endif /* CKLOGDIAL */
  10432.         } else
  10433.           z = (chkfn(x) > 0) ? 1 : 0;
  10434.         ifargs += 1;
  10435.         break;
  10436.  
  10437.       case XXIFSD:                      /* Started-From-Dialer */
  10438. #ifdef OS2
  10439.         z = StartedFromDialer;
  10440. #else
  10441.         z = 0;
  10442. #endif /* OS2 */
  10443.         break;
  10444.  
  10445.       case XXIFTM:                      /* Terminal-Macro */
  10446. #ifdef OS2
  10447.         z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
  10448. #else
  10449.         z = 0;
  10450. #endif /* OS2 */
  10451.         break;
  10452.  
  10453.       case XXIFEM:                      /* Emulation is active */
  10454. #ifdef OS2
  10455.         z = 1;
  10456. #else
  10457.         z = 0;
  10458. #endif /* OS2 */
  10459.         break;
  10460.  
  10461.       case XXIFIK:                      /* Running as IKSD? */
  10462.         z = inserver;
  10463.         break;
  10464.  
  10465.       case XXIFTA:                      /* Connection is TAPI */
  10466.         z = 0;
  10467. #ifndef NODIAL
  10468. #ifdef CK_TAPI
  10469.         if (local && !network && tttapi)
  10470.           z = 1;
  10471. #endif /* CK_TAPI */
  10472. #endif /* NODIAL */
  10473.         break;
  10474.  
  10475.       case XXIFMA:                      /* IF MATCH */
  10476.         x = cmfld("String or variable","",&s,xxstring);
  10477.         if (x == -3) {
  10478.             extern int cmflgs;
  10479.             if (cmflgs == 1) {
  10480.                 printf("?String required\n");
  10481.                 return(-9);
  10482.             }
  10483.         } else if (x < 0)
  10484.           return(x);
  10485.         ckstrncpy(line,s,LINBUFSIZ);
  10486.         s = brstrip(line);
  10487.         debug(F110,"xxifma string",line,0);
  10488.         x = cmfld("Pattern","",&p,xxstring);
  10489.         if (x == -3) {
  10490.             extern int cmflgs;
  10491.             if (cmflgs == 1) {
  10492.                 printf("?Pattern required\n");
  10493.                 return(-9);
  10494.             }
  10495.         } else if (x < 0)
  10496.           return(x);
  10497.         ckstrncpy(tmpbuf,p,TMPBUFSIZ);
  10498.         p = brstrip(tmpbuf);
  10499.         debug(F110,"xxifma pattern",tmpbuf,0);
  10500.         z = ckmatch(p,s,inpcas[cmdlvl],1);
  10501.         break;
  10502.  
  10503.       case XXIFFL: {                    /* IF FLAG */
  10504.           extern int ooflag;
  10505.           z = ooflag;
  10506.           break;
  10507.       }
  10508.       case XXIFAV: {                    /* IF AVAILABLE */
  10509.           if ((x = cmkey(availtab,availtabn,"","",xxstring)) < 0)
  10510.             return(x);
  10511.           switch (x) {
  10512.             case AV_KRB4:
  10513.               z = ck_krb4_is_installed();
  10514.               break;
  10515.             case AV_KRB5:
  10516.               z = ck_krb5_is_installed();
  10517.               break;
  10518.             case AV_SRP:
  10519.               z = ck_srp_is_installed();
  10520.               break;
  10521.             case AV_SSL:
  10522.               z = ck_ssleay_is_installed();
  10523.               break;
  10524.             case AV_NTLM:
  10525.               z = ck_ntlm_is_installed();
  10526.               break;
  10527.             case AV_CRYPTO:
  10528.               z = ck_crypt_is_installed();
  10529.               break;
  10530.             case AV_SSH:
  10531.               z = ck_ssh_is_installed();
  10532.               break;
  10533.             default:
  10534.               z = 0;
  10535.           }
  10536.           break;
  10537.       }
  10538.       case XXIFAT:                      /* IF ASKTIMEOUT */
  10539.         z = asktimedout;
  10540.         break;
  10541.  
  10542.       case XXIFRD:                      /* IF READABLE */
  10543.       case XXIFWR:                      /* IF WRITEABLE */
  10544.         if ((x = cmfld("File or directory name",
  10545.                        "",
  10546.                        &s,
  10547. #ifdef OS2
  10548.                        NULL             /* This allows \'s in filenames */
  10549. #else
  10550.                        xxstring
  10551. #endif /* OS2 */
  10552.                        )) < 0) {
  10553.             if (x == -3) {
  10554.                 extern int cmflgs;
  10555.                 if (cmflgs == 1) {
  10556.                     printf("?File or directory name required\n");
  10557.                     return(-9);
  10558.                 }
  10559.             } else return(x);
  10560.         }
  10561.         s = brstrip(s);
  10562. /*
  10563.   zchk[io]() do not do what we want here for directories, so we set
  10564.   a global flag telling it to behave specially in this case.  Othewise
  10565.   we'd have to change the API and change all ck?fio.c modules accordingly.
  10566. */
  10567.         y = 0;                          /* Try-again control */
  10568. #ifdef OS2
  10569.   ifrdagain:
  10570. #endif /* OS2 */
  10571.         if (ifc == XXIFRD) {            /* IF READABLE */
  10572.             zchkid = 1;
  10573.             z = zchki(s) > -1;
  10574.             zchkid = 0;
  10575.         } else if (ifc == XXIFWR) {     /* IF WRITEABLE */
  10576.             zchkod = 1;
  10577.             z = zchko(s) > -1;
  10578.             zchkod = 0;
  10579.         }
  10580. #ifdef OS2
  10581.         if (!z && !y) {                 /* File not found. */
  10582.             int t;                      /* Try expanding variables */
  10583.             t = LINBUFSIZ-1;            /* and looking again. */
  10584.             lp = line;
  10585.             zzstring(s,&lp,&t);
  10586.             s = line;
  10587.             z = zchko(s) > -1;
  10588.             y++;
  10589.             goto ifrdagain;
  10590.         }
  10591. #endif /* OS2 */
  10592.         ifargs += 2;
  10593.         break;
  10594.       case XXIFQU:                      /* IF QUIET */
  10595.         z = quiet ? 1 : 0;
  10596.         debug(F101,"if quiet","",z);
  10597.         ifargs += 1;
  10598.         break;
  10599.  
  10600.       case XXIFWI:                      /* WILD */
  10601.         if ((x = cmfld("File specification","",&s,xxstring)) < 0) return(x);
  10602.         z = iswild(s);
  10603.         break;
  10604.  
  10605.       case XXIFCK:                      /* C-KERMIT */
  10606. #ifdef OS2
  10607.         z = 0;
  10608. #else
  10609.         z = 1;
  10610. #endif /* OS2 */
  10611.         break;
  10612.  
  10613.       case XXIFK9:                      /* K-95 */
  10614. #ifdef OS2
  10615.         z = 1;
  10616. #else
  10617.         z = 0;
  10618. #endif /* OS2 */
  10619.         break;
  10620.  
  10621.       case XXIFGU:                      /* GUI */
  10622. #ifdef KUI
  10623.         z = 1;
  10624. #else
  10625.         z = 0;
  10626. #endif /* KUI */
  10627.         break;
  10628.  
  10629.       case XXIFMS:                      /* MS-KERMIT */
  10630.         z = 0;
  10631.         break;
  10632.  
  10633.       case XXIFLO:                      /* IF LOCAL */
  10634.         z = local ? 1 : 0;
  10635.         break;
  10636.  
  10637.       case XXIFCM: {                    /* IF COMMAND */
  10638.           extern struct keytab cmdtab[];
  10639.           extern int ncmd;
  10640.           if ((x = cmfld("Word","",&s,xxstring)) < 0)
  10641.             return(x);
  10642.           z = lookup(cmdtab,s,ncmd,&y);
  10643.           z = (z == -2 || z > -1) ? 1 : 0;
  10644.           break;
  10645.       }
  10646. #ifdef CKFLOAT
  10647.       case XXIFFP:                      /* IF FLOAT */
  10648.         if ((x = cmfld("Number","",&s,xxstring)) < 0)
  10649.           if (x != -3)                  /* e.g. empty variable */
  10650.             return(x);
  10651.         z = isfloat(s,0);
  10652.         break;
  10653. #endif /* CKFLOAT */
  10654.  
  10655.       case XXIFKB:                      /* KBHIT */
  10656.         z = conchk();
  10657.         if (z < 0) z = 0;
  10658.         if (z > 1) z = 1;
  10659.         break;
  10660.  
  10661.       case XXIFKG: {                    /* KERBANG */
  10662.           extern int cfilef;
  10663.           z = (xcmdsrc == 0) ? 0 : (cfilef && cmdlvl == 1);
  10664.           break;
  10665.       }
  10666.  
  10667.       default:                          /* Shouldn't happen */
  10668.         return(-2);
  10669.     } /* end of switch */
  10670.  
  10671.     if (z)
  10672.       *bx++ = '1';
  10673.     else
  10674.       *bx++ = '0';
  10675.     *bx = NUL;
  10676.     if (bx > boolval + BOOLLEN - 2) {
  10677.         printf("?Boolean expression too long");
  10678.         return(-9);
  10679.     }
  10680.     ecount++;                           /* Expression counter */
  10681.     debug(F101,"boolexp parens","",parens);
  10682.     debug(F101,"boolexp pcount","",pcount);
  10683.     if (parens && pcount > 0)
  10684.       goto ifagain;
  10685.  
  10686.   ifend:                                /* No more - done */
  10687.     *bx = NUL;
  10688.     z = atoi(evalx(boolval));
  10689.     debug(F111,"boolexp boolval",boolval,z);
  10690.     return(z);
  10691. }
  10692.  
  10693. /*  D O I F  --  Do the IF command  */
  10694.  
  10695. int
  10696. doif(cx) int cx; {
  10697.     int x, y, z; char *s, *p;
  10698.     char *q;
  10699. #ifdef OS2
  10700.     extern int keymac;
  10701. #endif /* OS2 */
  10702.  
  10703.     debug(F101,"doif cx","",cx);
  10704.  
  10705.     z = boolexp(cx);                    /* Evaluate the condition(s) */
  10706.     debug(F010,"doif cmdbuf",cmdbuf,0);
  10707.     debug(F101,"doif boolexp","",z);
  10708.     if (z < 0)
  10709.       return(z);
  10710.  
  10711.     if (cx == XXIF) {                   /* Allow IF to have XIF semantics. */
  10712.         char * p;
  10713.         p = cmpeek();
  10714.         if (!p) p = "";
  10715.         while (*p) {
  10716.             if (*p == SP || *p == HT)
  10717.               p++;
  10718.             else
  10719.               break;
  10720.         }
  10721.         if (*p == '{')
  10722.           cx = XXIFX;
  10723.     }
  10724.     switch (cx) {                       /* Separate handling for IF and XIF */
  10725.  
  10726.       case XXASSER:                     /* And ASSERT */
  10727.         if ((x = cmcfm()) < 0)
  10728.           return(x);
  10729.         return(success = z);
  10730.  
  10731.       case XXIF:                        /* This is IF... */
  10732.         ifcmd[cmdlvl] = 1;              /* We just completed an IF command */
  10733.         debug(F101,"doif condition","",z);
  10734.         if (z) {                        /* Condition is true */
  10735.             iftest[cmdlvl] = 1;         /* Remember that IF succeeded */
  10736.             if (maclvl > -1) {          /* In macro, */
  10737.                 pushcmd(NULL);          /* save rest of command. */
  10738.             } else if (tlevel > -1) {   /* In take file, */
  10739.                 debug(F100, "doif: pushing command", "", 0);
  10740.                 pushcmd(NULL);          /* save rest of command. */
  10741.             } else {                    /* If interactive, */
  10742.                 cmini(ckxech);          /* just start a new command */
  10743.                 printf("\n");           /* (like in MS-DOS Kermit) */
  10744.                 if (pflag) prompt(xxstring);
  10745.             }
  10746.         } else {                        /* Condition is false */
  10747.             iftest[cmdlvl] = 0;         /* Remember command failed. */
  10748.             if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  10749.               return(y);                /* Gobble up rest of line */
  10750.         }
  10751.         return(0);
  10752.  
  10753.       case XXIFX: {                     /* This is XIF (Extended IF) */
  10754.           char *p;
  10755.           char e[5];
  10756.           int i;
  10757.           if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  10758.             return(y);                  /* Get object command. */
  10759.           p = s;
  10760.           lp = line;
  10761.           debug(F110,"doif THEN part",s,-54);
  10762.           if (litcmd(&p,&lp,LINBUFSIZ - 1) < 0) { /* Quote THEN-part */
  10763.               return(-2);
  10764.           }
  10765.           debug(F111,"doif THEN part 2",line,z);
  10766.  
  10767.           while (*p == SP) p++;         /* Strip trailing spaces */
  10768.           ifcmd[cmdlvl] = 0;            /* Assume ELSE part in same line */
  10769.           iftest[cmdlvl] = z ? 1 : 0;
  10770.           if (*p) {                     /* At end? */
  10771.               if (!z) {                 /* No, use ELSE-part, if any */
  10772.                   for (i = 0; i < 4; i++) e[i] = *p++;
  10773.                   if (ckstrcmp(e,"else",4,0)) /* See if we have an ELSE */
  10774.                     return(-2);         /* Something else - error. */
  10775.                   debug(F010,"doif ELSE line 1",p,0);
  10776.                   while (*p == SP) p++; /* Skip spaces */
  10777.                   if (*p != '{') {      /* Brace ELSE part if necessary */
  10778.                       ckmakmsg(tmpbuf,TMPBUFSIZ,"{",p," }",NULL);
  10779.                       p = tmpbuf;
  10780.                       debug(F010,"doif ELSE line 2",p,0);
  10781.                   }
  10782.                   lp = line;            /* Write over THEN part... */
  10783.                   *lp = NUL;            /* with ELSE part. */
  10784.                   if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) {
  10785.                       return(-2);
  10786.                   }
  10787.                   while (*p == SP) p++; /* Strip trailing spaces */
  10788.                   if (*p) return(-2);   /* Should be nothing here. */
  10789.                   debug(F010,"doif ELSE line 3",line,0);
  10790.               }
  10791.           } else {                      /* At end, treat like an IF command */
  10792.               if (!z) line[0] = NUL;    /* Condition not true and no ELSE */
  10793.               ifcmd[cmdlvl] = 1;        /* Allow ELSE on next line */
  10794.               debug(F101,"IF condition","",z);
  10795.           }
  10796.           if (line[0]) {
  10797.               x = mlook(mactab,"_xif",nmac); /* Get index of "_xif" macro. */
  10798.               if (x < 0) {                      /* Not there? */
  10799.                   addmmac("_xif",xif_def);      /* Put it back. */
  10800.                   if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
  10801.                       printf("?XIF macro gone!\n");
  10802.                       return(success = 0);
  10803.                   }
  10804.               }
  10805.               dodo(x,line,cmdstk[cmdlvl].ccflgs | CF_IMAC);
  10806.           }
  10807.           return(0);
  10808.       }
  10809.       case XXWHI: {                     /* WHILE Command */
  10810.           p = cmdbuf;                   /* Capture IF condition */
  10811.           ifcond[0] = NUL;              /* from command buffer */
  10812.           while (*p == SP) p++;
  10813.           while (*p != SP) p++;
  10814.           ifcp = ifcond;
  10815.           ifcp += ckstrncpy(ifcp,"{ \\flit(if ( not ",IFCONDLEN);
  10816. #ifdef COMMENT
  10817. /*
  10818.   This doesn't work because it breaks on the first left brace, which does
  10819.   not necessarily start the command list, e.g. "while equal \%a {\35}".
  10820. */
  10821.           while (*p != '{' && *p != NUL) *ifcp++ = *p++;
  10822.           p = " ) goto _..bot) } ";
  10823.           while (*ifcp++ = *p++) ;
  10824. #else
  10825. /*
  10826.   The command parser sets cmbptr to the spot where it left off parsing in
  10827.   the command buffer.
  10828. */
  10829.           {
  10830.               extern char * cmbptr;
  10831.               if (cmbptr) {
  10832.                   while (p < cmbptr && *p != NUL)
  10833.                     *ifcp++ = *p++;
  10834.                   p = " ) goto _..bot) } ";
  10835.                   while ((*ifcp++ = *p++)) ;
  10836.               } else {
  10837.                   printf("?Internal error parsing WHILE condition\n");
  10838.                   return(-9);
  10839.               }
  10840.           }
  10841. #endif /* COMMENT */
  10842.  
  10843.           debug(F110,"WHILE cmd",ifcond,0);
  10844.  
  10845.           if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  10846.             return(y);                  /* Get object command. */
  10847.           p = s;
  10848.           lp = line;
  10849.           if (litcmd(&p,&lp,LINBUFSIZ - 2) < 0) { /* Quote object command */
  10850.               return(-2);
  10851.           }
  10852.           debug(F101,"WHILE body",line,-54);
  10853.           if (line[0]) {
  10854.               char *p;
  10855.               x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
  10856.               if (x < 0) {              /* Not there? */
  10857.                   addmmac("_while",whil_def); /* Put it back. */
  10858.                   if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
  10859.                       printf("?WHILE macro definition gone!\n");
  10860.                       return(success = 0);
  10861.                   }
  10862.               }
  10863.               p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
  10864.               if (p) {
  10865.                   strcpy(p,ifcond);     /* safe (prechecked) */
  10866.                   strcat(p,line);       /* safe (prechecked) */
  10867.                   debug(F010,"WHILE dodo",p,0);
  10868.                   dodo(x,p,cmdstk[cmdlvl].ccflgs | CF_IMAC);
  10869.                   free(p);
  10870.                   p = NULL;
  10871.               } else {
  10872.                   printf("?Can't allocate storage for WHILE command");
  10873.                   return(success = 0);
  10874.               }
  10875.           }
  10876.           return(0);
  10877.       }
  10878.       default:
  10879.         return(-2);
  10880.     }
  10881. }
  10882. #endif /* NOSPL */
  10883.  
  10884. /* Set up a TAKE command file */
  10885.  
  10886. int
  10887. dotake(s) char *s; {
  10888. #ifndef NOSPL
  10889.     extern int tra_cmd;
  10890. #endif /* NOSPL */
  10891. #ifndef NOLOCAL
  10892. #ifdef OS2
  10893.     extern int term_io;
  10894.     int term_io_sav = term_io;
  10895. #endif /* OS2 */
  10896. #endif /* NOLOCAL */
  10897.     int slen;
  10898.  
  10899.     debug(F110,"dotake",s,0);
  10900.     if (!s) s = "";
  10901.     if (!*s) return(success = 0);
  10902.     slen = strlen(s);
  10903.     debug(F101,"dotake len","",slen);
  10904.  
  10905.     if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
  10906.         perror(s);
  10907.         debug(F110,"dotake fail",s,0);
  10908.         tlevel--;
  10909.         return(success = 0);
  10910.     } else {
  10911.         tfline[tlevel] = 0;             /* Line counter */
  10912. #ifdef VMS
  10913.         conres();                       /* So Ctrl-C will work */
  10914. #endif /* VMS */
  10915. #ifndef NOLOCAL
  10916. #ifdef OS2
  10917.         term_io = 0;                    /* Disable Terminal Emulator I/O */
  10918. #endif /* OS2 */
  10919. #endif /* NOLOCAL */
  10920. #ifndef NOSPL
  10921.         cmdlvl++;                       /* Entering a new command level */
  10922.         debug(F111,"CMD +F",s,cmdlvl);
  10923.         debug(F101,"dotake cmdlvl","",cmdlvl);
  10924.         debug(F101,"dotake tlevel","",tlevel);
  10925.         if (cmdlvl > CMDSTKL) {
  10926.             debug(F100,"dotake stack overflow","",0);
  10927.             cmdlvl--;
  10928.             debug(F111,"CMD*-F",s,cmdlvl);
  10929.             fclose(tfile[tlevel--]);
  10930.             printf("?TAKE files and/or DO commands nested too deeply\n");
  10931.             return(success = 0);
  10932.         }
  10933.         if (tfnam[tlevel]) {            /* Copy the filename */
  10934.             free(tfnam[tlevel]);
  10935.             tfnam[tlevel] = NULL;
  10936.         }
  10937.         if ((tfnam[tlevel] = malloc(strlen(s) + 1))) {
  10938.             strcpy(tfnam[tlevel],s);    /* safe */
  10939.         } else {
  10940.             printf("?Memory allocation failure\n");
  10941.             return(success = 0);
  10942.         }
  10943.         ifcmd[cmdlvl] = 0;              /* Set variables for this cmd file */
  10944.         iftest[cmdlvl] = 0;
  10945.         count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
  10946.         intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
  10947.         inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
  10948.         takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
  10949.         merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
  10950.         xquiet[cmdlvl] = quiet;
  10951.         xcmdsrc = CMD_TF;
  10952.         cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
  10953.         cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
  10954.         cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
  10955. #else
  10956.         takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
  10957. #endif /* NOSPL */
  10958.     }
  10959. #ifndef NOSPL
  10960.     if (tra_cmd)
  10961.       printf("[%d] +F: \"%s\"\n",cmdlvl,s);
  10962. #endif /* NOSPL */
  10963. #ifndef NOLOCAL
  10964. #ifdef OS2
  10965.     term_io = term_io_sav;
  10966. #endif /* OS2 */
  10967. #endif /* NOLOCAL */
  10968.     return(1);
  10969. }
  10970. #endif /* NOICP */
  10971.