home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc190.zip / ckuus6.c < prev    next >
C/C++ Source or Header  |  1994-10-02  |  68KB  |  2,298 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, FDCCU@CUVMA.BITNET),
  8.   Columbia University Academic Information Systems, New York City.
  9.  
  10.   Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New
  11.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  12.   sold for profit as a software product itself, nor may it be included in or
  13.   distributed with commercial products or otherwise distributed by commercial
  14.   concerns to their clients or customers without written permission of the
  15.   Office of Kermit Development and Distribution, Columbia University.  This
  16.   copyright notice must not be removed, altered, or obscured.
  17. */
  18.  
  19. /* 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.  
  28. #ifdef datageneral
  29. #define fgets(stringbuf,max,fd) dg_fgets(stringbuf,max,fd)
  30. #endif /* datageneral */
  31.  
  32. /* External Kermit Variables, see ckmain.c for description. */
  33.  
  34. extern xx_strp xxstring;
  35.  
  36. extern int size, rpsiz, urpsiz, local, stdinf, sndsrc, xitsta,
  37.   displa, binary, parity, escape, flow,
  38.   turn, duplex, nfils, ckxech, pktlog, seslog, tralog, stdouf,
  39.   turnch, dfloc, keep, maxrps, warn, cnflg, tlevel, pflag, msgflg,
  40.   mdmtyp, zincnt, fblksiz, frecl, frecfm, atcapr, atdiso, verwho, quiet;
  41. extern int repars, techo;
  42.  
  43. #ifdef CK_IFRO
  44. extern int remonly;
  45. #endif /* CK_IFRO */
  46.  
  47. extern long vernum, speed;
  48. extern char *versio, *protv, *ckxv, *ckzv, *fnsv, *connv, *dftty, *cmdv;
  49. extern char *dialv, *loginv, *for_def[], *whil_def[], *xif_def[];
  50. extern char *ckxsys, *ckzsys, *cmarg, *cmarg2;
  51. extern char *DIRCMD, *PWDCMD, *DELCMD, *WHOCMD, ttname[], filnam[];
  52. extern CHAR sstate;
  53. extern char *zinptr;
  54.  
  55. #ifndef NOMSEND                /* Multiple SEND */
  56. extern char *msfiles[];
  57. #endif /* NOMSEND */
  58. extern char fspec[];            /* Most recent filespec */
  59.  
  60. #ifdef CK_TMPDIR
  61. extern int f_tmpdir;            /* Directory changed temporarily */
  62. extern char savdir[];            /* For saving current directory */
  63. #endif /* CK_TMPDIR */
  64.  
  65. /* Declarations from cmd package */
  66.  
  67. #ifdef DCMDBUF
  68. extern char *cmdbuf, *atmbuf;        /* Command buffers */
  69. #else
  70. extern char cmdbuf[], atmbuf[];        /* Command buffers */
  71. #endif /* DCMDBUF */
  72.  
  73. #ifndef NOSPL
  74. extern struct mtab *mactab;
  75. extern int nmac;
  76. #endif /* NOSPL */
  77.  
  78. /* Declarations from ck?fio.c module */
  79.  
  80. extern int backgrd, bgset;        /* Kermit executing in background */
  81.  
  82. #ifdef COMMENT
  83. /*
  84.   These must be on stack!
  85. */
  86. #ifndef NOSPL
  87. extern char vnambuf[];            /* Buffer for variable names */
  88. extern char *vnp;            /* Pointer to same */
  89. #endif /* NOSPL */
  90. #endif /* COMMENT */
  91.  
  92. extern char psave[];            /* For saving & restoring prompt */
  93. extern char *tp;            /* Temporary buffer */
  94.  
  95. /* Keyword tables specific to this module */
  96.  
  97. /* Modem signal table */
  98.  
  99. struct keytab mstab[] = {
  100. #ifdef COMMENT
  101. /* The forms preceded by backslash are for MS-DOS Kermit compatibility. */
  102. /* But... \dsr doesn't work because \d = decimal constant introducer */
  103.     "\\cd",  BM_DCD, CM_INV,        /* Carrier Detect */
  104.     "\\cts", BM_CTS, CM_INV,        /* Clear To Send  */
  105.     "\\dsr", BM_DSR, CM_INV,        /* Data Set Ready */
  106.     "\\ri",  BM_RNG, CM_INV,        /* Ring Indicator */
  107. #endif /* COMMENT */
  108.     "cd",    BM_DCD, 0,            /* Carrier Detect */
  109.     "cts",   BM_CTS, 0,            /* Clear To Send  */
  110.     "dsr",   BM_DSR, 0,            /* Data Set Ready */
  111.     "ri",    BM_RNG, 0            /* Ring Indicator */
  112. };
  113. int nms = (sizeof(mstab) / sizeof(struct keytab));
  114.  
  115. #ifndef NOSPL
  116. struct keytab opntab[] = {
  117. #ifndef NOPUSH
  118.     "!read",  XYFZ_Y, 0,
  119.     "!write", XYFZ_X, 0,
  120. #endif /* NOPUSH */
  121.     "append", XYFZ_A, 0,
  122.     "read",   XYFZ_O, 0,
  123.     "write",  XYFZ_N, 0
  124. };
  125. int nopn = (sizeof(opntab) / sizeof(struct keytab));
  126.  
  127. struct keytab iftab[] = {        /* IF commands */
  128.     "<",          XXIFLT, 0,
  129.     "=",          XXIFAE, 0,
  130.     ">",          XXIFGT, 0,
  131.     "background", XXIFBG, 0,
  132.     "count",      XXIFCO, 0,
  133.     "defined",    XXIFDE, 0,
  134. #ifdef CK_TMPDIR
  135.     "directory",  XXIFDI, 0,
  136. #endif /* CK_TMPDIR */
  137. #ifdef COMMENT
  138.     "eof",        XXIFEO, 0,
  139. #endif /* COMMENT */
  140.     "equal",      XXIFEQ, 0,
  141.     "error",      XXIFFA, CM_INV,
  142.     "exist",      XXIFEX, 0,
  143.     "failure",    XXIFFA, 0,
  144.     "foreground", XXIFFG, 0,
  145.     "llt",        XXIFLL, 0,
  146.     "lgt",        XXIFLG, 0,
  147. #ifdef ZFCDAT
  148.     "newer",      XXIFNE, 0,
  149. #endif /* ZFCDAT */
  150.     "not",        XXIFNO, 0,
  151.     "ok",         XXIFSU, CM_INV,
  152.     "numeric",    XXIFNU, 0,
  153.     "remote-only",XXIFRO, 0,
  154.     "success",    XXIFSU, 0
  155. };
  156. int nif = (sizeof(iftab) / sizeof(struct keytab));
  157. #endif /* NOSPL */
  158.  
  159. /* Variables and symbols local to this module */
  160.  
  161. #ifndef NODIAL 
  162. char *dialnum = (char *)0;        /* Remember DIAL number for REDIAL */
  163. extern char * dialdir;            /* Dial directory file name */
  164. extern FILE * dialfd;            /* Dial directory file descriptor */
  165. #endif /* NODIAL */
  166.  
  167. #ifndef NOSPL
  168. int ifc,                /* IF case */
  169.     not = 0,                /* Flag for IF NOT */
  170.     ifargs;                /* Count of IF condition words */
  171. char ifcond[100];            /* IF condition text */
  172. char *ifcp;                /* Pointer to IF condition text */
  173. #ifdef DCMDBUF
  174. extern int *ifcmd, *count, *iftest, *intime, *inpcas, *takerr, *merror;
  175. #else
  176. extern int ifcmd[];            /* Last command was IF */
  177. extern int iftest[];            /* Last IF was true */
  178. extern int count[];            /* For IF COUNT, one for each cmdlvl */
  179. extern int intime[];
  180. extern int inpcas[];
  181. extern int takerr[];
  182. extern int merror[];
  183. #endif /* DCMDBUF */
  184. #else
  185. extern int takerr[];
  186. #endif /* NOSPL */
  187.  
  188. #ifdef DCMDBUF
  189. extern char *line;            /* Character buffer for anything */
  190. extern char *tmpbuf;
  191. #else
  192. extern char line[], tmpbuf[];
  193. #endif /* DCMDBUF */
  194. extern char *lp;            /* Pointer to line buffer */
  195.  
  196. int cwdf = 0;                /* CWD has been done */
  197.  
  198. #ifndef NOSERVER
  199. extern int en_cwd, en_del, en_dir, en_fin, /* Flags for ENABLE/DISABLE */
  200.    en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who, en_bye,
  201.    en_asg, en_que;
  202. #endif /* NOSERVER */
  203.  
  204. extern FILE *tfile[];            /* File pointers for TAKE command */
  205. extern char *tfnam[];            /* Names of TAKE files */
  206.  
  207. extern int success;            /* Command success/failure flag */
  208.  
  209. #ifndef NOSPL
  210. extern int maclvl;            /* Macro to execute */
  211. extern char *macx[];            /* Index of current macro */
  212. extern char *mrval[];            /* Macro return value */
  213. extern char *macp[];            /* Pointer to macro */
  214. extern int macargc[];            /* ARGC from macro invocation */
  215.  
  216. extern char *m_arg[MACLEVEL][NARGS];    /* Stack of macro arguments */
  217. extern char *g_var[];            /* Global variables %a, %b, etc */
  218.  
  219. #ifdef DCMDBUF
  220. extern struct cmdptr *cmdstk;        /* The command stack itself */
  221. #else
  222. extern struct cmdptr cmdstk[];        /* The command stack itself */
  223. #endif /* DCMDBUF */
  224. extern int cmdlvl;            /* Current position in command stack */
  225. #endif /* NOSPL */
  226.  
  227. #define xsystem(s) zsyscmd(s)
  228.  
  229. static int x, y, z = 0;
  230. static char *s, *p;
  231.  
  232. /*  X X S T R C M P  --  Caseless string comparison  */
  233. /*
  234.   Call with pointers to the two strings, s1 and s2, and a length, n.
  235.   Compares up to n characters of the two strings and returns:
  236.     1 if s1 > t1
  237.     0 if s1 = s2
  238.    -1 if s1 < t1
  239. */
  240. int
  241. xxstrcmp(s1,s2,n) char *s1, *s2; int n; { /* Caseless string comparison. */
  242.     char t1, t2;            
  243.  
  244.     if (!s1) s1 = "";            /* Watch out for null pointers. */
  245.     if (!s2) s2 = "";
  246.     while (n--) {
  247.     t1 = *s1++;            /* Get next character from each. */
  248.     if (isupper(t1)) t1 = tolower(t1);
  249.     t2 = *s2++;
  250.     if (isupper(t2)) t2 = tolower(t2);
  251.     if (t1 < t2) return(-1);    /* s1 < s2 */
  252.     if (t1 > t2) return(1);        /* s1 > s2 */
  253.     }
  254.     return(0);                /* They're equal */
  255. }
  256.  
  257. #ifndef NOSPL
  258.  
  259. /* Do the ASK, ASKQ, GETOK, and READ commands */
  260.  
  261. #ifndef NOFRILLS
  262.    extern struct keytab yesno[];
  263.    extern int nyesno;
  264. #endif /* NOFRILLS */
  265.  
  266. int
  267. doask(cx) int cx; {
  268. #ifdef CK_RECALL
  269.     int sv_recall;
  270.     extern int on_recall;
  271. #endif /* CK_RECALL */
  272.     if (cx != XXGOK) {            /* Get variable name */
  273.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  274.         if (y == -3) {
  275.         printf("?Variable name required\n");
  276.         return(-9);
  277.         } else return(y);
  278.     }
  279.     strcpy(line,s);            /* Make a copy. */
  280.     lp = line;
  281.     if ((y = parsevar(s,&x,&z)) < 0)  /* Check to make sure it's a */
  282.       return(y);              /* variable name. */
  283.     }
  284.     if (cx == XXREA) {            /* READ command */
  285.     if ((y = cmcfm()) < 0)        /* Get confirmation */
  286.       return(y);
  287.     if (chkfn(ZRFILE) < 1) {    /* File open? */
  288.         printf("?Read file not open\n");
  289.         return(0);
  290.     }
  291.     s = line+VNAML+1;        /* Where to read into. */
  292.     y = zsinl(ZRFILE, s, LINBUFSIZ - VNAML - 1); /* Read a line. */
  293.     debug(F111,"read zsinl",s,y);
  294.     if (y < 0) {            /* On EOF or other error, */
  295.         zclose(ZRFILE);        /* close the file, */
  296.         delmac(lp);            /* delete the variable, */
  297.         return(success = 0);    /* and return failure. */
  298.     } else {            /* Read was OK. */
  299.         success = (addmac(lp,s) < 0 ? 0 : 1); /* Define the variable */
  300.             debug(F111,"read addmac",lp,success);
  301.         return(success);        /* Return success. */
  302.     }
  303.     }
  304.  
  305.     /* ASK, ASKQ, or GETOK */
  306.  
  307.     if ((y = cmtxt("Prompt, enclose in { braces } to preserve\n\
  308. leading and trailing spaces, precede question mark with backslash (\\).",
  309.            cx == XXGOK ? "{ Yes or no? }" : "",
  310.            &p,xxstring)) < 0) {
  311.     return(y);
  312.     }
  313. #ifdef VMS
  314. /*
  315.   In VMS, whenever a TAKE file or macro is active, we had to restore the 
  316.   original console modes or else Ctrl-C/Ctrl-Y would not work.  But here we
  317.   go interactive again, so we have to temporarily put them back.
  318. */
  319.     if (cmdlvl > 0)
  320.       concb((char)escape);
  321. #endif /* VMS */
  322.       
  323.     cmsavp(psave,PROMPTL);        /* Save old prompt */
  324.     cmsetp(brstrip(p));            /* Make new prompt */
  325.     if (cx == XXASKQ) {            /* For ASKQ, */
  326.     concb((char)escape);        /* put console in cbreak mode */
  327.     cmini(0);            /* and no-echo mode. */
  328.     } else {                /* For others, regular echoing. */
  329.     cmini(ckxech);
  330.     }
  331.     x = -1;                /* This means to reparse. */
  332. reprompt:
  333.     if (pflag) prompt(xxstring);    /* Issue prompt. */
  334.     if (cx == XXGOK) {
  335. #ifndef NOFRILLS
  336.     x = cmkey(yesno,nyesno,"","",xxstring);    /* GETOK uses keyword table */
  337.     if (x < 0) {            /* Parse error */
  338.         if (x == -3) {        /* No answer? */
  339.         printf("Please respond Yes or No\n"); /* Make them answer */
  340.         cmini(ckxech);
  341.         }
  342.         goto reprompt;
  343.     }
  344.     if ((y = cmcfm()) < 0)        /* Get confirmation */
  345.       goto reprompt;
  346.     cmsetp(psave);            /* Restore prompt */
  347. #ifdef VMS
  348.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  349.       conres();            /*  restore console again. */
  350. #endif /* VMS */
  351.     return(x);            /* Return success or failure */
  352. #else /* NOFRILLS */
  353.     ;
  354. #endif /* NOFRILLS */
  355.     } else if (cx == XXGETC) {        /* GETC */
  356.     char tmp[2];
  357.     x = coninc(0);            /* Just read one character */
  358.     if (x > -1) {
  359.         printf("\r\n");
  360.         tmp[0] = (char) (x & 0xff);
  361.         tmp[1] = NUL;
  362.         y = addmac(lp,tmp);        /* Add it to the macro table. */
  363.         debug(F111,"getc addmac",lp,y);
  364.         cmsetp(psave);        /* Restore old prompt. */
  365.     } else y = -1;
  366.     return(success = y < 0 ? 0 : 1);
  367.     } else {                /* ASK or ASKQ */
  368. #ifdef CK_RECALL
  369.     sv_recall = on_recall;
  370.     on_recall = 0;
  371. #endif /* CK_RECALL */
  372.     y = cmdgquo();            /* Get current quoting */
  373.     cmdsquo(0);            /* Turn off quoting */
  374.     while (x == -1) {        /* Prompt till they answer */
  375.         x = cmtxt("Please respond.","",&s,NULL);
  376.         debug(F111," cmtxt",s,x);
  377.     }
  378.     cmdsquo(y);            /* Restore previous quoting */
  379. #ifdef CK_RECALL
  380.     on_recall = sv_recall;
  381. #endif /* CK_RECALL */
  382.     if (cx == XXASKQ)        /* ASKQ must echo CRLF here */
  383.       printf("\r\n");
  384.     if (x < 0) {            /* If cmtxt parse error, */
  385.         cmsetp(psave);        /* restore original prompt */
  386. #ifdef VMS
  387.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  388.           conres();            /*  restore console again. */
  389. #endif /* VMS */
  390.         return(x);            /* and return cmtxt's error code. */
  391.     }
  392.     if (*s == NUL) {        /* If user typed a bare CR, */
  393.         cmsetp(psave);        /* Restore old prompt, */
  394.         delmac(lp);            /* delete variable if it exists, */
  395. #ifdef VMS
  396.         if (cmdlvl > 0)        /* In VMS and not at top level, */
  397.           conres();            /*  restore console again. */
  398. #endif /* VMS */
  399.         return(success = 1);    /* and return. */
  400.     }
  401.     y = addmac(lp,s);        /* Add it to the macro table. */
  402.     debug(F111,"ask addmac",lp,y);
  403.     cmsetp(psave);            /* Restore old prompt. */
  404. #ifdef VMS
  405.     if (cmdlvl > 0)            /* In VMS and not at top level, */
  406.       conres();            /*  restore console again. */
  407. #endif /* VMS */
  408.     return(success = y < 0 ? 0 : 1);
  409.     }
  410. }
  411. #endif /* NOSPL */
  412.  
  413. #ifndef NOSPL
  414. int
  415. doincr(cx) int cx; {            /* INCREMENT, DECREMENT */
  416.     char vnambuf[VNAML];        /* Buffer for variable names */
  417.  
  418.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) {
  419.     if (y == -3) {
  420.         printf("?Variable name required\n");
  421.         return(-9);
  422.     } else return(y);
  423.     }
  424.     if (*s != CMDQ) {
  425.         *vnambuf = CMDQ;
  426.     strncpy(vnambuf+1,s,VNAML-1);
  427.     } else strncpy(vnambuf,s,VNAML);
  428.  
  429.     if ((y = parsevar(vnambuf,&x,&z)) < 0)
  430.       return(y);
  431.  
  432.     if ((y = cmnum("by amount","1",10,&x,xxstring)) < 0) return(y);
  433.     if ((y = cmcfm()) < 0) return(y);
  434.  
  435.     z = (cx == XXINC ? 1 : 0);        /* Increment or decrement? */
  436.  
  437.     if (incvar(vnambuf,x,z,&y) < 0) {
  438.     printf("?Variable %s not defined or not numeric\n",vnambuf);
  439.     return(success = 0);
  440.     }
  441.     return(success = 1);
  442. }
  443. #endif /* NOSPL */
  444.  
  445.  
  446. /* Do the (_)DEFINE and (_)ASSIGN commands */
  447.  
  448. #ifndef NOSPL
  449. int
  450. dodef(cx) int cx; {
  451.     char vnambuf[VNAML];        /* Buffer for variable names */
  452.     char *vnp;                /* Pointer to same */
  453.     if (cx == XXDFX || cx == XXASX) 
  454.       y = cmfld("Macro or variable name","",&s,xxstring); /* eval var name */
  455.     else 
  456.       y = cmfld("Macro or variable name","",&s,NULL);     /* don't evaluate */
  457.     if (y < 0) {
  458.     if (y == -3) {
  459.         printf("?Variable name required\n");
  460.         return(-9);
  461.     } else return(y);
  462.     }
  463.     debug(F111,"dodef success",s,success);
  464.     strcpy(vnambuf,s);
  465.     vnp = vnambuf;
  466.     if (vnambuf[0] == CMDQ && (vnambuf[1] == '%' || vnambuf[1] == '&')) vnp++;
  467.     if (*vnp == '%' || *vnp == '&') {
  468.     if ((y = parsevar(vnp,&x,&z)) < 0) return(y);
  469.     debug(F101,"dodef","",x);
  470.     if (y == 1) {            /* Simple variable */
  471.         if ((y = cmtxt("Definition of variable","",&s,NULL)) < 0)
  472.           return(y);
  473.         s = brstrip(s);
  474.         debug(F110,"xxdef var name",vnp,0);
  475.         debug(F110,"xxdef var def",s,0);
  476.     } else if (y == 2) {        /* Array element */
  477.         if ((y = arraynam(s,&x,&z)) < 0) return(y);
  478.         if (x == 96) {
  479.         printf("?Argument vector array is read-only\n");
  480.         return(-9);
  481.         }
  482.         if (chkarray(x,z) < 0) return(-2);
  483.         if ((y = cmtxt("Definition of array element","",&s,NULL)) < 0)
  484.           return(y);
  485.         debug(F110,"xxdef array ref",vnp,0);
  486.         debug(F110,"xxdef array def",s,0);
  487.     }
  488.     } else {                /* Macro */
  489.     if ((y = cmtxt("Definition of macro","",&s,NULL)) < 0) return(y);
  490.     debug(F110,"xxdef macro name",vnp,0);
  491.     debug(F110,"xxdef macro def",s,0);
  492.     if (*s == '{') {        /* Allow macro def to be bracketed. */
  493.         s++;            /* If it is, remove the brackets. */
  494.         y = (int)strlen(s);        /* FOR command depends on this! */
  495.         if (y > 0 && s[y-1] == '}') s[y-1] = NUL;
  496.     }
  497.     }
  498.     if (*s == NUL) {            /* No arg given, undefine */
  499.     delmac(vnp);            /* silently... */
  500.     return(success = 1);        /* even if it doesn't exist... */
  501.     } 
  502.  
  503.     /* Defining a new macro or variable */
  504.  
  505.     if (cx == XXASS || cx == XXASX) {    /* ASSIGN rather than DEFINE? */
  506.     int t;
  507.     t = LINBUFSIZ-1;
  508.     lp = line;            /* If so, expand its value now */
  509.     zzstring(s,&lp,&t);
  510.     s = line;
  511.     }
  512.     debug(F111,"calling addmac",s,(int)strlen(s));
  513.  
  514.     y = addmac(vnp,s);            /* Add it to the appropriate table. */
  515.     if (y < 0) {
  516.     printf("?%s failed\n",(cx == XXASS || cx == XXASX) ?
  517.            "ASSIGN" : "DEFINE");
  518.     return(success = 0);
  519.     } else if (cx == XXASX || cx == XXDFX) /* For _ASG or _DEF, */
  520.       return(1);               /* don't change success variable */
  521.     else
  522.       return(success = 1);
  523. }
  524. #endif /* NOSPL */
  525.  
  526.  
  527. #ifndef NODIAL
  528. extern struct keytab partbl[];
  529. /*
  530.    L U D I A L  --  Lookup up dialing directory entry.
  531.   
  532.    Call with string to look up and file descriptor of open dialing directory
  533.    file.  On success, returns pointer to phone number and sets speed
  534.    and parity according to the directory entry.  On failure, returns the NULL
  535.    pointer.
  536. */
  537. char *
  538. ludial(s,f) char *s; FILE *f; {
  539.     int n, n1, n2, i, t;        /* Workers */
  540.     long xspeed = -1L, x2;        /* Speed to set from directory entry */
  541.     int xparity = -1;            /* Parity to set ...*/
  542.     char *info[5];            /* Array of words from entry */
  543.  
  544.     if (!s || !f) return(NULL);        /* Validate arguments */
  545.     if ((n1 = strlen(s)) < 1)
  546.       return(NULL);
  547. /*
  548.   We make one or two passes.  The first pass searches for an exact match.
  549.   If it fails, the second pass searches for the first entry of which the
  550.   search string is an abbreviation.  Of course this could be done in one
  551.   pass, but it was safer to add a couple lines for the for-loop than to
  552.   totally rearrange the code at the last minute.  (Edit 186)
  553. */
  554.     for (i = 0; i < 2; i++) {        /* Do this twice */
  555.     debug(F101,"ludial pass","",i+1);
  556.     rewind(f);            /* Go to beginning of directory file */
  557.     while (1) {
  558.         if (fgets(line,LINBUFSIZ,f) == NULL) { /* Read a line */
  559.         if (i == 0)        /* EOF */
  560.           break;        /* If first pass, start second pass */
  561.         if (!backgrd && !quiet)    /* If second pass, give message */
  562.           printf(" %s not in %s\n",s,dialdir);
  563.         debug(F110,"ludial fails",s,0);
  564.         return(NULL);
  565.         }
  566.         n = strlen(line);        /* Strip terminator(s) */
  567.         while ((n > 0) && (line[n-1] < '!'))
  568.           line[--n] = NUL;
  569.         debug(F111,"ludial",line,n);
  570.  
  571.         info[0] = NULL; info[1] = NULL; info[2] = NULL;
  572.         info[3] = NULL; info[4] = NULL;
  573.  
  574.         xwords(line,4,info);    /* Get the words. */
  575.         if (info[1]) {        /* First word. */
  576.         if ((n2 = (int) strlen(info[1])) < 1) /* Its length */
  577.           continue;        /* If no first word, keep looking. */
  578.  
  579.         if (n2 < n1)        /* If directory entry name shorter */
  580.           continue;        /* than search name, then no match. */
  581.         if (i == 0 && n2 != n1)    /* Require exact match on first pass */
  582.           continue;
  583.         if (xxstrcmp(s,info[1],n1)) /* Caseless string comparison */
  584.           continue;        /* up to length of search name */
  585.         if (!backgrd && !quiet)
  586.           printf(" From dialing directory %s: %s=%s\n",
  587.             dialdir,info[1],info[2] ? info[2] : "(number missing)");
  588.         if (!info[2])
  589.           return("");
  590.         if (info[3]) {        /* Third word = speed */
  591.             if (*info[3] != '=') { /* "=" means don't change it */
  592.             xspeed = atol(info[3]);
  593.             x2 = xspeed / 10L;
  594.             if (x2 > 0) {
  595.                 if (ttsspd((int) x2) < 0)
  596.                   printf("\n Can't set speed to %s\n",info[3]);
  597.                 else 
  598.                   speed = ttgspd();
  599.             }
  600.             }
  601.         }
  602.         if (info[4]) {        /* 4th word = parity */
  603.             if (*info[4] != '=') { /* "=" means don't change it */
  604.             if ((xparity = lookup(partbl,info[4],5,&t)) > -1)
  605.               parity = xparity;
  606.             }
  607.         }
  608.         return(info[2]);    /* Return 2nd word = phone number */
  609.         }
  610.     }
  611.     }
  612.     return(NULL);            /* Failure */
  613. }
  614.  
  615. int
  616. dodial(cx) int cx; {            /* DIAL or REDIAL */
  617.     int sparity;            /* For saving global parity value */
  618.     if (cx == XXRED) {            /* REDIAL or... */
  619.     if ((y = cmcfm()) < 0) return(y);
  620.     if (dialnum) {
  621.         s = dialnum;
  622.     } else {
  623.         printf("?No DIAL command given yet\n");
  624.         return(-9);
  625.     }
  626.     } else if (cx == XXDIAL) {        /* DIAL command */
  627.     char *s2;
  628.     if (dialdir && *dialdir)
  629.       s2 = "Number to dial or entry from dial directory";
  630.     else
  631.       s2 = "Number to dial";
  632.     if ((x = cmtxt(s2,"",&s,xxstring)) < 0)
  633.       return(x);
  634.     if (s == NULL || (int)strlen(s) == 0) {
  635.         printf("?You must specify a number to dial\n");
  636.         return(-9);
  637.     }
  638.     if (dialfd) {            /* Have dialing directory? */
  639.         s2 = ludial(s,dialfd);    /* Look up in dialing directory */
  640.         if (s2) {
  641.         if ((int)strlen(s2) < 1) {
  642.             printf(
  643.              "?Dialing directory \"%s\" entry lacks phone number\n",s);
  644.             return(-9);
  645.         } else
  646.           s = s2;        /* Make substitution if found */
  647.         }
  648.     }
  649.     if (dialnum) free(dialnum);    /* Make copy for REDIAL */
  650.     dialnum = malloc((int)strlen(s) + 1);
  651.     if (dialnum) strcpy(dialnum,s);
  652.     } else return(-2);
  653. #ifdef VMS
  654.     conres();                /* So Ctrl-C/Y will work */
  655. #endif /* VMS */
  656. /*
  657.   A rather radical change for edit 190...
  658.  
  659.   Some modems do not react well to parity.  Also, if we are dialing through a
  660.   TCP/IP TELNET modem server, parity can be fatally misinterpreted as TELNET
  661.   negotiations.  Note that at this point it is very likely that we picked up a
  662.   parity setting from the dialing directory (in the call to ludial() above).
  663.   So now we save the current parity, set it to NONE during the dialing
  664.   process, and then restore it afterwards.  This should work even if the user
  665.   interrupts the DIAL command, because the DIAL module has its own interrupt
  666.   handler.  BUT... if, for some reason, a dialing device actually *requires*
  667.   parity (e.g. CCITT V.25bis says that even parity should be used), this
  668.   might prevent successful dialing.
  669. */
  670.     sparity = parity;            /* Save current parity */
  671.     parity = 0;                /* Set parity to NONE */
  672.     success = ckdial(s);        /* Try to dial */
  673.     parity = sparity;            /* Restore parity */
  674. #ifdef OS2
  675.     ttres();
  676. #endif /* OS2 */
  677. #ifdef VMS
  678.     concb((char)escape);        /* Back to command parsing mode */
  679. #endif /* VMS */
  680.     return(success);
  681. }
  682. #endif /* NODIAL */
  683.  
  684. int                    /* Do the DIRECTORY command */
  685. dodir() {
  686. #ifndef MAC
  687.     char *dc;
  688. #endif /* MAC */
  689. #ifdef MAC
  690. /*
  691.   This is a crude, do-it-yourself directory command.  It shows all the
  692.   files in the current directory: size and name of each file.  Only regular
  693.   files are shown.  With a little more work, it could also show directories,
  694.   and mark files as regular or directories, and it could also show dates.
  695.   See sample code in zldir() routine in ckmfio.c.
  696. */
  697.     char mac_name[65];
  698.     long mac_len, nfiles, nbytes;
  699.     extern long mac_znextlen;        /* See ckmfio.c for this. */
  700.  
  701.     if ((y = cmcfm()) < 0)
  702.       return(y);
  703.  
  704.     nfiles = nbytes = 0L;
  705.     printf("\nDirectory of %s\n\n",zgtdir());
  706.     x = zxpand(":");
  707.     while (x-- > 0) {
  708.     if (!znext(mac_name))
  709.       break;
  710.     mac_len = zchki(mac_name);
  711.     if (mac_len > -1L) {
  712.         nfiles++;
  713.         nbytes += mac_znextlen;
  714.         printf("%10ld %s\n", mac_znextlen, mac_name);
  715.     }
  716.     }
  717.     printf("\n%ld file%s, %ld byte%s\n\n",
  718.        nfiles,
  719.        (nfiles == 1) ? "" : "s",
  720.        nbytes,
  721.        (nbytes == 1) ? "" : "s"
  722.        );
  723.     return(success = 1);
  724. #else
  725. #ifdef VMS
  726.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  727.       return(x);
  728.     /* now do this the same as a shell command - helps with LAT  */
  729.     conres();                /* Make console normal */
  730.     lp = line;
  731.     if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
  732.     sprintf(lp,"%s %s",dc,s);
  733.     debug(F110,"DIR string", line, 0);
  734.     x = zshcmd(lp);
  735.     debug(F101,"DIR return code", "", x);
  736.     concb((char)escape);
  737.     return(success = (x > 0) ? 1 : 0);
  738. #else
  739. #ifdef AMIGA
  740.     if ((x = cmtxt("Directory/file specification","",&s,xxstring)) < 0)
  741.       return(x);
  742. #else
  743. #ifdef datageneral
  744.     if ((x = cmtxt("Directory/file specification","+",&s,xxstring)) < 0)
  745.       return(x);
  746. #else
  747. #ifdef OS2
  748.     tmpbuf[0] = NUL;
  749.     if ((x = cmifi2(
  750. "Device, directory, and/or file specification,\n\
  751.  or switch(es), or '> file'","",
  752.             &s,&y,1,xxstring)) < 0) {
  753.     debug(F101,"DIR cmifi2","",x);
  754.     if (x == -3) {            /* Done. */
  755.         goto sw_skip;
  756.     } else if (x == -2 && (*s == '/' || *s == '>')) {
  757.         strncpy(tmpbuf,s,TMPBUFSIZ); /* Switch or redirect */
  758.         if ((y = cmcfm()) < 0)
  759.           return(y);
  760.         else
  761.           goto sw_skip;
  762.     } else if (x == -2 && !strchr(s,'.')) {    /* Maybe ".*" is missing */
  763.         goto fs_copy;
  764.     } else if (x == -2) {
  765.         printf("%s not found\n",s);
  766.         return(-9);
  767.     } else
  768.       return(x);
  769.     }
  770. #else /* General Case */
  771.     if ((x = cmdir("Directory/file specification","",&s,xxstring)) < 0)
  772.       if (x != -3) return(x);
  773. #endif /* OS2 */
  774. #endif /* datageneral */
  775. #endif /* AMIGA */
  776.  
  777. #ifdef OS2
  778. fs_copy:
  779. #endif /* OS2 */
  780.     debug(F110,"DIR fs_copy",s,0);
  781.     strncpy(tmpbuf,s,TMPBUFSIZ);    /* Copy the filespec */
  782.  
  783. #ifdef OS2
  784.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  785.     /* Only do this to filenames, not switches! */
  786.     char *p = tmpbuf;
  787.     while (*p) {            /* Change them back to \ */
  788.         if (*p == '/') *p = '\\';
  789.         p++;
  790.     }
  791.     }
  792.     debug(F110,"DIR tmpbuf 1",tmpbuf,0);
  793.     /* Now parse trailing switches like /P/O-D... */
  794.     if ((x = cmtxt("Optional switches and/or redirect for OS/2 DIR command",
  795.            "",&s,xxstring)) < 0)
  796.       return(x);
  797.     strcat(tmpbuf,s);            /* Append them to the filespec */
  798.     debug(F110,"DIR tmpbuf 2",tmpbuf,0);
  799. sw_skip:
  800. #else
  801.     if ((y = cmcfm()) < 0) return(y);
  802. #endif /* OS2 */
  803.     s = tmpbuf;
  804.     lp = line;
  805.     if (!(dc = getenv("CK_DIR"))) dc = DIRCMD;
  806.     sprintf(lp,"%s %s",dc,s);
  807.     debug(F110,"DIR",line,0);
  808.     xsystem(line);
  809.     return(success = 1);        /* who cares... */
  810. #endif /* VMS */
  811. #endif /* MAC */
  812. }
  813.  
  814. #ifndef NOSERVER
  815. #ifndef NOFRILLS
  816. /* Do the ENABLE and DISABLE commands */
  817.  
  818. int
  819. doenable(cx,x) int cx, x; {
  820.     y = ((cx == XXENA) ? 1 : 0);
  821.     switch (x) {
  822.       case EN_ALL:
  823.     en_cwd = en_del = en_dir = en_fin = en_get = y;
  824.     en_sen = en_set = en_spa = en_typ = en_who = y;
  825. #ifndef datageneral
  826.         en_bye = y;
  827. #endif /* datageneral */
  828. #ifndef NOPUSH
  829.     en_hos = y;
  830. #endif /* NOPUSH */
  831. #ifndef NOSPL
  832.     en_asg = en_que = y;
  833. #endif /* NOSPL */
  834.     break;
  835.       case EN_BYE:
  836. #ifndef datageneral
  837. /*
  838.   In Data General AOS/VS Kermit can't log out its superior process.
  839. */
  840.         en_bye = y;
  841. #endif /* datageneral */
  842.     break;
  843.       case EN_CWD:
  844.     en_cwd = y;
  845.     break;
  846.       case EN_DEL:
  847.     en_del = y;
  848.     break;
  849.       case EN_DIR:
  850.     en_dir = y;
  851.     break;
  852.       case EN_FIN:
  853.     en_fin = y;
  854.     break;
  855.       case EN_GET:
  856.     en_get = y;
  857.     break;
  858. #ifndef NOPUSH
  859.       case EN_HOS:
  860.     en_hos = y;
  861.     break;
  862. #endif /* NOPUSH */
  863.       case EN_SEN:
  864.     en_sen = y;
  865.     break;
  866.       case EN_SET:
  867.     en_set = y;
  868.     break;
  869.       case EN_SPA:
  870.     en_spa = y;
  871.     break;
  872.       case EN_TYP:
  873.     en_typ = y;
  874.     break;
  875.       case EN_WHO:
  876.     en_who = y;
  877.     break;
  878. #ifndef NOSPL
  879.       case EN_ASG:
  880.     en_asg = y;
  881.     break;
  882.       case EN_QUE:
  883.     en_que = y;
  884.     break;
  885. #endif /* NOSPL */
  886.       default:
  887.     return(-2);
  888.     }
  889.     return(1);
  890. }
  891. #endif /* NOFRILLS */
  892. #endif /* NOSERVER */
  893.  
  894. #ifndef NOFRILLS
  895. int
  896. dodel() {                /* DELETE */
  897. #ifndef MAC
  898.     long zl;
  899. #endif /* MAC */
  900.     if ((x = cmifi("File(s) to delete","",&s,&y,xxstring)) < 0) {
  901.     if (x == -3) {
  902.         printf("?A file specification is required\n");
  903.         return(-9);
  904.     } else return(x);
  905.     }
  906. #ifdef MAC
  907.     strcpy(line,s);
  908. #else
  909.     strncpy(tmpbuf,s,TMPBUFSIZ);    /* Make a safe copy of the name. */
  910. #ifdef OS2
  911.     {   /* Lower level functions change / to \, not good for CMD.EXE. */
  912.     char *p = tmpbuf;
  913.     while (*p) {            /* Change them back to \ */
  914.         if (*p == '/') *p = '\\';
  915.         p++;
  916.     }
  917.     }
  918. #endif /* OS2 */
  919.     debug(F110,"xxdel tmpbuf",tmpbuf,0);
  920.     sprintf(line,"%s %s",DELCMD,tmpbuf); /* Construct the system command. */
  921. #endif /* MAC */
  922.     debug(F110,"xxdel line",line,0);
  923.     if ((y = cmcfm()) < 0) return(y);    /* Confirm the user's command. */
  924. #ifdef VMS
  925.     conres();
  926. #endif /* VMS */
  927. #ifdef MAC
  928.     s = line;
  929.     success = (zdelet(line) == 0);
  930. #else
  931.     s = tmpbuf;
  932.     xsystem(line);            /* Let the system do it. */
  933.     zl = zchki(tmpbuf);
  934.     success = (zl == -1L);
  935. #endif /* MAC */
  936.     if (msgflg)
  937.       printf("%s - %sdeleted\n",s, success ? "" : "not ");
  938. #ifdef VMS
  939.     concb((char)escape);
  940. #endif /* VMS */
  941.     return(success);
  942. }
  943. #endif /* NOFRILLS */
  944.  
  945. #ifndef NOSPL                /* The ELSE command */
  946. int
  947. doelse() {
  948.     if (!ifcmd[cmdlvl]) {
  949.     printf("?ELSE doesn't follow IF\n");
  950.     return(-2);
  951.     }
  952. #ifdef COMMENT
  953. /*
  954.   Wrong.  This prevents IF..ELSE IF...ELSE IF...ELSE IF...ELSE...
  955.   from working.
  956. */
  957.     ifcmd[cmdlvl] = 0;
  958. #endif /* COMMENT */
  959.     if (!iftest[cmdlvl]) {        /* If IF was false do ELSE part */
  960.     if (maclvl > -1) {        /* In macro, */
  961.         pushcmd();            /* save rest of command. */
  962.     } else if (tlevel > -1) {    /* In take file, */
  963.         pushcmd();            /* save rest of command. */
  964.     } else {            /* If interactive, */
  965.         cmini(ckxech);        /* just start a new command */
  966.         printf("\n");        /* (like in MS-DOS Kermit) */
  967.         if (pflag) prompt(xxstring);
  968.     }
  969.     } else {                /* Condition is false */
  970.     if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  971.       return(y);            /* Gobble up rest of line */
  972.     }
  973.     return(0);
  974. }
  975. #endif /* NOSPL */
  976.  
  977. #ifndef NOSPL
  978. int
  979. dofor() {                /* The FOR command. */
  980.     int fx, fy, fz;            /* loop variables */
  981.     char *ap;                /* macro argument pointer */
  982.  
  983.     if ((y = cmfld("Variable name","",&s,NULL)) < 0) { /* Get variable name */
  984.     if (y == -3) {
  985.         printf("?Variable name required\n");
  986.         return(-9);
  987.     } else return(y);
  988.     }
  989.     if ((y = parsevar(s,&x,&z)) < 0)    /* Check it. */
  990.       return(y);
  991.  
  992.     lp = line;                /* Build a copy of the command */
  993.     strcpy(lp,"_forx ");
  994.     lp += (int)strlen(line);        /* "_for" macro. */
  995.     ap = lp;                /* Save pointer to macro args. */
  996.  
  997.     if (*s == CMDQ) s++;        /* Skip past backslash if any. */
  998.     while (*lp++ = *s++) ;        /* copy it */
  999.     lp--; *lp++ = SP;            /* add a space */
  1000.  
  1001.     if ((y = cmnum("initial value","",10,&fx,xxstring)) < 0) {
  1002.     if (y == -3) return(-2);
  1003.     else return(y);
  1004.     }
  1005.     s = atmbuf;                /* Copy the atom buffer */
  1006.     if ((int)strlen(s) < 1) goto badfor;
  1007.     while (*lp++ = *s++) ;        /* (what they actually typed) */
  1008.     lp--; *lp++ = SP;
  1009.  
  1010.     if ((y = cmnum("final value","",10,&fy,xxstring)) < 0) {
  1011.     if (y == -3) return(-2);
  1012.     else return(y);
  1013.     }
  1014.     s = atmbuf;                /* Same deal */
  1015.     if ((int)strlen(s) < 1) goto badfor;
  1016.     while (*lp++ = *s++) ;
  1017.     lp--; *lp++ = SP;
  1018.  
  1019.     if ((y = cmnum("increment","1",10,&fz,xxstring)) < 0) {
  1020.     if (y == -3) return(-2);
  1021.     else return(y);
  1022.     }
  1023.     sprintf(tmpbuf,"%d ",fz);
  1024.     s = atmbuf;                /* same deal */
  1025.     if ((int)strlen(s) < 1) goto badfor;
  1026.     while (*lp++ = *s++) ;
  1027.     lp--; *lp++ = SP;
  1028.  
  1029.     /* Insert the appropriate comparison operator */
  1030.     if (fz < 0)
  1031.       *lp++ = '<';
  1032.     else
  1033.       *lp++ = '>';
  1034.     *lp++ = SP;
  1035.  
  1036.     if ((y = cmtxt("Command to execute","",&s,NULL)) < 0) return(y);
  1037.     if ((int)strlen(s) < 1) return(-2);
  1038.     
  1039.     if (litcmd(&s,&lp) < 0) {
  1040.     printf("?Unbalanced brackets\n");
  1041.     return(0);
  1042.     }
  1043.     if (fz == 0) {
  1044.     printf("?Zero increment not allowed\n");
  1045.     return(0);
  1046.     }
  1047.     x = mlook(mactab,"_forx",nmac);    /* Look up FOR macro definition */
  1048.     if (x < 0) {            /* Not there? */
  1049.     addmmac("_forx",for_def);    /* Put it back. */
  1050.     if ((x = mlook(mactab,"_forx",nmac)) < 0) { /* Look it up again. */
  1051.         printf("?FOR macro definition gone!\n"); /* Shouldn't happen. */
  1052.         return(success = 0);
  1053.     }
  1054.     }
  1055.     debug(F110,"FOR command",line,0);
  1056.     return(success = dodo(x,ap));    /* Execute the FOR macro. */
  1057.  
  1058. badfor: printf("?Incomplete FOR command\n");
  1059.     return(-2);
  1060. }
  1061. #endif /* NOSPL */
  1062.  
  1063. #ifndef NOFRILLS
  1064. /* Do the BUG command */
  1065.  
  1066. int
  1067. dobug() {
  1068.     printf("\n%s,%s\n Numeric: %ld",versio,ckxsys,vernum);
  1069.     if (verwho) printf("-%d",verwho);
  1070.     printf("\n\n\
  1071. Before deciding you have found a bug, please consult the documentation:\n");
  1072.     printf(" . \"Using C-Kermit\"\n");
  1073. #ifndef OS2
  1074.    printf(" . The CKCKER.BWR file\n");
  1075. #endif /* OS2 */
  1076. #ifdef UNIX
  1077.     printf(" . The CKUKER.BWR file\n");
  1078. #else
  1079. #ifdef VMS
  1080.     printf(" . The CKVKER.BWR file\n");
  1081. #else
  1082. #ifdef OS2
  1083.     printf(" . The CKERMIT.INF file\n");
  1084. #else
  1085. #ifdef datageneral
  1086.     printf(" . The CKDKER.BWR file\n");
  1087. #else
  1088. #ifdef STRATUS
  1089.     printf(" . The CKLKER.BWR file\n");
  1090. #else
  1091. #ifdef AMIGA
  1092.     printf(" . The CKIKER.BWR file\n");
  1093. #else
  1094. #ifdef GEMDOS
  1095.     printf(" . The CKSKER.BWR file\n");
  1096. #else
  1097. #ifdef MAC
  1098.     printf(" . The CKMKER.BWR file\n");
  1099. #else
  1100. #ifdef OSK
  1101.     printf(" . The CK9KER.BWR file\n");
  1102. #else
  1103.     printf(" . The appropriate system-dependent CK?KER.BWR file\n");
  1104. #endif
  1105. #endif
  1106. #endif
  1107. #endif
  1108. #endif
  1109. #endif
  1110. #endif
  1111. #endif
  1112. #endif
  1113.  
  1114.     printf("\nTo report C-Kermit bugs, send e-mail to:\n");
  1115.     printf(" kermit@columbia.edu (Internet)\n");
  1116.     printf(" KERMIT@CUVMA (EARN/CREN/BITNET)\n");
  1117.     printf(" ...!uunet!columbia.edu!kermit (Usenet)\n");
  1118.     printf("Or write to:\n Kermit Development\n Columbia University\n");
  1119.     printf(" 612 W 115 Street\n");
  1120.     printf(" New York, NY  10025  USA\nOr call:\n +1 212 854-5126 (USA)\n\n");
  1121. #ifndef NOSHOW
  1122. #ifndef NOFRILLS
  1123.     printf(
  1124. "Before reporting problems, please use the SHOW VERSION and SHOW FEATURES\n");
  1125.     printf(
  1126. "commands to get detailed program version and configuration information.\n\n");
  1127. #endif /* NOFRILLS */
  1128. #endif /* NOSHOW */
  1129.     return(1);
  1130. }
  1131. #endif /* NOFRILLS */
  1132.  
  1133. #ifndef NOSPL
  1134. int
  1135. dopaus(cx) int cx; {
  1136.     /* Both should take not only secs but also hh:mm:ss as argument. */
  1137.     if (cx == XXWAI)
  1138.       y = cmnum("seconds to wait","1",10,&x,xxstring);
  1139.     else if (cx == XXPAU)
  1140.       y = cmnum("seconds to pause","1",10,&x,xxstring);
  1141.     else
  1142.       y = cmnum("milliseconds to sleep","100",10,&x,xxstring);
  1143.     if (y < 0) return(y);
  1144.     if (x < 0) x = 0;
  1145.     switch (cx) {
  1146.       case XXPAU:            /* PAUSE */
  1147.       case XXMSL:            /* MSLEEP */
  1148.     if ((y = cmcfm()) < 0) return(y);
  1149.     break;
  1150.       case XXWAI:            /* WAIT */
  1151.     z = 0;                /* Modem signal mask */
  1152.     while (1) {            /* Read zero or more signal names */
  1153.         y = cmkey(mstab,nms,"modem signal","",xxstring);
  1154.         if (y == -3) break;        /* -3 means they typed CR */
  1155.         if (y < 0) return(y);    /* Other negatives are errors */
  1156.         z |= y;            /* OR the bit into the signal mask */
  1157.     }
  1158.     break;
  1159.  
  1160.       default:                /* Shouldn't happen */
  1161.     return(-2);
  1162.     }
  1163.  
  1164. /* Command is entered, now do it. */
  1165.  
  1166.     if (cx == XXMSL) {            /* Millisecond sleep */
  1167.     msleep(x);
  1168.     return(success = 1);
  1169.     }
  1170.     while (x--) {            /* Sleep loop */
  1171.     int mdmsig;
  1172.     if (y = conchk()) {        /* Did they type something? */
  1173. #ifdef COMMENT
  1174.         while (y--) coninc(0);    /* Yes, gobble it up */
  1175. #endif
  1176.         break;            /* And quit PAUSing or WAITing */
  1177.     }
  1178.     if (cx == XXWAI && z != 0) {
  1179.         mdmsig = ttgmdm();
  1180.         if (mdmsig < 0) return(success = 0);
  1181.         if ((mdmsig & z) == z) return(success = 1);
  1182.     }
  1183.     sleep(1);            /* No interrupt, sleep one second */
  1184.     }
  1185.     if (cx == XXWAI) success = 0;
  1186.     else success = (x == -1);        /* Set SUCCESS/FAILURE for PAUSE. */
  1187.     return(0);
  1188. }
  1189. #endif /* NOSPL */
  1190.  
  1191.  
  1192. #ifndef NOFRILLS
  1193. int
  1194. dorenam() {
  1195.     if ((x = cmifi("File to rename","",&s,&y,xxstring)) < 0) {
  1196.     if (x == -3) {
  1197.         printf("?Name of existing file required\n");
  1198.         return(-9);
  1199.     } else return(x);
  1200.     }
  1201.     if (y) {                /* No wildcards allowed */
  1202.     printf("\n?Please specify a single file\n");
  1203.     return(-9);
  1204.     }
  1205.     strcpy(line,s);            /* Make a safe copy of the old name */
  1206.     p = line + (int)strlen(line) + 2;    /* Place for new name */
  1207.     if ((x = cmofi("New name","",&s,xxstring)) < 0) { /* Get new name */
  1208.     if (x == -3) {
  1209.         printf("?New name for file required\n");
  1210.         return(-9);
  1211.     } else return(x);
  1212.     }
  1213.     strcpy(p,s);            /* Make a safe copy of the new name */
  1214.     if ((y = cmcfm()) < 0) return(y);
  1215. #ifdef VMS
  1216.     conres();                /* Let Ctrl-C work. */
  1217. #endif /* VMS */
  1218.     debug(F110,"dorename line",line,0);
  1219.     debug(F110,"dorename p",p,0);
  1220.     if (zrename(line,p) < 0) {
  1221.     printf("?Can't rename %s to %s\n",line,p);
  1222. #ifdef VMS
  1223.     concb((char)escape);
  1224. #endif /* VMS */
  1225.     return(-9);
  1226.     } else {
  1227. #ifdef VMS
  1228.     concb((char)escape);
  1229. #endif /* VMS */
  1230.     return(success = 1);
  1231.     }
  1232. }
  1233. #endif /* NOFRILLS */
  1234.  
  1235.  
  1236. #ifndef NOSPL
  1237.  
  1238. /* Do the RETURN command */
  1239.  
  1240. int
  1241. doreturn(s) char *s; {
  1242.     int x; char *p;
  1243.     if (maclvl < 0) {
  1244.     printf("\n?Can't return from level %d\n",maclvl);
  1245.     return(success = 0);
  1246.     }
  1247.     lp = line;                /* Expand return value now */
  1248.     x = LINBUFSIZ-1;
  1249.     if (zzstring(s,&lp,&x) > -1) {
  1250.     s = line;
  1251.     debug(F110,"RETURN parse",s,0);
  1252.     }
  1253.     debug(F101,"RETURN maclvl 1","",maclvl);
  1254.     /* Pop from all FOR/WHILE/XIFs */
  1255.     while ((maclvl > 0) &&
  1256.        (m_arg[maclvl-1][0]) &&
  1257.        (cmdstk[cmdlvl].src == CMD_MD) &&
  1258.        (!strncmp(m_arg[maclvl-1][0],"_xif",4) ||
  1259.         !strncmp(m_arg[maclvl-1][0],"_for",4) ||
  1260.         !strncmp(m_arg[maclvl-1][0],"_whi",4))) {
  1261.     debug(F110,"RETURN popping",m_arg[maclvl-1][0],0);
  1262.     dogta(XXPTA);        /* Put args back */
  1263.     popclvl();        /* Pop up two levels */
  1264.     popclvl();
  1265.     debug(F101,"RETURN maclvl 2","",maclvl);
  1266.     }
  1267.     popclvl();                /* Pop from enclosing TAKE or macro */
  1268.     debug(F101,"RETURN maclvl 3","",maclvl);
  1269.  
  1270.     x = (int)strlen(s);            /* Length of return value */
  1271.     if (x > 0) {            /* Have return value? */
  1272.     p = malloc(x+2);        /* Allocate a place to keep it */
  1273.     if (mrval[maclvl+1])        /* Free old one, if any */
  1274.       free(mrval[maclvl+1]);
  1275.     if (p) {            /* Did we get a place? */
  1276.         strcpy(p, s);        /* Yes, copy the string into it. */
  1277.         mrval[maclvl+1] = p;    /* Make return value point to it. */
  1278.         debug(F110,"RETURN copy",mrval[maclvl],0);
  1279.     } else {            /* No, could not get space. */
  1280.         mrval[maclvl+1] = NULL;    /* Return null pointer. */
  1281.         x = 0;            /* Set failure return code. */
  1282.     }
  1283.     } else mrval[maclvl+1] = NULL;    /* Blank return code */
  1284.     return(success = x ? 1 : 0);    /* Return status code */    
  1285. }
  1286. #endif /* NOSPL */
  1287.  
  1288. #ifndef NOSPL
  1289. /* Do the OPEN command */
  1290.  
  1291. int
  1292. doopen()  {                /* OPEN { append, read, write } */
  1293.     int x, y, z; char *s;
  1294.     static struct filinfo fcb;        /* (must be static) */
  1295.     if ((x = cmkey(opntab,nopn,"mode","",xxstring)) < 0) {
  1296.     if (x == -3) {
  1297.         printf("?Mode required\n");
  1298.         return(-9);
  1299.     } else return(x);
  1300.     }
  1301.     switch (x) {
  1302.       case XYFZ_O:            /* Old file (READ) */
  1303.     if (chkfn(ZRFILE) > 0) {
  1304.         printf("?Read file already open\n");
  1305.         return(-2);
  1306.     }
  1307.     if ((z = cmifi("File to read","",&s,&y,xxstring)) < 0) {
  1308.         if (z == -3) {
  1309.         printf("?Input filename required\n");
  1310.         return(-9);
  1311.         } else return(z);
  1312.     }
  1313.     if (y) {                /* No wildcards allowed */
  1314.         printf("\n?Please specify a single file\n");
  1315.         return(-2);
  1316.     }
  1317.     strcpy(line,s);
  1318.     if ((int)strlen(line) < 1) return(-2);
  1319.     if ((y = cmcfm()) < 0) return(y);
  1320.     return(success = zopeni(ZRFILE,line));
  1321.  
  1322. #ifndef MAC
  1323. #ifndef NOPUSH
  1324.       case XYFZ_Y:            /* Pipe/Process (READ) */
  1325.     if (chkfn(ZRFILE) > 0) {
  1326.         printf("?Read file already open\n");
  1327.         return(-2);
  1328.     }
  1329.         if ((y = cmtxt("System command to read from","",&s,xxstring)) < 0) {
  1330.         if (y == -3) {
  1331.         printf("?Command name required\n");
  1332.         return(-9);
  1333.         } else return(y);
  1334.     }
  1335.     strcpy(line,s);
  1336.     if ((int)strlen(line) < 1) return(-2);
  1337.     if ((y = cmcfm()) < 0) return(y);
  1338.     return(success = zxcmd(ZRFILE,line));
  1339.  
  1340.       case XYFZ_X:            /* Write to pipe */
  1341.     if (chkfn(ZWFILE) > 0) {
  1342.         printf("?Write file already open\n");
  1343.         return(-2);
  1344.     }
  1345.         if ((y = cmtxt("System command to write to","",&s,xxstring)) < 0) {
  1346.         if (y == -3) {
  1347.         printf("?Command name required\n");
  1348.         return(-9);
  1349.         } else return(y);
  1350.     }
  1351.     strcpy(line,s);
  1352.     if ((int)strlen(line) < 1) return(-2);
  1353.     if ((y = cmcfm()) < 0) return(y);
  1354.     success = zxcmd(ZWFILE,line);
  1355.     if (!success && msgflg)
  1356.       printf("Can't open process for writing: %s\n",line);
  1357.     return(success);
  1358. #endif /* NOPUSH */
  1359. #endif /* MAC */
  1360.  
  1361.       case XYFZ_N:            /* New file (WRITE) */
  1362.       case XYFZ_A:            /* (APPEND) */
  1363.     if ((z = cmofi("Name of local file to create","",&s,xxstring)) < 0) {
  1364.         if (z == -3) {
  1365.         printf("?Filename required\n");
  1366.         return(-9);
  1367.         } else return(z);
  1368.     }
  1369.     if (z == 2) {
  1370.         printf("?Sorry, %s is a directory name\n",s);
  1371.         return(-9);
  1372.     }
  1373.     if (chkfn(ZWFILE) > 0) {
  1374.         printf("?Write/Append file already open\n");
  1375.         return(-2);
  1376.     }
  1377.         fcb.bs = fcb.cs = fcb.rl = fcb.fmt = fcb.org = fcb.cc = fcb.typ = 0;
  1378.     fcb.lblopts = 0;
  1379.     fcb.dsp = x;            /* Create or Append */
  1380.     strcpy(line,s);
  1381.     if ((int)strlen(line) < 1) return(-2);
  1382.     if ((y = cmcfm()) < 0) return(y);
  1383.     return(success = zopeno(ZWFILE,line,NULL,&fcb));
  1384.  
  1385.       default:
  1386.     printf("?Not implemented");
  1387.     return(-2);
  1388.     }
  1389. }
  1390. #endif /* NOSPL */
  1391.  
  1392. /* Finish parsing and do the GET command */
  1393.  
  1394. int
  1395. doget() {
  1396.     int x, y;
  1397.     char *cbp;
  1398.  
  1399.     cmarg2 = "";            /* Initialize as-name to nothing */
  1400.     x = 0;
  1401. #ifdef NOFRILLS
  1402.     if (*cmarg == NUL) {
  1403.     printf("?Remote filespec required\n");
  1404.     return(-3);
  1405.     }
  1406. #else
  1407. /*
  1408.   If remote file name omitted, get foreign and local names separately.
  1409.   But multine GET is allowed only if NOFRILLS is not defined.
  1410. */
  1411.     if (*cmarg == NUL) {
  1412.  
  1413.     if (tlevel > -1
  1414. #ifndef NOSPL
  1415.         && cmdstk[cmdlvl].src == CMD_TF
  1416. #endif /* NOSPL */
  1417.         ) {
  1418.  
  1419. /* Input is from a command file. */
  1420.  
  1421.         /* Read 2nd line of GET command */
  1422.  
  1423.         if (getnct(cmdbuf,CMDBL) < 0) {
  1424.         printf("Command file ends prematurely in multiline GET\n");
  1425.         popclvl();
  1426.         return(-9);
  1427.         }
  1428.         cmres();            /* Parse it */
  1429.         if ((x = cmtxt("Oofa","",&s,xxstring)) < 0)
  1430.           return(x);
  1431.         strcpy(line,brstrip(s));    /* Make a safe copy */
  1432.         cmarg = line;        /* Point to remote filename */
  1433.         if (*cmarg == NUL) {    /* Make sure there is one */
  1434.         printf("Remote filename missing in multiline GET\n");
  1435.         return(-9);
  1436.         }
  1437.         lp = line + strlen(line) + 1; /* Place for as-name */
  1438.  
  1439.         /* And third line... */
  1440.  
  1441.         cmarg2 = "";        /* Assume no as-name */
  1442.         if (getnct(cmdbuf,CMDBL) < 0) { /* Get next line */
  1443.         popclvl();        /* There isn't one. */
  1444.         } else {            /* There is... */
  1445.         if (*cmdbuf >= ' ') {    /* Parse as output filename */
  1446.             cmres();
  1447.             if ((x = cmofi("Mupeen",cmarg,&s,xxstring)) < 0)
  1448.               return(x);
  1449.             strcpy(lp,s);    /* Make a safe copy */
  1450.             cmarg2 = lp;    /* Point as-name pointer at it */
  1451.         }
  1452.         }
  1453.             x = 0;            /* Return code OK */
  1454.  
  1455. #ifndef NOSPL
  1456. /* Reading commands from a macro definition */
  1457.  
  1458.     } else if (cmdlvl > 0 && cmdstk[cmdlvl].src == CMD_MD) {
  1459.  
  1460.         /* Read second line of GET command */
  1461.  
  1462.         cbp = cmdbuf;
  1463.         if (getncm(cbp,CMDBL) < 0) {
  1464.         printf("Macro definition ends prematurely in multiline GET\n");
  1465.         return(-9);
  1466.         }
  1467.         cmres();
  1468.         if ((x = cmtxt("Oofa","",&s,xxstring)) < 0) return(x);
  1469.         if (*s == NUL) {        /* Make sure we got something */
  1470.         printf("Remote filename missing in multiline GET\n");
  1471.         return(-9);
  1472.         }
  1473.         strcpy(line,brstrip(s));    /* Copy filename to safe place */
  1474.         cmarg = line;        /* Point to it */
  1475.         x = strlen(line);        /* Get its length */
  1476.         lp = line + x + 1;        /* Where to put the next bit */
  1477.         y = LINBUFSIZ - x - 1;    /* Room left for next bit */
  1478.  
  1479.         /* And third line... */
  1480.  
  1481.         cmarg2 = "";        /* Assume no as-name */
  1482.         if (getncm(lp,y) > -1 && *lp >= ' ') { /* Read next line */
  1483.         x = strlen(lp);
  1484.         if (lp[x-1] == CR) lp[x-1] = NUL; /* Remove CR */
  1485.         cbp = cmdbuf;        /* Interpret the line */
  1486.         *cbp = NUL;        /* ... */
  1487.         y = CMDBL;        /* into the command buffer */
  1488.         zzstring(lp,&cbp,&y);
  1489.         if (*cmdbuf) {        /* If we have something */
  1490.             cmres();        /* parse it as an output filename */
  1491.             strcat(cmdbuf," ");
  1492.             if ((x = cmofi("Mupeen","",&s,NULL)) < 0)
  1493.               return(x);
  1494.             strcpy(lp,s);    /* Copy the name to safe place */
  1495.             cmarg2 = lp;    /* and make as-name pointer */
  1496.         }
  1497.         }
  1498.             x = 0;            /* Return code OK */
  1499. #endif /* NOSPL */
  1500.         } else {            /* Input is from terminal */
  1501.  
  1502.         cmsavp(psave,PROMPTL);
  1503.         cmsetp(" Remote file specification: "); /* Make new one */
  1504.         cmini(ckxech);
  1505.         x = -1;
  1506.         if (pflag) prompt(xxstring);
  1507.         while (x == -1) {        /* Prompt till they answer */
  1508.             x = cmtxt("Name of remote file(s)","",&cmarg,xxstring);
  1509.         debug(F111," cmtxt",cmarg,x);
  1510.         }
  1511.         if (x < 0) {
  1512.         cmsetp(psave);
  1513.         return(x);
  1514.         }
  1515.         if (*cmarg == NUL) {     /* If user types a bare CR, */
  1516.         printf("(cancelled)\n"); /* Forget about this. */
  1517.             cmsetp(psave);        /* Restore old prompt, */
  1518.         return(0);        /* and return. */
  1519.         }
  1520.         strcpy(line,brstrip(cmarg)); /* Make a safe copy */
  1521.         cmarg = line;
  1522.         cmsetp(" Local name to store it under: "); /* New prompt */
  1523.         cmini(ckxech);
  1524.         x = -1;
  1525.         if (pflag) prompt(xxstring);
  1526.         while (x == -1) {        /* Again, parse till answered */
  1527.             x = cmofi("Local file name","",&cmarg2,xxstring);
  1528.         }
  1529.         if (x < 0) {        /* Parse error */
  1530.         if (x == -3) {        /* CR = cancel */
  1531.             printf("(cancelled)\n"); /* Print message */
  1532.             x = 0;        /* Avoid further messages */
  1533.         }
  1534.         cmsetp(psave);        /* Restore prompt */
  1535.         return(x);
  1536.         }        
  1537.         x = -1;            /* Get confirmation. */
  1538.         while (x == -1) x = cmcfm();
  1539.         cmsetp(psave);        /* Restore old prompt. */
  1540.         }
  1541.     }
  1542. #endif /* NOFRILLS */
  1543.  
  1544.     if (x == 0) {            /* Good return from cmtxt or cmcfm, */
  1545.     debug(F110,"xxget cmarg",cmarg,0);
  1546.     strncpy(fspec,cmarg,FSPECL);
  1547.     debug(F111,"xxget fspec",fspec,FSPECL);
  1548.     sstate = 'r';            /* Set start state. */
  1549.     if (local) {
  1550.         displa = 1;
  1551.         ttflui();
  1552.     }
  1553.     }
  1554. #ifndef NOFRILLS
  1555. #ifdef CK_TMPDIR
  1556. /* cmarg2 is also allowed to be a device or directory name */
  1557.  
  1558.     y = strlen(cmarg2);
  1559.     if (
  1560. #ifdef OS2
  1561.         (isalpha(cmarg2[0]) &&
  1562.          cmarg2[1] == ':' &&
  1563.          cmarg2[2] == '\0') ||
  1564.         isdir(cmarg2)
  1565. #else
  1566. #ifdef UNIX
  1567.         (y > 0 && cmarg2[y-1] == '/') || isdir(cmarg2)
  1568. #else
  1569. #ifdef VMS
  1570.         (y > 0) && isdir(cmarg2)
  1571. #else
  1572. #ifdef STRATUS
  1573.         (y > 0) && isdir(cmarg2)
  1574. #endif /* STRATUS */
  1575. #endif /* VMS */
  1576. #endif /* UNIX */
  1577.  
  1578. #endif /* OS2 */
  1579.         ) {
  1580.         debug(F110,"RECEIVE arg disk or dir",cmarg2,0);
  1581.         if (s = zgtdir()) {        /* Get current directory, */
  1582.         if (zchdir(cmarg2)) {    /* change to given disk/directory, */
  1583.             strncpy(savdir,s,TMPDIRLEN); /* remember old disk/dir */
  1584.             debug(F110,"tmpdir saving",savdir,0);
  1585.             debug(F110,"tmpdir changing",cmarg2,0);
  1586.             f_tmpdir = 1;    /* and that we did this */
  1587.             cmarg2 = "";    /* and we don't have an as-name. */
  1588.         } else {
  1589.             printf("?Can't access %s\n",cmarg2);
  1590.             f_tmpdir = 0;
  1591.             cmarg2 = "";
  1592.             return(-9);
  1593.         }
  1594.         } else {
  1595.         printf("?Can't get current directory\n");
  1596.         cmarg2 = "";
  1597.         f_tmpdir = 0;
  1598.         return(-9);
  1599.         }
  1600.     }
  1601. #endif /* CK_TMPDIR */
  1602. #endif /* NOFRILLS */
  1603.  
  1604.     return(x);
  1605. }
  1606.  
  1607. #ifndef NOSPL
  1608.  
  1609. /*
  1610.   _ G E T A R G S
  1611.  
  1612.   Used by XIF, FOR, and WHILE, each of which are implemented as 2-level
  1613.   macros; the first level defines the macro, the second runs it.
  1614.   This routine hides the fact that they are macros by importing the
  1615.   macro arguments (if any) from two levels up, to make them available
  1616.   in the XIF, FOR, and WHILE commands themselves; for example as loop
  1617.   indices, etc.
  1618. */
  1619. int
  1620. dogta(cx) int cx; {
  1621.     int i; char c; char mbuf[4]; char *p;
  1622.  
  1623.     if ((y = cmcfm()) < 0)
  1624.       return(y);
  1625.     if (cx == XXGTA)
  1626.       debug(F101,"_getargs maclvl","",maclvl);
  1627.     else if (cx == XXPTA)
  1628.       debug(F101,"_putargs maclvl","",maclvl);
  1629.     else
  1630.       return(-2);
  1631.     if (maclvl < 1)
  1632.       return(success = 0);
  1633.  
  1634.     debug(F101,"success","",success);
  1635.  
  1636.     mbuf[0] = '%'; mbuf[1] = '0'; mbuf[2] = '\0'; /* Argument name buf */
  1637.     for (i = 0; i < 10; i++) {        /* For all args */
  1638.     c = (char) i + '0';        /* Make name */
  1639.     mbuf[1] = c;            /* Insert digit */
  1640.     if (cx == XXGTA) {        /* Get arg from level-minus-2 */
  1641.         if (maclvl == 1) p = g_var[c]; /* If at level 1 use globals 0..9 */
  1642.         else p = m_arg[maclvl-2][i]; /* Otherwise they're on the stack */
  1643.         if (!p) {
  1644.         debug(F111,"_getarg p","(null pointer)",i);
  1645.         } else debug(F111,"_getarg p",p,i);
  1646.         addmac(mbuf,p);
  1647.     } else if (cx == XXPTA) {    /* Put args level+2 */
  1648. #ifndef MAC
  1649.         connoi();            /* Turn off interrupts. */
  1650. #endif /* MAC */
  1651.         maclvl -= 2;        /* This is gross.. */
  1652.         p = m_arg[maclvl+2][i];
  1653.         if (p)
  1654.           debug(F111,"_putarg m_arg[maclvl+2][i]",p,i);
  1655.         else
  1656.           debug(F111,"_putarg m_arg[maclvl+2][i]","(null pointer)",i);
  1657.         addmac(mbuf,m_arg[maclvl+2][i]);
  1658.         maclvl += 2;
  1659. #ifndef MAC
  1660.         conint(trap,stptrap);    /* Restore interrupts */
  1661. #endif /* MAC */
  1662.     } else return(success = 0);
  1663.     }
  1664.     debug(F101,"_get/putarg exit","",i);
  1665.     debug(F101,"_get/putarg exit maclvl","",maclvl);
  1666. #ifdef COMMENT
  1667. /*
  1668.   Internal commands don't change success variable if they succeed.
  1669. */
  1670.     return(success = 1);
  1671. #else
  1672.     return(1);
  1673. #endif /* COMMENT */
  1674.  
  1675. }
  1676. #endif /* NOSPL */
  1677.  
  1678. #ifndef NOSPL
  1679. /*
  1680.   Do the GOTO and FORWARD commands.
  1681.   s = Label to search for, cx = function code, XXGOTO or XXFWD.
  1682. */
  1683. int
  1684. dogoto(s, cx) char *s; int cx; {
  1685.     int i, j, x, y;
  1686.     char tmplbl[50], *lp;
  1687.  
  1688.     debug(F101,"goto cx","",cx);
  1689.     debug(F101,"goto cmdlvl","",cmdlvl);
  1690.     debug(F101,"goto maclvl","",maclvl);
  1691.     debug(F101,"goto tlevel","",tlevel);
  1692.     debug(F110,"goto before conversion",s,0);
  1693.     y = (int)strlen(s);
  1694.     if (*s != ':') {            /* If the label mentioned */
  1695.     for (i = y; i > 0; i--) {    /* does not begin with a colon, */
  1696.         s[i] = s[i-1];        /* then insert one. */
  1697.     }                /* Also, convert to lowercase. */
  1698.     s[0] = ':';
  1699.     s[++y] = '\0';
  1700.     }
  1701.     debug(F111,"goto after conversion",s,y);
  1702.     if (s[1] == '.' || s[1] == SP || s[1] == NUL) {
  1703.     printf("?Bad label syntax - '%s'\n",s);
  1704.     return(success = 0);
  1705.     }
  1706.     if (cmdlvl == 0) {
  1707.     printf("?Sorry, GOTO only works in a command file or macro\n");
  1708.     return(success = 0);
  1709.     }
  1710.     while (cmdlvl > 0) {        /* Only works inside macros & files */
  1711.     if (cmdstk[cmdlvl].src == CMD_MD) { /* GOTO inside macro */
  1712.         int i, m, flag;
  1713.         char *xp, *tp;
  1714.  
  1715.         /* GOTO: rewind the macro; FORWARD: start at current position */
  1716.  
  1717.         lp = (cx == XXGOTO) ? macx[maclvl] : macp[maclvl];
  1718.         m = (int)strlen(lp) - y + 1;
  1719.         debug(F111,"goto in macro",lp,m);
  1720.  
  1721.         flag = 1;            /* flag for valid label position */
  1722.         for (i = 0; i < m; i++,lp++) { /* search for label in macro body */
  1723.         if (*lp == ',') {    /* Really should also watch out */
  1724.             flag = 1;        /* for braces here...  Commas in */
  1725.             continue;        /* in braces are not really commas */
  1726.         }
  1727.         if (flag) {        /* If in valid label position */
  1728.             if (*lp == SP)    /* eat leading spaces */
  1729.               continue;
  1730.             if (*lp != ':') {    /* Look for label introducer */
  1731.             flag = 0;    /* this isn't it */
  1732.             continue;    /* keep looking */
  1733.             }
  1734.         }
  1735.         if (!flag)        /* We don't have a label */
  1736.           continue;        /*  so keep looking... */
  1737.         xp = lp; tp = tmplbl;    /* Copy the label from the macro */
  1738.         j = 0;            /* to make it null-terminated */
  1739.         while (*tp = *xp) {
  1740.             if (j++ > 50) break;  /* j = length of word from macro */
  1741.             if (*tp < 33 || *tp == ',')    /* Look for end of word */
  1742.               break;
  1743.             else tp++, xp++;    /* Next character */
  1744.         }
  1745.         *tp = '\0';        /* In case we stopped early */
  1746.         /* Now do caseless string comparison, using longest length */
  1747.         debug(F111,"macro GOTO label",s,y);
  1748.         debug(F111,"macro target label",tmplbl,j);
  1749.         if (!xxstrcmp(s,tmplbl,(y > j) ? y : j))
  1750.           break;
  1751.         else flag = 0;
  1752.         }
  1753.         if (i == m) {        /* didn't find the label */
  1754.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  1755.         if (!popclvl()) {    /* pop up to next higher level */
  1756.             printf("?Label '%s' not found\n",s); /* if none */
  1757.             return(0);        /* quit */
  1758.         } else continue;    /* otherwise look again */
  1759.         }
  1760.         debug(F110,"goto found macro label",lp,0);
  1761.         macp[maclvl] = lp;        /* set macro buffer pointer */
  1762.         return(1);
  1763.     } else if (cmdstk[cmdlvl].src == CMD_TF) {
  1764.         x = 0;            /* GOTO issued in take file */
  1765.         if (cx == XXGOTO)        /* If GOTO, but not FORWARD, */
  1766.           rewind(tfile[tlevel]);    /* search file from beginning */
  1767.         while (! feof(tfile[tlevel])) {
  1768.         if (fgets(line,LINBUFSIZ,tfile[tlevel]) == NULL) /* Get line */
  1769.           break;        /* If no more, done, label not found */
  1770.         lp = line;        /* Got line */
  1771.         while (*lp == SP || *lp == HT)
  1772.           lp++;            /* Strip leading whitespace */
  1773.         if (*lp != ':') continue; /* Check for label introducer */
  1774.         tp = lp;        /* Get end of word */
  1775.         j = 0;
  1776.         while (*tp) {        /* And null-terminate it */
  1777.             if (*tp < 33) {
  1778.             *tp = '\0';
  1779.             break;
  1780.             } else tp++, j++;
  1781.         }
  1782.         if (!xxstrcmp(lp,s,(y > j) ? y : j)) { /* Caseless compare */
  1783.             x = 1;        /* Got it */
  1784.             break;        /* done. */
  1785.         }
  1786.         }
  1787.         if (x == 0) {        /* If not found, print message */
  1788.         debug(F101,"goto failed at cmdlvl","",cmdlvl);
  1789.         if (!popclvl()) {    /* pop up to next higher level */
  1790.             printf("?Label '%s' not found\n",s);    /* if none */
  1791.             return(0);        /* quit */
  1792.         } else continue;    /* otherwise look again */
  1793.         }
  1794.         return(x);            /* Send back return code */
  1795.     }
  1796.     }
  1797.     printf("?Stack problem in GOTO %s\n",s); /* Shouldn't see this */
  1798.     return(0);
  1799. }
  1800. #endif /* NOSPL */
  1801.  
  1802. /* Finish parsing and do the IF, XIF, and WHILE commands */
  1803.  
  1804. char *
  1805. brstrip(p) char *p; {
  1806.     if (!p) return("");
  1807.     if (*p == '{') {
  1808.     int x;
  1809.     x = (int)strlen(p) - 1;
  1810.     if (p[x] == '}') {
  1811.         p[x] = NUL;
  1812.         p++;
  1813.     }
  1814.     }
  1815.     return(p);
  1816. }
  1817.  
  1818. #ifndef NOSPL
  1819. int
  1820. doif(cx) int cx; {
  1821.     int x, y, z; char *s, *p;
  1822.  
  1823.     not = 0;                /* Flag for whether "NOT" was seen */
  1824.     z = 0;                /* Initial IF condition */
  1825.     ifargs = 0;                /* Count of IF condition words */
  1826.  
  1827. ifagain:
  1828.     if ((ifc = cmkey(iftab,nif,"","",xxstring)) < 0) { /* If what?... */
  1829.     if (ifc == -3) {
  1830.         printf("?Condition required\n");
  1831.         return(-9);
  1832.     } else return(ifc);
  1833.     }
  1834.     switch (ifc) {            /* set z = 1 for true, 0 for false */
  1835.       case XXIFNO:            /* IF NOT */
  1836.     not ^= 1;            /* So NOT NOT NOT ... will work */
  1837.     ifargs++;
  1838.     goto ifagain;
  1839.       case XXIFSU:            /* IF SUCCESS */
  1840.     z = ( success != 0 );
  1841.     debug(F101,"if success","",z);
  1842.     ifargs += 1;
  1843.     break;
  1844.       case XXIFFA:            /* IF FAILURE */
  1845.     z = ( success == 0 );
  1846.     debug(F101,"if failure","",z);
  1847.     ifargs += 1;
  1848.     break;
  1849.       case XXIFDE:            /* IF DEFINED */
  1850.     if ((x = cmfld("Macro or variable name","",&s,NULL)) < 0) {
  1851.         if (x == -3) return(-2);
  1852.         else return(x);
  1853.     }
  1854. #ifdef COMMENT
  1855.     strcpy(line,s);            /* Make a copy */
  1856.         if ((int)strlen(line) < 1) return(-2);
  1857.     lp = line;
  1858.     if (line[0] == CMDQ && (line[1] == '%' || line[1] == '&')) lp++;
  1859.     if (*lp == '%')    {        /* Is it a variable? */
  1860.         x = *(lp + 1);        /* Fold case */
  1861.         if (isupper(x)) *(lp + 1) = tolower(x);
  1862.         if (x >= '0' && x <= '9' && maclvl > -1) /* Digit is macro arg */
  1863.           z = ( (m_arg[maclvl][x - '0'] != (char *)0)
  1864.            && (int)strlen(m_arg[maclvl][x - '0']) != 0);
  1865.         else            /* Otherwise it's a global variable */
  1866.           z = ( (g_var[x] != (char *)0)
  1867.            &&  (int)strlen(g_var[x]) != 0 );
  1868.     } else if (*lp == '&') {    /* Array reference */
  1869.         int cc, nn;
  1870.         if (arraynam(lp,&cc,&nn) < 0)
  1871.           z = 0;
  1872.         else z = (arrayval(cc,nn) == NULL ? 0 : 1);
  1873.     }
  1874. #else
  1875.         if ((int)strlen(s) < 1) return(-2);
  1876.     z = 0;                /* Assume failure. */
  1877.     if (*s == CMDQ) {        /* Object begins with backslash. */
  1878.         char c;
  1879.         c = s[1];            /* Character following backslash */
  1880.         if (c) {
  1881.         c = islower(c) ? toupper(c) : c;
  1882.         if (c == '%' ||        /* Simple variable */
  1883.             c == '&' ||        /* Array element */
  1884.             c == '$' ||        /* Environment variable */
  1885.             c == 'V' ||        /* Builtin named variable */
  1886.             c == 'M' ||        /* Macro name */
  1887.             c == 'F') {        /* Builtin function */
  1888.             int t;        /* Let zzstring() evaluate it */
  1889.             t = LINBUFSIZ-1;    /* This lets us test \v(xxx) */
  1890.             lp = line;        /* and even \f...(xxx) */
  1891.             zzstring(s,&lp,&t);    /* Evaluate it, whatever it is. */
  1892.             t = strlen(line);    /* Get its length. */
  1893.             debug(F111,"IF DEF",line,t);
  1894.             z = t > 0;        /* If length > 0, it's defined */
  1895.         }
  1896.         }
  1897.     }
  1898. #endif /* COMMENT */
  1899.     else {            /* Otherwise it's a macro name */
  1900.         z = ( mxlook(mactab,s,nmac) > -1 ); /* Look for exact match */
  1901.     }
  1902.     debug(F111,"if defined",s,z);
  1903.     ifargs += 2;
  1904.     break;
  1905.  
  1906.       case XXIFBG:            /* IF BACKGROUND */
  1907.       case XXIFFG:            /* IF FOREGROUND */    
  1908.     bgchk();            /* Check background status */
  1909.     if (ifc == XXIFFG)        /* Foreground */
  1910.       z = pflag ? 1 : 0;
  1911.         else z = pflag ? 0 : 1;        /* Background */
  1912.     ifargs += 1;
  1913.     break;
  1914.  
  1915.       case XXIFCO:            /* IF COUNT */
  1916.     z = ( --count[cmdlvl] > 0 );
  1917.     if (cx == XXWHI) count[cmdlvl] += 2; /* Don't ask... */
  1918.     debug(F101,"if count","",z);
  1919.     ifargs += 1;
  1920.     break;
  1921.  
  1922.       case XXIFEX:            /* IF EXIST */
  1923. #ifdef CK_TMPDIR
  1924.       case XXIFDI:            /* IF DIRECTORY */
  1925. #endif /* CK_TMPDIR */
  1926.     if ((x = cmfld(
  1927.                ((ifc == XXIFEX) ? "File" : "Directory name"),
  1928.                "",&s,
  1929. #ifdef OS2
  1930.                NULL        /* This allows \'s in filenames */
  1931. #else
  1932.                xxstring
  1933. #endif /* OS2 */
  1934.                )) < 0) {
  1935.         if (x == -3) {
  1936.         printf("?File or directory name required\n");
  1937.         return(-9);
  1938.         } else return(x);
  1939.     }
  1940.     if (ifc == XXIFEX) {
  1941.         z = ( zchki(s) > -1L );
  1942.         debug(F101,"if exist 1","",z);
  1943. #ifdef OS2        
  1944.         if (!z) {            /* File not found. */
  1945.         int t;            /* Try expanding variables */
  1946.         t = LINBUFSIZ-1;    /* and looking again. */
  1947.         lp = line;
  1948.         zzstring(s,&lp,&t);
  1949.         s = line;
  1950.         z = ( zchki(s) > -1L );
  1951.         debug(F101,"if exist 2","",z);
  1952.         }
  1953. #endif /* OS2 */
  1954. #ifdef CK_TMPDIR
  1955.     } else {
  1956.         z = isdir(s)
  1957. #ifdef OS2
  1958.           || (isalpha(cmarg2[0]) &&
  1959.           cmarg2[1] == ':' &&
  1960.           cmarg2[2] == '\0')
  1961. #endif /* OS2 */
  1962.           ;
  1963.         debug(F101,"if directory 1","",z);
  1964.  
  1965.         if (!z) {            /* File not found. */
  1966.         int t;            /* Try expanding variables */
  1967.         t = LINBUFSIZ-1;    /* and looking again. */
  1968.         lp = line;
  1969.         zzstring(s,&lp,&t);
  1970.         s = line;
  1971.         z = isdir(s)
  1972. #ifdef OS2
  1973.           || (isalpha(cmarg2[0]) &&
  1974.               cmarg2[1] == ':' &&
  1975.               cmarg2[2] == '\0')
  1976. #endif /* OS2 */
  1977.             ;
  1978.         debug(F101,"if directory 2","",z);
  1979.         }
  1980. #endif /* CK_TMPDIR */
  1981.     }
  1982.     ifargs += 2;
  1983.     break;
  1984.  
  1985.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  1986.       case XXIFLL:            /* IF Lexically Less Than */
  1987.       case XXIFLG:            /* If Lexically Greater Than */
  1988.     if ((x = cmfld("first word or variable name","",&s,xxstring)) < 0) {
  1989.         if (x == -3) {
  1990.         printf("?Text required\n");
  1991.         return(-9);
  1992.         } else return(x);
  1993.     }
  1994.     s = brstrip(s);            /* Strip braces */
  1995.     x = (int)strlen(s);
  1996.     if (x > LINBUFSIZ-1) {
  1997.         printf("?IF: strings too long\n");
  1998.         return(-2);
  1999.     }
  2000.     lp = line;            /* lp points to first string */
  2001.     strcpy(lp,s);
  2002.     if ((y = cmfld("second word or variable name","",&s,xxstring)) < 0) {
  2003.         if (y == -3) {
  2004.         printf("?Text required\n");
  2005.         return(-9);
  2006.         } else return(y);
  2007.     }
  2008.     s = brstrip(s);
  2009.     y = (int)strlen(s);
  2010.     if (x + y + 2 > LINBUFSIZ) {
  2011.         printf("?IF: strings too long\n");
  2012.         return(-2);
  2013.     }
  2014.     tp = lp + y + 2;        /* tp points to second string */
  2015.     strcpy(tp,s);
  2016.     debug(F111,"IF EQ string 1, x",lp,x);
  2017.     debug(F111,"IF EQ string 2, y",tp,y);
  2018.     if (inpcas[cmdlvl]) {        /* INPUT CASE OBSERVE */
  2019.         x = strcmp(lp,tp);
  2020.         debug(F101,"IF EQ strcmp","",x);
  2021.     } else {                /* INPUT CASE IGNORE */
  2022.         x = xxstrcmp(lp,tp,(y > x) ? y : x); /* Use longest length */
  2023.         debug(F101,"IF EQ xxstrcmp","",x);
  2024.     }
  2025.     switch (ifc) {
  2026.       case XXIFEQ:             /* IF EQUAL (string comparison) */
  2027.         z = (x == 0);
  2028.         break;
  2029.       case XXIFLL:            /* IF Lexically Less Than */
  2030.         z = (x < 0);
  2031.         break;
  2032.       case XXIFLG:            /* If Lexically Greater Than */
  2033.         z = (x > 0);
  2034.         break;
  2035.     }
  2036.     ifargs += 3;
  2037.     break;
  2038.  
  2039.       case XXIFAE:            /* IF (arithmetically) = */
  2040.       case XXIFLT:            /* IF (arithmetically) < */
  2041.       case XXIFGT: {            /* IF (arithmetically) > */
  2042.     /* Really should use longs here... */
  2043.     /* But cmnum parses ints. */
  2044.     int n1, n2;
  2045.     x = cmfld("first number or variable name","",&s,xxstring);
  2046.     if (x == -3) {
  2047.         printf("?Quantity required\n");
  2048.         return(-9);
  2049.     }
  2050.     if (x < 0) return(x);
  2051.     debug(F101,"xxifgt cmfld","",x);
  2052.     lp = line;
  2053.     strcpy(lp,s);
  2054.     debug(F110,"xxifgt exp1",lp,0);
  2055.     if (!xxstrcmp(lp,"count",5)) {
  2056.         n1 = count[cmdlvl];
  2057.     } else if (!xxstrcmp(lp,"version",7)) {
  2058.         n1 = (int) vernum;
  2059.     } else if (!xxstrcmp(lp,"argc",4)) {
  2060.         n1 = (int) macargc[maclvl];
  2061.     } else {
  2062.         if (!chknum(lp)) return(-2);
  2063.         n1 = atoi(lp);
  2064.     }
  2065.     y = cmfld("second number or variable name","",&s,xxstring);
  2066.     if (y == -3) {
  2067.         printf("?Quantity required\n");
  2068.         return(-9);
  2069.     }
  2070.     if (y < 0) return(y);
  2071.         if ((int)strlen(s) < 1) return(-2);
  2072.     x = (int)strlen(lp);
  2073.     tp = line + x + 2;
  2074.     strcpy(tp,s);
  2075.     debug(F110,"xxifgt exp2",tp,0);
  2076.     if (!xxstrcmp(tp,"count",5)) {
  2077.         n2 = count[cmdlvl];
  2078.     } else if (!xxstrcmp(tp,"version",7)) {
  2079.         n2 = (int) vernum;
  2080.     } else if (!xxstrcmp(tp,"argc",4)) {
  2081.         n2 = (int) macargc[maclvl];
  2082.     } else {
  2083.         if (!chknum(tp)) return(-2);
  2084.         n2 = atoi(tp);
  2085.     }
  2086.     debug(F101,"xxifft ifc","",ifc);
  2087.     z = ((n1 <  n2 && ifc == XXIFLT)
  2088.       || (n1 == n2 && ifc == XXIFAE)
  2089.       || (n1 >  n2 && ifc == XXIFGT));
  2090.     debug(F101,"xxifft n1","",n1);
  2091.     debug(F101,"xxifft n2","",n2);
  2092.     debug(F101,"xxifft z","",z);
  2093.     ifargs += 3;
  2094.     break; }
  2095.  
  2096.       case XXIFNU:            /* IF NUMERIC */
  2097.     x = cmfld("variable name or constant","",&s,xxstring);
  2098.     if (x == -3) {
  2099.         printf("?Quantity required\n");
  2100.         return(-9);
  2101.     }
  2102.     if (x < 0) return(x);
  2103.     debug(F111,"xxifnu cmfld",s,x);
  2104.     lp = line;
  2105.     strcpy(lp,s);
  2106.     debug(F110,"xxifnu quantity",lp,0);
  2107.         z = chknum(lp);
  2108.         debug(F101,"xxifnu chknum","",z);
  2109.     ifargs += 2;
  2110.     break;
  2111.  
  2112. #ifdef ZFCDAT
  2113.       case XXIFNE: {            /* IF NEWER */
  2114.     char d1[20], * d2;        /* Buffers for 2 dates */
  2115.     if ((z = cmifi("First file","",&s,&y,xxstring)) < 0)
  2116.       return(z);
  2117.     strcpy(d1,zfcdat(s));
  2118.     if ((z = cmifi("Second file","",&s,&y,xxstring)) < 0)
  2119.       return(z);
  2120.     d2 = zfcdat(s);
  2121.     if ((int)strlen(d1) != 17 || (int)strlen(d2) != 17) {
  2122.         printf("?Failure to get file date\n");
  2123.         return(-9);
  2124.     }
  2125.     debug(F110,"xxifnewer d1",d1,0);
  2126.     debug(F110,"xxifnewer d2",d2,0);
  2127.     z = (strcmp(d1,d2) > 0) ? 1 : 0;
  2128.         debug(F101,"xxifnewer","",z);
  2129.     ifargs += 2;
  2130.     break;
  2131.       }
  2132. #endif /* ZFCDAT */
  2133.  
  2134. #ifdef CK_IFRO
  2135.       case XXIFRO:            /* REMOTE-ONLY advisory */
  2136.     ifargs++;
  2137.     z = remonly;
  2138.     break;
  2139. #endif /* CK_IFRO */
  2140.  
  2141.       default:                /* Shouldn't happen */
  2142.     return(-2);
  2143.     }
  2144.     if (not) z = !z;            /* Handle NOT here for both IF & XIF */
  2145.  
  2146.     switch (cx) {            /* Separate handling for IF and XIF */
  2147.  
  2148.       case XXIF:            /* This is IF... */
  2149.     ifcmd[cmdlvl] = 1;        /* We just completed an IF command */
  2150.         debug(F101,"IF condition","",z);
  2151.     if (z) {            /* Condition is true */
  2152.         iftest[cmdlvl] = 1;        /* Remember that IF succeeded */
  2153.         if (maclvl > -1) {        /* In macro, */
  2154.         pushcmd();        /* save rest of command. */
  2155.         } else if (tlevel > -1) {    /* In take file, */
  2156.         debug(F100, "doif: pushing command", "", 0);
  2157.         pushcmd();        /* save rest of command. */
  2158.         } else {            /* If interactive, */
  2159.         cmini(ckxech);        /* just start a new command */
  2160.         printf("\n");        /* (like in MS-DOS Kermit) */
  2161.         if (pflag) prompt(xxstring);
  2162.         }
  2163.     } else {            /* Condition is false */
  2164.         iftest[cmdlvl] = 0;        /* Remember command failed. */
  2165.         if ((y = cmtxt("command to be ignored","",&s,NULL)) < 0)
  2166.           return(y);        /* Gobble up rest of line */
  2167.     }
  2168.     return(0);
  2169.  
  2170.       case XXIFX: {            /* This is XIF (Extended IF) */
  2171.       char *p;
  2172.       char e[5];
  2173.       int i;
  2174.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  2175.         return(y);            /* Get object command. */
  2176.       p = s;
  2177.       lp = line;
  2178.       if (litcmd(&p,&lp) < 0) {    /* Insert quotes in THEN-part */
  2179.           return(-2);
  2180.       }
  2181.       if (!z) {            /* Use ELSE-part, if any */
  2182.           lp = line;        /* Write over THEN part. */
  2183.           *lp = NUL;
  2184.           while (*p == SP) p++;    /* Strip trailing spaces */
  2185.           if (*p) {            /* At end? */
  2186.           for (i = 0; i < 4; i++) e[i] = *p++; /* No, check for ELSE */
  2187.           if (xxstrcmp(e,"else",4)) return(-2);    /* No, syntax error */
  2188.           if (litcmd(&p,&lp) < 0) { /* Insert quotes */
  2189.               return(-2);
  2190.           }
  2191.           while (*p == SP) p++;    /* Strip trailing spaces */
  2192.           if (*p) return(-2);    /* Should be nothing here. */
  2193.           }
  2194.       }
  2195.       if (line[0]) {
  2196.           x = mlook(mactab,"_xif",nmac); /* get index of "_xif" macro. */
  2197.           if (x < 0) {            /* Not there? */
  2198.           addmmac("_xif",xif_def);    /* Put it back. */
  2199.           if (mlook(mactab,"_xif",nmac) < 0) { /* Look it up again. */
  2200.               printf("?XIF macro gone!\n");
  2201.               return(success = 0);
  2202.           }
  2203.           }
  2204.           dodo(x,line);        /* Do the XIF macro */
  2205.       }
  2206.       return(0);
  2207.       }
  2208.       case XXWHI: {            /* WHILE Command */
  2209.       p = cmdbuf;            /* Capture IF condition */
  2210.       ifcond[0] = NUL;        /* from command buffer */
  2211.       while (*p == SP) p++;
  2212.       while (*p != SP) p++;
  2213.       ifcp = ifcond;
  2214.       strcpy(ifcp,"{ \\flit(if not ");
  2215.       ifcp += (int)strlen(ifcp);
  2216.       while (*p != '{' && *p != NUL) *ifcp++ = *p++;
  2217.       p = " goto bot) } ";
  2218.       while (*ifcp++ = *p++) ;
  2219.       debug(F110,"WHILE cmd",ifcond,0);
  2220.  
  2221.       if ((y = cmtxt("Object command","",&s,NULL)) < 0)
  2222.         return(y);            /* Get object command. */
  2223.       p = s;
  2224.       lp = line;
  2225.       if (litcmd(&p,&lp) < 0) {    /* Insert quotes in object command */
  2226.           return(-2);
  2227.       }
  2228.       debug(F110,"WHILE body",line,0);
  2229.       if (line[0]) {
  2230.           char *p;
  2231.           x = mlook(mactab,"_while",nmac); /* index of "_while" macro. */
  2232.           if (x < 0) {        /* Not there? */
  2233.           addmmac("_while",whil_def); /* Put it back. */
  2234.           if (mlook(mactab,"_while",nmac) < 0) { /* Look it up again */
  2235.               printf("?WHILE macro definition gone!\n");
  2236.               return(success = 0);
  2237.           }
  2238.           }
  2239.           p = malloc((int)strlen(ifcond) + (int)strlen(line) + 2);
  2240.           if (p) {
  2241.           strcpy(p,ifcond);
  2242.           strcat(p,line);
  2243.           debug(F110,"WHILE dodo",p,0);
  2244.           dodo(x,p);
  2245.           free(p);
  2246.           } else {
  2247.           printf("?Can't allocate storage for WHILE command");
  2248.           return(success = 0);
  2249.           }
  2250.       }
  2251.       return(0);
  2252.       }
  2253.       default:
  2254.     return(-2);
  2255.     }
  2256. }
  2257. #endif /* NOSPL */
  2258.  
  2259. /* Set up a TAKE command file */
  2260.  
  2261. int
  2262. dotake(s) char *s; {
  2263.     if ((tfile[++tlevel] = fopen(s,"r")) == NULL) {
  2264.     perror(s);
  2265.     debug(F110,"Failure to open",s,0);
  2266.     success = 0;
  2267.     tlevel--;
  2268.     } else {
  2269. #ifdef VMS
  2270.     conres();            /* So Ctrl-C will work */
  2271. #endif /* VMS */
  2272. #ifndef NOSPL
  2273.     cmdlvl++;            /* Entering a new command level */
  2274.     if (cmdlvl > CMDSTKL) {
  2275.         cmdlvl--;
  2276.         printf("?TAKE files and/or DO commands nested too deeply\n");
  2277.         return(success = 0);
  2278.     }
  2279.     if (tfnam[tlevel]) free(tfnam[tlevel]);    /* Copy the filename */
  2280.     if (tfnam[tlevel] = malloc(strlen(s) + 1))
  2281.       strcpy(tfnam[tlevel],s);
  2282.     ifcmd[cmdlvl] = 0;        /* Set variables for this cmd file */
  2283.     iftest[cmdlvl] = 0;
  2284.     count[cmdlvl]  = count[cmdlvl-1];  /* Inherit this */
  2285.     intime[cmdlvl] = intime[cmdlvl-1]; /* Inherit this */
  2286.     inpcas[cmdlvl] = inpcas[cmdlvl-1]; /* Inherit this */
  2287.     takerr[cmdlvl] = takerr[cmdlvl-1]; /* Inherit this */
  2288.     merror[cmdlvl] = merror[cmdlvl-1]; /* Inherit this */
  2289.     cmdstk[cmdlvl].src = CMD_TF;    /* Say we're in a TAKE file */
  2290.     cmdstk[cmdlvl].lvl = tlevel;    /* nested at this level */
  2291. #else
  2292.     takerr[tlevel] = takerr[tlevel-1]; /* Inherit this */
  2293. #endif /* NOSPL */
  2294.     }
  2295.     return(1);
  2296. }
  2297. #endif /* NOICP */
  2298.