home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit60 / ckuus6.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  112KB  |  4,193 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.   Author: Frank da Cruz (fdc@columbia.edu),
  8.   Columbia University Academic Information Systems, New York City.
  9.  
  10.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  11.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  12.   sold for profit as a software product itself, nor may it be included in or
  13.   distributed with commercial products or otherwise distributed by commercial
  14.   concerns to their clients or customers without written permission of the
  15.   Office of Kermit Development and Distribution, Columbia University.  This
  16.   copyright notice must not be removed, altered, or obscured.
  17. */
  18.  
  19. /* 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 datageneral
  30. #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
  31. #endif /* datageneral */
  32.  
  33. /* External Kermit Variables, see ckmain.c for description. */
  34.  
  35. extern xx_strp xxstring;
  36.  
  37. extern int size, rpsiz, urpsiz, local, stdinf, sndsrc, xitsta,
  38.   displa, binary, parity, escape, flow, cmd_rows,
  39.   turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf,
  40.   turnch, dfloc, keep, maxrps, warn, cnflg, tlevel, pflag, msgflg,
  41.   mdmtyp, zincnt, fblksiz, frecl, frecfm, atcapr, atdiso, verwho, quiet;
  42. extern int repars, techo, network;
  43.  
  44. #ifdef CK_IFRO
  45. extern int remonly;
  46. #endif /* CK_IFRO */
  47.  
  48. #ifdef OS2
  49. extern int StartedFromDialer ;
  50. #ifndef NT
  51. #define INCL_NOPM
  52. #define INCL_VIO            /* Needed for ckocon.h */
  53. #include <os2.h> 
  54. #undef COMMENT
  55. #else 
  56. #define APIRET ULONG
  57. #include <windows.h>
  58. #endif /* NT */
  59. #include "ckocon.h"
  60. #endif /* OS2 */
  61.  
  62. extern long vernum, speed;
  63. extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
  64. extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[], *sw_def[];
  65. extern char *ckxsys, *ckzsys, *cmarg, *cmarg2;
  66. extern char *DIRCMD, *PWDCMD, *DELCMD, *WHOCMD, ttname[], filnam[];
  67. extern CHAR sstate;
  68. extern char *zinptr;
  69.  
  70. #ifndef NOMSEND                /* Multiple SEND */
  71. extern char *msfiles[];
  72. #endif /* NOMSEND */
  73. extern char fspec[];            /* Most recent filespec */
  74.  
  75. #ifdef CK_TMPDIR
  76. extern int f_tmpdir;            /* Directory changed temporarily */
  77. extern char savdir[];            /* For saving current directory */
  78. extern char * dldir;
  79. #endif /* CK_TMPDIR */
  80.  
  81. /* Declarations from cmd package */
  82.  
  83. #ifdef DCMDBUF
  84. extern char *cmdbuf, *atmbuf;        /* Command buffers */
  85. #else
  86. extern char cmdbuf[], atmbuf[];        /* Command buffers */
  87. #endif /* DCMDBUF */
  88.  
  89. #ifndef NOPUSH
  90. extern int nopush ;
  91. #endif /* NOPUSH */
  92.  
  93. #ifndef NOSPL
  94. extern struct mtab *mactab;
  95. extern int nmac;
  96. extern long ck_alarm;
  97. extern char alrm_date[], alrm_time[];
  98. extern int x_ifnum;
  99. #endif /* NOSPL */
  100.  
  101. /* Declarations from ck?fio.c module */
  102.  
  103. extern int backgrd;            /* Kermit executing in background */
  104.  
  105. #ifdef COMMENT
  106. /*
  107.   These must be on stack!
  108. */
  109. #ifndef NOSPL
  110. extern char vnambuf[];            /* Buffer for variable names */
  111. extern char *vnp;            /* Pointer to same */
  112. #endif /* NOSPL */
  113. #endif /* COMMENT */
  114.  
  115. extern char psave[];            /* For saving & restoring prompt */
  116. extern char *tp;            /* Temporary buffer */
  117.  
  118. int readblock = 4096;            /* READ buffer size */
  119. CHAR * readbuf = NULL;            /* Pointer to read buffer */
  120. int readsize = 0;            /* Number of chars actually read */
  121.  
  122. /* Keyword tables specific to this module */
  123.  
  124. /* Modem signal table */
  125.  
  126. struct keytab mstab[] = {
  127. #ifdef COMMENT
  128. /* The forms preceded by backslash are for MS-DOS Kermit compatibility. */
  129. /* But... \dsr doesn't work because \d = decimal constant introducer */
  130.     "\\cd",  BM_DCD, CM_INV,        /* Carrier Detect */
  131.     "\\cts", BM_CTS, CM_INV,        /* Clear To Send  */
  132.     "\\dsr", BM_DSR, CM_INV,        /* Data Set Ready */
  133.     "\\ri",  BM_RNG, CM_INV,        /* Ring Indicator */
  134. #endif /* COMMENT */
  135.     "cd",    BM_DCD, 0,            /* Carrier Detect */
  136.     "cts",   BM_CTS, 0,            /* Clear To Send  */
  137.     "dsr",   BM_DSR, 0,            /* Data Set Ready */
  138.     "ri",    BM_RNG, 0            /* Ring Indicator */
  139. };
  140. int nms = (sizeof(mstab) / sizeof(struct keytab));
  141.  
  142. #ifndef NOSPL
  143. struct keytab opntab[] = {
  144. #ifndef NOPUSH
  145.     "!read",  XYFZ_Y, 0,
  146.     "!write", XYFZ_X, 0,
  147. #endif /* NOPUSH */
  148.     "append", XYFZ_A, 0,
  149.     "read",   XYFZ_O, 0,
  150.     "write",  XYFZ_N, 0
  151. };
  152. int nopn = (sizeof(opntab) / sizeof(struct keytab));
  153.  
  154. struct keytab iftab[] = {        /* IF commands */
  155.     "<",          XXIFLT, 0,
  156.     "=",          XXIFAE, 0,
  157.     ">",          XXIFGT, 0,
  158.     "alarm",      XXIFAL, 0,
  159.     "background", XXIFBG, 0,
  160.     "count",      XXIFCO, 0,
  161.     "defined",    XXIFDE, 0,
  162. #ifdef CK_TMPDIR
  163.     "directory",  XXIFDI, 0,
  164. #endif /* CK_TMPDIR */
  165. #ifdef COMMENT
  166.     "eof",        XXIFEO, 0,
  167. #endif /* COMMENT */
  168.     "emulation",  XXIFEM, 0,
  169.     "equal",      XXIFEQ, 0,
  170.     "error",      XXIFFA, CM_INV,
  171.     "exist",      XXIFEX, 0,
  172.     "failure",    XXIFFA, 0,
  173.     "false",      XXIFNT, 0,
  174.     "foreground", XXIFFG, 0,
  175.     "llt",        XXIFLL, 0,
  176.     "lgt",        XXIFLG, 0,
  177. #ifdef OS2
  178.     "terminal-macro", XXIFTM, CM_INV,
  179. #endif /* OS2 */
  180. #ifdef ZFCDAT
  181.     "newer",      XXIFNE, 0,
  182. #endif /* ZFCDAT */
  183.     "not",        XXIFNO, 0,
  184.     "ok",         XXIFSU, CM_INV,
  185.     "numeric",    XXIFNU, 0,
  186.     "remote-only",XXIFRO, 0,
  187.     "started-from-dialer",XXIFSD, CM_INV,
  188.     "success",    XXIFSU, 0,
  189.     "true",       XXIFTR, 0
  190. };
  191. int nif = (sizeof(iftab) / sizeof(struct keytab));
  192. #endif /* NOSPL */
  193.  
  194. /* Variables and symbols local to this module */
  195.  
  196. #ifndef NODIAL 
  197. _PROTOTYP(static int ddcvt, (char *, FILE *, int) );
  198. _PROTOTYP(static int dncvt, (int, int) );
  199. _PROTOTYP(char * getdname, (void) );
  200.  
  201. char *dialnum = (char *)0;        /* Remember DIAL number for REDIAL */
  202. int dirline = 0;            /* Dial directory line number */
  203. extern char * dialdir[];        /* Dial directory file names */
  204. extern int dialdpy;            /* DIAL DISPLAY on/off */
  205. extern int ndialdir;            /* How many dial directories */
  206. #ifdef NETCONN
  207. extern int nnetdir;            /* How many network directories */
  208. #endif /* NETCONN */
  209. extern int ntollfree;            /* Toll-free call info */
  210. extern char *dialtfc[];
  211. extern int tttapi;
  212. extern int dialatmo;
  213. extern char * dialnpr, * dialsfx;
  214. extern char * diallcc;            /* Dial local country code */
  215. extern char * diallac;            /* Dial local area code */
  216. extern char * dialixp, * dialixs;
  217. extern char * dialldp, * diallds, * dialtfp;
  218. extern char * dialpxx, * dialpxi, * dialpxo;
  219. extern int dialcnf;            /* DIAL CONFIRMATION */
  220. int dialsrt = 1;            /* DIAL SORT ON */
  221. int dialrstr = 6;            /* DIAL RESTRICTION */
  222.  
  223. extern int dialsta;            /* Dial status */
  224. int dialrtr = 0,            /* Dial retries */
  225.     dialint = 10;            /* Dial retry interval */
  226. extern long dialcapas;            /* Modem capabilities */
  227. extern int dialcvt;            /* DIAL CONVERT-DIRECTORY */
  228. #endif /* NODIAL */
  229.  
  230. #ifndef NOSPL
  231. int ifc,                /* IF case */
  232.     not = 0,                /* Flag for IF NOT */
  233.     ifargs;                /* Count of IF condition words */
  234. char ifcond[100];            /* IF condition text */
  235. char *ifcp;                /* Pointer to IF condition text */
  236. #ifdef DCMDBUF
  237. extern int *ifcmd, *count, *iftest, *intime, *inpcas, *takerr, *merror;
  238. #else
  239. extern int ifcmd[];            /* Last command was IF */
  240. extern int iftest[];            /* Last IF was true */
  241. extern int count[];            /* For IF COUNT, one for each cmdlvl */
  242. extern int intime[];
  243. extern int inpcas[];
  244. extern int takerr[];
  245. extern int merror[];
  246. #endif /* DCMDBUF */
  247. #else
  248. extern int takerr[];
  249. #endif /* NOSPL */
  250.  
  251. #ifdef DCMDBUF
  252. extern char *line;            /* Character buffer for anything */
  253. extern char *tmpbuf;
  254. #else
  255. extern char line[], tmpbuf[];
  256. #endif /* DCMDBUF */
  257. extern char *lp;            /* Pointer to line buffer */
  258.  
  259. int cwdf = 0;                /* CWD has been done */
  260.  
  261. #ifndef NOSERVER
  262. /* Flags for ENABLE/DISABLE */
  263. extern int en_cwd, en_cpy, en_del, en_dir, en_fin, 
  264.    en_get, en_hos, en_ren, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
  265.    en_asg, en_que, en_ret, en_mai, en_pri;
  266. #endif /* NOSERVER */
  267.  
  268. extern FILE *tfile[];            /* File pointers for TAKE command */
  269. extern char *tfnam[];            /* Names of TAKE files */
  270. extern int tfline[];            /* TAKE-file line number */
  271.  
  272. extern int success;            /* Command success/failure flag */
  273.  
  274. #ifndef NOSPL
  275. extern int maclvl;            /* Macro to execute */
  276. extern char *macx[];            /* Index of current macro */
  277. extern char *mrval[];            /* Macro return value */
  278. extern char *macp[];            /* Pointer to macro */
  279. extern int macargc[];            /* ARGC from macro invocation */
  280.  
  281. extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
  282. extern char *g_var[];            /* Global variables %a, %b, etc */
  283.  
  284. #ifdef DCMDBUF
  285. extern struct cmdptr *cmdstk;        /* The command stack itself */
  286. #else
  287. extern struct cmdptr cmdstk[];        /* The command stack itself */
  288. #endif /* DCMDBUF */
  289. extern int cmdlvl;            /* Current position in command stack */
  290. #endif /* NOSPL */
  291.  
  292. #define xsystem(s) zsyscmd(s)
  293.  
  294. static int x, y, z = 0;
  295. static char *s, *p;
  296.  
  297. #ifdef OS2
  298. _PROTOTYP( int os2settitle, (char *, int) );
  299. #endif /* OS2 */
  300.  
  301. extern struct keytab yesno[];
  302. extern int nyesno;
  303.  
  304. #ifndef NOSPL
  305.  
  306. /* Do the ASK, ASKQ, GETOK, and READ commands */
  307.  
  308. int
  309. doask(cx) int cx; {
  310.     extern int cmflgs;
  311. #ifdef CK_RECALL
  312.     int sv_recall;
  313.     extern int on_recall;
  314. #endif /* CK_RECALL */
  315.  
  316.     char vnambuf[VNAML];        /* Buffer for variable names */
  317.     char *vnp = NULL;            /* Pointer to same */
  318.     if (cx != XXGOK && cx != XXRDBL) {    /* Get variable name */
  319.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  320.         if (y == -3) {
  321.         printf("?Variable name required\n");
  322.         return(-9);
  323.         } else return(y);
  324.     }
  325.     strcpy(vnambuf,s);        /* Make a copy. */
  326.     vnp = vnambuf;
  327.     if (vnambuf[0] == CMDQ &&
  328.         (vnambuf[1] == '%' || vnambuf[1] == '&'))
  329.       vnp++;
  330.     y = 0;
  331.     if (*vnp == '%' || *vnp == '&') {
  332.         if ((y = parsevar(vnp,&x,&z)) < 0)
  333.           return(y);
  334.     }
  335.     }
  336.     if (cx == XXREA || cx == XXRDBL) {    /* READ or READBLOCK command */
  337.     if ((y = cmcfm()) < 0)        /* Get confirmation */
  338.       return(y);
  339.     if (chkfn(ZRFILE) < 1) {    /* File open? */
  340.         printf("?Read file not open\n");
  341.         return(0);
  342.     }
  343.     if (!(s = (char *)readbuf)) {        /* Where to read into. */
  344.         printf("?Oops, no READ buffer!\n");
  345.         return(0);
  346.     }
  347. #ifdef BINREAD
  348.     if (cx == XXRDBL) {        /* READBLOCK */
  349.         y = zxin(ZRFILE, s, readblock);
  350.         if (y < 1) {
  351.         zclose(ZRFILE);        /* close the file, */
  352.         return(success = 0);
  353.         }
  354.         readsize = y;
  355.         printf("READBLOCK %d\n",y);
  356.     } else
  357. #endif /* BINREAD */
  358.       {
  359.         y = zsinl(ZRFILE, s, readblock); /* Read a line. */
  360.         debug(F111,"read zsinl",s,y);
  361.         if (y < 0) {        /* On EOF or other error, */
  362.         zclose(ZRFILE);        /* close the file, */
  363.         delmac(vnp);        /* delete the variable, */
  364.         return(success = 0);    /* and return failure. */
  365.         } else {            /* Read was OK. */
  366.         readsize = (int) strlen(s);
  367.         success = (addmac(vnp,s) < 0 ? 0 : 1); /* Define variable */
  368.         debug(F111,"read addmac",vnp,success);
  369.         return(success);    /* Return success. */
  370.         }
  371.     }
  372.     }
  373.  
  374.     /* ASK, ASKQ, or GETOK */
  375.  
  376.     if ((y = cmtxt("Prompt, enclose in { braces } to preserve\n\
  377. leading and trailing spaces, precede question mark with backslash (\\).",
  378.            cx == XXGOK ? "{ Yes or no? }" : "",
  379.            &p,NULL)) < 0) {
  380.     return(y);
  381.     }
  382. #ifdef VMS
  383. /*
  384.   In VMS, whenever a TAKE file or macro is active, we had to restore the 
  385.   original console modes or else Ctrl-C/Ctrl-Y would not work.  But here we
  386.   go interactive again, so we have to temporarily put them back.
  387. */
  388.     if (cmdlvl > 0)
  389.       concb((char)escape);
  390. #endif /* VMS */
  391.       
  392.     cmsavp(psave,PROMPTL);        /* Save old prompt */
  393.     cmsetp(brstrip(p));            /* Make new prompt */
  394. reprompt:
  395.     if (cx == XXASKQ) {            /* For ASKQ, */
  396.     concb((char)escape);        /* put console in cbreak mode */
  397.     cmini(0);            /* and no-echo mode. */
  398.     } else {                /* For others, regular echoing. */
  399.     cmini(ckxech);
  400.     }
  401.     x = -1;                /* This means to reparse. */
  402.     cmflgs = 0;
  403.     if (pflag) prompt(xxstring);    /* Issue prompt. */
  404. reparse:
  405.     cmres();
  406.     if (cx == XXGOK) {
  407. #ifdef CK_RECALL
  408.     sv_recall = on_recall;
  409.     on_recall = 0;
  410. #endif /* CK_RECALL */
  411.     x = cmkey(yesno,nyesno,"","",xxstring);    /* GETOK uses keyword table */
  412.     if (x < 0) {            /* Parse error */
  413.         if (x == -3) {        /* No answer? */
  414.         printf("Please respond Yes or No\n"); /* Make them answer */
  415.         cmini(ckxech);
  416.         goto reprompt;
  417.         } else if (x == -1) {
  418.         goto reparse;
  419.         } else
  420.           goto reprompt;
  421.     }
  422.     if (cmcfm() < 0)        /* Get confirmation */
  423.       goto reparse;
  424.     cmsetp(psave);            /* Restore prompt */
  425. #ifdef VMS
  426.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  427.       conres();            /*  restore console again. */
  428. #endif /* VMS */
  429. #ifdef CK_RECALL
  430.     on_recall = sv_recall;
  431. #endif /* CK_RECALL */
  432.     return(x);            /* Return success or failure */
  433.     } else if (cx == XXGETC) {        /* GETC */
  434.     char tmp[2];
  435.     x = coninc(0);            /* Just read one character */
  436.     if (x > -1) {
  437.         printf("\r\n");
  438.         tmp[0] = (char) (x & 0xff);
  439.         tmp[1] = NUL;
  440.         y = addmac(vnp,tmp);    /* Add it to the macro table. */
  441.         debug(F111,"getc addmac",vnp,y);
  442.         cmsetp(psave);        /* Restore old prompt. */
  443.     } else y = -1;
  444.     return(success = y < 0 ? 0 : 1);
  445.     } else {                /* ASK or ASKQ */
  446. #ifdef CK_RECALL
  447.     sv_recall = on_recall;
  448.     on_recall = 0;
  449. #endif /* CK_RECALL */
  450.     y = cmdgquo();            /* Get current quoting */
  451.     cmdsquo(0);            /* Turn off quoting */
  452.     while (x == -1) {        /* Prompt till they answer */
  453.         x = cmtxt("Please respond.","",&s,NULL);
  454.         debug(F111,"ASK cmtxt",s,x);
  455.         cmres();
  456.     }
  457.     cmdsquo(y);            /* Restore previous quoting */
  458. #ifdef CK_RECALL
  459.     on_recall = sv_recall;
  460. #endif /* CK_RECALL */
  461.     if (cx == XXASKQ)        /* ASKQ must echo CRLF here */
  462.       printf("\r\n");
  463.     if (x < 0) {            /* If cmtxt parse error, */
  464.         cmsetp(psave);        /* restore original prompt */
  465. #ifdef VMS
  466.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  467.           conres();            /*  restore console again. */
  468. #endif /* VMS */
  469.         return(x);            /* and return cmtxt's error code. */
  470.     }
  471.     if (*s == NUL) {        /* If user typed a bare CR, */
  472.         cmsetp(psave);        /* Restore old prompt, */
  473.         delmac(vnp);        /* delete variable if it exists, */
  474. #ifdef VMS
  475.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  476.           conres();            /*  restore console again. */
  477. #endif /* VMS */
  478.         return(success = 1);    /* and return. */
  479.     }
  480.     y = addmac(vnp,s);        /* Add it to the macro table. */
  481.     debug(F111,"ask addmac",vnp,y);
  482.     cmsetp(psave);            /* Restore old prompt. */
  483. #ifdef VMS
  484.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  485.       conres();            /*  restore console again. */
  486. #endif /* VMS */
  487.     return(success = y < 0 ? 0 : 1);
  488.     }
  489. }
  490. #endif /* NOSPL */
  491.  
  492. #ifndef NOSPL
  493. int
  494. doincr(cx) int cx; {            /* INCREMENT, DECREMENT */
  495.     char vnambuf[VNAML+1];        /* Buffer for variable names */
  496.  
  497.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  498.     if (y == -3) {
  499.         printf("?Variable name required\n");
  500.         return(-9);
  501.     } else return(y);
  502.     }
  503.     strncpy(vnambuf,s,VNAML);
  504.     if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0)
  505.       return(y);
  506.     if ((y = cmcfm()) < 0)
  507.       return(y);
  508.  
  509.     z = (cx == XXINC ? 1 : 0);        /* Increment or decrement? */
  510.  
  511.     if (incvar(vnambuf,x,z) < 0) {
  512.     printf("?Variable %s not defined or not numeric\n",vnambuf);
  513.     return(success = 0);
  514.     }
  515.     return(success = 1);
  516. }
  517. #endif /* NOSPL */
  518.  
  519.  
  520. /* Do the (_)DEFINE, (_)ASSIGN, and UNDEFINE commands */
  521.  
  522. #ifndef NOSPL
  523. int
  524. dodef(cx) int cx; {
  525.     char vnambuf[VNAML];        /* Buffer for variable names */
  526.     char *vnp;                /* Pointer to same */
  527.     if (cx == XXDFX || cx == XXASX) 
  528.       y = cmfld("Macro or variable name","",&s,xxstring); /* eval var name */
  529.     else 
  530.       y = cmfld("Macro or variable name","",&s,NULL);     /* don't evaluate */
  531.     if (y < 0) {
  532.     if (y == -3) {
  533.         printf("?Variable name required\n");
  534.         return(-9);
  535.     } else return(y);
  536.     }
  537.     debug(F111,"dodef success",s,success);
  538.     strcpy(vnambuf,s);
  539.     vnp = vnambuf;
  540.     if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
  541.     if (*vnp == '%' || *vnp == '&') {
  542.     if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
  543.     if (cx == XXUNDEF) {        /* Undefine */
  544.         if ((y = cmcfm()) < 0) return(y);
  545.         delmac(vnp);
  546.         return(success = 1);
  547.     }
  548.     debug(F101,"dodef","",x);
  549.     if (y == 1) {            /* Simple variable */
  550.         if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
  551.           return(y);
  552.         s = brstrip(s);
  553.         debug(F110,"xxdef var name",vnp,0);
  554.         debug(F110,"xxdef var def",s,0);
  555.     } else if (y == 2) {        /* Array element */
  556.         if ((y = arraynam(s,&x,&z)) < 0) return(y);
  557.         if (x == 96) {
  558.         printf("?Argument vector array is read-only\n");
  559.         return(-9);
  560.         }
  561.         if (chkarray(x,z) < 0) return(-2);
  562.         if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
  563.           return(y);
  564.         debug(F110,"xxdef array ref",vnp,0);
  565.         debug(F110,"xxdef array def",s,0);
  566.     }
  567.     } else {                /* Macro */
  568.     if (cx == XXUNDEF) {        /* Undefine */
  569.         if ((y = cmcfm()) < 0) return(y);
  570.         delmac(vnp);
  571.         return(success = 1);
  572.     }
  573.     if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
  574.     debug(F110,"xxdef macro name",vnp,0);
  575.     debug(F110,"xxdef macro def",s,0);
  576.     if (*s == '{') {        /* Allow macro def to be bracketed. */
  577.         s++;            /* If it is, remove the brackets. */
  578.         y = (int)strlen(s);        /* FOR command depends on this! */
  579.         if (y > 0 && s[y-1] == '}') s[y-1] = NUL;
  580.     }
  581.     }
  582.     if (*s == NUL) {            /* No arg given, undefine */
  583.     delmac(vnp);            /* silently... */
  584.     return(success = 1);        /* even if it doesn't exist... */
  585.     } 
  586.  
  587.     /* Defining a new macro or variable */
  588.  
  589.     if (cx == XXASS || cx == XXASX) {    /* ASSIGN rather than DEFINE? */
  590.     int t;
  591.     t = LINBUFSIZ-1;
  592.     lp = line;            /* If so, expand its value now */
  593.     zzstring(s,&lp,&t);
  594.     s = line;
  595.     }
  596.     debug(F111,"calling addmac",s,(int)strlen(s));
  597.  
  598.     y = addmac(vnp,s);            /* Add it to the appropriate table. */
  599.     if (y < 0) {
  600.     printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
  601.            "ASSIGN" : "DEFINE");
  602.     return(success = 0);
  603.     } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
  604.       return(1);               /* don't change success variable */
  605.     else
  606.       return(success = 1);
  607. }
  608. #endif /* NOSPL */
  609.  
  610.  
  611. #ifndef NODIAL
  612. /*
  613.    L U D I A L  --  Lookup up dialing directory entry.
  614.   
  615.    Call with string to look up and file descriptor of open dialing directory
  616.    file.  On success, returns number of matches found, with numbers stored
  617.    in an array accessible via getdnum().
  618. */
  619. static char *dn_p[MAXDNUMS + 1];    /* Dial Number pointers */
  620. static char *dn_p2[MAXDNUMS + 1];    /* Converted dial number pointers */
  621. static int dn_x[MAXDNUMS + 1];        /* Type of call */
  622. static int dncount = 0;
  623. char * d_name = NULL;            /* Dial name pointer */
  624.  
  625. char *                    /* Get dial directory entry name */
  626. getdname() {
  627.     return(d_name ? d_name : "");
  628. }
  629.  
  630. char *
  631. getdnum(n) int n; {            /* Get dial number n from directory */
  632.     if (n < 0 || n > dncount || n > MAXDNUMS)
  633.       return("");
  634.     else
  635.       return(dn_p[n]);
  636. }
  637.  
  638. char *            /* Check area code for spurious leading digit */
  639. chk_ac(i,buf) int i; char buf[]; {
  640.     char *p;
  641.     if (!buf)
  642.       return("");
  643.     p = (char *) buf;            /* Country we are calling: */
  644.     if (i ==  44 ||            /* UK */
  645.     i ==  49 ||            /* Germany */
  646.     i ==  39 ||            /* Italy */
  647.     i ==  31 ||            /* Netherlands */
  648.     i == 351 ||            /* Portugal */
  649.     i ==  55 ||            /* Brazil */
  650.     i == 972 ||            /* Israel */
  651.     i ==  41 ||            /* Switzerland */
  652.     i ==  43 ||            /* Austria */
  653.     i ==  42 ||            /* Czech Republic */
  654.     i ==  36 ||            /* Hungary */
  655.     i ==  30 ||            /* Greece */
  656.     i == 352 ||            /* Luxembourg */
  657.     i ==  48 ||            /* Poland */
  658.     i ==  27 ||            /* South Africa */
  659.     ((i == 33) && ((int) strcmp(zzndate(),"19961017") > 0))    /* France */
  660.     ) {
  661.     if (buf[0] == '0')
  662.       p++;
  663.     } else if (i == 358) {        /* Finland */
  664.     char c = '9';
  665.     if ((int) strcmp(zzndate(),"19961011") > 0)
  666.       c = '0';
  667.     if (buf[0] == c)        /* But only until 12 Oct 96! */
  668.       p++;
  669.     }
  670.     return(p);
  671. }
  672.  
  673. static int
  674. dncvt(k,cx) int k, cx; {        /* Dial Number Convert */
  675.     int i, j, n, what;
  676.     char *ss;
  677.     char *p, *pxo;
  678.     char **pp;
  679.     char *lac;
  680.     char *npr;
  681.     char *sfx;
  682.     char ccbuf[128];
  683.     int cc;
  684.     char acbuf[24];
  685.     char *acptr;
  686.     char outbuf[256];
  687.  
  688. #define DN_INTERN 0
  689. #define DN_FREE   1
  690. #define DN_LOCAL  2
  691. #define DN_UNK    3
  692. #define DN_LONG   4
  693. #define DN_INTL   5
  694. /*
  695.   First pass for strict (punctuation-based) interpretation.
  696.   If it fails, we try the looser (length-based) one.
  697. */
  698.     what = 0;                /* Type of call */
  699.     s = dn_p[k];            /* Number to be converted. */
  700.     debug(F111,"dncvt",s,k);
  701.     if (dn_p2[k]) {
  702.     free(dn_p2[k]);
  703.     dn_p2[k] = NULL;
  704.     }
  705.     if (!s) {
  706.     printf("Error - No phone number to convert\n");
  707.     return(-1);
  708.     }
  709.     pp = &(dn_p2[k]);            /* Address for converted number */
  710.  
  711.     if (tttapi) {            /* When using TAPI */
  712.     npr = "";            /* TAPI supplies all the */
  713.     sfx = "";            /* prefixes and suffixes */
  714.     pxo = "";
  715.     } else {
  716.     npr = dialnpr ? dialnpr : "";
  717.     sfx = dialsfx ? dialsfx : "";
  718.     pxo = dialpxo ? dialpxo : "";
  719.     }
  720.     lac = diallac ? diallac : "";    /* Local area code */
  721.  
  722.     outbuf[0] = NUL;            /* Initialize conversion buffer */
  723.     ss = s;                /* Remember original string */
  724.  
  725.     if (*s != '+') {            /* Literal number */
  726.     sprintf(outbuf,            /* Sandwich it between */
  727.         "%s%s%s%s",        /* DIAL PREFIX and SUFFIX */
  728.         pxo,npr,s,sfx
  729.         );
  730.     makestr(pp, outbuf);
  731.     dn_x[k] = DN_UNK;        /* Sort key is "unknown". */
  732.     return(0);            /* Done. */
  733.     }
  734.     i = 0;                /* Portable number */
  735.     s++;                /* Tiptoe past the plus sign */
  736.     ccbuf[0] = NUL;            /* Do country code first */
  737.  
  738.     if (!diallcc) {            /* Do we know our own? */
  739.     if (cx != XXLOOK)
  740.       printf("Error - prior SET DIAL COUNTRY-CODE command required\n");
  741.     return(-1);
  742.     }
  743.  
  744.     /* Parse the number */
  745.  
  746.     while (1) {                /* Get the country code */
  747.         while (*s == HT || *s == SP)
  748.       s++;
  749.     if (!s)                /* Not in standard format */
  750.       break;
  751.         if (*s == '(') {        /* Beginning of area code  */
  752.         s++;            /* Skip past parenthesis   */
  753.         ccbuf[i] = NUL;        /* End of country code */
  754.         if (!s) {            /* Check for end of string */
  755.         printf("Error - phone number ends prematurely: \"%s\"\n",ss);
  756.         return(-1);
  757.         }
  758.         break;
  759.     } else {            /* Collect country code */
  760.         if (isdigit(*s))
  761.           ccbuf[i++] = *s;        /* copy this character */
  762.         s++;
  763.         if (!*s || i > 127)        /* watch out for memory leak */
  764.           break;
  765.     }
  766.     }
  767.     cc = atoi(ccbuf);            /* Numeric version of country code */
  768.  
  769.     i = 0;                /* Now get area code */
  770.     acbuf[0] = NUL;            /* Initialize area-code buffer */
  771.     acptr = acbuf;            /* and pointer. */
  772.     while (1) {
  773.         while (*s == HT || *s == SP)    /* Ignore whitespace */
  774.       s++;
  775.     if (!s)                /* String finished */
  776.       break;
  777.     if (*s == ')') {        /* End of area code  */
  778.         s++;            /* Skip past parenthesis   */
  779.         acbuf[i] = NUL;        /* Terminate area-code buffer */
  780.         break;
  781.     } else {            /* Part of area code */
  782.         if (isdigit(*s))        /* If it's a digit, */
  783.           acbuf[i++] = *s;        /* copy this character */
  784.         s++;            /* Point to next */
  785.         if (!*s || i > 23)        /* Watch out for overflow */
  786.           break;
  787.     }
  788.     }
  789.  
  790. /*
  791.    Here we strip any leading 0 for countries that we know have
  792.    0 as a long-distance prefix and do not have any area codes that
  793.    start with 0 (ditto for "9" in Finland...)
  794. */
  795.     i = atoi(ccbuf);
  796.     acptr = chk_ac(i,acbuf);
  797.  
  798.     while (*s == HT || *s == SP)    /* Skip whitespace */
  799.       s++;
  800.  
  801. /* printf("S=[%s], ACPTR=[%s]\n",s,acptr); */
  802.  
  803.     if (*s && *acptr) {            /* Area code was delimited */
  804.  
  805.     while (*s == '-' || *s == '.')    /* Skip past gratuitious punctuation */
  806.       s++;
  807.     if (!*s) s--;            /* But not to end of string */
  808.  
  809.     if (strcmp(diallcc,ccbuf)) {    /* Out of country? */
  810.         char * p2;
  811.         if (!dialixp) {        /* Need intl-prefix */
  812.         if (cx != XXLOOK)
  813.           printf("Error - No international dialing prefix defined\n");
  814.         return(-1);
  815.         }
  816.         what = dn_x[k] = DN_INTL;
  817.         if (tttapi) {
  818.         p  = "";        /* Intl-suffix */
  819.         p2 = "";        /* Intl-prefix */
  820.         } else {
  821.         p  = dialixp ? dialixp : ""; /* Intl-prefix */
  822.         p2 = dialixs ? dialixs : ""; /* Intl-suffix */
  823.         }
  824.         sprintf(outbuf,        /* Form the final phone number */
  825.             "%s%s%s%s%s%s%s%s",
  826.             pxo,npr,p,ccbuf,acptr,s,p2,sfx
  827.             );
  828.     } else if (strcmp(lac,acptr)) { /* In-country */
  829.         char * p2;
  830. #ifdef COMMENT
  831. /* Wrong - Sometimes it has to be null, e.g. for NANP 10-digit dialing... */
  832.         if (!dialldp) {        /* Out of area code */
  833.         if (cx != XXLOOK)    /* Need ld-prefix */
  834.           printf("Error - No long-distance prefix defined\n");
  835.         return(-1);
  836.         }
  837. #endif /* COMMENT */
  838.         if (!diallac && cx != XXLOOK) { /* Don't know my own area code */
  839.         if (cc == 1)
  840.           printf("WARNING - Prior SET DIAL AREA-CODE needed\n");
  841.         }
  842.  
  843.         what = dn_x[k] = DN_LONG;    /* Long-distance */
  844.  
  845.         for (i = 0; i < ntollfree; i++) { /* Check for toll-free call */
  846.         if (!strcmp(acptr,dialtfc[i])) {
  847.             what = dn_x[k] = DN_FREE;          
  848.             break;
  849.         }
  850.         }
  851.         if (tttapi) {        /* TAPI supplies its own */
  852.         p  = "";        /* ld-suffix */
  853.         p2 = "";        /* ld-prefix */
  854.         } else if (what == DN_FREE) { /* Toll-free call */
  855.         p = dialtfp ? dialtfp : (dialldp ? dialldp : "");
  856.         p2 = "";        /* no suffix */
  857.         } else {            /* normal long distance */
  858.         p  = dialldp ? dialldp : ""; /* ld-prefix */
  859.         p2 = diallds ? diallds : ""; /* ld-suffix */
  860.         }
  861.         sprintf(outbuf,"%s%s%s%s%s%s%s", /* Form the number to be dialed */
  862.             pxo,npr,p,acptr,s,p2,sfx
  863.             );
  864.     } else {            /* Same country, same area code */
  865.         what = dn_x[k] = DN_LOCAL;    /* So it's a local call. */
  866.         if (!dialpxo || tttapi) {    /* TAPI or not dialing out from PBX */
  867.         sprintf(outbuf,"%s%s%s",
  868.             npr,s,sfx
  869.             );
  870.         } else {            /* Dialing from a PBX and not TAPI */
  871.         if (dialpxx) {        /* Is it internal? */
  872.             i = (int) strlen(dialpxx);
  873.             j = (int) strlen(s);
  874.             x = -1;
  875.             if (j > i)
  876.               x = xxstrcmp(dialpxx,s,i);
  877.             if (!x) {
  878.             what = dn_x[k] = DN_INTERN;   /* Internal call. */
  879.             s += i;
  880.             p = (dialpxi) ? dialpxi : ""; /* Internal prefix */
  881.             sprintf(outbuf,"%s%s%s%s",    
  882.                 npr,p,s,sfx
  883.                 );
  884.             } else {    /* External local call */
  885.             sprintf(outbuf,"%s%s%s%s",
  886.                 dialpxo,npr,s,sfx
  887.                 );
  888.             }
  889.         }
  890.         }
  891.     }
  892.  
  893.     } else {                /* Area code was not delimited */
  894.  
  895.     char xbuf[256];            /* Comparison based only on length */
  896.     char ybuf[256];
  897.     s = ss;
  898.     for (i = 0; i < 255; i++) {
  899.         if (!*s)
  900.           break;
  901.         while (!isdigit(*s))    /* Only pay attention to digits */
  902.           s++;
  903.         xbuf[i] = *s++;
  904.     }
  905.     xbuf[i] = NUL;
  906.     sprintf(ybuf,"%s%s",diallcc,lac);
  907.     n = (int) strlen(ybuf);
  908.     if (n > 0 && !xxstrcmp(xbuf,ybuf,n)) { /* Local call */
  909.         dn_x[k] = DN_LOCAL;
  910.         s = xbuf + n;
  911.         sprintf(outbuf,"%s%s%s%s",pxo,npr,s,sfx);
  912.     } else {            /* Not local */
  913.         sprintf(ybuf,"%s",diallcc);
  914.         n = (int) strlen(ybuf);
  915.         if (n > 0 && !xxstrcmp(xbuf,ybuf,n)) { /* Long distance */
  916.         char * p2;
  917.         dn_x[k] = DN_LONG;
  918. #ifdef COMMENT
  919.         if (!dialldp) {
  920.             if (cx != XXLOOK && !tttapi)
  921.               printf("Error - No long-distance prefix defined\n");
  922.             return(-1);
  923.         }
  924. #endif /* COMMENT */
  925.         if (tttapi) {
  926.             p = "";
  927.             p2 = "";
  928.         } else {
  929.             p = dialldp ? dialldp : "";
  930.             p2 = diallds ? diallds : "";
  931.         }
  932.         s = xbuf + n;
  933.         while (*s == '-' || *s == '.')
  934.           s++;
  935.         sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,s,p2,sfx);
  936.         } else {
  937.         char * p2;        /* International */
  938.         dn_x[k] = DN_INTL;
  939.         if (!dialixp) {
  940.             if (cx != XXLOOK && !tttapi) {
  941.             printf(
  942.               "Error - No international dialing prefix defined\n"
  943.                    );
  944.             return(-1);
  945.             }
  946.         }
  947.         if (tttapi) {
  948.             p = "";
  949.             p2 = "";
  950.         } else {
  951.             p = dialixp ? dialixp : ""; 
  952.             p2 = dialixs ? dialixs : "";
  953.         }
  954.         sprintf(outbuf,"%s%s%s%s%s%s",pxo,npr,p,xbuf,p2,sfx);
  955.         }
  956.     }
  957.     }
  958.     makestr(pp, outbuf);
  959.     return(0);
  960. }
  961.  
  962. static int
  963. ddcvt(s, f, n) char * s; FILE * f; int n; { /* Dial Directory Convert */
  964.     char *line, *s2;            /* buffers */
  965. #ifdef VMS
  966.     char * temp;
  967. #endif /* VMS */
  968.     char *info[8];            /* Pointers to words from entry */
  969.     FILE * f2;
  970.     int x, rc;
  971.     rc = -1;
  972.  
  973.     if (!s || !f)            /* No filename or file */
  974.       return(-1);
  975.     if ((int) strlen(s) < 1)
  976.       return(-1);
  977.     if (!(line = malloc(1024)))        /* Allocate input buffer */
  978.       return(-1);
  979.     f2 = NULL;
  980.  
  981.     fclose(f);
  982.     znewn(s,&s2);            /* s2 = address of static buffer */
  983. #ifdef VMS
  984.     temp = s2;                /* Swap - otherwise the new */
  985.     s2 = s;                /* version has the older version */
  986.     s = temp;                /* number... */
  987.     if (temp =  (char *)malloc((int)strlen(s)+1))
  988.       strcpy(temp,s);
  989.     if (dialdir[n])            /* Replace filename in list */
  990.       free(dialdir[n]);
  991.     dialdir[n] = temp;
  992.     s = temp;
  993. #else
  994.     if (zrename(s,s2) < 0) {        /* Not VMS - rename old file */
  995.     perror(s2);            /* to new (wierd) name. */
  996.     goto ddexit;
  997.     }
  998. #endif /* VMS */
  999.     if ((f = fopen(s2,"r")) == NULL) {    /* Reopen old file with wierd name */
  1000.     dirline = 0;            /* (or in VMS, old version) */
  1001.     perror(s2);
  1002.     goto ddexit;
  1003.     }
  1004.     if ((f2 = fopen(s,"w")) == NULL) {    /* Create new file with old name */
  1005.     perror(s);            /* (or in VMS, new version) */
  1006.     goto ddexit;
  1007.     }
  1008.     printf("\nSaving old directory as %s.\nConverting %s...",s2,s);
  1009.     fprintf(f2,"; %s - Kermit dialing directory\n", s);
  1010.     fprintf(f2,"%-16s %-20s ; %5s %-6s ; %s\n",
  1011.            "; Name","Number","Speed","Parity","Comment"
  1012.            );
  1013.  
  1014.     while (1) {
  1015.     line[0] = NUL;            /* Read a line */
  1016.     if (fgets(line,1023,f) == NULL)
  1017.       break;
  1018.     if (!line[0]) {            /* Empty line */
  1019.         fprintf(f2,"\n");
  1020.         continue;
  1021.     }
  1022.     x = (int) strlen(line);        /* Strip line terminator, */
  1023.     while (x-- > 0) {        /* if any. */
  1024.         if (line[x] <= SP)
  1025.           line[x] = NUL;
  1026.         else
  1027.           break;
  1028.     }
  1029.     xwords(line,5,info,1);        /* Parse it the old way */
  1030.     for (x = 1; x < 6; x++)
  1031.       if (!info[x]) info[x] = "";
  1032.     fprintf(f2,"%-16s %-20s ; %5s %-6s %s\n",
  1033.            info[1],info[2],info[3],info[4],info[5]
  1034.            );
  1035.     }    
  1036.     printf(" OK\n\n");
  1037.     rc = 0;                /* Success */
  1038.   ddexit:
  1039.     if (f) fclose(f);
  1040.     if (f2) fclose(f2);
  1041.     if (line) free(line);
  1042.     return(rc);
  1043. }
  1044.  
  1045. int                    /* s = name to look up   */
  1046. #ifdef CK_ANSIC                /* cx = index of command */
  1047. ludial(char *s, int cx)            /* (DIAL, LOOKUP, etc)   */
  1048. #else
  1049. ludial(s, cx) char *s; int cx;
  1050. #endif /* CK_ANSIC */
  1051. /* ludial */ {
  1052.  
  1053.     int dd, n1, n2, n3, i, j, t;    /* Workers */
  1054.     int olddir, newdir, oldentry, newentry;
  1055.     int pass = 0;
  1056.     int oldflg = 0;
  1057.     int ambiguous = 0;            /* Flag for lookup was ambiguous */
  1058.     char *info[7];            /* Pointers to words from entry */
  1059.     char *pp;                /* Pointer to element of array */
  1060.     FILE * f;
  1061.     char *line;                /* File input buffer */
  1062.  
  1063. /* #define LUDEBUG */
  1064.  
  1065. #ifdef LUDEBUG
  1066. int zz = 1;
  1067. #endif /* LUDEBUG */
  1068.  
  1069.     if (!s || ndialdir < 1)        /* Validate arguments */
  1070.       return(-1);
  1071.  
  1072.     if ((n1 = (int) strlen(s)) < 1)    /* Length of string to look up */
  1073.       return(-1);
  1074.  
  1075.     if (!(line = malloc(1024)))        /* Allocate input buffer */
  1076.       return(-1);
  1077.  
  1078. #ifdef LUDEBUG
  1079. if (zz) printf("LUDIAL 1 s[%s], n1=%d\n",s,n1);
  1080. #endif /* LUDEBUG */
  1081.  
  1082.     pass = 0;
  1083.   lu_again:
  1084.     f = NULL;                /* Dial directory file descriptor */
  1085.     t = dncount = 0;            /* Dial-number match count */
  1086.     dd = 0;                /* Directory counter */
  1087.     olddir = 0;
  1088.     newdir = 0;
  1089. /*
  1090.   We need to recognize both old- and new-style directories.
  1091.   But we can't allow old-style and new-style entries in the same
  1092.   directory because there is no way to tell for sure the difference between
  1093.   and old-style entry like this:
  1094.  
  1095.     foo  5551212  9600
  1096.  
  1097.   and a new-style literal entry like this:
  1098.  
  1099.     foo  555 9600
  1100.  
  1101.   I.e. is the "9600" a speed, or part of the phone number?
  1102. */
  1103.     while (1) {                /* We make one pass */
  1104.     if (!f) {            /* Directory not open */
  1105.             if (dd >= ndialdir)        /* No directories left? */
  1106.           break;            /* Done. */
  1107.         if ((f = fopen(dialdir[dd],"r")) == NULL) { /* Open it */
  1108.         perror(dialdir[dd]);    /* Can't, print message saying why */
  1109.         if (line) {
  1110.             free(line);
  1111.             line = NULL;
  1112.         }
  1113.         dd++;            /* Go on to next one, if any... */
  1114.         continue;
  1115.         }
  1116.         dirline = 0;        /* Directory file line number */
  1117.         if (dialdpy && !pass)
  1118.           printf("Opening: %s...\n",dialdir[dd]);
  1119.             dd++;
  1120.         if (!oldflg) olddir = 0;
  1121.         newdir = 0;
  1122.     }
  1123.     oldentry = 0;
  1124.     newentry = 0;
  1125.     line[0] = NUL;
  1126.     if (getnct(line,1023,f,1) < 0) { /* Read a line */
  1127.         if (f) {            /* f can be clobbered! */
  1128.         fclose(f);        /* Close the file */
  1129.         f = NULL;        /* Indicate next one needs opening */
  1130.         oldflg = 0;
  1131.         }
  1132.         continue;
  1133.     }
  1134.     if (!line[0])            /* Empty line */
  1135.       continue;
  1136. #ifdef LUDEBUG
  1137. if (zz) printf("LUDIAL 2 s[%s]\n",s);
  1138. #endif /* LUDEBUG */
  1139.  
  1140.     /* Make a copy and parse it the old way */
  1141.     /* A copy is needed because xwords() pokes NULs into the string */
  1142.  
  1143.     if (pp = malloc((int)strlen(line) + 1)) {
  1144.         strcpy(pp,line);
  1145.         xwords(pp,5,info,0);    /* Parse it the old way */
  1146.  
  1147. #ifdef LUDEBUG
  1148. if (zz) printf("LUDIAL 3 s[%s]\n",s);
  1149. #endif /* LUDEBUG */
  1150.  
  1151.         if (!info[1])
  1152.           continue;
  1153.         if (*info[1] == ';') {    /* If full-line comment, */
  1154.         newdir = 1;        /* (only new directories have them) */
  1155.         continue;        /* keep reading. */
  1156.         }
  1157.         if (!info[2]) 
  1158.           continue;
  1159.         if (*info[2] == '+')
  1160.           newentry = 1;
  1161.         if (info[4]) {
  1162.         if ((*info[4] == '=') ||
  1163.             !xxstrcmp(info[4],"none", 4) ||
  1164.             !xxstrcmp(info[4],"even", 4) ||
  1165.             !xxstrcmp(info[4],"space",5) ||
  1166.             !xxstrcmp(info[4],"mark", 4) ||
  1167.             !xxstrcmp(info[4],"odd",  3)
  1168.             )
  1169.           oldentry = 1;
  1170.         }
  1171.     }
  1172.     if (pp) {
  1173.         free(pp);
  1174.         pp = NULL;
  1175.     }
  1176.  
  1177.     /* Check consistency */
  1178.  
  1179.     if ((oldentry || olddir) && (newentry || newdir)) {
  1180.         printf(
  1181. "\nERROR: You seem to have old- and new-format entries mixed in your\n");
  1182.         printf(
  1183. "dialing directory.  You'll have to edit it by hand to convert it to the\n");
  1184. #ifndef NOHELP
  1185.         printf("new format.  Type HELP DIAL for further information.\n\n");
  1186. #else
  1187.         printf("new format.\n\n");
  1188. #endif /* NOHELP */
  1189.         if (line) {
  1190.         free(line);
  1191.         line = NULL;
  1192.         }
  1193.         return(-1);
  1194.     }
  1195.     if (!olddir && oldentry) {
  1196.         int convert = 0;
  1197.         olddir = 1;
  1198.         if (dialcvt == 2) {        /* 2 == ASK */
  1199.         printf(
  1200. "\nWARNING: Old-style dialing directory detected:\n%s\n\n", line);
  1201.         convert = getyesno("Shall I convert it for you? ");
  1202.         } else
  1203.           convert = dialcvt;
  1204.         if (convert) {
  1205.         if (ddcvt(dialdir[dd-1],f,dd-1) < 0) {
  1206.             oldflg = 1;
  1207.             printf(
  1208. "  Sorry, can't convert.");
  1209.             printf(
  1210. "  Will ignore speed and parity fields, continuing...\n\n");
  1211.         } else {
  1212.             olddir = newdir = 0;
  1213.         }
  1214.         dd--;
  1215.         f = NULL;
  1216.         continue;
  1217.         } else {
  1218.         if (dialcvt == 2)
  1219.           printf(
  1220. "  OK, will ignore speed and parity fields, continuing...\n\n");
  1221.         olddir = 1;
  1222.         }
  1223.     }
  1224.  
  1225. #ifdef LUDEBUG
  1226. if (zz) printf("LUDIAL XX s[%s], n1=%d\n",s,n1);
  1227. #endif /* LUDEBUG */
  1228.  
  1229.     /* Now parse again for real */
  1230.  
  1231.     if (oldentry)            /* Parse it the old way */
  1232.       xwords(line,5,info,0);
  1233.     else                /* Parse it the new way */
  1234.       xwords(line,2,info,1);
  1235.  
  1236. #ifdef LUDEBUG
  1237. if (zz) printf("LUDIAL YY s[%s], n1=%d\n",s,n1);
  1238. if (zz) printf("%s [%s]\n",info[1],info[2]);
  1239. #endif /* LUDEBUG */
  1240.  
  1241.     if (info[1]) {            /* First word is entry name */
  1242.         if ((n3 = (int) strlen(info[1])) < 1) /* Its length */
  1243.           continue;            /* If no first word, keep reading. */
  1244.         if (n3 < n1)        /* Search name is longer */
  1245.           continue;            /* Can't possibly match */
  1246.         if (ambiguous && n3 != n1)
  1247.           continue;
  1248.  
  1249. #ifdef LUDEBUG
  1250. if (zz) printf("MATCHING: [%s] [%s], n1=%d\n",s,info[1],n1);
  1251. #endif /* LUDEBUG */
  1252.  
  1253.         if (xxstrcmp(s,info[1],n1)) /* Caseless string comparison */
  1254.           continue;
  1255.  
  1256. #ifdef LUDEBUG
  1257. if (zz) printf("MATCH OK: [%s] [%s], n1=%d\n",s,info[1],n1);
  1258. #endif /* LUDEBUG */
  1259.  
  1260.         if (!info[2])        /* No phone number given */
  1261.           continue;
  1262.         if ((n2 = (int) strlen(info[2])) < 1) /* Length of phone number */
  1263.           continue;            /* Ignore empty phone numbers */
  1264.  
  1265.         /* Got one */
  1266.  
  1267.         if (!(pp = (char *)malloc(n2 + 1))) { /* Allocate storage for it */
  1268.         printf("?internal error - ludial malloc 1\n");
  1269.         if (line) {
  1270.             free(line);
  1271.             line = NULL;
  1272.         }
  1273.         dncount = 0;
  1274.         return(-1);
  1275.         }
  1276.         strcpy(pp,info[2]);        /* Copy number into malloc'd storage */
  1277.  
  1278.         if (dncount > MAXDNUMS) {
  1279.         printf("Warning: %d matches found, %d max\n",
  1280.                dncount,
  1281.                MAXDNUMS
  1282.                );
  1283.         dncount = MAXDNUMS;
  1284.         break;
  1285.         }
  1286.         dn_p[dncount++] = pp;    /* Add pointer to array. */
  1287.         if (dncount == 1) {        /* First one... */
  1288.         if (d_name) free(d_name);
  1289.         if (!(d_name = (char *)malloc(n3 + 1))) { /* Save its name */
  1290.             printf("?internal error - ludial malloc 2\n");
  1291.             if (line) {
  1292.             free(line);
  1293.             line = NULL;
  1294.             }
  1295.             dncount = 0;
  1296.             return(-1);
  1297.         }
  1298.         t = n3;            /* And its length */
  1299.         strcpy(d_name,info[1]);
  1300.         } else {            /* Second or subsequent one */
  1301.  
  1302. #ifdef LUDEBUG
  1303.         if (zz)
  1304.           printf("d_name=[%s],info[1]=%s,t=[%d]\n",d_name,info[1],t);
  1305. #endif /* LUDEBUG */
  1306.  
  1307.         if ((int) strlen(info[1]) == t) /* Lengths compare */
  1308.           if (!xxstrcmp(d_name,info[1],t)) /* Caseless compare OK */
  1309.             continue;
  1310.  
  1311.         /* Name given by user matches entries with different names */
  1312.  
  1313.         if (ambiguous)        /* Been here before */
  1314.           break;
  1315.  
  1316.         ambiguous = 1;        /* Now an exact match is required */
  1317.         for (j = 0; j < dncount; j++) { /* Clean out previous list */
  1318.             if (dn_p[j]) {
  1319.             free(dn_p[j]);
  1320.             dn_p[j] = NULL;
  1321.             }
  1322.         }
  1323.         pass++;            /* Second pass... */
  1324.         goto lu_again;        /* Do it all over again. */
  1325.         }
  1326.     }
  1327.     }
  1328.     if (line) free(line);
  1329.     if (dncount == 0 && ambiguous) {
  1330.     printf(" Lookup: \"%s\" - ambiguous%s\n",
  1331.            s,
  1332.            cx == XXLOOK ? "" : " - dialing skipped"
  1333.            );
  1334.     return(-2);
  1335.     }
  1336.     return(dncount);
  1337. }
  1338.  
  1339. static char *dscopy = NULL;
  1340.  
  1341. int
  1342. dodial(cx) int cx; {            /* DIAL or REDIAL */
  1343.     int i = 0, x = 0;            /* Workers */
  1344.     int sparity = -1;            /* For saving global parity value */
  1345.     int partial  = 0;            /* For partial dial */
  1346.     int previous = 0;
  1347.     int len = 0;
  1348.     int literal = 0;
  1349.  
  1350.     char *p = NULL, *s3 = NULL, **s2 = NULL;
  1351.     int j = 0, t = 0, n = 0;
  1352.  
  1353.     if (cx == XXPDIA) {            /* Shortcut... */
  1354.     cx = XXDIAL;
  1355.     partial = 1;
  1356.     }
  1357.     previous = dialsta;            /* Status of previous call, if any */
  1358.  
  1359.     if (cx != XXLOOK) {
  1360.     if (mdmtyp < 1) {
  1361.         if (network)
  1362.           printf("Please SET HOST first, and then SET MODEM\n");
  1363.         else
  1364.           printf("Sorry, you must SET MODEM first\n");
  1365.         dialsta = DIA_NOMO;
  1366.         return(0);
  1367.     }
  1368.     if (!local) {
  1369.         printf("Sorry, you must SET LINE or SET HOST first\n");
  1370.         dialsta = DIA_NOLI;
  1371.         return(0);
  1372.     }
  1373.     if (!network &&
  1374.         (speed < 0L)
  1375. #ifdef UNIX
  1376.         && (strcmp(ttname,"/dev/null"))
  1377. #else
  1378. #ifdef OSK
  1379.         && (strcmp(ttname,"/nil"))
  1380. #endif /* OSK */
  1381. #endif /* UNIX */
  1382.         ) {
  1383.         printf("Sorry, you must SET SPEED first\n");
  1384.         dialsta = DIA_NOSP;
  1385.         return(0);
  1386.     }
  1387.     }
  1388.     s = NULL;                /* Initialize user's dial string */
  1389.     if (cx == XXRED) {            /* REDIAL or... */
  1390.     if ((y = cmcfm()) < 0)
  1391.       return(y);
  1392.     } else if (cx == XXANSW) {        /* ANSWER or ... */
  1393.     if ((y = cmnum("timeout (seconds)","0",10,&x,xxstring)) < 0)
  1394.       return(y);
  1395.     dialatmo = x;
  1396.     if ((y = cmcfm()) < 0)
  1397.       return(y);
  1398.     } else {                /* DIAL or LOOKUP */
  1399.     if (ndialdir > 0)
  1400.       s3 = "Number to dial or entry from dial directory";
  1401.     else
  1402.       s3 = "Number to dial";
  1403.     if ((x = cmtxt(s3, dialnum ? dialnum : "",&s,xxstring)) < 0)
  1404.       return(x);
  1405.     if (s) {
  1406.         len = (int) strlen(s);
  1407.         if (len > 1) {        /* Strip outer braces if given */
  1408.         if (*s == '{') {
  1409.             if (s[len-1] == '}') {
  1410.             s[len-1] = NUL;
  1411.             s++;
  1412.             len -= 2;
  1413.             }
  1414.         }
  1415.         }
  1416.     }        
  1417.     }
  1418.     if (cx != XXANSW) {
  1419.     for (j = 0; j < MAXDNUMS; j++) { /* Initialize dial-number list */
  1420.         if (!dialnum) {        /* First time dialing */
  1421.         dn_p[j] = NULL;        /* initialize all pointers. */
  1422.         dn_p2[j] = NULL;
  1423.         } else if (dn_p[j]) {    /* Not the first time, */
  1424.         free(dn_p[j]);        /* free previous, if any, */
  1425.         dn_p[j] = NULL;        /* then set to NULL. */
  1426.         if (dn_p2[j])
  1427.           free(dn_p2[j]);
  1428.         dn_p2[j] = NULL;
  1429.         } else break;        /* Already NULL */
  1430.     }
  1431.     if (len == 0)
  1432.       s = NULL;
  1433.     if (!s)
  1434.       s = dialnum;
  1435.     if (!s) {
  1436.         if (cx == XXLOOK)
  1437.           printf("?Lookup what?\n");
  1438.         else
  1439.           printf("%s\n", (cx == XXRED) ?
  1440.            "?No DIAL command given yet" :
  1441.            "?You must specify a number to dial"
  1442.            );
  1443.         return(-9);
  1444.     }
  1445.  
  1446.     /* Now we have the "raw" dial or lookup string and s is not NULL */
  1447.  
  1448.     makestr(&dscopy,s);        /* Put it in a safe place */
  1449.     s = dscopy;
  1450.     n = 0;
  1451.  
  1452.     debug(F111,"dodial",s,ndialdir);
  1453.  
  1454.     if (isalpha(*s)) {
  1455.         if (ndialdir > 0) {        /* Do we have a dialing directory? */
  1456.         n = ludial(s,cx);    /* Look up what the user typed */
  1457.         if (n == 0)
  1458.           printf(" Lookup: \"%s\" - not found%s\n",
  1459.              s,
  1460.              cx == XXLOOK ? "" : " - dialing as given\n"
  1461.              );
  1462.         }
  1463.         debug(F101,"dodial",s,n);
  1464.         if (n < 0 && cx != XXLOOK) { /* Error out if they wanted to dial */
  1465.         if (n == -1)        /* -2 means ludial already gave msg */
  1466.           printf(" Lookup: fatal error - dialing skipped\n");
  1467.         dialsta = DIA_DIR;
  1468.         return(-9);
  1469.         }    
  1470.     } else {            /* "=" forces no lookup. */
  1471.         n = 0;
  1472.         if (*s == '=') {        /* If number starts with = sign */
  1473.         s++;            /* strip it */
  1474.         literal = 1;        /* remember this */
  1475.         while (*s == SP) s++;    /* and then also any leading spaces */
  1476.         }
  1477.         if (ndialdir > 0)
  1478.           printf(" Lookup: skipped\n");
  1479.     }
  1480.  
  1481.     /* Save DIAL or successful LOOKUP string for future DIAL or REDIAL */
  1482.     /* But don't save pieces of partial dial ... */
  1483.  
  1484.     if ((cx == XXDIAL && partial == 0 && previous != DIA_PART) ||
  1485.         (cx == XXLOOK && n > 0)) {
  1486.         makestr(&dialnum,dscopy);
  1487.     }
  1488.     if (n > 0) {
  1489.         if (!quiet && !backgrd && dialdpy) {
  1490.         if (!strcmp(d_name,s))
  1491.           printf(" Lookup: \"%s\" - exact match\n",s);
  1492.         else
  1493.           printf(" Lookup: \"%s\" - uniquely matches \"%s\"\n",
  1494.              s,
  1495.              d_name
  1496.              );
  1497.         }
  1498.         if ((cx == XXLOOK) || (n > 1)  && !quiet && !backgrd && dialdpy) {
  1499.         printf(" %d telephone number%sfound for \"%s\"%s\n",
  1500.                n,
  1501.                (n == 1) ? " " : "s ",
  1502.                s,
  1503.                (n > 0) ? ":" : "."
  1504.                );
  1505.         s3 = getdname();
  1506.         }
  1507.         for (i = 0; i < n; i++) {    /* Convert */
  1508.         dn_x[i] = -1;
  1509.         if (dncvt(i,cx) < 0) {
  1510.             if (cx != XXLOOK) {
  1511.             dialsta = DIA_DIR;
  1512.             return(-9);
  1513.             }
  1514.         }
  1515.         }
  1516.         if (dialsrt && n > 1) {    /* Sort into optimal order */
  1517.         for (i = 0; i < n-1; i++) {
  1518.             for (j = i+1; j < n; j++) {
  1519.             if (dn_x[j] < dn_x[i]) {
  1520.                 t = dn_x[j];
  1521.                 dn_x[j] = dn_x[i];
  1522.                 dn_x[i] = t;
  1523.                 p = dn_p[j];
  1524.                 dn_p[j] = dn_p[i];
  1525.                 dn_p[i] = p;
  1526.                 p = dn_p2[j];
  1527.                 dn_p2[j] = dn_p2[i];
  1528.                 dn_p2[i] = p;
  1529.             }
  1530.             }
  1531.         }
  1532.         }
  1533.         if ((cx == XXLOOK) || (n > 1)  && !quiet && !backgrd && dialdpy) {
  1534.         int nn = n;
  1535.         if (cx != XXLOOK)
  1536.           if (n > 12) nn = 12;
  1537.         for (i = 0; i < nn; i++) {
  1538.             printf("%3d. %-12s  %-20s =>  %-20s  (%d)\n",i+1,
  1539.                s3, dn_p[i],
  1540.                dn_p2[i] ? dn_p2[i] : "(processing failed)",
  1541.                dn_x[i]
  1542.                );
  1543.         }
  1544.         if (cx != XXLOOK && n != nn)
  1545.           printf("And %d more...\n", n - nn);
  1546.         }
  1547.     } else if (n == 0) {        /* Not found in directory */
  1548.         makestr(&(dn_p[0]),literal ? s : dscopy);
  1549.         makestr(&d_name,literal ? s : dscopy);
  1550.         dncount = 1;
  1551.         n = 1;
  1552.         if (dncvt(0,cx) < 0) {    /* In case they typed a */
  1553.         dialsta = DIA_DIR;    /* portable-format number ... */
  1554.         return(-9);
  1555.         }
  1556.     }
  1557.  
  1558. #ifdef NETCONN
  1559.     /* It's not good that the networks directory depends on NOT-NODIAL.. */
  1560.     if (cx == XXLOOK && dscopy) {    /* Networks here too... */
  1561.         extern char *nh_p[], *nh_p2[], *n_name;
  1562.         extern char *nh_px[4][MAXDNUMS+1];
  1563.         n = 0;
  1564.         if (nnetdir > 0) {        /* Do we have a network directory? */
  1565.         dirline = 0;
  1566.         n = lunet(dscopy);    /* Look up what the user typed */
  1567.         }
  1568.         if (n > -1) {
  1569.         int k;
  1570.         if (cx == XXLOOK && n == 0)
  1571.           printf(" Lookup: \"%s\" - not found\n",dscopy);
  1572.         else
  1573.           printf("%s %d network entr%s found for \"%s\"%s\n",
  1574.              cx == XXLOOK ? " Lookup:" : "",
  1575.              n,
  1576.              (n == 1) ? "y" : "ies",
  1577.              dscopy,
  1578.              (n > 0) ? ":" : "."
  1579.              );
  1580.  
  1581.         for (i = 0; i < n; i++) {
  1582.  
  1583.             printf("%3d. %-12s => %-9s %s",
  1584.                i+1,n_name,nh_p2[i],nh_p[i]);
  1585.             for (k = 0; k < 4; k++) {
  1586.             if (nh_px[k][i])
  1587.               printf(" %s",nh_px[k][i]);
  1588.             else
  1589.               break;
  1590.             }
  1591.             printf("\n");
  1592.         }
  1593.         }
  1594.     }
  1595. #endif /* NETCONN */
  1596.     if (cx == XXLOOK)
  1597.       return(success = 1);
  1598.     } /* cx != XXANSW */
  1599.  
  1600. #ifdef VMS
  1601.     conres();            /* So Ctrl-C/Y will work */
  1602. #endif /* VMS */
  1603. /*
  1604.   Some modems do not react well to parity.  Also, if we are dialing through a
  1605.   TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
  1606.   negotiations.
  1607.  
  1608.   This should work even if the user interrupts the DIAL command, because the
  1609.   DIAL module has its own interrupt handler.  BUT... if, for some reason, a
  1610.   dialing device actually *requires* parity (e.g. CCITT V.25bis says that even
  1611.   parity should be used), this might prevent successful dialing.  For that
  1612.   reason, we don't do this for V.25bis modems.
  1613. */
  1614.     sparity = parity;            /* Save current parity */
  1615.     if (dialcapas & CKD_V25 == 0)    /* If not V.25bis...  */
  1616.       parity = 0;            /* Set parity to NONE */
  1617.  
  1618.     if (cx == XXANSW) {            /* ANSWER */
  1619.     success = ckdial("",0,0,1);
  1620.     goto dialfin;
  1621.     }
  1622.  
  1623. /* Edit 192 adds the ability to dial repeatedly. */
  1624.  
  1625.     i = 0;
  1626.     do {
  1627.     if (i > 0) printf("\nDial attempt %d of %d...\n", i+1, dialrtr);
  1628.     success = 0;
  1629.     /* And the ability to dial alternate numbers. */
  1630.     /* Loop to dial each in a list of numbers for the same name... */
  1631.     for (j = 0; j < n && !success; j++) { /* until one answers. */
  1632.         s = dn_p2[j];        /* Next number in list */
  1633.         if (dn_x[j] >= dialrstr) {    /* Dial restriction */
  1634.         printf("Restricted: %s, skipping...\n",dn_p[j]);
  1635.         continue;
  1636.         }
  1637.         if (!s) s = dn_p[j];
  1638.         if (i == 0 && dialcnf) {
  1639.         printf("Dialing %s\n",s);
  1640.         x = getyesno(" Is this number correct? ");
  1641.         if (!x) {
  1642.             char **p;
  1643. #ifdef CK_RECALL
  1644.             int sv_recall;
  1645.             extern int on_recall;
  1646. #endif /* CK_RECALL */
  1647.             cmsavp(psave,PROMPTL);
  1648.             cmsetp(
  1649. #ifdef OS2
  1650. " Please enter the correct number,\r\n or press Enter to skip: "
  1651. #else
  1652. " Please enter the correct number,\r\n or press Return to skip: "
  1653. #endif /* OS2 */
  1654. );
  1655.             cmini(ckxech);
  1656.             x = -1;
  1657.             if (pflag) prompt(NULL);
  1658. #ifdef CK_RECALL
  1659.             sv_recall = on_recall;
  1660.             on_recall = 0;
  1661. #endif /* CK_RECALL */
  1662.             y = cmdgquo();
  1663.             cmdsquo(0);
  1664.             while (x < 0) {
  1665.             x = cmtxt("Corrected phone number","",&s,NULL);
  1666.             cmres();
  1667.             }
  1668.             if ((int) strlen(s) < 1) {
  1669.             cmsetp(psave);
  1670.             continue;
  1671.             }
  1672.             makestr(&(dn_p2[j]), s);
  1673.             cmdsquo(y);
  1674. #ifdef CK_RECALL
  1675.             on_recall = sv_recall;
  1676. #endif /* CK_RECALL */
  1677.             cmsetp(psave);
  1678.         }
  1679.         }
  1680. #ifdef COMMENT
  1681. /* for testing without dialing ... */
  1682.         success = 0;
  1683. #else
  1684.         success = ckdial(s,i,j,partial ? 3 : 0); /* Dial it */
  1685.         if (!success)
  1686.           if (dialsta < 8 ||    /* Break out if unrecoverable error */
  1687.           dialsta == DIA_INTR ||
  1688.           dialsta == DIA_ERR ||
  1689.           previous == DIA_PART
  1690.           )
  1691.           break;
  1692. #endif /* COMMENT */
  1693.     }
  1694.     if (success)            /* Succeeded, leave the outer loop */
  1695.       break;
  1696.     if (dialsta < 8 ||        /* Break out if unrecoverable error */
  1697.         dialsta == DIA_INTR ||
  1698.         dialsta == DIA_ERR ||
  1699.         previous == DIA_PART)
  1700.       break;
  1701.     if (++i >= dialrtr)        /* Break out if too many tries */
  1702.       break;
  1703.     if (!backgrd && !quiet) {
  1704.         printf(
  1705. "\nWill redial in %d second%s- press any key to redial immediately.\n",
  1706.                dialint,
  1707.                dialint == 1 ? " " : "s "
  1708.                );
  1709.         printf("Ctrl-C to cancel...\n");
  1710.         }
  1711.         x = dialint;        /* Redial interval */
  1712.         while (x-- > 0) {
  1713.         if (y = conchk())    /* Did they type something? */
  1714.           break;        /* If so, wake up */
  1715.         sleep(1);        /* No interrupt, sleep a sec */
  1716.         }
  1717.     } while (!success);
  1718.  
  1719.   dialfin:
  1720.  
  1721.     if (cx != XXLOOK) {
  1722.     bleep(success ? BP_NOTE : BP_FAIL);
  1723. #ifdef OS2
  1724.     setint();            /* Fix OS/2 interrupts */
  1725. #endif /* OS2 */
  1726.     if (sparity > -1)
  1727.       parity = sparity;        /* Restore parity if we saved it */
  1728. #ifdef OS2
  1729.     ttres();            /* Restore DIAL device */
  1730. #endif /* OS2 */
  1731. #ifdef VMS
  1732.     concb((char)escape);        /* Restore console */
  1733. #endif /* VMS */
  1734. #ifdef OS2
  1735.     {                /* Set session title */
  1736.         char * p, name[72];        /* in window list. */
  1737.         char * q;
  1738.         if (cx == XXANSW) {
  1739.         q = "Incoming call";
  1740.         } else {
  1741.         if (d_name)
  1742.           q = d_name;
  1743.         else if (dialnum)
  1744.           q = dialnum;
  1745.         else if (ttname[0])
  1746.           q = ttname;
  1747.         else q = "";
  1748.         }
  1749.         p = name;
  1750.         if (success) {
  1751.         strncpy(name,q,48);
  1752.         while (*p) {        /* Uppercase it for emphasis. */
  1753.             if (islower(*p))
  1754.               *p = toupper(*p);
  1755.             p++;
  1756.         }
  1757.         } else 
  1758.           name[0] = '\0' ;
  1759.         os2settitle((char *) name, TRUE);
  1760.     }
  1761. #endif /* OS2 */
  1762.     }
  1763.     return(success);
  1764. }
  1765. #endif /* NODIAL */
  1766.  
  1767. /*  D O T Y P E  --  Type a file  */
  1768.  
  1769. int
  1770. dotype(file) char * file; {        /* Do the TYPE command */
  1771. #ifdef VMS
  1772.     char command[512];
  1773.     sprintf(command,"type %s",file);    /* Construct TYPE command */
  1774.     conres();                /* Let user interrupt */
  1775.     success = zshcmd((char *)command);    /* Execute it */
  1776.     concb((char)escape);        /* Back to console CBREAK mode */
  1777.     return(success);
  1778. #else
  1779.     char * p, name[257]; 
  1780. #ifdef MAC
  1781.     int count = 100;
  1782. #endif /* MAC */
  1783.     int rc = 1;
  1784.     int c;
  1785.     int save;
  1786.  
  1787.     save = binary;            /* Save file type */
  1788.  
  1789. #ifdef OS2
  1790.     if (*file) {
  1791.         strcpy( name, file );        /* Change / to \. */
  1792.         p = name;
  1793.         while (*p) {
  1794.             if (*p == '/') *p = '\\';
  1795.             p++;
  1796.         }
  1797.     } else
  1798.       return(0);
  1799. #else
  1800.     strcpy(name, file);
  1801. #endif /* OS2 */
  1802.  
  1803.     if (zchki(name) == -2)        /* It's a directory */
  1804.       return(0);
  1805.  
  1806.     binary = 0;                /* Set file type to text for zopeni */
  1807.     if (!zopeni(ZIFILE, name)) {    /* Not a directory, open it */
  1808.     binary = save;            /* Failed, restore file type */
  1809.     return(0);            /* and return */
  1810.     }
  1811.     while ((c = zminchar()) != -1) {    /* Loop for all characters in file */
  1812. #ifdef MAC
  1813.     /*
  1814.      * It is expensive to run the miniparser so don't do it for
  1815.      * every character.
  1816.      */
  1817.     if (--count < 0) {
  1818.         count = 100;
  1819.         miniparser(1);
  1820.         if (sstate == 'a') {
  1821.         sstate = '\0';
  1822.         rc = 0;
  1823.         break;
  1824.         }
  1825.     }
  1826. #else /* Not MAC */
  1827.     if (putchar(c) == EOF) {    /* Echo character on screen */
  1828.         rc = 0;
  1829.         break;
  1830.     }
  1831. #endif /* MAC */
  1832.     }
  1833.     zclose(ZIFILE);            /* Done, close the file */
  1834.     binary = save;
  1835.     return(rc);
  1836. #endif /* VMS */
  1837. }
  1838.  
  1839. int                    /* Do the DIRECTORY command */
  1840. dodir() {
  1841. #ifndef MAC
  1842.     char *dc;
  1843. #endif /* MAC */
  1844. #ifdef MAC
  1845. /*
  1846.   This is a crude, do-it-yourself directory command.  It shows all the
  1847.   files in the current directory: size and name of each file.  Only regular
  1848.   files are shown.  With a little more work, it could also show directories,
  1849.   and mark files as regular or directories, and it could also show dates.
  1850.   See sample code in zldir() routine in ckmfio.c.
  1851. */
  1852.     char mac_name[65];
  1853.     long mac_len, nfiles, nbytes;
  1854.     extern long mac_znextlen;        /* See ckmfio.c for this. */
  1855.  
  1856.     if ((y = cmcfm()) < 0)
  1857.       return(y);
  1858.  
  1859.     nfiles = nbytes = 0L;
  1860.     printf("\nDirectory of %s\n\n",zgtdir());
  1861.     x = zxpand(":");
  1862.     while (x-- > 0) {
  1863.         if (!znext(mac_name))
  1864.             break;
  1865.         mac_len = zchki(mac_name);
  1866.         if (mac_len > -1L) {
  1867.             nfiles++;
  1868.             nbytes += mac_znextlen;
  1869.             printf("%10ld %s\n", mac_znextlen, mac_name);
  1870.         }
  1871.     }
  1872.     printf("\n%ld file%s, %ld byte%s\n\n",
  1873.        nfiles,
  1874.        (nfiles == 1) ? "" : "s",
  1875.        nbytes,
  1876.        (nbytes == 1) ? "" : "s"
  1877.        );
  1878.     return(success = 1);
  1879. #else
  1880. #ifdef VMS
  1881.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  1882.      return(x);
  1883.     /* now do this the same as a shell command - helps with LAT  */
  1884.     conres();                /* Make console normal */
  1885.     lp = line;
  1886.     if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
  1887.     sprintf(lp,"%s %s",dc,s);
  1888.     debug(F110,"DIR string", line, 0);
  1889.     x = zshcmd(lp);
  1890.     debug(F101,"DIR return code", "", x);
  1891.     concb((char)escape);
  1892.     return(success = (x > 0) ? 1 : 0);
  1893. #else
  1894. #ifdef AMIGA
  1895.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  1896.       return(x);
  1897. #else
  1898. #ifdef datageneral
  1899.     if ((x = cmtxt("Directory/file specification","+",&s,xxstring)) < 0)
  1900.         return(x);
  1901. #else
  1902. #ifdef OS2
  1903. #ifdef ONETERMUPD
  1904.     {
  1905.     char name[257], *p = NULL;
  1906.     char * mstr = NULL, * dstr = NULL;
  1907.     long len, ndirs, nfiles, nbytes;
  1908.     short month, date, year, hour, minute, seconds;
  1909.  
  1910.     /* Note: cmifi2() parses a filespec OR a directory name */
  1911.  
  1912.     x = cmifi2("Device, directory, and/or file specification",
  1913.            "*",
  1914.            &s,
  1915.            &y,
  1916.            1,
  1917.            NULL,
  1918.            xxstring
  1919.            );
  1920.     if (x == -4 || x == -1)
  1921.       return(x);
  1922.     if (x == -2) {
  1923. #ifdef OS2
  1924.         if (!ckindex(".",s,1,0,0) && !ckindex("*",s,1,0,0)) {
  1925.         if (s[1] == ':' && s[2] == NUL)    /* e.g. "dir a:" */
  1926.           sprintf(line,"%s*.*",s);
  1927.         else
  1928.           sprintf(line,"%s.*",s);
  1929.         s = line;
  1930.         if (zxpand(s) < 1) {
  1931.             printf("%s - not found\n",s);
  1932.             return(-9);
  1933.         }
  1934.         } else {
  1935. #endif /* OS2 */
  1936.         printf("%s - not found\n",s);
  1937.         return(-9);
  1938. #ifdef OS2
  1939.         }
  1940. #endif /* OS2 */
  1941.     }
  1942.     if ((y = cmcfm()) < 0)
  1943.       return(y);
  1944.  
  1945.     /* Lower-level functions change / to \. */
  1946.     p = s;
  1947.     while (*p) {            /* Change them back to \ */
  1948.         if (*p == '/') *p = '\\';
  1949.         p++;
  1950.     }
  1951.     ndirs = nfiles = nbytes = 0L;
  1952.     printf("\nDirectory of %s\n\n",s);
  1953.     if (zchki(s) == -2) {
  1954.         /* Found a directory */
  1955. #ifdef OS2
  1956.         if (p != s) {
  1957.         p--;
  1958.         if (*p == '\\' || *p == '/')
  1959.           strcat(s, "*.*");
  1960.         else if (*p == ':')
  1961.           strcat(s, ".\\*.*");
  1962.         else
  1963.           strcat(s, "\\*.*");
  1964.         } else {
  1965.         strcat(s, "*.*");
  1966.         }
  1967. #else
  1968.         if (p != s) {
  1969.         p--;
  1970.         if (*p == '\\' || *p == '/')
  1971.           strcat(s, "*");
  1972.         else if (*p == ':')
  1973.           strcat(s, ".");
  1974.         else
  1975.           strcat(s, "\\*");
  1976.         } else {
  1977.         strcat(s, "*");
  1978.         }
  1979. #endif
  1980.     }
  1981. #ifdef OS2
  1982.     else if (!ckindex(".",s,1,0,0) && !ckindex("*",s,1,0,0)) {
  1983.         sprintf(line,"%s.*",s);
  1984.         s = line;
  1985.     }
  1986. #endif /* OS2 */
  1987.  
  1988.     x = zxpand(s);
  1989.     while (x-- > 0) {
  1990.         if (!znext(name))
  1991.           break;
  1992.         dstr = zfcdat(name);
  1993.         month = (dstr[4]-48)*10 + (dstr[5]-48);
  1994.         switch(month) {
  1995.           case 1:  mstr = "Jan"; break;
  1996.           case 2:  mstr = "Feb"; break;
  1997.           case 3:  mstr = "Mar"; break;
  1998.           case 4:  mstr = "Apr"; break;
  1999.           case 5:  mstr = "May"; break;
  2000.           case 6:  mstr = "Jun"; break;
  2001.           case 7:  mstr = "Jul"; break;
  2002.           case 8:  mstr = "Aug"; break;
  2003.           case 9:  mstr = "Sep"; break;
  2004.           case 10: mstr = "Oct"; break;
  2005.           case 11: mstr = "Nov"; break;
  2006.           case 12: mstr = "Dec"; break;
  2007.           default: mstr = "   ";
  2008.         }
  2009.         date   = (dstr[6]-48)*10 + (dstr[7]-48);
  2010.         year  = (((dstr[0]-48)*10 
  2011.               + (dstr[1]-48))*10
  2012.              + (dstr[2]-48))*10
  2013.                + (dstr[3]-48);
  2014.         hour  = (dstr[9]-48)*10 + (dstr[10]-48);
  2015.         minute = (dstr[12]-48)*10 + (dstr[13]-48);
  2016.         seconds = (dstr[15]-48)*10 + (dstr[16]-48);
  2017.         len = zchki(name);
  2018.         /* find just the name of the file */
  2019.         for (p = name + (int) strlen(name); 
  2020.          p != name && *p != '/' 
  2021.          && *p != '\\' && *p != ':' ;
  2022.          p--
  2023.          )
  2024.           ;
  2025.         if (*p == '/' || *p == '\\' || *p == ':')
  2026.           p++ ;
  2027.  
  2028.         if (len > -1L) {
  2029.         nfiles++;
  2030.         nbytes += len;
  2031.         printf(" %3s-%02d-%04d  %02d:%02d %10ld %s\n", 
  2032.                mstr, date, year, hour, minute, len, p
  2033.                );
  2034.         } else {
  2035.         ndirs++;
  2036.         printf(" %3s-%02d-%04d  %02d:%02d %10s %s\n", 
  2037.                mstr, date, year, hour, minute, "<DIR>", p);
  2038.         }
  2039.     }
  2040.     printf("\n%ld director%s, %ld file%s, %ld byte%s\n\n",
  2041.            ndirs,
  2042.            (ndirs == 1) ? "y" : "ies",
  2043.            nfiles,
  2044.            (nfiles == 1) ? "" : "s",
  2045.            nbytes,
  2046.            (nbytes == 1) ? "" : "s"
  2047.            );
  2048.     return(success = 1);
  2049.     }
  2050. #else /* ONETERMUPD */
  2051.     tmpbuf[0] = NUL;
  2052.     if ((x = cmifi2(
  2053. "Device, directory, and/or file specification,\n\
  2054.  or switch(es), or '> file'","*.*",
  2055.             &s,&y,1,NULL,xxstring)) < 0) {
  2056.     debug(F101,"DIR cmifi2","",x);
  2057.     if (x == -3) {            /* Done. */
  2058.         goto sw_skip;
  2059.     } else if (x == -2 && (*s == '/' || *s == '>')) {
  2060.         strncpy(tmpbuf,s,TMPBUFSIZ); /* Switch or redirect */
  2061.         if ((y = cmcfm()) < 0)
  2062.           return(y);
  2063.         else
  2064.           goto sw_skip;
  2065.     } else if (x == -2 && !strchr(s,'.')) {    /* Maybe ".*" is missing */
  2066.         goto fs_copy;
  2067.     } else if (x == -2) {
  2068.         printf("%s - not found\n",s);
  2069.         return(-9);
  2070.     } else
  2071.       return(x);
  2072.     }
  2073. #endif /* ONETERMUPD */
  2074. #else /* General Case */
  2075.     if ((x = cmdir("Directory/file specification","",&s,xxstring)) < 0)
  2076.       if (x != -3) return(x);
  2077. #endif /* OS2 */
  2078. #endif /* datageneral */
  2079. #endif /* AMIGA */
  2080.  
  2081. #ifdef OS2
  2082. fs_copy:
  2083. #endif /* OS2 */
  2084.     debug(F110,"DIR fs_copy",s,0);
  2085.     strncpy(tmpbuf,s,TMPBUFSIZ);    /* Copy the filespec */
  2086.  
  2087. #ifdef OS2
  2088.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  2089.     /* Only do this to filenames, not switches! */
  2090.     char *p = tmpbuf;
  2091.     while (*p) {            /* Change them back to \ */
  2092.         if (*p == '/') *p = '\\';
  2093.         p++;
  2094.     }
  2095.     }
  2096.     debug(F110,"DIR tmpbuf 1",tmpbuf,0);
  2097.     /* Now parse trailing switches like /P/O-D... */
  2098.     if ((x = cmtxt("Optional switches and/or redirect for OS/2 DIR command",
  2099.            "",&s,xxstring)) < 0)
  2100.       return(x);
  2101.     strcat(tmpbuf,s);            /* Append them to the filespec */
  2102.     debug(F110,"DIR tmpbuf 2",tmpbuf,0);
  2103. sw_skip:
  2104. #else
  2105.     if ((y = cmcfm()) < 0) return(y);
  2106. #endif /* OS2 */
  2107.     s = tmpbuf;
  2108.     lp = line;
  2109.     if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
  2110.     sprintf(lp,"%s %s",dc,s);
  2111.     debug(F110,"DIR",line,0);
  2112.     xsystem(line);
  2113.     return(success = 1);        /* who cares... */
  2114. #endif /* VMS */
  2115. #endif /* MAC */
  2116. }
  2117.  
  2118. #ifndef NOSERVER
  2119. #ifndef NOFRILLS
  2120. /* Do the ENABLE and DISABLE commands */
  2121.  
  2122. int
  2123. doenable(y,x) int y, x; {
  2124.     switch (x) {
  2125.       case EN_ALL:
  2126.     en_cwd = en_cpy = en_del = en_dir = en_fin = en_get = y;
  2127.     en_ren = en_sen = en_set = en_spa = en_typ = en_who = en_ret = y;
  2128.         en_mai = en_pri = y;
  2129. #ifndef datageneral
  2130.         en_bye = y;
  2131. #endif /* datageneral */
  2132. #ifndef NOPUSH
  2133.     if (!nopush)
  2134.       en_hos = y;
  2135. #endif /* NOPUSH */
  2136. #ifndef NOSPL
  2137.     en_asg = en_que = y;
  2138. #endif /* NOSPL */
  2139.     break;
  2140.       case EN_BYE:
  2141. #ifndef datageneral
  2142. /*
  2143.   In Data General AOS/VS Kermit can't log out its superior process.
  2144. */
  2145.         en_bye = y;
  2146. #endif /* datageneral */
  2147.     break;
  2148.     case EN_CPY:
  2149.         en_cpy = y;
  2150.         break;
  2151.       case EN_CWD:
  2152.     en_cwd = y;
  2153.     break;
  2154.       case EN_DEL:
  2155.     en_del = y;
  2156.     break;
  2157.       case EN_DIR:
  2158.     en_dir = y;
  2159.     break;
  2160.       case EN_FIN:
  2161.     en_fin = y;
  2162.     break;
  2163.       case EN_GET:
  2164.     en_get = y;
  2165.     break;
  2166. #ifndef NOPUSH
  2167.       case EN_HOS:
  2168.     if (!nopush)
  2169.          en_hos = y;
  2170.     break;
  2171. #endif /* NOPUSH */
  2172.     case EN_REN:
  2173.         en_ren = y;
  2174.         break;
  2175.       case EN_SEN:
  2176.     en_sen = y;
  2177.     break;
  2178.       case EN_SET:
  2179.     en_set = y;
  2180.     break;
  2181.       case EN_SPA:
  2182.     en_spa = y;
  2183.     break;
  2184.       case EN_TYP:
  2185.     en_typ = y;
  2186.     break;
  2187.       case EN_WHO:
  2188.     en_who = y;
  2189.     break;
  2190. #ifndef NOSPL
  2191.       case EN_ASG:
  2192.     en_asg = y;
  2193.     break;
  2194.       case EN_QUE:
  2195.     en_que = y;
  2196.     break;
  2197. #endif /* NOSPL */
  2198.       case EN_RET:
  2199.     en_ret = y;
  2200.     break;
  2201.       case EN_MAI:
  2202.     en_mai = y;
  2203.     break;
  2204.       case EN_PRI:
  2205.     en_pri = y;
  2206.     break;
  2207.       default:
  2208.     return(-2);
  2209.     }
  2210.     return(1);
  2211. }
  2212. #endif /* NOFRILLS */
  2213. #endif /* NOSERVER */
  2214.  
  2215. #ifndef NOFRILLS
  2216. int
  2217. dodel() {                /* DELETE */
  2218. #ifndef MAC
  2219.     long zl;
  2220. #endif /* MAC */
  2221.     if ((x = cmifi("File(s) to delete","",&s,&y,xxstring)) < 0) {
  2222.     if (x == -3) {
  2223.         printf("?A file specification is required\n");
  2224.         return(-9);
  2225.     } else return(x);
  2226.     }
  2227. #ifdef MAC
  2228.     strcpy(line,s);
  2229. #else
  2230.     strncpy(tmpbuf,s,TMPBUFSIZ);    /* Make a safe copy of the name. */
  2231. #ifdef OS2
  2232.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  2233.     char *p = tmpbuf;
  2234.     while (*p) {            /* Change them back to \ */
  2235.         if (*p == '/') *p = '\\';
  2236.         p++;
  2237.     }
  2238.     }
  2239.     debug(F110,"xxdel tmpbuf",tmpbuf,0);
  2240.     strcpy(line,tmpbuf);        /* Now copy it back */
  2241. #else /* OS2 */
  2242.    debug(F110,"xxdel tmpbuf",tmpbuf,0);
  2243.    sprintf(line,"%s %s",DELCMD,tmpbuf); /* Construct the system command. */
  2244. #endif /* OS2 */
  2245. #endif /* MAC */
  2246.     debug(F110,"xxdel line",line,0);
  2247.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the user's command. */
  2248. #ifdef VMS
  2249.     conres();
  2250. #endif /* VMS */
  2251. #ifdef MAC
  2252.     s = line;
  2253.     success = (zdelet(line) == 0);
  2254. #else
  2255. #ifdef OS2
  2256.     {
  2257.         int filespace = 0;
  2258.         int len = 0;
  2259.         int count = 0;
  2260.  
  2261.         s = line;
  2262.         z = zxpand(line);
  2263.         if (z > 0) {
  2264.             int i;
  2265.             success = 1;
  2266.  
  2267.             if ( msgflg )
  2268.               printf("\n");
  2269.  
  2270.             for ( i = 0; i < z; i++) {
  2271.         znext(tmpbuf);
  2272.         len = zchki(tmpbuf);
  2273.         if (len >= 0) { 
  2274.             zdelet(tmpbuf);
  2275.             if (zchki(tmpbuf) < 0) {
  2276.             filespace += len;
  2277.             count++;
  2278.             if (msgflg)
  2279.               printf(" %s - deleted\n",tmpbuf);
  2280.             } else {
  2281.             success = 0;
  2282.             if (msgflg)
  2283.               printf(" %s - not deleted\n",tmpbuf);
  2284.             }
  2285.         }
  2286.             }
  2287.         if (msgflg)
  2288.               printf("\n%d files deleted, %d bytes freed\n",count,filespace);
  2289.         } else {
  2290.             if (msgflg)
  2291.           printf("?Can not delete file: %s\n", line );
  2292.         }
  2293.     }
  2294. #else /* OS2 */
  2295.     s = tmpbuf;
  2296.     xsystem(line);            /* Let the system do it. */
  2297.     zl = zchki(tmpbuf);
  2298.     success = (zl == -1L);
  2299. #endif /* OS2 */
  2300. #endif /* MAC */
  2301. #ifndef OS2 
  2302.     if (msgflg)
  2303.       printf("%s - %sdeleted\n",s, success ? "" : "not ");
  2304. #ifdef VMS
  2305.     concb((char)escape);
  2306. #endif /* VMS */
  2307. #endif /* OS2 */
  2308.     return(success);
  2309. }
  2310. #endif /* NOFRILLS */
  2311.  
  2312. #ifndef NOSPL                /* The ELSE command */
  2313. int
  2314. doelse() {
  2315.     if (!ifcmd[cmdlvl]) {
  2316.     printf("?ELSE doesn't follow IF\n");
  2317.     return(-2);
  2318.     }
  2319. #ifdef COMMENT
  2320. /*
  2321.   Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
  2322.   from working.
  2323. */
  2324.     ifcmd[cmdlvl] = 0;
  2325. #endif /* COMMENT */
  2326.     if (!iftest[cmdlvl]) {        /* If IF was false do ELSE part */
  2327.     if (maclvl > -1) {        /* In macro, */
  2328.         pushcmd();            /* save rest of command. */
  2329.     } else if (tlevel > -1) {    /* In take file, */
  2330.         pushcmd();            /* save rest of command. */
  2331.     } else {            /* If interactive, */
  2332.         cmini(ckxech);        /* just start a new command */
  2333.         printf("\n");        /* (like in MS-DOS Kermit) */
  2334.         if (pflag) prompt(xxstring);
  2335.     }
  2336.     } else {                /* Condition is false */
  2337.     if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  2338.       return(y);            /* Gobble up rest of line */
  2339.     }
  2340.     return(0);
  2341. }
  2342. #endif /* NOSPL */
  2343.  
  2344. #ifndef NOSPL
  2345. int
  2346. doswitch() {
  2347.     char *lp, *ap;            /* macro argument pointer */
  2348.  
  2349.     /* Get variable name */
  2350.     if ((y = cmfld("Variable name","",&s,xxstring)) < 0)
  2351.       return(y);
  2352.     if (*s == CMDQ) {
  2353.     if (chkvar(s) < 1) {
  2354.         printf("?Variable name required\n");
  2355.         return(-9);
  2356.     }
  2357.     }
  2358.     lp = line;
  2359.     strcpy(lp,"_switx ");        /* _switx + space */
  2360.     lp += (int)strlen(line);
  2361.     ap = lp;
  2362.     debug(F110,"SWITCH",atmbuf,0);
  2363.     strcpy(lp,atmbuf);            /* + variable name */
  2364.     lp += (int)strlen(atmbuf);
  2365.     strcat(lp," ");            /* + space */
  2366.     lp++;
  2367.     debug(F110,"SWITCH 2",line,0);
  2368.  
  2369.     /* Get body */
  2370.  
  2371.     if ((y = cmtxt("series of cases","",&s,NULL)) < 0) return(y);
  2372.     if ((int)strlen(s) < 1) return(-2);
  2373.     
  2374.     if (litcmd(&s,&lp) < 0) {
  2375.     printf("?Unbalanced brackets\n");
  2376.     return(0);
  2377.     }
  2378.     debug(F110,"SWITCH 3",line,0);
  2379.  
  2380.     x = mlook(mactab,"_switx",nmac);    /* Look up SWITCH macro definition */
  2381.     if (x < 0) {            /* Not there? */
  2382.     addmmac("_switx",sw_def);    /* Put it back. */
  2383.     if ((x = mlook(mactab,"_switx",nmac)) < 0) { /* Look it up again. */
  2384.         printf("?SWITCH macro definition gone!\n"); /* Shouldn't happen. */
  2385.         return(success = 0);
  2386.     }
  2387.     }
  2388.     debug(F110,"SWITCH command",line,0); /* Execute the SWITCH macro. */
  2389.     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs));
  2390. }
  2391.  
  2392. int
  2393. dofor() {                /* The FOR command. */
  2394.     int fx, fy, fz;            /* loop variables */
  2395.     char *ap;                /* macro argument pointer */
  2396.  
  2397.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) { /* Get variable name */
  2398.     if (y == -3) {
  2399.         printf("?Variable name required\n");
  2400.         return(-9);
  2401.     } else return(y);
  2402.     }
  2403.     if ((y = parsevar(s,&x,&z)) < 0)    /* Check it. */
  2404.       return(y);
  2405.  
  2406.     lp = line;                /* Build a copy of the command */
  2407.     strcpy(lp,"_forx ");
  2408.     lp += (int)strlen(line);        /* "_for" macro. */
  2409.     ap = lp;                /* Save pointer to macro args. */
  2410.  
  2411.     if (*s == CMDQ) s++;        /* Skip past backslash if any. */
  2412.     while (*lp++ = *s++) ;        /* copy it */
  2413.     lp--; *lp++ = SP;            /* add a space */
  2414.  
  2415.     if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
  2416.     if (y == -3) return(-2);
  2417.     else return(y);
  2418.     }
  2419.     debug(F101,"dofor fx","",fx);
  2420.     s = atmbuf;                /* Copy the atom buffer */
  2421.  
  2422.     if ((int)strlen(s) < 1) goto badfor;
  2423. /*
  2424.   In edit 192, we change the loop variables to be evaluated at loop entry,
  2425.   not each time through the loop.  This was required in order to allow
  2426.   \v(argc) to be used as a loop variable, or in a loop-variable expression.
  2427.   Thus, we can't have FOR loops that modify their own exit conditions by
  2428.   changing the final value or the increment.  The problem with \v(argc) was
  2429.   that it is on the macro stack; after entry into the _forx macro, it is at
  2430.   the wrong 
  2431. */
  2432.     sprintf(tmpbuf,"%d",fx);    /* Substitute actual value */
  2433.     s = tmpbuf;
  2434.  
  2435.     while (*lp++ = *s++) ;        /* (what they actually typed) */
  2436.     lp--; *lp++ = SP;
  2437.  
  2438.     if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
  2439.     if (y == -3) return(-2);
  2440.     else return(y);
  2441.     }
  2442.     debug(F101,"dofor fy","",fy);
  2443.     s = atmbuf;                /* Same deal */
  2444.     if ((int)strlen(s) < 1) goto badfor;
  2445.  
  2446.     sprintf(tmpbuf,"%d",fy);
  2447.     s = tmpbuf;
  2448.  
  2449.     while (*lp++ = *s++) ;
  2450.     lp--;
  2451.     *lp++ = SP;
  2452.  
  2453.     if ((y = cmnum("increment","1",10,&fz,xxstring)) < 0) {
  2454.     if (y == -3) return(-2);
  2455.     else return(y);
  2456.     }
  2457.     debug(F101,"dofor fz","",fz);
  2458.     s = atmbuf;                /* Same deal */
  2459.     if ((int)strlen(s) < 1) goto badfor;
  2460.  
  2461.     sprintf(tmpbuf,"%d",fz);
  2462.     s = tmpbuf;
  2463.  
  2464.     while (*lp++ = *s++) ;
  2465.     lp--; *lp++ = SP;
  2466.  
  2467.     /* Insert the appropriate comparison operator */
  2468.     if (fz < 0)
  2469.       *lp++ = '<';
  2470.     else
  2471.       *lp++ = '>';
  2472.     *lp++ = SP;
  2473.  
  2474.     if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
  2475.     if ((int)strlen(s) < 1) return(-2);
  2476.     
  2477.     if (litcmd(&s,&lp) < 0) {
  2478.     printf("?Unbalanced brackets\n");
  2479.     return(0);
  2480.     }
  2481. #ifdef COMMENT
  2482. /* Too strict */
  2483.     if (fz == 0) {
  2484.     printf("?Zero increment not allowed\n");
  2485.     return(0);
  2486.     }
  2487. #endif /* COMMENT */
  2488.     x = mlook(mactab,"_forx",nmac);    /* Look up FOR macro definition */
  2489.     if (x < 0) {            /* Not there? */
  2490.     addmmac("_forx",for_def);    /* Put it back. */
  2491.     if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
  2492.         printf("?FOR macro definition gone!\n"); /* Shouldn't happen. */
  2493.         return(success = 0);
  2494.     }
  2495.     }
  2496.     debug(F110,"FOR command",line,0);    /* Execute the FOR macro. */
  2497.     return(success = dodo(x,ap,cmdstk[cmdlvl].ccflgs));
  2498.  
  2499. badfor: printf("?Incomplete FOR command\n");
  2500.     return(-2);
  2501. }
  2502. #endif /* NOSPL */
  2503.  
  2504. #ifndef NOFRILLS
  2505. /* Do the BUG command */
  2506.  
  2507. int
  2508. dobug() {
  2509.     int n;
  2510. #ifdef COMMENT
  2511.     printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
  2512.     if (verwho) printf("-%d",verwho);
  2513. #endif /* COMMENT */
  2514.     printf(
  2515. "\nBefore requesting technical support from Columbia U., please consult:\n\n"
  2516.        );
  2517.     n = 6;
  2518. #ifdef NT
  2519.     printf(" . Your \"Kermit 95\" user manual.\n");
  2520.     printf(" . The technical reference manual, \"Using C-Kermit\".\n");
  2521.     printf(" . The READ.ME file in Kermit 95's directory on your disk.\n");
  2522.     n += 3;
  2523. #else
  2524.     printf(" . The book \"Using C-Kermit\".\n");
  2525.     n += 1;    
  2526. #ifndef OS2
  2527.     printf(" . The CKCKER.UPD and CKCKER.BWR files.\n");
  2528.     n += 1;    
  2529. #endif /* OS2 */
  2530. #ifdef UNIX
  2531.     printf(" . The CKUKER.BWR and CKUINS.DOC files.\n");
  2532.     n += 1;    
  2533. #else
  2534. #ifdef VMS
  2535.     printf(" . The CKVKER.BWR and CKVINS.DOC files.\n");
  2536.     n += 1;    
  2537. #else
  2538. #ifdef OS2ONLY
  2539.     printf(" . The CKERMIT.INF file (use the UPDATES command).\n");
  2540.     n += 1;    
  2541. #else
  2542. #ifdef datageneral
  2543.     printf(" . The CKDKER.BWR file\n");
  2544.     n += 1;    
  2545. #else
  2546. #ifdef STRATUS
  2547.     printf(" . The CKLKER.BWR file\n");
  2548.     n += 1;    
  2549. #else
  2550. #ifdef AMIGA
  2551.     printf(" . The CKIKER.BWR file\n");
  2552.     n += 1;
  2553. #else
  2554. #ifdef GEMDOS
  2555.     printf(" . The CKSKER.BWR file\n");
  2556.     n += 1;
  2557. #else
  2558. #ifdef MAC
  2559.     printf(" . The CKMKER.BWR file\n");
  2560.     n += 1;
  2561. #else
  2562. #ifdef OSK
  2563.     printf(" . The CK9KER.BWR file\n");
  2564.     n += 1;
  2565. #else
  2566.     printf(" . The appropriate system-dependent CK?KER.BWR file\n");
  2567.     n += 1;
  2568. #endif
  2569. #endif
  2570. #endif
  2571. #endif
  2572. #endif
  2573. #endif
  2574. #endif
  2575. #endif
  2576. #endif
  2577. #endif /* NT */
  2578.  
  2579.     printf(" . Your own organization's support staff, if any.\n");
  2580.     printf(
  2581. " . The comp.protocols.kermit.* newsgroups if you have Netnews access.\n");
  2582.     printf(
  2583. " . Our FAQ, \
  2584. http://www.columbia.edu/kermit/faq.html, if you have Web access.\n");
  2585.     n += 2;
  2586.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2587.     printf("\n\
  2588. If you still need help or have a bug to report after consulting these sources,"
  2589.        );
  2590.     printf("\nsend e-mail to:\n\n");
  2591.     n += 2;
  2592.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2593.     printf("  kermit-support@columbia.edu\n\n");
  2594.     n += 1;
  2595.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2596.     printf("Or contact us by post:\n\n");
  2597.     printf(
  2598. "  Kermit, Columbia University, 612 W 115 Street, New York NY  10025, USA\n\n"
  2599.        );
  2600.     n += 1;
  2601.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2602.     printf("Or by fax at +1 (212) 663-8202.\n\n");
  2603.     n += 1;
  2604.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2605.     printf("Telephone support is available too:\n\n");
  2606.     n += 1;
  2607.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2608.     printf("  +1 (900) 555-5595, USA only, $2.50 per minute\n");
  2609.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2610.     printf("  +1 (212) 854-5126, from anywhere, $25.00 per call, MC/Visa\n\n");
  2611.     n += 1;
  2612.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2613. #ifndef NOSHOW
  2614. #ifndef NOFRILLS
  2615.     printf(
  2616. "Before reporting problems, please use the SHOW VERSION and SHOW FEATURES\n");
  2617.     if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
  2618.     printf(
  2619. "commands to get detailed program version and configuration information.\n\n");
  2620. #endif /* NOFRILLS */
  2621. #endif /* NOSHOW */
  2622.     return(1);
  2623. }
  2624. #endif /* NOFRILLS */
  2625.  
  2626. #ifndef NOSPL
  2627.  
  2628. /*  T O D 2 S E C  --  Convert time of day as hh:mm:ss to secs since midnite */
  2629. /*
  2630.   Call with a string hh:mm or hh:mm:ss.
  2631.   Returns a 0 to 86400 on success, or a negative number on failure.
  2632. */
  2633. long
  2634. tod2sec(t) char * t; {
  2635.     long t2;
  2636.     long hh = 0L, mm = 0L, ss = 0L;
  2637.  
  2638.     if (!t) t = "";
  2639.     if (!*t)
  2640.       return(-3);
  2641.     debug(F110,"tod2sec",t,0);
  2642.  
  2643.     if (isdigit(*t))            /* Get hours from argument */
  2644.       hh = *t++ - '0';
  2645.     else
  2646.       return(-1L);
  2647.     if (isdigit(*t))
  2648.       hh = hh * 10 + *t++ - '0';
  2649.     if (hh > 24L)
  2650.       return(-1L);
  2651.     if (*t == ':')
  2652.       t++;
  2653.     else if (!*t)
  2654.       goto xtod2sec;
  2655.     else
  2656.       return(-1L);
  2657.             
  2658.     if (isdigit(*t))            /* Minutes */
  2659.       mm = *t++ - '0';
  2660.     else
  2661.       return(-1L);
  2662.     if (isdigit(*t))
  2663.       mm = mm * 10 + *t++ - '0';
  2664.     if (mm > 60L)
  2665.       return(-1L);
  2666.     if (*t == ':')
  2667.       t++;
  2668.     else if (!*t)
  2669.       goto xtod2sec;
  2670.     else
  2671.       return(-1L);
  2672.  
  2673.     if (isdigit(*t))            /* Seconds */
  2674.       ss = *t++ - '0';
  2675.     else
  2676.       return(-1L);
  2677.     if (isdigit(*t))
  2678.       ss = ss * 10 + *t++ - '0';
  2679.     if (ss > 60L)
  2680.       return(-1L);
  2681.  
  2682.     if (*t > 32)            /* No trailing junk allowed */
  2683.       return(-1L);
  2684.  
  2685.   xtod2sec:
  2686.  
  2687.     t2 = hh * 3600L + mm * 60L + ss;    /* Seconds since midnight from arg */
  2688.     debug(F100,"tod2sec t2","",t2);
  2689.  
  2690.     return(t2);
  2691. }
  2692.  
  2693. int
  2694. dopaus(cx) int cx; {
  2695.     long zz;
  2696.  
  2697.     zz = -1L;
  2698.     x_ifnum = 1;            /* Turn off internal complaints */
  2699.     if (cx == XXWAI)
  2700.       y = cmnum("seconds to wait, or time of day hh:mm:ss","1",10,&x,xxstring);
  2701.     else if (cx == XXPAU)
  2702.       y = cmnum("seconds to pause, or time of day hh:mm:ss",
  2703.         "1",10,&x,xxstring);
  2704.     else
  2705.       y = cmnum("milliseconds to sleep, or time of day hh:mm:ss",
  2706.         "100",10,&x,xxstring);
  2707.     x_ifnum = 0;
  2708.     if (y < 0) {
  2709.     if (y == -2) {            /* Invalid number or expression */
  2710.         zz = tod2sec(atmbuf);    /* Convert to secs since midnight */
  2711.         if (zz < 0L) {
  2712.         printf("?Number, expression, or time of day required\n");
  2713.         return(-9);
  2714.         } else {
  2715.         char now[32];        /* Current time */
  2716.         char *p;
  2717.         long tnow;
  2718.         p = now;
  2719.         ztime(&p);
  2720.         tnow = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  2721.         if (zz < tnow)        /* User's time before now */
  2722.           zz += 86400L;        /* So make it tomorrow */
  2723.         zz -= tnow;        /* Seconds from now. */
  2724.         }
  2725.     } else
  2726.       return(y);
  2727.     }
  2728.     if (x < 0) x = 0;
  2729.     switch (cx) {
  2730.       case XXPAU:            /* PAUSE */
  2731.       case XXMSL:            /* MSLEEP */
  2732.     if ((y = cmcfm()) < 0) return(y);
  2733.     break;
  2734.       case XXWAI:            /* WAIT */
  2735.     z = 0;                /* Modem signal mask */
  2736.     while (1) {            /* Read zero or more signal names */
  2737.         y = cmkey(mstab,nms,"modem signal","",xxstring);
  2738.         if (y == -3) break;        /* -3 means they typed CR */
  2739.         if (y < 0) return(y);    /* Other negatives are errors */
  2740.         z |= y;            /* OR the bit into the signal mask */
  2741.     }
  2742.     break;
  2743.  
  2744.       default:                /* Shouldn't happen */
  2745.     return(-2);
  2746.     }
  2747.  
  2748. /* Command is entered, now do it. */
  2749.  
  2750.     if (zz > -1L) {            /* Time of day given? */
  2751.     x = zz;
  2752.     if (zz != (long) x) {
  2753.         printf(
  2754. "Sorry, arithmetic overflow - hh:mm:ss not usable on this platform.\n"
  2755.            );
  2756.         return(-9);
  2757.     }
  2758.     }
  2759.     if (cx == XXMSL) {            /* Millisecond sleep */
  2760.     msleep(zz < 0 ? x : x * 1000);
  2761.     return(success = 1);
  2762.     }
  2763.     while (x--) {            /* Sleep loop */
  2764.     int mdmsig;
  2765.     if (y = conchk()) {        /* Did they type something? */
  2766. #ifdef COMMENT
  2767.         while (y--) coninc(0);    /* Yes, gobble it up */
  2768. #else
  2769.         /* There is a debate over whether PAUSE should absorb    */
  2770.         /* its cancelling character(s).  There are several       */
  2771.         /* reasons why it should gobble at least one character:  */
  2772.         /* (1) MS-DOS Kermit does it                             */
  2773.         /* (2) if not, subsequent PAUSE commands will terminate  */
  2774.         /*     immediately                                       */
  2775.         /* (3) if not, subsequent ASK commands will use it as    */
  2776.         /*     valid input.  If \13, then it will get no input   */
  2777.         /* (4) if not, then the character appears on the command */
  2778.         /*     line after all enclosing macros are complete      */
  2779.         coninc(0);            /* Gobble one up */
  2780. #endif /* COMMENT */
  2781.         break;            /* And quit PAUSing or WAITing */
  2782.     }
  2783.     if (cx == XXWAI && z != 0) {
  2784.         mdmsig = ttgmdm();
  2785.         if (mdmsig < 0) return(success = 0);
  2786.         if ((mdmsig & z) == z) return(success = 1);
  2787.     }
  2788.     sleep(1);            /* No interrupt, sleep one second */
  2789.     }
  2790.     if (cx == XXWAI) success = 0;
  2791.     else success = (x == -1);        /* Set SUCCESS/FAILURE for PAUSE. */
  2792.     return(0);
  2793. }
  2794. #endif /* NOSPL */
  2795.  
  2796.  
  2797. #ifndef NOFRILLS
  2798. #ifdef ZCOPY
  2799. int
  2800. docopy() {
  2801.     if ((x = cmifi("File to copy","",&s,&y,xxstring)) < 0) {
  2802.     if (x == -3) {
  2803.         printf("?Name of existing file required\n");
  2804.         return(-9);
  2805.     } else return(x);
  2806.     }
  2807.     if (y) {                /* No wildcards allowed */
  2808.     printf("\n?Please specify a single file\n");
  2809.     return(-9);
  2810.     }
  2811.     strcpy(line,s);            /* Make a safe copy of source name */
  2812.     p = line + (int)strlen(line) + 2;    /* Place for destination name */
  2813.     if ((x = cmofi("destination name","",&s,xxstring)) < 0) {
  2814.         /* Get destination name */
  2815.     if (x == -3) {
  2816.         printf("?Name for destination file required\n");
  2817.         return(-9);
  2818.     } else return(x);
  2819.     }
  2820.     strcpy(p,s);            /* Safe copy of destination name */
  2821.     if ((y = cmcfm()) < 0) return(y);
  2822. #ifdef VMS
  2823.     conres();                /* Let Ctrl-C work. */
  2824. #endif /* VMS */
  2825.     debug(F110,"docopy line",line,0);
  2826.     debug(F110,"docopy p",p,0);
  2827.     if (zcopy(line,p) < 0) {
  2828.     printf("?Can't copy %s to %s\n",line,p);
  2829. #ifdef VMS
  2830.     concb((char)escape);
  2831. #endif /* VMS */
  2832.     return(-9);
  2833.     } else {
  2834. #ifdef VMS
  2835.     concb((char)escape);
  2836. #endif /* VMS */
  2837.     return(success = 1);
  2838.     }
  2839. }
  2840. #endif /* ZCOPY */
  2841. #endif /* NOFRILLS */
  2842.  
  2843. #ifndef NOFRILLS
  2844. #ifdef ZRENAME
  2845. int
  2846. dorenam() {
  2847.     if ((x = cmifi("File to rename","",&s,&y,xxstring)) < 0) {
  2848.     if (x == -3) {
  2849.         printf("?Name of existing file required\n");
  2850.         return(-9);
  2851.     } else return(x);
  2852.     }
  2853.     if (y) {                /* No wildcards allowed */
  2854.     printf("\n?Please specify a single file\n");
  2855.     return(-9);
  2856.     }
  2857.     strcpy(line,s);            /* Make a safe copy of the old name */
  2858.     p = line + (int)strlen(line) + 2;    /* Place for new name */
  2859.     if ((x = cmofi("New name","",&s,xxstring)) < 0) { /* Get new name */
  2860.     if (x == -3) {
  2861.         printf("?New name for file required\n");
  2862.         return(-9);
  2863.     } else return(x);
  2864.     }
  2865.     strcpy(p,s);            /* Make a safe copy of the new name */
  2866.     if ((y = cmcfm()) < 0) return(y);
  2867. #ifdef VMS
  2868.     conres();                /* Let Ctrl-C work. */
  2869. #endif /* VMS */
  2870.     debug(F110,"dorename line",line,0);
  2871.     debug(F110,"dorename p",p,0);
  2872.     if (zrename(line,p) < 0) {
  2873.     printf("?Can't rename %s to %s\n",line,p);
  2874. #ifdef VMS
  2875.     concb((char)escape);
  2876. #endif /* VMS */
  2877.     return(-9);
  2878.     } else {
  2879. #ifdef VMS
  2880.     concb((char)escape);
  2881. #endif /* VMS */
  2882.     return(success = 1);
  2883.     }
  2884. }
  2885. #endif /* ZRENAME */
  2886. #endif /* NOFRILLS */
  2887.  
  2888. #ifndef NOSPL
  2889.  
  2890. /* Do the RETURN command */
  2891.  
  2892. int
  2893. doreturn(s) char *s; {
  2894.     int x; char *p;
  2895.     if (maclvl < 0) {
  2896.     printf("\n?Can't return from level %d\n",maclvl);
  2897.     return(success = 0);
  2898.     }
  2899.     lp = line;                /* Expand return value now */
  2900.     x = LINBUFSIZ-1;
  2901.     if (zzstring(s,&lp,&x) > -1) {
  2902.     s = line;
  2903.     debug(F110,"RETURN parse",s,0);
  2904.     }
  2905.     debug(F101,"RETURN maclvl 1","",maclvl);
  2906.     /* Pop from all FOR/WHILE/XIFs */
  2907.     while ((maclvl > 0) &&
  2908.        (m_arg[maclvl-1][0]) &&
  2909.        (cmdstk[cmdlvl].src == CMD_MD) &&
  2910.        (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  2911.         !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  2912.         !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  2913.     debug(F110,"RETURN popping",m_arg[maclvl-1][0],0);
  2914.     dogta(XXPTA);        /* Put args back */
  2915.     popclvl();        /* Pop up two levels */
  2916.     popclvl();
  2917.     debug(F101,"RETURN maclvl 2","",maclvl);
  2918.     }
  2919.     popclvl();                /* Pop from enclosing TAKE or macro */
  2920.     debug(F101,"RETURN maclvl 3","",maclvl);
  2921.  
  2922.     x = (int)strlen(s);            /* Length of return value */
  2923.     if (x > 0) {            /* Have return value? */
  2924.     p = malloc(x+2);        /* Allocate a place to keep it */
  2925.     if (mrval[maclvl+1]) {        /* Free old one, if any */
  2926.         free(mrval[maclvl+1]);
  2927.         mrval[maclvl+1] = NULL;
  2928.     }
  2929.     if (p) {            /* Did we get a place? */
  2930.         strcpy(p, s);        /* Yes, copy the string into it. */
  2931.         mrval[maclvl+1] = p;    /* Make return value point to it. */
  2932.         debug(F110,"RETURN copy",mrval[maclvl],0);
  2933.     } else {            /* No, could not get space. */
  2934.         mrval[maclvl+1] = NULL;    /* Return null pointer. */
  2935.         x = 0;            /* Set failure return code. */
  2936.     }
  2937.     } else mrval[maclvl+1] = NULL;    /* Blank return code */
  2938.     return(success = x ? 1 : 0);    /* Return status code */    
  2939. }
  2940. #endif /* NOSPL */
  2941.  
  2942. #ifndef NOSPL
  2943. /* Do the OPEN command */
  2944.  
  2945. int
  2946. doopen()  {                /* OPEN { append, read, write } */
  2947.     int x, y, z; char *s;
  2948.     static struct filinfo fcb;        /* (must be static) */
  2949.     if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
  2950.     if (x == -3) {
  2951.         printf("?Mode required\n");
  2952.         return(-9);
  2953.     } else return(x);
  2954.     }
  2955.     switch (x) {
  2956.       case XYFZ_O:            /* Old file (READ) */
  2957.     if (chkfn(ZRFILE) > 0) {
  2958.         printf("?Read file already open\n");
  2959.         return(-2);
  2960.     }
  2961.     if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
  2962.         if (z == -3) {
  2963.         printf("?Input filename required\n");
  2964.         return(-9);
  2965.         } else return(z);
  2966.     }
  2967.     if (y) {                /* No wildcards allowed */
  2968.         printf("\n?Please specify a single file\n");
  2969.         return(-2);
  2970.     }
  2971.     strcpy(line,s);
  2972.     if ((int)strlen(line) < 1) return(-2);
  2973.     if ((z = cmnum("buffer size","4096",10,&y,xxstring)) < 0)
  2974.       return(z);
  2975.     if (y < 1) {
  2976.         printf("?Positive number required\n");
  2977.         return(-9);
  2978.     }
  2979.     if ((z = cmcfm()) < 0) return(z);
  2980.         readblock = y;
  2981.     if (readbuf)
  2982.       free(readbuf);
  2983.     if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  2984.         printf("?Can't allocate read buffer\n");
  2985.         return(-9);
  2986.     }
  2987.     return(success = zopeni(ZRFILE,line));
  2988.  
  2989. #ifndef MAC
  2990. #ifndef NOPUSH
  2991.       case XYFZ_Y:            /* Pipe/Process (READ) */
  2992.     if (nopush) {
  2993.         printf("?Read from pipe disabled\n");
  2994.         return(success=0);
  2995.     }
  2996.     if (chkfn(ZRFILE) > 0) {
  2997.         printf("?Read file already open\n");
  2998.         return(-2);
  2999.     }
  3000.         if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
  3001.         if (y == -3) {
  3002.         printf("?Command name required\n");
  3003.         return(-9);
  3004.         } else return(y);
  3005.     }
  3006.     strcpy(line,s);
  3007.     if ((int)strlen(line) < 1) return(-2);
  3008.     if ((y = cmcfm()) < 0) return(y);
  3009.     if (!readbuf) {
  3010.         if (!(readbuf = (CHAR *) malloc(readblock+1))) {
  3011.         printf("?Can't allocate read buffer\n");
  3012.         return(-9);
  3013.         }
  3014.     }
  3015.     return(success = zxcmd(ZRFILE,line));
  3016.  
  3017.       case XYFZ_X:            /* Write to pipe */
  3018.     if (nopush) {
  3019.         printf("?Write to pipe disabled\n");
  3020.         return(success=0);
  3021.     }
  3022.     if (chkfn(ZWFILE) > 0) {
  3023.         printf("?Write file already open\n");
  3024.         return(-2);
  3025.     }
  3026.         if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
  3027.         if (y == -3) {
  3028.         printf("?Command name required\n");
  3029.         return(-9);
  3030.         } else return(y);
  3031.     }
  3032.     strcpy(line,s);
  3033.     if ((int)strlen(line) < 1) return(-2);
  3034.     if ((y = cmcfm()) < 0) return(y);
  3035.     success = zxcmd(ZWFILE,line);
  3036.     if (!success && msgflg)
  3037.       printf("Can't open process for writing: %s\n",line);
  3038.     return(success);
  3039. #endif /* NOPUSH */
  3040. #endif /* MAC */
  3041.  
  3042.       case XYFZ_N:            /* New file (WRITE) */
  3043.       case XYFZ_A:            /* (APPEND) */
  3044.     if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
  3045.         if (z == -3) {
  3046.         printf("?Filename required\n");
  3047.         return(-9);
  3048.         } else return(z);
  3049.     }
  3050.     if (z == 2) {
  3051.         printf("?Sorry, %s is a directory name\n",s);
  3052.         return(-9);
  3053.     }
  3054.     if (chkfn(ZWFILE) > 0) {
  3055.         printf("?Write/Append file already open\n");
  3056.         return(-2);
  3057.     }
  3058.         fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
  3059.     fcb.lblopts = 0;
  3060.     fcb.dsp = x;            /* Create or Append */
  3061.     strcpy(line,s);
  3062.     if ((int)strlen(line) < 1) return(-2);
  3063.     if ((y = cmcfm()) < 0) return(y);
  3064.     return(success = zopeno(ZWFILE,line,NULL,&fcb));
  3065.  
  3066.       default:
  3067.     printf("?Not implemented");
  3068.     return(-2);
  3069.     }
  3070. }
  3071. #endif /* NOSPL */
  3072.  
  3073. /* Finish parsing and do the GET or REGET command */
  3074.  
  3075. int
  3076. doget(cx) int cx; {
  3077.     int x, y, rc;
  3078.     char *cbp;
  3079.  
  3080. #ifdef CK_TMPDIR
  3081.     if (dldir && !f_tmpdir) {    /* If they have a download directory */
  3082.     if (s = zgtdir()) {        /* Get current directory, */
  3083.         if (zchdir(line)) {    /* change to download directory */
  3084.         strncpy(savdir,s,TMPDIRLEN);
  3085.         f_tmpdir = 1;    /* remember that we did this */
  3086.         }
  3087.     }
  3088.     }
  3089. #endif /* CK_TMPDIR */
  3090.  
  3091.     cmarg2 = "";            /* Initialize as-name to nothing */
  3092.     x = 0;
  3093. #ifdef NOFRILLS
  3094.     if (*cmarg == NUL) {
  3095.     printf("?Remote filespec required\n");
  3096.     rc = -3;
  3097.     goto endget;
  3098.     }
  3099. #else
  3100. /*
  3101.   If remote file name omitted, get foreign and local names separately.
  3102.   But multine GET is allowed only if NOFRILLS is not defined.
  3103. */
  3104.     if (*cmarg == NUL) {
  3105.  
  3106.     if (tlevel > -1
  3107. #ifndef NOSPL
  3108.         && cmdstk[cmdlvl].src == CMD_TF
  3109. #endif /* NOSPL */
  3110.         ) {
  3111.  
  3112. /* Input is from a command file. */
  3113.  
  3114.         /* Read 2nd line of GET command */
  3115.  
  3116.         if (getnct(cmdbuf,CMDBL,tfile[tlevel],0) < 0) {
  3117.         printf("Command file ends prematurely in multiline GET\n");
  3118.         popclvl();
  3119.         rc = -9;
  3120.         goto endget;
  3121.         }
  3122.         cmres();            /* Parse it */
  3123.         if ((x = cmtxt("Oofa","",&s,xxstring)) < 0) {
  3124.         rc = x;
  3125.         goto endget;
  3126.         }
  3127.         strcpy(line,brstrip(s));    /* Make a safe copy */
  3128.         cmarg = line;        /* Point to remote filename */
  3129.         if (*cmarg == NUL) {    /* Make sure there is one */
  3130.         printf("Remote filename missing in multiline GET\n");
  3131.         rc = -9;
  3132.         goto endget;
  3133.         }
  3134.         lp = line + strlen(line) + 1; /* Place for as-name */
  3135.  
  3136.         /* And third line... */
  3137.  
  3138.         cmarg2 = "";        /* Assume no as-name */
  3139.         if (getnct(cmdbuf,CMDBL,tfile[tlevel],0) < 0) { /* Get next line */
  3140.         popclvl();        /* There isn't one. */
  3141.         } else {            /* There is... */
  3142.         if (*cmdbuf >= ' ') {    /* Parse as output filename */
  3143.             cmres();
  3144.             if ((x = cmofi("Mupeen",cmarg,&s,xxstring)) < 0) {
  3145.             rc = x;
  3146.             goto endget;
  3147.             }
  3148.             strcpy(lp,s);    /* Make a safe copy */
  3149.             cmarg2 = lp;    /* Point as-name pointer at it */
  3150.         }
  3151.         }
  3152.             x = 0;            /* Return code OK */
  3153.  
  3154. #ifndef NOSPL
  3155. /* Reading commands from a macro definition */
  3156.  
  3157.     } else if (cmdlvl > 0 && cmdstk[cmdlvl].src == CMD_MD) {
  3158.  
  3159.         /* Read second line of GET command */
  3160.  
  3161.         cbp = cmdbuf;
  3162.         if (getncm(cbp,CMDBL) < 0) {
  3163.         printf("Macro definition ends prematurely in multiline GET\n");
  3164.         rc = -9;
  3165.         goto endget;
  3166.         }
  3167.         cmres();
  3168.         if ((x = cmtxt("Oofa","",&s,xxstring)) < 0) return(x);
  3169.         if (*s == NUL) {        /* Make sure we got something */
  3170.         printf("Remote filename missing in multiline GET\n");
  3171.         rc = -9;
  3172.         goto endget;
  3173.         }
  3174.         strcpy(line,brstrip(s));    /* Copy filename to safe place */
  3175.         cmarg = line;        /* Point to it */
  3176.         x = strlen(line);        /* Get its length */
  3177.         lp = line + x + 1;        /* Where to put the next bit */
  3178.         y = LINBUFSIZ - x - 1;    /* Room left for next bit */
  3179.  
  3180.         /* And third line... */
  3181.  
  3182.         cmarg2 = "";        /* Assume no as-name */
  3183.         if (getncm(lp,y) > -1 && *lp >= ' ') { /* Read next line */
  3184.         x = strlen(lp);
  3185.         if (lp[x-1] == CR) lp[x-1] = NUL; /* Remove CR */
  3186.         cbp = cmdbuf;        /* Interpret the line */
  3187.         *cbp = NUL;        /* ... */
  3188.         y = CMDBL;        /* into the command buffer */
  3189.         zzstring(lp,&cbp,&y);
  3190.         if (*cmdbuf) {        /* If we have something */
  3191.             cmres();        /* parse it as an output filename */
  3192.             strcat(cmdbuf," ");
  3193.             if ((x = cmofi("Mupeen","",&s,NULL)) < 0) {
  3194.             rc = x;
  3195.             goto endget;
  3196.             }
  3197.             strcpy(lp,s);    /* Copy the name to safe place */
  3198.             cmarg2 = lp;    /* and make as-name pointer */
  3199.         }
  3200.         }
  3201.             x = 0;            /* Return code OK */
  3202. #endif /* NOSPL */
  3203.         } else {            /* Input is from terminal */
  3204.  
  3205.         cmsavp(psave,PROMPTL);
  3206.         cmsetp(" Remote file specification: "); /* Make new one */
  3207.         cmini(ckxech);
  3208.         x = -1;
  3209.         if (pflag) prompt(xxstring);
  3210.         while (x == -1) {        /* Prompt till they answer */
  3211.             x = cmtxt("Name of remote file(s)","",&cmarg,xxstring);
  3212.         debug(F111," cmtxt",cmarg,x);
  3213.         }
  3214.         if (x < 0) {
  3215.         cmsetp(psave);
  3216.         rc = x;
  3217.         goto endget;
  3218.         }
  3219.         if (*cmarg == NUL) {     /* If user types a bare CR, */
  3220.         printf("(cancelled)\n"); /* Forget about this. */
  3221.             cmsetp(psave);        /* Restore old prompt, */
  3222.         rc = 0;
  3223.         goto endget;
  3224.         }
  3225.         strcpy(line,brstrip(cmarg)); /* Make a safe copy */
  3226.         cmarg = line;
  3227.         cmsetp(" Local name to store it under: "); /* New prompt */
  3228.         cmini(ckxech);
  3229.         x = -1;
  3230.         if (pflag) prompt(xxstring);
  3231.         while (x == -1) {        /* Again, parse till answered */
  3232.             x = cmofi("Local file name","",&cmarg2,xxstring);
  3233.         }
  3234.         if (x < 0) {        /* Parse error */
  3235.         if (x == -3) {        /* CR = cancel */
  3236.             printf("(cancelled)\n"); /* Print message */
  3237.             x = 0;        /* Avoid further messages */
  3238.         }
  3239.         cmsetp(psave);        /* Restore prompt */
  3240.         rc = x;
  3241.         goto endget;
  3242.         }        
  3243.         x = -1;            /* Get confirmation. */
  3244.         while (x == -1) x = cmcfm();
  3245.         cmsetp(psave);        /* Restore old prompt. */
  3246.         }
  3247.     }
  3248. #endif /* NOFRILLS */
  3249.  
  3250.     if (x == 0) {            /* Good return from cmtxt or cmcfm, */
  3251.     debug(F110,"xxget cmarg",cmarg,0);
  3252.     strncpy(fspec,cmarg,CKMAXPATH);
  3253.     debug(F111,"xxget fspec",fspec,CKMAXPATH);
  3254.     if (cx == XXRETR)
  3255.       sstate = (CHAR) 'h';
  3256.     else
  3257.       sstate = (CHAR) ((cx == XXGET) ? 'r' : 'j'); /* Set start state. */
  3258.     if (local) {
  3259.         displa = 1;
  3260.         ttflui();
  3261.     }
  3262.     }
  3263. #ifndef NOFRILLS
  3264. #ifdef CK_TMPDIR
  3265. /* cmarg2 is also allowed to be a device or directory name */
  3266.  
  3267.     y = strlen(cmarg2);
  3268.     if (
  3269. #ifdef OS2
  3270.     (isalpha(cmarg2[0]) &&
  3271.      cmarg2[1] == ':' &&
  3272.      cmarg2[2] == '\0') ||
  3273.     isdir(cmarg2)
  3274. #else
  3275. #ifdef UNIX
  3276.     (y > 0 && cmarg2[y-1] == '/') || isdir(cmarg2)
  3277. #else
  3278. #ifdef OSK
  3279.     (y > 0) && isdir(cmarg2)
  3280. #else
  3281. #ifdef VMS
  3282.     (y > 0) && isdir(cmarg2)
  3283. #else
  3284. #ifdef STRATUS
  3285.     (y > 0) && isdir(cmarg2)
  3286. #endif /* STRATUS */
  3287. #endif /* VMS */
  3288. #endif /* OSK */
  3289. #endif /* UNIX */
  3290.  
  3291. #endif /* OS2 */
  3292.     ) {
  3293.     debug(F110,"RECEIVE arg disk or dir",cmarg2,0);
  3294.     if (!f_tmpdir) {
  3295.         s = zgtdir();
  3296.         if (s) {
  3297.         strncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
  3298.         f_tmpdir = 1;    /* and that we did this */
  3299.         cmarg2 = "";    /* and we don't have an as-name. */
  3300.         } else {
  3301.         printf("?Can't get current directory\n");
  3302.         cmarg2 = "";
  3303.         f_tmpdir = 0;
  3304.         rc = -9;
  3305.         goto endget;
  3306.         }
  3307.         if (!zchdir(cmarg2)) {    /* change to given disk/directory, */
  3308.         printf("?Can't access %s\n",cmarg2);
  3309.         cmarg2 = "";
  3310.         rc = -9;
  3311.         goto endget;
  3312.         }
  3313.     }
  3314.     }
  3315. #endif /* CK_TMPDIR */
  3316. #endif /* NOFRILLS */
  3317.  
  3318.     return(x);
  3319.  
  3320.   endget:
  3321. #ifdef CK_TMPDIR
  3322.     if (f_tmpdir) {
  3323.     zchdir(savdir);
  3324.     f_tmpdir = 0;
  3325.     }
  3326. #endif /* CK_TMPDIR */
  3327.     return(rc);
  3328. }
  3329.  
  3330. #ifndef NOSPL
  3331.  
  3332. /*
  3333.   _ G E T A R G S
  3334.  
  3335.   Used by XIF, FOR, and WHILE, each of which are implemented as 2-level
  3336.   macros; the first level defines the macro, the second runs it.
  3337.   This routine hides the fact that they are macros by importing the
  3338.   macro arguments (if any) from two levels up, to make them available
  3339.   in the XIF, FOR, and WHILE commands themselves; for example as loop
  3340.   indices, etc.
  3341. */
  3342. int
  3343. dogta(cx) int cx; {
  3344.     int i; char c; char mbuf[4]; char *p;
  3345.  
  3346.     if ((y = cmcfm()) < 0)
  3347.       return(y);
  3348.     if (cx == XXGTA)
  3349.       debug(F101,"_getargs maclvl","",maclvl);
  3350.     else if (cx == XXPTA)
  3351.       debug(F101,"_putargs maclvl","",maclvl);
  3352.     else
  3353.       return(-2);
  3354.     if (maclvl < 1)
  3355.       return(success = 0);
  3356.  
  3357.     debug(F101,"success","",success);
  3358.  
  3359.     mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = '\0'; /* Argument name buf */
  3360.     for (i = 0; i < 10; i++) {        /* For all args */
  3361.     c = (char) (i + '0');        /* Make name */
  3362.     mbuf[1] = (char) c;        /* Insert digit */
  3363.     if (cx == XXGTA) {        /* Get arg from level-minus-2 */
  3364.         if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
  3365.         else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
  3366.         if (!p) {
  3367.         debug(F111,"_getarg p","(null pointer)",i);
  3368.         } else debug(F111,"_getarg p",p,i);
  3369.         addmac(mbuf,p);
  3370.     } else if (cx == XXPTA) {    /* Put args level+2 */
  3371. #ifndef MAC
  3372.         connoi();            /* Turn off interrupts. */
  3373. #endif /* MAC */
  3374.         maclvl -= 2;        /* This is gross.. */
  3375.         p = m_arg[maclvl+2][i];
  3376.         if (p)
  3377.           debug(F111,"_putarg m_arg[maclvl+2][i]",p,i);
  3378.         else
  3379.           debug(F111,"_putarg m_arg[maclvl+2][i]","(null pointer)",i);
  3380.         addmac(mbuf,m_arg[maclvl+2][i]);
  3381.         maclvl += 2;
  3382. #ifndef MAC
  3383.         conint(trap,stptrap);    /* Restore interrupts */
  3384. #endif /* MAC */
  3385.     } else return(success = 0);
  3386.     }
  3387.     debug(F101,"_get/putarg exit","",i);
  3388.     debug(F101,"_get/putarg exit maclvl","",maclvl);
  3389.     debug(F101,"_get/putarg exit argc maclvl","",macargc[maclvl]);
  3390.  
  3391.     if (cx == XXGTA && maclvl > 1) {
  3392.     macargc[maclvl] = macargc[maclvl - 2];
  3393.     /* macargc[maclvl - 1] = macargc[maclvl - 2]; */
  3394.     }
  3395.  
  3396. #ifdef COMMENT
  3397. /*
  3398.   Internal commands don't change success variable if they succeed.
  3399. */
  3400.     return(success = 1);
  3401. #else
  3402.     return(1);
  3403. #endif /* COMMENT */
  3404.  
  3405. }
  3406. #endif /* NOSPL */
  3407.  
  3408. #ifndef NOSPL
  3409. /*
  3410.   Do the GOTO and FORWARD commands.
  3411.   s = Label to search for, cx = function code, XXGOTO or XXFWD.
  3412. */
  3413. int
  3414. dogoto(s, cx) char *s; int cx; {
  3415.     int i, j, x, y, z, bc;
  3416.     int stopflg;
  3417.     char tmplbl[50], *lp;
  3418.  
  3419.     stopflg = (cx == XXXFWD);        /* _FORWARD (used in SWITCH) */
  3420.     bc = 0;                /* Brace counter */
  3421.  
  3422.     debug(F101,"goto cx","",cx);
  3423.     debug(F101,"goto cmdlvl","",cmdlvl);
  3424.     debug(F101,"goto maclvl","",maclvl);
  3425.     debug(F101,"goto tlevel","",tlevel);
  3426.     debug(F110,"goto before conversion",s,0);
  3427.     y = (int)strlen(s);
  3428.     if (*s != ':') {            /* If the label mentioned */
  3429.     for (i = y; i > 0; i--) {    /* does not begin with a colon, */
  3430.         s[i] = s[i-1];        /* then insert one. */
  3431.     }                /* Also, convert to lowercase. */
  3432.     s[0] = ':';
  3433.     s[++y] = '\0';
  3434.     }
  3435.     debug(F111,"goto after conversion",s,y);
  3436.     if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
  3437.     printf("?Bad label syntax - '%s'\n",s);
  3438.     return(success = 0);
  3439.     }
  3440.     if (cmdlvl == 0) {
  3441.     printf("?Sorry, GOTO only works in a command file or macro\n");
  3442.     return(success = 0);
  3443.     }
  3444.     while (cmdlvl > 0) {        /* Only works inside macros & files */
  3445.     if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
  3446.         int i, m, flag;
  3447.         char *xp, *tp;
  3448.  
  3449.         /* GOTO: rewind the macro; FORWARD: start at current position */
  3450.  
  3451.         lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
  3452.         m = (int)strlen(lp) - y + 1;
  3453.         debug(F111,"goto in macro",lp,m);
  3454.  
  3455.         flag = 1;            /* flag for valid label position */
  3456.         for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
  3457.         if (*lp == '{')        /* But only at this level */
  3458.           bc++;            /* Anything inside braces is off */
  3459.         else if (*lp == '}')    /* limits. */
  3460.           bc--;
  3461.         if (stopflg && bc > 0)    /* This is good for SWITCH */
  3462.           continue;        /* but interferes with WHILE, etc. */
  3463.         if (*lp == ',') {
  3464.             flag = 1;
  3465.             continue;
  3466.         }
  3467.         if (flag) {        /* If in valid label position */
  3468.             if (*lp == SP)    /* eat leading spaces */
  3469.               continue;
  3470.             if (*lp != ':') {    /* Look for label introducer */
  3471.             flag = 0;    /* this isn't it */
  3472.             continue;    /* keep looking */
  3473.             }
  3474.         }
  3475.         if (!flag)        /* We don't have a label */
  3476.           continue;        /*  so keep looking... */
  3477.         xp = lp; tp = tmplbl;    /* Copy the label from the macro */
  3478.         j = 0;            /* to make it null-terminated */
  3479.         while (*tp = *xp) {
  3480.             if (j++ > 50) break;  /* j = length of word from macro */
  3481.             if (*tp < 33 || *tp == ',')    /* Look for end of word */
  3482.               break;
  3483.             else tp++, xp++;    /* Next character */
  3484.         }
  3485.         *tp = '\0';        /* In case we stopped early */
  3486.         /* Now do caseless string comparison, using longest length */
  3487.         debug(F111,"macro GOTO label",s,y);
  3488.         debug(F111,"macro target label",tmplbl,j);
  3489.         z = (stopflg && inpcas[cmdlvl]) ?
  3490.           strcmp(s,tmplbl) :
  3491.             xxstrcmp(s,tmplbl,(y > j) ? y : j);
  3492.         if (!z)
  3493.           break;
  3494.         else if (stopflg &&
  3495.             !xxstrcmp(":default",tmplbl,(8 > j) ? 8 : j))
  3496.           break;
  3497.         else
  3498.           flag = 0;
  3499.         }
  3500.         if (i == m) {        /* didn't find the label */
  3501.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  3502.         if (stopflg)
  3503.           return(0);
  3504.         if (!popclvl()) {    /* pop up to next higher level */
  3505.             printf("?Label '%s' not found\n",s); /* if none */
  3506.             return(0);        /* quit */
  3507.         } else continue;    /* otherwise look again */
  3508.         }
  3509.         debug(F110,"goto found macro label",lp,0);
  3510.         macp[maclvl] = lp;        /* set macro buffer pointer */
  3511.         return(1);
  3512.     } else if (cmdstk[cmdlvl].src == CMD_TF) {
  3513.         x = 0;            /* GOTO issued in take file */
  3514.         if (cx == XXGOTO) {        /* If GOTO, but not FORWARD, */
  3515.         rewind(tfile[tlevel]);    /* search file from beginning */
  3516.         tfline[tlevel] = 0;
  3517.         }
  3518.         while (! feof(tfile[tlevel])) {
  3519.         if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
  3520.           break;        /* If no more, done, label not found */
  3521.         tfline[tlevel]++;
  3522.         lp = line;        /* Got line */
  3523.         while (*lp == SP || *lp == HT)
  3524.           lp++;            /* Strip leading whitespace */
  3525.         if (*lp != ':') continue; /* Check for label introducer */
  3526.         tp = lp;        /* Get end of word */
  3527.         j = 0;
  3528.         while (*tp) {        /* And null-terminate it */
  3529.             if (*tp < 33) {
  3530.             *tp = '\0';
  3531.             break;
  3532.             } else tp++, j++;
  3533.         }
  3534.         if (!xxstrcmp(lp,s,(y > j) ? y : j)) { /* Caseless compare */
  3535.             x = 1;        /* Got it */
  3536.             break;        /* done. */
  3537.         } else if (stopflg &&
  3538.                !xxstrcmp(":default",tmplbl,(8 > j) ? 8 : j)) {
  3539.             x = 1;
  3540.             break;
  3541.         }
  3542.         }
  3543.         if (x == 0) {        /* If not found, print message */
  3544.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  3545.         if (stopflg)
  3546.           return(0);
  3547.         if (!popclvl()) {    /* pop up to next higher level */
  3548.             printf("?Label '%s' not found\n",s); /* if none */
  3549.             return(0);        /* quit */
  3550.         } else continue;    /* otherwise look again */
  3551.         }
  3552.         return(x);            /* Send back return code */
  3553.     }
  3554.     }
  3555.     printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
  3556.     return(0);
  3557. }
  3558. #endif /* NOSPL */
  3559.  
  3560. /* Finish parsing and do the IF, XIF, and WHILE commands */
  3561.  
  3562. char *
  3563. brstrip(p) char *p; {
  3564.     if (!p) return("");
  3565.     if (*p == '{') {
  3566.     int x;
  3567.     x = (int)strlen(p) - 1;
  3568.     if (p[x] == '}') {
  3569.         p[x] = NUL;
  3570.         p++;
  3571.     }
  3572.     }
  3573.     return(p);
  3574. }
  3575.  
  3576. #ifndef NOSPL
  3577.  
  3578. /*  C H K V A R  --  Check (if it's a) Variable  */
  3579.   
  3580. /*
  3581.   Crude and disgusting, but needed for OS/2, DOS, and Windows, where filenames
  3582.   have backslashes in them.  How do we know if a backslash in a filename is a
  3583.   directory separator, or if it's a Kermit backslash?  This routine does a
  3584.   rough syntax check of the next few characters and if it looks like it MIGHT
  3585.   be a variable, then it tries to evaluate it, and if the result is not empty,
  3586.   we say it's a variable, although sometimes it might not be -- some cases are
  3587.   truly ambiguous.  For example there might a DOS directory called \&a, and
  3588.   we also have a variable with the same name.  This is all for the sake of not
  3589.   having to tell PC users that they have to double all backslashes in file
  3590.   and directory names.
  3591.  
  3592.   Call with a string pointer pointing at the backslash of the suspected
  3593.   variable.  Returns 1 if it seems to be a variable, 0 if not.
  3594. */
  3595. int
  3596. chkvar(s) char *s; {
  3597.     int z = 0;                /* Return code - assume failure */
  3598.     if ((int)strlen(s) < 1) return(-2);
  3599.     if (*s == CMDQ) {            /* Object begins with backslash. */
  3600.     char c;
  3601.     c = s[1];            /* Character following backslash */
  3602.     if (c) {
  3603.         int t = 0;
  3604.         c = (char) (islower(c) ? toupper(c) : c);
  3605.         if (c == '%') {        /* Simple variable */
  3606.         t = 1;
  3607.         } else if (c == '&') {    /* Array */
  3608.         if (s[3] == '[')
  3609.           t = ckindex("]",s,4,0,1);
  3610.         } else if (c == '$' ||    /* Environment variable */
  3611.                c == 'V' ||    /* Built-in variable */
  3612.                c == 'M')    /* Macro name */
  3613.             t = (s[2] == '(');
  3614.         else if (c == 'F') {    /* Function reference */
  3615.         int x;
  3616.         if (x = ckindex("(",s,3,0,1))
  3617.           if (x = ckindex(")",s,x,0,1))
  3618.             t = 1;
  3619.         }
  3620.         if (t) {
  3621.         t = LINBUFSIZ-1;    /* This lets us test \v(xxx) */
  3622.         lp = line;        /* and even \f...(xxx) */
  3623.         zzstring(s,&lp,&t);    /* Evaluate it, whatever it is. */
  3624.         t = strlen(line);    /* Get its length. */
  3625.         debug(F111,"chkvar",line,t);
  3626.         z = t > 0;        /* If length > 0, it's defined */
  3627.         }
  3628.     }
  3629.     }
  3630.     return(z);
  3631. }
  3632.  
  3633. /*  D O I F  --  Do the IF command  */
  3634.  
  3635. int
  3636. doif(cx) int cx; {
  3637.     int x, y, z; char *s, *p;
  3638.     char *q;
  3639.     _PROTOTYP(char * evala, (char *));        
  3640. #ifdef OS2
  3641.     extern int keymac;
  3642. #endif /* OS2 */
  3643.  
  3644.     not = 0;                /* Flag for whether "NOT" was seen */
  3645.     z = 0;                /* Initial IF condition */
  3646.     ifargs = 0;                /* Count of IF condition words */
  3647.  
  3648. ifagain:
  3649.     if ((ifc = cmkeyx(iftab,nif,"","",xxstring)) < 0) { /* If what?... */
  3650.     if (ifc == -3) {
  3651.         printf("?Condition required\n");
  3652.         return(-9);
  3653.     } else if (chknum(atmbuf)) {
  3654.         ifc = 9999;
  3655.     } else {
  3656.         if (ifc == -9)
  3657.           printf("?No keywords match - \"%s\"\n", atmbuf);
  3658.         return(ifc);
  3659.     }
  3660.     }
  3661.     if (ifc == 9999)
  3662.       z = !(atoi(atmbuf) == 0);
  3663.     else
  3664.     switch (ifc) {            /* set z = 1 for true, 0 for false */
  3665.       case XXIFNO:            /* IF NOT */
  3666.     not ^= 1;            /* So NOT NOT NOT ... will work */
  3667.     ifargs++;
  3668.     goto ifagain;
  3669.       case XXIFTR:            /* IF TRUE */
  3670.     z = 1;
  3671.     debug(F101,"if true","",z);
  3672.     ifargs += 1;
  3673.     break;
  3674.       case XXIFNT:            /* IF FALSE */
  3675.     z = 0;
  3676.     debug(F101,"if true","",z);
  3677.     ifargs += 1;
  3678.     break;
  3679.       case XXIFSU:            /* IF SUCCESS */
  3680.     z = ( success != 0 );
  3681.     debug(F101,"if success","",z);
  3682.     ifargs += 1;
  3683.     break;
  3684.       case XXIFFA:            /* IF FAILURE */
  3685.     z = ( success == 0 );
  3686.     debug(F101,"if failure","",z);
  3687.     ifargs += 1;
  3688.     break;
  3689.       case XXIFDE:            /* IF DEFINED */
  3690.     if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0) {
  3691.         if (x == -3) return(-2);
  3692.         else return(x);
  3693.     }
  3694.     if (*s == CMDQ)
  3695.       z = chkvar(s);            /* \-thing */
  3696.     else
  3697.       z = ( mxlook(mactab,s,nmac) > -1 ); /* Look for exact match */
  3698.     debug(F111,"if defined",s,z);
  3699.     ifargs += 2;
  3700.     break;
  3701.  
  3702.       case XXIFBG:            /* IF BACKGROUND */
  3703.       case XXIFFG:            /* IF FOREGROUND */    
  3704.     bgchk();            /* Check background status */
  3705.     if (ifc == XXIFFG)        /* Foreground */
  3706.       z = pflag ? 1 : 0;
  3707.         else z = pflag ? 0 : 1;        /* Background */
  3708.     ifargs += 1;
  3709.     break;
  3710.  
  3711.       case XXIFCO:            /* IF COUNT */
  3712.     z = ( --count[cmdlvl] > 0 );
  3713.     if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
  3714.     debug(F101,"if count","",z);
  3715.     ifargs += 1;
  3716.     break;
  3717.  
  3718.       case XXIFEX:            /* IF EXIST */
  3719. #ifdef CK_TMPDIR
  3720.       case XXIFDI:            /* IF DIRECTORY */
  3721. #endif /* CK_TMPDIR */
  3722.     if ((x = cmfld(
  3723.                ((ifc == XXIFEX) ? "File" : "Directory name"),
  3724.                "",&s,
  3725. #ifdef OS2
  3726.                NULL        /* This allows \'s in filenames */
  3727. #else
  3728.                xxstring
  3729. #endif /* OS2 */
  3730.                )) < 0) {
  3731.         if (x == -3) {
  3732.         extern int cmflgs;
  3733.         if (cmflgs == 1) {
  3734.             printf("?File or directory name required\n");
  3735.             return(-9);
  3736.         }
  3737.         } else return(x);
  3738.     }
  3739.     if (ifc == XXIFEX) {
  3740.         z = (zchki(s) > -1L);
  3741.         debug(F101,"if exist 1","",z);
  3742. #ifdef OS2        
  3743.         if (!z) {            /* File not found. */
  3744.         int t;            /* Try expanding variables */
  3745.         t = LINBUFSIZ-1;    /* and looking again. */
  3746.         lp = line;
  3747.         zzstring(s,&lp,&t);
  3748.         s = line;
  3749.         z = ( zchki(s) > -1L );
  3750.         debug(F101,"if exist 2","",z);
  3751.         }
  3752. #endif /* OS2 */
  3753. #ifdef CK_TMPDIR
  3754.     } else {
  3755. #ifdef VMS
  3756.         z = (zchki(s) == -2)
  3757. #else
  3758. /* Because this doesn't catch $DISK1:[FOO]BLAH.DIR;1 */
  3759.         z = isdir(s)
  3760. #ifdef OS2
  3761.           || (isalpha(cmarg2[0]) &&
  3762.           cmarg2[1] == ':' &&
  3763.           cmarg2[2] == '\0')
  3764. #endif /* OS2 */
  3765. #endif /* VMS */
  3766.           ;
  3767.         debug(F101,"if directory 1","",z);
  3768.  
  3769.         if (!z) {            /* File not found. */
  3770.         int t;            /* Try expanding variables */
  3771.         t = LINBUFSIZ-1;    /* and looking again. */
  3772.         lp = line;
  3773.         zzstring(s,&lp,&t);
  3774.         s = line;
  3775.         z = isdir(s)
  3776. #ifdef OS2
  3777.           || (isalpha(cmarg2[0]) &&
  3778.               cmarg2[1] == ':' &&
  3779.               cmarg2[2] == '\0')
  3780. #endif /* OS2 */
  3781.             ;
  3782.         debug(F101,"if directory 2","",z);
  3783.         }
  3784. #endif /* CK_TMPDIR */
  3785.     }
  3786.     ifargs += 2;
  3787.     break;
  3788.  
  3789.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  3790.       case XXIFLL:            /* IF Lexically Less Than */
  3791.       case XXIFLG:            /* If Lexically Greater Than */
  3792.     if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
  3793.         if (x == -3) {
  3794.         printf("?Text required\n");
  3795.         return(-9);
  3796.         } else return(x);
  3797.     }
  3798.     s = brstrip(s);            /* Strip braces */
  3799.     x = (int)strlen(s);
  3800.     if (x > LINBUFSIZ-1) {
  3801.         printf("?IF: strings too long\n");
  3802.         return(-2);
  3803.     }
  3804.     lp = line;            /* lp points to first string */
  3805.     strcpy(lp,s);
  3806.     if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
  3807.         if (y == -3) {
  3808.         printf("?Text required\n");
  3809.         return(-9);
  3810.         } else return(y);
  3811.     }
  3812.     s = brstrip(s);
  3813.     y = (int)strlen(s);
  3814.     if (x + y + 2 > LINBUFSIZ) {
  3815.         printf("?IF: strings too long\n");
  3816.         return(-2);
  3817.     }
  3818.     tp = lp + y + 2;        /* tp points to second string */
  3819.     strcpy(tp,s);
  3820.     debug(F111,"IF EQ string 1, x",lp,x);
  3821.     debug(F111,"IF EQ string 2, y",tp,y);
  3822.     if (inpcas[cmdlvl]) {        /* INPUT CASE OBSERVE */
  3823.         x = strcmp(lp,tp);
  3824.         debug(F101,"IF EQ strcmp","",x);
  3825.     } else {                /* INPUT CASE IGNORE */
  3826.         x = xxstrcmp(lp,tp,(y > x) ? y : x); /* Use longest length */
  3827.         debug(F101,"IF EQ xxstrcmp","",x);
  3828.     }
  3829.     switch (ifc) {
  3830.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  3831.         z = (x == 0);
  3832.         break;
  3833.       case XXIFLL:            /* IF Lexically Less Than */
  3834.         z = (x < 0);
  3835.         break;
  3836.       case XXIFLG:            /* If Lexically Greater Than */
  3837.         z = (x > 0);
  3838.         break;
  3839.     }
  3840.     ifargs += 3;
  3841.     break;
  3842.  
  3843.       case XXIFAE:            /* IF (arithmetically) = */
  3844.       case XXIFLT:            /* IF (arithmetically) < */
  3845.       case XXIFGT: {            /* IF (arithmetically) > */
  3846.     /* Really should use longs here... */
  3847.     /* But cmnum parses ints. */
  3848.     int n1, n2;
  3849.     x = cmfld("first number or variable name","",&s,xxstring);
  3850.     if (x == -3) {
  3851.         printf("?Quantity required\n");
  3852.         return(-9);
  3853.     }
  3854.     if (x < 0) return(x);
  3855.     debug(F101,"xxifgt cmfld","",x);
  3856.     lp = line;
  3857.     strcpy(lp,s);
  3858.     debug(F110,"xxifgt exp1",lp,0);
  3859.  
  3860. /* The following bit is for compatibility with old versions of MS-DOS Kermit */
  3861.  
  3862.     if (!xxstrcmp(lp,"count",5)) {
  3863.         n1 = count[cmdlvl];
  3864.     } else if (!xxstrcmp(lp,"version",7)) {
  3865.         n1 = (int) vernum;
  3866.     } else if (!xxstrcmp(lp,"argc",4)) {
  3867.         n1 = (int) macargc[maclvl];
  3868.     } else {
  3869.  
  3870. /* End of compatibility bit */
  3871.  
  3872.         if (chknum(lp)) {
  3873.         n1 = atoi(lp);
  3874.         } else {            /* Check for arithmetic expression */
  3875.         q = evala(lp);        /* cmnum() does this but ... */
  3876.         if (chknum(q))        /* we're not using cmnum(). */
  3877.           n1 = atoi(q);
  3878.         else
  3879.           return(-2);
  3880.         }        
  3881.     }
  3882.     y = cmfld("second number or variable name","",&s,xxstring);
  3883.     if (y == -3) {
  3884.         printf("?Quantity required\n");
  3885.         return(-9);
  3886.     }
  3887.     if (y < 0) return(y);
  3888.         if ((int)strlen(s) < 1) return(-2);
  3889.     x = (int)strlen(lp);
  3890.     tp = line + x + 2;
  3891.     strcpy(tp,s);
  3892.     debug(F110,"xxifgt exp2",tp,0);
  3893.     if (!xxstrcmp(tp,"count",5)) {
  3894.         n2 = count[cmdlvl];
  3895.     } else if (!xxstrcmp(tp,"version",7)) {
  3896.         n2 = (int) vernum;
  3897.     } else if (!xxstrcmp(tp,"argc",4)) {
  3898.         n2 = (int) macargc[maclvl];
  3899.     } else {
  3900.         if (chknum(tp)) {
  3901.         n2 = atoi(tp);
  3902.         } else {
  3903.         q = evala(tp);
  3904.         if (chknum(q))
  3905.           n2 = atoi(q);
  3906.         else
  3907.           return(-2);
  3908.         }        
  3909.     }
  3910.     debug(F101,"xxifft ifc","",ifc);
  3911.     z = ((n1 <  n2 && ifc == XXIFLT)
  3912.       || (n1 == n2 && ifc == XXIFAE)
  3913.       || (n1 >  n2 && ifc == XXIFGT));
  3914.     debug(F101,"xxifft n1","",n1);
  3915.     debug(F101,"xxifft n2","",n2);
  3916.     debug(F101,"xxifft z","",z);
  3917.     ifargs += 3;
  3918.     break; }
  3919.  
  3920.       case XXIFNU:            /* IF NUMERIC */
  3921.     x = cmfld("variable name or constant","",&s,xxstring);
  3922.     if (x == -3) {
  3923.         extern int cmflgs;
  3924.         if (cmflgs == 1) {
  3925.         printf("?Quantity required\n");
  3926.         return(-9);
  3927.         }
  3928.     } else if (x < 0)
  3929.       return(x);
  3930.     debug(F111,"xxifnu cmfld",s,x);
  3931.     lp = line;
  3932.     strcpy(lp,s);
  3933.     debug(F110,"xxifnu quantity",lp,0);
  3934.         z = chknum(lp);
  3935. #ifdef COMMENT
  3936. /*
  3937.   This works, but it's not wise -- IF NUMERIC is mostly used to see if a
  3938.   string really does contain only numeric characters.  If they want to force
  3939.   evaluation, they can use \feval().
  3940. */
  3941.     if (!z) {            /* Not a number */
  3942.         x_ifnum = 1;        /* Avoid "eval" error messages */
  3943.         q = evala(lp);        /* Maybe it's an expression */
  3944.         z = chknum(q);        /* that evaluates to a number */
  3945.         x_ifnum = 0;        /* Put eval messages back to normal */
  3946.         if (z) debug(F110,"xxifnu exp",lp,0);
  3947.     }
  3948. #endif /* COMMENT */
  3949.         debug(F101,"xxifnu chknum","",z);
  3950.     ifargs += 2;
  3951.     break;
  3952.  
  3953. #ifdef ZFCDAT
  3954.       case XXIFNE: {            /* IF NEWER */
  3955.     char d1[20], * d2;        /* Buffers for 2 rrrrrrrrrrdates */
  3956.     if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
  3957.       return(z);
  3958.     strcpy(d1,zfcdat(s));
  3959.     if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
  3960.       return(z);
  3961.     d2 = zfcdat(s);
  3962.     if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
  3963.         printf("?Failure to get file date\n");
  3964.         return(-9);
  3965.     }
  3966.     debug(F110,"xxifnewer d1",d1,0);
  3967.     debug(F110,"xxifnewer d2",d2,0);
  3968.     z = (strcmp(d1,d2) > 0) ? 1 : 0;
  3969.         debug(F101,"xxifnewer","",z);
  3970.     ifargs += 2;
  3971.     break;
  3972.       }
  3973. #endif /* ZFCDAT */
  3974.  
  3975. #ifdef CK_IFRO
  3976.       case XXIFRO:            /* REMOTE-ONLY advisory */
  3977.     ifargs++;
  3978. #ifdef NOLOCAL
  3979.     z = 1;
  3980. #else
  3981.     z = remonly;
  3982. #endif /* NOLOCAL */
  3983.     break;
  3984. #endif /* CK_IFRO */
  3985.  
  3986.       case XXIFAL: {            /* ALARM */
  3987.       ifargs++;
  3988.       if (ck_alarm < 1L || alrm_date[0] < '0' || alrm_time[0] < '0') {
  3989.           z = 0;            /* ALARM not SET */
  3990.           break;            /* so IF ALARM fails */
  3991.       }
  3992.       x = 9;            /* Compare current date */
  3993.       s = tmpbuf;            /* and time with alarm time */
  3994.       zzstring("\\v(ndate)",&s,&x);
  3995.       z = (int) strncmp(tmpbuf,alrm_date,8); /* Compare dates */
  3996.       debug(F111,"IF ALARM date",alrm_date,z);
  3997.       if (z >= 0) {
  3998.           x = 6;            /* If dates equal, compare times */
  3999.           s = tmpbuf;
  4000.           zzstring("\\v(ntime)",&s,&x);
  4001.           z = strncmp(tmpbuf,alrm_time,5);
  4002.           debug(F111,"IF ALARM time",alrm_time,z);
  4003.       }    
  4004.       tmpbuf[0] = NUL;        /* z >= 0 if alarm is passed */
  4005.       z = (z>=0 ? 1 : 0);        /* z <  0 otherwise */
  4006.       debug(F101,"IF ALARM","",z);
  4007.         }
  4008.     break;
  4009.  
  4010. #ifdef OS2
  4011.       case XXIFSD:            /* Started-From-Dialer */
  4012.     ifargs++;
  4013.     z = StartedFromDialer;
  4014.     break;
  4015.  
  4016.       case XXIFTM:            /* Terminal-Macro */
  4017.     ifargs++;
  4018.     z = cmdstk[cmdlvl].ccflgs & CF_KMAC;
  4019.     break;
  4020. #endif /* OS2 */
  4021.  
  4022.       case XXIFEM:            /* Emulation is active */
  4023. #ifdef OS2    
  4024.     z = 1;
  4025. #else
  4026.     z = 0;
  4027. #endif /* OS2 */
  4028.     break;
  4029.  
  4030.       default:                /* Shouldn't happen */
  4031.     return(-2);
  4032.     }
  4033.     if (not) z = !z;            /* Handle NOT here for both IF & XIF */
  4034.  
  4035.     switch (cx) {            /* Separate handling for IF and XIF */
  4036.  
  4037.       case XXIF:            /* This is IF... */
  4038.     ifcmd[cmdlvl] = 1;        /* We just completed an IF command */
  4039.         debug(F101,"IF condition","",z);
  4040.     if (z) {            /* Condition is true */
  4041.         iftest[cmdlvl] = 1;        /* Remember that IF succeeded */
  4042.         if (maclvl > -1) {        /* In macro, */
  4043.         pushcmd();        /* save rest of command. */
  4044.         } else if (tlevel > -1) {    /* In take file, */
  4045.         debug(F100, "doif: pushing command", "", 0);
  4046.         pushcmd();        /* save rest of command. */
  4047.         } else {            /* If interactive, */
  4048.         cmini(ckxech);        /* just start a new command */
  4049.         printf("\n");        /* (like in MS-DOS Kermit) */
  4050.         if (pflag) prompt(xxstring);
  4051.         }
  4052.     } else {            /* Condition is false */
  4053.         iftest[cmdlvl] = 0;        /* Remember command failed. */
  4054.         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  4055.           return(y);        /* Gobble up rest of line */
  4056.     }
  4057.     return(0);
  4058.  
  4059.       case XXIFX: {            /* This is XIF (Extended IF) */
  4060.       char *p;
  4061.       char e[5];
  4062.       int i;
  4063.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  4064.         return(y);            /* Get object command. */
  4065.       p = s;
  4066.       lp = line;
  4067.       if (litcmd(&p,&lp) < 0) {    /* Insert quotes in THEN-part */
  4068.           return(-2);
  4069.       }
  4070.       if (!z) {            /* Use ELSE-part, if any */
  4071.           lp = line;        /* Write over THEN part. */
  4072.           *lp = NUL;
  4073.           while (*p == SP) p++;    /* Strip trailing spaces */
  4074.           if (*p) {            /* At end? */
  4075.           for (i = 0; i < 4; i++) e[i] = *p++; /* No, check for ELSE */
  4076.           if (xxstrcmp(e,"else",4)) return(-2);    /* No, syntax error */
  4077.           if (litcmd(&p,&lp) < 0) { /* Insert quotes */
  4078.               return(-2);
  4079.           }
  4080.           while (*p == SP) p++;    /* Strip trailing spaces */
  4081.           if (*p) return(-2);    /* Should be nothing here. */
  4082.           }
  4083.       }
  4084.       if (line[0]) {
  4085.           x = mlook(mactab,"_xif",nmac); /* get index of "_xif" macro. */
  4086.           if (x < 0) {            /* Not there? */
  4087.           addmmac("_xif",xif_def);    /* Put it back. */
  4088.           if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
  4089.               printf("?XIF macro gone!\n");
  4090.               return(success = 0);
  4091.           }
  4092.           }
  4093.           dodo(x,line,cmdstk[cmdlvl].ccflgs); /* Do the XIF macro */
  4094.       }
  4095.       return(0);
  4096.       }
  4097.       case XXWHI: {            /* WHILE Command */
  4098.       p = cmdbuf;            /* Capture IF condition */
  4099.       ifcond[0] = NUL;        /* from command buffer */
  4100.       while (*p == SP) p++;
  4101.       while (*p != SP) p++;
  4102.       ifcp = ifcond;
  4103.       strcpy(ifcp,"{ \\flit(if not ");
  4104.       ifcp += (int)strlen(ifcp);
  4105.       while (*p != '{' && *p != NUL) *ifcp++ = *p++;
  4106.       p = " goto _..bot) } ";
  4107.       while (*ifcp++ = *p++) ;
  4108.       debug(F110,"WHILE cmd",ifcond,0);
  4109.  
  4110.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  4111.         return(y);            /* Get object command. */
  4112.       p = s;
  4113.       lp = line;
  4114.       if (litcmd(&p,&lp) < 0) {    /* Insert quotes in object command */
  4115.           return(-2);
  4116.       }
  4117.       debug(F110,"WHILE body",line,0);
  4118.       if (line[0]) {
  4119.           char *p;
  4120.           x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
  4121.           if (x < 0) {        /* Not there? */
  4122.           addmmac("_while",whil_def); /* Put it back. */
  4123.           if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
  4124.               printf("?WHILE macro definition gone!\n");
  4125.               return(success = 0);
  4126.           }
  4127.           }
  4128.           p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
  4129.           if (p) {
  4130.           strcpy(p,ifcond);
  4131.           strcat(p,line);
  4132.           debug(F110,"WHILE dodo",p,0);
  4133.           dodo(x,p,cmdstk[cmdlvl].ccflgs);
  4134.           free(p);
  4135.           p = NULL;
  4136.           } else {
  4137.           printf("?Can't allocate storage for WHILE command");
  4138.           return(success = 0);
  4139.           }
  4140.       }
  4141.       return(0);
  4142.       }
  4143.       default:
  4144.     return(-2);
  4145.     }
  4146. }
  4147. #endif /* NOSPL */
  4148.  
  4149. /* Set up a TAKE command file */
  4150.  
  4151. int
  4152. dotake(s) char *s; {
  4153.     if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
  4154.     perror(s);
  4155.     debug(F110,"Failure to open",s,0);
  4156.     tlevel--;
  4157.     return(success = 0);
  4158.     } else {
  4159.     tfline[tlevel] = 0;        /* Line counter */
  4160. #ifdef VMS
  4161.     conres();            /* So Ctrl-C will work */
  4162. #endif /* VMS */
  4163. #ifndef NOSPL
  4164.     cmdlvl++;            /* Entering a new command level */
  4165.     if (cmdlvl > CMDSTKL) {
  4166.         cmdlvl--;
  4167.         printf("?TAKE files and/or DO commands nested too deeply\n");
  4168.         return(success = 0);
  4169.     }
  4170.     if (tfnam[tlevel]) {        /* Copy the filename */
  4171.         free(tfnam[tlevel]);
  4172.         tfnam[tlevel] = NULL;
  4173.     }
  4174.     if (tfnam[tlevel] = malloc(strlen(s) + 1))
  4175.       strcpy(tfnam[tlevel],s);
  4176.     ifcmd[cmdlvl] = 0;        /* Set variables for this cmd file */
  4177.     iftest[cmdlvl] = 0;
  4178.     count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
  4179.     intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
  4180.     inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
  4181.     takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
  4182.     merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
  4183.     cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
  4184.     cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
  4185.     cmdstk[cmdlvl].ccflgs = cmdstk[cmdlvl-1].ccflgs;
  4186. #else
  4187.     takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
  4188. #endif /* NOSPL */
  4189.     }
  4190.     return(1);
  4191. }
  4192. #endif /* NOICP */
  4193.