|
|
1.1 root 1: #ifndef NOICP
2:
3: /* C K U U S 5 -- "User Interface" for Unix Kermit, part 5 */
4:
5: /*
6: Author: Frank da Cruz ([email protected], [email protected]),
7: Columbia University Center for Computing Activities.
8: First released January 1985.
9: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
10: York. Permission is granted to any individual or institution to use, copy, or
11: redistribute this software so long as it is not sold for profit, provided this
12: copyright notice is retained.
13: */
14:
15: /* Includes */
16:
17: #include "ckcdeb.h"
18: #include "ckcasc.h"
19: #include "ckcker.h"
20: #include "ckuusr.h"
21: #include "ckcnet.h"
22: #ifndef NOCSETS
23: #include "ckcxla.h"
24: #endif /* NOCSETS */
25: #ifdef MAC
26: #include "ckmasm.h"
27: #endif /* MAC */
28:
29: #ifdef FT18
30: #define isxdigit(c) isdigit(c)
31: #endif /* FT18 */
32:
33: #ifdef MAC /* Internal MAC file routines */
34: #define feof mac_feof
35: #define rewind mac_rewind
36: #define fgets mac_fgets
37: #define fopen mac_fopen
38: #define fclose mac_fclose
39:
40: int mac_feof();
41: void mac_rewind();
42: char *mac_fgets();
43: FILE *mac_fopen();
44: int mac_fclose();
45: #endif /* MAC */
46:
47: /* External variables */
48:
49: extern int local, backgrd, bgset, sosi, suspend,
50: displa, binary, deblog, escape, xargs, flow, cmdmsk,
51: duplex, ckxech, pktlog, seslog, tralog, what,
52: keep, warn, quiet, tlevel, cwdf, nfuncs,
53: mdmtyp, zincnt, cmask, rcflag, success, xitsta, pflag, lf_opts, tnlm;
54:
55: #ifndef NOFRILLS
56: extern int en_cwd, en_del, en_dir, en_fin, en_bye,
57: en_get, en_hos, en_sen, en_set, en_spa, en_typ, en_who;
58: #endif /* NOFRILLS */
59: extern long vernum;
60: extern int srvtim, srvdis, incase, inecho, intime, nvars, verwho;
61: extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav,
62: *cknetv, *clcmds;
63: extern char *connv, *dialv, *loginv, *nvlook();
64:
65: #ifndef NOSCRIPT
66: extern int secho;
67: #endif /* NOSCRIPT */
68:
69: #ifndef NODIAL
70: extern int nmdm;
71: extern struct keytab mdmtab[];
72: #endif /* NODIAL */
73:
74: #ifdef NETCONN
75: extern int tn_init, network, ttnproto;
76: #endif /* NETCONN */
77:
78: #ifdef OS2PM
79: extern int Term_mode;
80: #endif /* OS2 */
81:
82: #ifndef NOCSETS
83: extern int language, nfilc, tcsr, tcsl;
84: extern struct keytab fcstab[];
85: #endif /* NOCSETS */
86:
87: extern int atcapr,
88: atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
89: attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
90:
91: extern long speed;
92:
93: extern char *DIRCMD, *PWDCMD, *DELCMD;
94: #ifndef NOXMIT
95: extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
96: extern char xmitbuf[];
97: #endif /* NOXMIT */
98:
99: extern char **xargv, *versio, *ckxsys, *dftty, *cmarg, *homdir, *lp;
100:
101: #ifdef DCMDBUF
102: extern char *cmdbuf, *atmbuf; /* Command buffers */
103: #ifndef NOSPL
104: extern char *savbuf; /* Command buffers */
105: #endif /* NOSPL */
106: #else
107: extern char cmdbuf[], atmbuf[]; /* Command buffers */
108: #ifndef NOSPL
109: extern char savbuf[]; /* Command buffers */
110: #endif /* NOSPL */
111: #endif /* DCMDBUF */
112:
113: extern char toktab[], ttname[], psave[];
114: extern CHAR sstate;
115: extern int cmflgs, techo, terror, repars, ncmd;
116: extern struct keytab cmdtab[];
117:
118: #ifndef MAC
119: #ifndef NOSETKEY
120: KEY *keymap;
121: MACRO *macrotab;
122: #endif /* NOSETKEY */
123: #endif /* MAC */
124:
125: #ifndef NOSPL
126: extern struct mtab *mactab;
127: extern struct keytab vartab[], fnctab[];
128: extern int cmdlvl, maclvl, nmac, mecho, merror;
129: #endif /* NOSPL */
130:
131: FILE *tfile[MAXTAKE]; /* TAKE file stack */
132:
133: #ifndef NOSPL
134: /* Local declarations */
135:
136: int nulcmd = 0; /* Flag for next cmd to be ignored */
137:
138: /* Definitions for built-in macros */
139:
140: /* First, the single line macros, installed with addmac()... */
141:
142: /* IBM-LINEMODE macro */
143: char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none";
144:
145: /* FATAL macro */
146: char *m_fat = "if def \\%1 echo \\%1, stop";
147:
148: #ifdef COMMENT
149: /*
150: Long macro definitions were formerly done like this. But some compilers
151: cannot handle continued string constants, others cannot handle string
152: constants that are this long. So these definitions have been broken up
153: into pieces and put into arrays, see below.
154: */
155: char *m_forx = "if def _floop ass \\%9 \\fdef(_floop),else def \\%9,\
156: ass _floop { _getargs,\
157: define \\\\\\%1 \\%2,:top,if \\%5 \\\\\\%1 \\%3 goto bot,\
158: \\%6,:inc, incr \\\\\\%1 \\%4,goto top,:bot,_putargs,return},\
159: def break goto bot, def continue goto inc,\
160: do _floop \\%1 \\%2 \\%3 \\%4 { \\%5 },assign _floop \\fcont(\\%9)";
161:
162: char *m_while = "if def _wloop ass \\%9 \\fdef(_wloop),\
163: ass _wloop {_getargs,:wtest,\\%1,\\%2,goto wtest,:wbot,_putargs,return},\
164: def break goto wbot, def continue goto wtest,\
165: do _wloop,assign _wloop \\fcont(\\%9)";
166:
167: char *m_xif = "ass \\%9 \\fdef(_ify),ass _ify {_getargs, \\%1, _putargs},\
168: do _ify,ass _ify \\fcont(\\%9)";
169: #endif /* COMMENT */
170:
171: /* Now the multiline macros, defined with addmmac()... */
172:
173: /* FOR macro */
174: char *for_def[] = { "if def _floop ass \\%9 \\fdef(_floop),else def \\%9,",
175: "ass _floop { _getargs,",
176: "define \\\\\\%1 \\%2,:top,if \\%5 \\\\\\%1 \\%3 goto bot,",
177: "\\%6,:inc, incr \\\\\\%1 \\%4,goto top,:bot,_putargs,return},",
178: "def break goto bot, def continue goto inc,",
179: "do _floop \\%1 \\%2 \\%3 \\%4 { \\%5 },assign _floop \\fcont(\\%9)",
180: ""};
181:
182: /* WHILE macro */
183: char *whil_def[] = { "if def _wloop ass \\%9 \\fdef(_wloop),",
184: "ass _wloop {_getargs,:wtest,\\%1,\\%2,goto wtest,:wbot,_putargs,return},",
185: "def break goto wbot, def continue goto wtest,",
186: "do _wloop,assign _wloop \\fcont(\\%9)",
187: ""};
188:
189: /* XIF macro */
190: char *xif_def[] = {
191: "ass \\%9 \\fdef(_ify),ass _ify {_getargs, \\%1, _putargs},",
192: "do _ify,ass _ify \\fcont(\\%9)",
193: ""};
194:
195: /* Variables declared here for use by other ckuus*.c modules */
196: /* Space is allocated here to save room in ckuusr.c */
197:
198: #ifdef DCMDBUF
199: struct cmdptr *cmdstk;
200: int *ifcmd, *count, *iftest;
201: #else
202: struct cmdptr cmdstk[CMDSTKL];
203: int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL];
204: #endif /* DCMDBUF */
205:
206: char *m_arg[MACLEVEL][NARGS];
207: char *g_var[GVARS], *macp[MACLEVEL], *mrval[MACLEVEL];
208: int macargc[MACLEVEL];
209: char *macx[MACLEVEL];
210: extern char varnam[];
211:
212: char **a_ptr[27]; /* Array pointers, for arrays a-z */
213: int a_dim[27]; /* Dimensions for each array */
214:
215: char inpbuf[INPBUFSIZ]; /* Buffer for INPUT and REINPUT */
216: char vnambuf[VNAML]; /* Buffer for variable names */
217: char *vnp; /* Pointer to same */
218: char lblbuf[50]; /* Buffer for labels */
219: #endif /* NOSPL */
220:
221: #ifdef DCMDBUF
222: char *line; /* Character buffer for anything */
223: #else
224: char line[LINBUFSIZ];
225: #endif /* DCMDBUF */
226:
227: extern char pktfil[],
228: #ifdef DEBUG
229: debfil[],
230: #endif /* DEBUG */
231: #ifdef TLOG
232: trafil[],
233: #endif /* TLOG */
234: sesfil[],
235: cmdstr[];
236: #ifndef NOFRILLS
237: extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */
238: extern char optbuf[];
239: #endif /* NOFRILLS */
240:
241: char *homdir; /* Pointer to home directory string */
242:
243: char tmpbuf[50], *tp; /* Temporary buffer */
244: char numbuf[20]; /* Buffer for numeric strings. */
245: char kermrc[100]; /* Name of initialization file */
246: int noinit = 0; /* Flag for skipping init file */
247:
248: #ifndef NOSPL
249: _PROTOTYP( static long expon, (long, long) );
250: _PROTOTYP( static long gcd, (long, long) );
251: _PROTOTYP( static long fact, (long) );
252: int /* Initialize macro data structures. */
253: macini() { /* Allocate mactab and preset the first element. */
254: if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX)))
255: return(-1);
256: mactab[0].kwd = NULL;
257: mactab[0].mval = NULL;
258: mactab[0].flgs = 0;
259: return(0);
260: }
261: #endif /* NOSPL */
262:
263: /* C M D I N I -- Initialize the interactive command parser */
264:
265: VOID
266: cmdini() {
267: int i, x, y, z;
268:
269: #ifndef MAC
270: #ifndef NOSETKEY /* Allocate & initialize the keymap */
271: if (!(keymap = (KEY *) malloc(sizeof(KEY)*KMSIZE)))
272: fatal("cmdini: no memory for keymap");
273: if (!(macrotab = (MACRO *) malloc(sizeof(MACRO)*KMSIZE)))
274: fatal("cmdini: no memory for macrotab");
275: for ( i = 0; i < KMSIZE; i++ ) {
276: keymap[i] = i;
277: macrotab[i] = NULL;
278: }
279: #endif /* NOSETKEY */
280: #endif /* MAC */
281:
282: #ifdef DCMDBUF
283: if (cmsetup() < 0) fatal("Can't allocate command buffers!");
284: #ifndef NOSPL
285: if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL)))
286: fatal("cmdini: no memory for cmdstk");
287: if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL)))
288: fatal("cmdini: no memory for ifcmd");
289: if (!(count = (int *) malloc(sizeof(int)*CMDSTKL)))
290: fatal("cmdini: no memory for count");
291: if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL)))
292: fatal("cmdini: no memory for iftest");
293: #endif /* NOSPL */
294: if (!(line = malloc(LINBUFSIZ)))
295: fatal("cmdini: no memory for line");
296: #ifdef COMMENT
297: if (!(m_arg = (struct m_arg *) malloc(sizeof(struct m_arg)*MACLEVEL)))
298: fatal("cmdini: no memory for m_arg");
299: #endif /* COMMENT */
300: #endif /* DCMDBUF */
301:
302: #ifndef NOSPL
303: if (macini() < 0) fatal("Can't allocate macro buffers!");
304: #endif /* NOSPL */
305:
306: #ifdef AMIGA
307: if (tlevel < 0)
308: concb(escape);
309: #endif /* AMIGA */
310:
311: #ifndef NOSPL
312: cmdlvl = 0; /* Start at command level 0 */
313: cmdstk[cmdlvl].src = CMD_KB;
314: cmdstk[cmdlvl].lvl = 0;
315: #endif /* NOSPL */
316:
317: tlevel = -1; /* Take file level = keyboard */
318: #ifdef MAC
319: cmsetp("Mac-Kermit>"); /* Set default prompt */
320: #else
321: cmsetp("C-Kermit>"); /* Set default prompt */
322: #endif /* MAC */
323:
324: #ifndef NOSPL
325: initmac(); /* Initialize macro table */
326: /* Add one-line macros */
327: addmac("ibm-linemode",m_ibm); /* Add built-in macros. */
328: addmac("fatal",m_fat); /* FATAL macro. */
329: /* Add multiline macros */
330: addmmac("_forx",for_def); /* FOR macro. */
331: addmmac("_xif",xif_def); /* XIF macro. */
332: addmmac("_while",whil_def); /* WHILE macro. */
333: /* Fill in command line argument vector */
334: sprintf(vnambuf,"\\&@[%d]",xargs); /* Command line argument vector */
335: y = arraynam(vnambuf,&x,&z); /* goes in array \&@[] */
336: if (y > -1) {
337: dclarray((char)x,z); /* Declare the array */
338: for (i = 0; i < xargs; i++) { /* Fill it */
339: sprintf(vnambuf,"\\&@[%d]",i);
340: addmac(vnambuf,xargv[i]);
341: }
342: }
343: *vnambuf = NUL;
344: #endif /* NOSPL */
345:
346: /* If skipping init file ('-Y' on Kermit command line), return now. */
347:
348: if (noinit) return;
349:
350: /* Look for init file in home or current directory. */
351: /* (NOTE - should really use zkermini for this!) */
352: homdir = zhome(); /* (===OS2 change===) */
353: #ifdef OS2
354: /*
355: The -y init file must be fully specified or in the current directory.
356: KERMRC is looked for via INIT, PATH and DPATH in that order. Finally, our
357: own executable file path is taken and the .EXE suffix is replaced by .INI
358: and this is tried as initialization file.
359: */
360: if (rcflag) {
361: strcpy(line, kermrc);
362: } else {
363: _searchenv(kermrc,"INIT",line);
364: if (line[0] == 0)
365: _searchenv(kermrc,"PATH",line);
366: if (line[0] == 0)
367: _searchenv(kermrc,"DPATH",line);
368: if (line[0] == 0) {
369: extern char *_pgmptr;
370: lp = strrchr(_pgmptr, '.');
371: strncpy(line, _pgmptr, lp - _pgmptr);
372: strcpy(line + (lp - _pgmptr), ".ini");
373: }
374: }
375: if ((tfile[0] = fopen(line,"r")) != NULL) {
376: tlevel = 0;
377: #ifndef NOSPL
378: cmdlvl++;
379: cmdstk[cmdlvl].src = CMD_TF;
380: cmdstk[cmdlvl].lvl = tlevel;
381: ifcmd[cmdlvl] = 0;
382: iftest[cmdlvl] = 0;
383: count[cmdlvl] = 0;
384: #endif /* NOSPL */
385: debug(F110,"init file",line,0);
386: } else {
387: debug(F100,"no init file","",0);
388: }
389: #else /* not OS2 */
390: lp = line;
391: lp[0] = '\0';
392: #ifdef VMS
393: zkermini(line,LINBUFSIZ,kermrc);
394: #else /* not VMS */
395: if (rcflag) { /* If init file name from cmd line */
396: strcpy(lp,kermrc); /* use it */
397: } else { /* otherwise */
398: if (homdir) { /* look in home directory for it */
399: strcpy(lp,homdir);
400: if (lp[0] == '/') strcat(lp,"/");
401: }
402: strcat(lp,kermrc); /* and use the default name */
403: }
404: #endif /* VMS */
405:
406: #ifdef AMIGA
407: reqoff(); /* disable requestors */
408: #endif /* AMIGA */
409:
410: debug(F110,"ini file is",line,0);
411: if ((tfile[0] = fopen(line,"r")) != NULL) {
412: tlevel = 0;
413: #ifndef NOSPL
414: cmdlvl++;
415: ifcmd[cmdlvl] = 0;
416: iftest[cmdlvl] = 0;
417: count[cmdlvl] = 0;
418: debug(F101,"open ok","",cmdlvl);
419: cmdstk[cmdlvl].src = CMD_TF;
420: cmdstk[cmdlvl].lvl = tlevel;
421: #endif /* NOSPL */
422: debug(F110,"init file",line,0);
423: }
424: if (homdir && (tlevel < 0)) {
425: strcpy(lp,kermrc);
426: if ((tfile[0] = fopen(line,"r")) != NULL) {
427: tlevel = 0;
428: #ifndef NOSPL
429: cmdlvl++;
430: cmdstk[cmdlvl].src = CMD_TF;
431: cmdstk[cmdlvl].lvl = tlevel;
432: ifcmd[cmdlvl] = 0;
433: iftest[cmdlvl] = 0;
434: count[cmdlvl] = 0;
435: #endif /* NOSPL */
436: }
437: }
438: #endif /* OS2 */
439: #ifdef AMIGA
440: reqpop(); /* Restore requestors */
441: #endif /* AMIGA */
442: }
443:
444: /* P A R S E R -- Top-level interactive command parser. */
445:
446: /*
447: Call with:
448: m = 0 for normal behavior: keep parsing and executing commands
449: until an action command is parsed, then return with a
450: Kermit start-state as the value of this function.
451: m = 1 to parse only one command, can also be used to call parser()
452: recursively.
453: m = 2 to read but do not execute one command.
454: In all cases, parser() returns:
455: 0 if no Kermit protocol action required
456: > 0 with a Kermit protocol start-state.
457: < 0 upon error.
458: */
459: int
460: parser(m) int m; {
461: int y, xx, yy, zz; /* Workers */
462: char ic; /* Interruption character */
463: int icn; /* Interruption character counter */
464: #ifndef NOSPL
465: int inlevel; /* Level we were called at */
466: int pp; /* Paren nesting level */
467: int kp; /* Bracket nesting level */
468: #endif /* NOSPL */
469: char *cbp; /* Command buffer pointer */
470: int cbn; /* Command buffer length */
471: #ifdef MAC
472: extern char *lfiles; /* fake extern cast */
473: #endif /* MAC */
474:
475: #ifdef AMIGA
476: reqres(); /* restore AmigaDOS requestors */
477: #endif /* AMIGA */
478:
479: what = W_COMMAND; /* Now we're parsing commands. */
480: #ifndef NOSPL
481: if (cmdlvl == 0) /* If at top (interactive) level, */
482: #else
483: if (tlevel < 0)
484: #endif /* NOSPL */
485: concb((char)escape); /* put console in cbreak mode. */
486:
487: #ifndef NOSPL
488: ifcmd[0] = 0; /* Command-level related variables */
489: iftest[0] = 0; /* initialize variables at top level */
490: count[0] = 0; /* of stack... */
491: inlevel = maclvl; /* Current macro level */
492: debug(F101,"&parser entry maclvl","",maclvl);
493: debug(F101,"&parser entry inlevel","",inlevel);
494: #endif /* NOSPL */
495:
496: /*
497: sstate becomes nonzero when a command has been parsed that requires some
498: action from the protocol module. Any non-protocol actions, such as local
499: directory listing or terminal emulation, are invoked directly from below.
500: */
501: if (local && pflag) /* Just returned from connect? */
502: printf("\n");
503: sstate = 0; /* Start with no start state. */
504: #ifndef NOFRILLS
505: rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
506: *optbuf = NUL; /* MAIL and PRINT options */
507: #endif /* NOFRILLS */
508: while (sstate == 0) { /* Parse cmds until action requested */
509: debug(F100,"top of parse loop","",0);
510:
511: /* Take requested action if there was an error in the previous command */
512:
513: #ifndef MAC
514: conint(trap,stptrap); /* In case we were just fg'd */
515: bgchk(); /* Check background status */
516: #endif /* MAC */
517:
518: #ifndef NOSPL /* In case we just reached top level */
519: if (cmdlvl == 0) concb((char)escape);
520: #else
521: if (tlevel < 0) concb((char)escape);
522: #endif /* NOSPL */
523:
524: #ifndef NOSPL
525: if (success == 0) {
526: if (cmdstk[cmdlvl].src == CMD_TF && terror) {
527: printf("Command error: take file terminated.");
528: popclvl();
529: if (cmdlvl == 0) return(0);
530: }
531: if (cmdstk[cmdlvl].src == CMD_MD && merror) {
532: printf("Command error: macro terminated.");
533: popclvl();
534: if (m && (maclvl < inlevel))
535: return((int) sstate);
536: }
537: }
538:
539: nulcmd = (m == 2);
540: #endif /* NOSPL */
541:
542: #ifdef MAC
543: if ((tlevel == -1) && lfiles) /* Check for take initiated by menu. */
544: startlfile();
545: #endif /* MAC */
546:
547: /* If in TAKE file, check for EOF */
548:
549: #ifndef NOSPL
550: #ifdef MAC
551: if
552: #else
553: while
554: #endif /* MAC */
555: ((cmdstk[cmdlvl].src == CMD_TF) /* If end of take file */
556: && (tlevel > -1)
557: && feof(tfile[tlevel])) {
558: popclvl(); /* pop command level */
559: cmini(ckxech); /* and clear the cmd buffer. */
560: if (cmdlvl == 0) /* Just popped out of all cmd files? */
561: return(0); /* End of init file or whatever. */
562: }
563: #ifdef MAC
564: miniparser(1);
565: if (sstate == 'a') { /* if cmd-. cancel */
566: debug(F100, "parser: cancel take due to sstate", "", sstate);
567: sstate = '\0';
568: dostop();
569: return(0); /* End of init file or whatever. */
570: }
571: #endif /* MAC */
572:
573: #else /* NOSPL */
574: if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */
575: popclvl(); /* Pop up one level. */
576: cmini(ckxech); /* and clear the cmd buffer. */
577: if (tlevel < 0) /* Just popped out of cmd files? */
578: return(0); /* End of init file or whatever. */
579: }
580: #endif /* NOSPL */
581:
582: #ifndef NOSPL
583: /* If macro, check for interruption and then get next command */
584:
585: if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
586: debug(F100,"parser macro","",0);
587: if (icn = conchk()) { /* Yes */
588: while (icn--) { /* User typed something */
589: ic = coninc(0);
590: if (ic == CR) { /* Carriage return? */
591: printf(" Interrupted...\n");
592: dostop();
593: } else {
594: putchar(BEL);
595: }
596: }
597: }
598: debug(F101,"parser maclvl","",maclvl);
599: maclvl = cmdstk[cmdlvl].lvl; /* No interrupt, get current level */
600: cbp = cmdbuf; /* Copy next cmd to command buffer. */
601: *cbp = NUL;
602: if (*savbuf) { /* In case then-part of 'if' command */
603: strcpy(cbp,savbuf); /* was saved, restore it. */
604: *savbuf = '\0';
605: } else { /* Else get next cmd from macro def */
606: debug(F111,"macro maclvl", macp[maclvl], maclvl);
607: kp = pp = 0;
608:
609: for (y = 0; /* copy next macro part */
610: *macp[maclvl] && y < CMDBL;
611: y++, cbp++, macp[maclvl]++) {
612:
613: /* Allow braces around macro def to prevent */
614: /* commas from being turned to end-of-lines */
615: /* and also treat any commas within parens */
616: /* as text so that multiple-argument functions */
617: /* won't cause the command to break prematurely. */
618:
619: *cbp = *macp[maclvl]; /* Get next character */
620:
621: if (*cbp == '{') kp++; /* Count braces */
622: if (*cbp == '}') kp--;
623: if (*cbp == '(') pp++; /* Count parentheses. */
624: if (*cbp == ')') pp--;
625: if (*cbp == ',' && pp <= 0 && kp <= 0) {
626: macp[maclvl]++;
627: kp = pp = 0;
628: break;
629: }
630: } /* Reached end. */
631: if (*cmdbuf == NUL) { /* If nothing was copied, */
632: popclvl(); /* pop command level. */
633: debug(F101,"macro level popped","",maclvl);
634: if (m && (maclvl < inlevel))
635: return((int) sstate);
636: else if (!m) continue;
637: } else { /* otherwise, tack CR onto end */
638: *cbp++ = CR; /* NOTE: NOT '\r' !!! */
639: *cbp = '\0';
640: if (mecho && pflag)
641: printf("%s\n",cmdbuf);
642: debug(F110,"cmdbuf",cmdbuf,0);
643: }
644: }
645:
646: /* If TAKE file, get next line */
647:
648: } else if (cmdstk[cmdlvl].src == CMD_TF)
649: #else
650: if (tlevel > -1)
651: #endif /* NOSPL */
652: {
653: debug(F101,"tlevel","",tlevel);
654: cbp = cmdbuf; /* Get the next line. */
655: cbn = CMDBL;
656:
657: /* Loop to get next command line and all continuation lines from take file. */
658:
659: again:
660: #ifndef NOSPL
661: if (*savbuf) { /* In case then-part of 'if' command */
662: strcpy(line,savbuf); /* was saved, restore it. */
663: *savbuf = '\0';
664: } else
665: #endif /* NOSPL */
666: if (fgets(line,cbn,tfile[tlevel]) == NULL) continue;
667: if (icn = conchk()) {
668: while (icn--) { /* User typed something... */
669: ic = coninc(0); /* Look for carriage return */
670: if (ic == CR) {
671: printf(" Interrupted...\n");
672: dostop();
673: } else putchar(BEL); /* Ignore anything else */
674: }
675: }
676: lp = line; /* Got a line, copy it. */
677: debug(F110,"from TAKE file",line,0);
678: { /* Trim trailing whitespace */
679: char c; int i, j;
680: j = (int)strlen(line) - 1; /* Position of line terminator */
681: c = line[j]; /* Value of line terminator */
682: for (i = j - 1; i > -1; i--)
683: if (line[i] != SP && line[i] != HT) break;
684: line[i+1] = c; /* Move after last nonblank char */
685: line[i+2] = NUL; /* Terminate */
686: }
687: while (*cbp++ = *lp++) {
688: if (--cbn < 2) {
689: printf("?Command too long, maximum length: %d.\n",CMDBL);
690: return(dostop());
691: }
692: }
693: if (*(cbp - 3) == CMDQ || *(cbp - 3) == '-') { /* Continued? */
694: cbp -= 3; /* If so, back up pointer, */
695: goto again; /* go back, get next line. */
696: }
697: untab(cmdbuf); /* Convert tabs to spaces */
698: if (techo && pflag) /* "take echo on" */
699: printf("%s",cmdbuf);
700:
701: /* If interactive, get next command from user. */
702:
703: } else { /* User types it in. */
704: if (pflag) prompt(xxstring);
705: cmini(ckxech);
706: }
707:
708: /* Now know where next command is coming from. Parse and execute it. */
709:
710: repars = 1; /* 1 = command needs parsing */
711: displa = 0; /* Assume no file transfer display */
712:
713: while (repars) { /* Parse this cmd until entered. */
714: debug(F101,"parser top of while loop","",0);
715: cmres(); /* Reset buffer pointers. */
716: xx = cmkey2(cmdtab,ncmd,"Command","",toktab,xxstring);
717: debug(F101,"top-level cmkey2","",xx);
718: if (xx == -5) {
719: yy = chktok(toktab);
720: debug(F101,"top-level cmkey token","",yy);
721: ungword();
722: switch (yy) {
723: case '!': xx = XXSHE; break;
724: case '#': xx = XXCOM; break;
725: case ';': xx = XXCOM; break;
726: #ifndef NOSPL
727: case ':': xx = XXLBL; break;
728: #endif /* NOSPL */
729: case '@': xx = XXSHE; break;
730: default:
731: printf("\n?Invalid - %s\n",cmdbuf);
732: xx = -2;
733: }
734: }
735:
736: #ifndef NOSPL
737: /* Special handling for IF..ELSE */
738:
739: if (ifcmd[cmdlvl]) /* Count stmts after IF */
740: ifcmd[cmdlvl]++;
741: if (ifcmd[cmdlvl] > 2 && xx != XXELS && xx != XXCOM)
742: ifcmd[cmdlvl] = 0;
743:
744: /* Execute the command and take action based on return code. */
745:
746: if (nulcmd) { /* Ignoring this command? */
747: xx = XXCOM; /* Make this command a comment. */
748: }
749: #endif /* NOSPL */
750:
751: zz = docmd(xx); /* Parse rest of command & execute. */
752: debug(F101,"docmd returns","",zz);
753: #ifdef MAC
754: if (tlevel > -1) {
755: if (sstate == 'a') { /* if cmd-. cancel */
756: debug(F110, "parser: cancel take, sstate:", "a", 0);
757: sstate = '\0';
758: dostop();
759: return(0); /* End of init file or whatever. */
760: }
761: }
762: #endif /* MAC */
763: switch (zz) {
764: case -4: /* EOF (e.g. on redirected stdin) */
765: doexit(GOOD_EXIT,xitsta); /* ...exit successfully */
766: case -1: /* Reparse needed */
767: repars = 1; /* Just set reparse flag and */
768: continue;
769: case -6: /* Invalid command given w/no args */
770: case -2: /* Invalid command given w/args */
771: #ifndef NOSPL
772: /* This is going to be really ugly... */
773: yy = mlook(mactab,atmbuf,nmac); /* Look in macro table */
774: if (yy > -1) { /* If it's there */
775: if (zz == -2) { /* insert "do" */
776: char *mp;
777: mp = malloc((int)strlen(cmdbuf) + 5);
778: if (!mp) {
779: printf("?malloc error 1\n");
780: return(-2);
781: }
782: sprintf(mp,"do %s ",cmdbuf);
783: strcpy(cmdbuf,mp);
784: free(mp);
785: } else sprintf(cmdbuf,"do %s %c",atmbuf, CR);
786: if (ifcmd[cmdlvl] == 2) /* This one doesn't count! */
787: ifcmd[cmdlvl]--;
788: debug(F111,"stuff cmdbuf",cmdbuf,zz);
789: repars = 1; /* go for reparse */
790: continue;
791: } else {
792: char *p;
793: int n;
794: p = cmdbuf;
795: lp = line;
796: n = LINBUFSIZ;
797: if (cmflgs == 0) printf("\n");
798: if (xxstring(p,&lp,&n) > -1)
799: printf("?Invalid: %s\n",line);
800: else
801: printf("?Invalid: %s\n",cmdbuf);
802: } /* (fall thru...) */
803: #else
804: printf("?Invalid: %s\n",cmdbuf);
805: #endif /* NOSPL */
806:
807: case -9: /* Bad, error message already done */
808: success = 0;
809: debug(F110,"top-level cmkey failed",cmdbuf,0);
810: if (pflag == 0) /* if background, terminate */
811: fatal("Kermit command error in background execution");
812: cmini(ckxech); /* (fall thru) */
813:
814: case -3: /* Empty command OK at top level */
815: repars = 0; /* Don't need to reparse. */
816: continue; /* Go back and get another command. */
817:
818: default: /* Command was successful. */
819: #ifndef NOSPL
820: debug(F101,"parser preparing to continue","",maclvl);
821: #endif /* NOSPL */
822: repars = 0; /* Don't need to reparse. */
823: continue; /* Go back and get another command. */
824: }
825: }
826: #ifndef NOSPL
827: debug(F101,"parser breaks out of while loop","",maclvl);
828: if (m && (maclvl < inlevel)) return((int) sstate);
829: #endif /* NOSPL */
830: }
831:
832: /* Got an action command, return start state. */
833:
834: #ifdef COMMENT
835: /* This is done in ckcpro.w instead, no need to do it twice. */
836: /* Interrupts off only if remote */
837: if (!local) connoi();
838: #endif /* COMMENT */
839: return((int) sstate);
840: }
841:
842: #ifndef NOSPL
843: /* OUTPUT command */
844:
845: int
846: #ifdef CK_ANSIC
847: xxout(char c)
848: #else
849: xxout(c) char c;
850: #endif /* CK_ANSIC */
851: /* xxout */ { /* Function to output a character. */
852: debug(F101,"xxout","",c);
853: if (local) /* If in local mode */
854: return(ttoc(c)); /* then to the external line */
855: else return(conoc(c)); /* otherwise to the console. */
856: }
857:
858: /* Returns 0 on failure, 1 on success */
859:
860: int
861: dooutput(s) char *s; {
862: int x, y, quote;
863:
864: if (local) { /* Condition external line */
865: y = ttvt(speed,flow);
866: if (y < 0) return(0);
867: }
868: quote = 0; /* Initialize backslash (\) quote */
869:
870: #ifdef COMMENT
871: /* This is done automatically in ttopen() now... */
872: #ifdef NETCONN
873: if (network && ttnproto == NP_TELNET) /* If telnet connection, */
874: if (!tn_init++) tn_ini(); /* initialize it if necessary */
875: #endif /* NETCONN */
876: #endif /* COMMENT */
877: while (x = *s++) { /* Loop through the string */
878: y = 0; /* Error code, 0 = no error. */
879: if (x == CMDQ) { /* Look for \b or \B in string */
880: quote = 1; /* Got \ */
881: continue; /* Get next character */
882: } else if (quote) { /* This character is quoted */
883: quote = 0; /* Turn off quote flag */
884: if (x == 'b' || x == 'B') { /* If \b or \B */
885: debug(F100,"OUTPUT BREAK","",0);
886: ttsndb(); /* send BREAK signal */
887: continue; /* and not the b or B */
888: #ifdef UNIX
889: } else if (x == 'l' || x == 'L') { /* If \l or \L */
890: debug(F100,"OUTPUT Long BREAK","",0);
891: ttsndlb(); /* send Long BREAK signal */
892: continue; /* and not the l or L */
893: #endif /* UNIX */
894: } else { /* if \ not followed by b or B */
895: y = xxout(dopar(CMDQ)); /* output the backslash. */
896: }
897: }
898: y = xxout(dopar((char)x)); /* Output this character */
899: if (y < 0) {
900: printf("output error.\n");
901: return(0);
902: }
903: if (seslog && duplex)
904: if (zchout(ZSFILE,(char)x) < 0) seslog = 0;
905: }
906: return(1);
907: }
908: #endif /* NOSPL */
909:
910:
911: /* Display version herald and initial prompt */
912:
913: VOID
914: herald() {
915: int x = 0;
916: if (bgset > 0 || (bgset != 0 && backgrd != 0)) x = 1;
917: debug(F101,"herald","",backgrd);
918: if (x == 0)
919: printf("%s,%s\nType ? or HELP for help\n",versio,ckxsys);
920: }
921: #ifndef NOSPL
922: /* M L O O K -- Lookup the macro name in the macro table */
923:
924: /*
925: Call this way: v = mlook(table,word,n);
926:
927: table - a 'struct mtab' table.
928: word - the target string to look up in the table.
929: n - the number of elements in the table.
930:
931: The keyword table must be arranged in ascending alphabetical order, and
932: all letters must be lowercase.
933:
934: Returns the table index, 0 or greater, if the name was found, or:
935:
936: -3 if nothing to look up (target was null),
937: -2 if ambiguous,
938: -1 if not found.
939:
940: A match is successful if the target matches a keyword exactly, or if
941: the target is a prefix of exactly one keyword. It is ambiguous if the
942: target matches two or more keywords from the table.
943: */
944: int
945: mlook(table,cmd,n) struct mtab table[]; char *cmd; int n; {
946:
947: int i, v, cmdlen;
948:
949: /* Lowercase & get length of target, if it's null return code -3. */
950:
951: if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
952:
953: /* Not null, look it up */
954:
955: for (i = 0; i < n-1; i++) {
956: if (!strcmp(table[i].kwd,cmd) ||
957: ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
958: strncmp(table[i+1].kwd,cmd,cmdlen))) {
959: return(i);
960: }
961: if (v) return(-2);
962: }
963:
964: /* Last (or only) element */
965:
966: if (!strncmp(table[n-1].kwd,cmd,cmdlen)) {
967: return(n-1);
968: } else return(-1);
969: }
970:
971: /* mxlook is like mlook, but an exact full-length match is required */
972:
973: int
974: mxlook(table,cmd,n) char *cmd; struct mtab table[]; int n; {
975: int i, cmdlen;
976: if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
977: for (i = 0; i < n; i++)
978: if (((int)strlen(table[i].kwd) == cmdlen) &&
979: (!strncmp(table[i].kwd,cmd,cmdlen))) return(i);
980: return(-1);
981: }
982:
983: /*
984: This routine is for the benefit of those compilers that can't handle
985: long string constants or continued lines within them. Long predefined
986: macros like FOR, WHILE, and XIF have their contents broken up into
987: arrays of string pointers. This routine concatenates them back into a
988: single string again, and then calls the real addmac() routine to enter
989: the definition into the macro table.
990: */
991: int
992: addmmac(nam,s) char *nam, *s[]; { /* Add a multiline macro definition */
993: int i, x, y; char *p;
994: x = 0; /* Length counter */
995: for (i = 0; (y = (int)strlen(s[i])) > 0; i++) { /* Add up total length */
996: debug(F111,"addmmac line",s[i],y);
997: x += y;
998: }
999: debug(F101,"addmmac lines","",i);
1000: debug(F101,"addmmac loop exit","",y);
1001: debug(F111,"addmmac length",nam,x);
1002: if (x < 0) return(-1);
1003:
1004: p = malloc(x+1); /* Allocate space for all of it. */
1005: if (!p) {
1006: printf("?addmmac malloc error: %s\n",nam);
1007: debug(F110,"addmmac malloc error",nam,0);
1008: return(-1);
1009: }
1010: *p = '\0'; /* Start off with null string. */
1011: for (i = 0; *s[i]; i++) /* Concatenate them all together. */
1012: strcat(p,s[i]);
1013: y = (int)strlen(p); /* Final precaution. */
1014: debug(F111,"addmmac constructed string",p,y);
1015: if (y == x) {
1016: y = addmac(nam,p); /* Add result to the macro table. */
1017: } else {
1018: debug(F100,"addmmac length mismatch","",0);
1019: printf("\n!addmmac internal error!\n");
1020: y = -1;
1021: }
1022: free(p); /* Free the temporary copy. */
1023: return(y);
1024: }
1025:
1026: /* Here is the real addmac routine. */
1027:
1028: int
1029: addmac(nam,def) char *nam, *def; { /* Add a macro to the macro table */
1030: int i, x, y, z, namlen, deflen;
1031: char *p, c;
1032:
1033: if (!nam) return(-1);
1034: namlen = (int)strlen(nam); /* Get argument lengths */
1035: debug(F111,"addmac nam",nam,namlen);
1036: if (!def) { /* Watch out for null pointer */
1037: deflen = 0;
1038: debug(F111,"addmac def","(null pointer)",deflen);
1039: } else {
1040: deflen = (int)strlen(def);
1041: debug(F111,"addmac def",def,deflen);
1042: }
1043: if (deflen < 0) return(-1); /* strlen() failure, fail. */
1044: if (namlen < 1) return(-1); /* No name given, fail. */
1045:
1046: if (*nam == CMDQ) nam++; /* Backslash quote? */
1047: if (*nam == '%') { /* Yes, if it's a variable name, */
1048: delmac(nam); /* Delete any old value. */
1049: if (!(c = *(nam + 1))) return(-1); /* Variable name letter or digit */
1050: if (deflen < 1) { /* Null definition */
1051: p = NULL; /* Better not malloc or strcpy! */
1052: } else { /* A substantial definition */
1053: p = malloc(deflen + 1); /* Allocate space for it */
1054: if (!p) {
1055: printf("?addmac malloc error 2\n");
1056: return(-1);
1057: } else strcpy(p,def); /* Copy definition into new space */
1058: }
1059:
1060: /* Now p points to the definition, or is a null pointer */
1061:
1062: if (p)
1063: debug(F110,"addmac p",p,0);
1064: else
1065: debug(F110,"addmac p","(null pointer)",0);
1066:
1067: if (c >= '0' && c <= '9') { /* Digit variable */
1068: if (maclvl < 0) { /* Are we calling or in a macro? */
1069: g_var[c] = p; /* No, it's a global "top level" one */
1070: debug(F101,"addmac numeric global maclvl","",maclvl);
1071: } else { /* Yes, it's a macro argument */
1072: m_arg[maclvl][c - '0'] = p;
1073: debug(F101,"addmac macro arg maclvl","",maclvl);
1074: }
1075: } else { /* It's a global variable */
1076: if (c < 33 || c > GVARS) return(-1);
1077: if (isupper(c)) c = tolower(c);
1078: g_var[c] = p; /* Put pointer in global-var table */
1079: debug(F100,"addmac global","",0);
1080: }
1081: return(0);
1082: } else if (*nam == '&') { /* An array reference? */
1083: char **q;
1084: if ((y = arraynam(nam,&x,&z)) < 0) /* If syntax is bad */
1085: return(-1); /* return -1. */
1086: if (chkarray(x,z) < 0) /* If array not declared or */
1087: return(-2); /* subscript out of range, ret -2 */
1088: delmac(nam); /* Delete any current definition. */
1089: x -= 96; /* Convert name letter to index. */
1090: if ((q = a_ptr[x]) == NULL) /* If array not declared, */
1091: return(-3); /* return -3. */
1092: if (deflen > 0) {
1093: if ((p = malloc(deflen+1)) == NULL) { /* Allocate space */
1094: printf("addmac macro error 7: %s\n",nam);
1095: return(-4); /* for new def, return -4 on fail. */
1096: }
1097: strcpy(p,def); /* Copy definition into new space. */
1098: } else p = NULL;
1099: q[z] = p; /* Store pointer to it. */
1100: return(0); /* Done. */
1101: } else debug(F110,"addmac macro def",nam,0);
1102:
1103: /* Not a macro argument or a variable, so it's a macro definition */
1104:
1105: lower(nam); /* Lowercase the name */
1106: delmac(nam); /* if it's already there, delete it. */
1107: debug(F111,"addmac table size",nam,nmac);
1108: for (y = 0; /* Find the alphabetical slot */
1109: y < MAC_MAX && mactab[y].kwd != NULL && strcmp(nam,mactab[y].kwd) > 0;
1110: y++) ;
1111: if (y == MAC_MAX) { /* No more room. */
1112: debug(F101,"addmac table overflow","",y);
1113: return(-1);
1114: } else debug(F111,"addmac position",nam,y);
1115: if (mactab[y].kwd != NULL) { /* Must insert */
1116: for (i = nmac; i > y; i--) { /* Move the rest down one slot */
1117: mactab[i].kwd = mactab[i-1].kwd;
1118: mactab[i].mval = mactab[i-1].mval;
1119: mactab[i].flgs = mactab[i-1].flgs;
1120: }
1121: }
1122: p = malloc(namlen + 1); /* Allocate space for name */
1123: if (!p) {
1124: printf("?addmac malloc error 3: %s\n",nam);
1125: return(-1);
1126: }
1127: strcpy(p,nam); /* Copy name into new space */
1128: mactab[y].kwd = p; /* Add pointer to table */
1129:
1130: if (deflen > 0) { /* Same deal for definition */
1131: p = malloc(deflen + 1); /* but watch out for null pointer */
1132: if (p == NULL) {
1133: printf("?addmac malloc error 5: %s\n", nam);
1134: free(mactab[y].kwd);
1135: mactab[y].kwd = NULL;
1136: return(-1);
1137: } else strcpy(p,def); /* Copy the definition */
1138: } else p = NULL;
1139: mactab[y].mval = p;
1140: mactab[y].flgs = 0;
1141: nmac++; /* Count this macro */
1142: return(y);
1143: }
1144:
1145: int
1146: delmac(nam) char *nam; { /* Delete the named macro */
1147: int i, x, z;
1148: char *p, c;
1149:
1150: if (!nam) return(0); /* Watch out for null pointer */
1151: debug(F110,"delmac nam",nam,0);
1152: if (*nam == CMDQ) nam++;
1153: if (*nam == '%') { /* If it's a variable name */
1154: if (!(c = *(nam+1))) return(0); /* Get variable name letter or digit */
1155: p = (char *)0; /* Initialize value pointer */
1156: if (maclvl > -1 && c >= '0' && c <= '9') { /* Digit? */
1157: p = m_arg[maclvl][c - '0']; /* Get pointer from macro-arg table */
1158: m_arg[maclvl][c - '0'] = NULL; /* Zero the table pointer */
1159: } else { /* It's a global variable */
1160: if (c < 33 || c > GVARS) return(0);
1161: p = g_var[c]; /* Get pointer from global-var table */
1162: g_var[c] = NULL; /* Zero the table entry */
1163: }
1164: if (p) {
1165: debug(F110,"delmac def",p,0);
1166: free(p); /* Free the storage */
1167: } else debug(F110,"delmac def","(null pointer)",0);
1168: return(0);
1169: }
1170:
1171: if (*nam == '&') { /* An array reference? */
1172: char **q;
1173: if (arraynam(nam,&x,&z) < 0) /* If syntax is bad */
1174: return(-1); /* return -1. */
1175: x -= 96; /* Convert name to number. */
1176: if ((q = a_ptr[x]) == NULL) /* If array not declared, */
1177: return(-2); /* return -2. */
1178: if (z > a_dim[x]) /* If subscript out of range, */
1179: return(-3); /* return -3. */
1180: if (q[z]) { /* If there is an old value, */
1181: debug(F110,"delman def",q[z],0);
1182: free(q[z]); /* delete it. */
1183: q[z] = NULL;
1184: } else debug(F110,"delmac def","(null pointer)",0);
1185: }
1186:
1187: /* Not a variable or an array, so it must be a macro. */
1188:
1189: if ((x = mlook(mactab,nam,nmac)) < 0) return(x); /* Look it up */
1190:
1191: if (mactab[x].kwd) /* Free the storage for the name */
1192: free(mactab[x].kwd);
1193: if (mactab[x].mval) /* and for the definition */
1194: free(mactab[x].mval);
1195:
1196: for (i = x; i < nmac; i++) { /* Now move up the others. */
1197: mactab[i].kwd = mactab[i+1].kwd;
1198: mactab[i].mval = mactab[i+1].mval;
1199: mactab[i].flgs = mactab[i+1].flgs;
1200: }
1201: nmac--; /* One less macro */
1202: mactab[nmac].kwd = NULL; /* Delete last item from table */
1203: mactab[nmac].mval = NULL;
1204: mactab[nmac].flgs = 0;
1205: return(0);
1206: }
1207:
1208: VOID
1209: initmac() { /* Init macro & variable tables */
1210: int i, j;
1211:
1212: nmac = 0; /* No macros */
1213: for (i = 0; i < MAC_MAX; i++) { /* Initialize the macro table */
1214: mactab[i].kwd = NULL;
1215: mactab[i].mval = NULL;
1216: mactab[i].flgs = 0;
1217: }
1218: for (i = 0; i < MACLEVEL; i++) { /* Init the macro argument tables */
1219: mrval[i] = NULL;
1220: for (j = 0; j < 10; j++) {
1221: m_arg[i][j] = NULL;
1222: }
1223: }
1224: for (i = 0; i < GVARS; i++) { /* And the global variables table */
1225: g_var[i] = NULL;
1226: }
1227: for (i = 0; i < 26; i++) { /* And the table of arrays */
1228: a_ptr[i] = (char **) NULL; /* Null pointer for each */
1229: a_dim[i] = 0; /* and a dimension of zero */
1230: }
1231: }
1232:
1233: int
1234: popclvl() { /* Pop command level, return cmdlvl */
1235: if (cmdlvl < 1) { /* If we're already at top level */
1236: cmdlvl = 0; /* just make sure all the */
1237: tlevel = -1; /* stack pointers are set right */
1238: maclvl = -1; /* and return */
1239: } else if (cmdstk[cmdlvl].src == CMD_TF) { /* Reading from TAKE file? */
1240: if (tlevel > -1) { /* Yes, */
1241: fclose(tfile[tlevel--]); /* close it and pop take level */
1242: cmdlvl--; /* pop command level */
1243: } else tlevel = -1;
1244: } else if (cmdstk[cmdlvl].src == CMD_MD) { /* In a macro? */
1245: if (maclvl > -1) { /* Yes, */
1246: macp[maclvl] = ""; /* set macro pointer to null string */
1247: *cmdbuf = '\0'; /* clear the command buffer */
1248: if (mrval[maclvl+1]) { /* Free any deeper return values. */
1249: free(mrval[maclvl+1]);
1250: mrval[maclvl+1] = NULL;
1251: }
1252: maclvl--; /* pop macro level */
1253: cmdlvl--; /* and command level */
1254: } else maclvl = -1;
1255: }
1256: if (cmdlvl < 1) { /* If back at top level */
1257: #ifndef MAC
1258: conint(trap,stptrap); /* Fix interrupts */
1259: bgchk(); /* Check background status */
1260: concb((char)escape); /* Go into cbreak mode */
1261: #endif /* MAC */
1262: }
1263: return(cmdlvl < 1 ? 0 : cmdlvl); /* Return command level */
1264: }
1265: #else /* No script programming language */
1266: int popclvl() { /* Just close current take file. */
1267: if (tlevel > -1) /* if any... */
1268: fclose(tfile[tlevel--]);
1269: if (tlevel == -1) { /* And if back at top level */
1270: conint(trap,stptrap); /* check and set interrupts */
1271: bgchk(); /* and background status */
1272: concb((char)escape); /* and go back into cbreak mode. */
1273: }
1274: return(tlevel + 1);
1275: }
1276: #endif /* NOSPL */
1277:
1278: /* STOP - get back to C-Kermit prompt, no matter where from. */
1279:
1280: int
1281: dostop() {
1282: while ( popclvl() ) ; /* Pop all macros & take files */
1283: #ifndef NOSPL
1284: while (cmpop() > -1) ; /* And all recursive cmd pkg invocations */
1285: #endif /* NOSPL */
1286: cmini(ckxech); /* Clear the command buffer. */
1287: return(0);
1288: }
1289:
1290:
1291: /* Close the given log */
1292:
1293: int
1294: doclslog(x) int x; {
1295: int y;
1296: switch (x) {
1297: #ifdef DEBUG
1298: case LOGD:
1299: if (deblog == 0) {
1300: printf("?Debugging log wasn't open\n");
1301: return(0);
1302: }
1303: *debfil = '\0';
1304: deblog = 0;
1305: return(zclose(ZDFILE));
1306: #endif /* DEBUG */
1307:
1308: case LOGP:
1309: if (pktlog == 0) {
1310: printf("?Packet log wasn't open\n");
1311: return(0);
1312: }
1313: *pktfil = '\0';
1314: pktlog = 0;
1315: return(zclose(ZPFILE));
1316:
1317: case LOGS:
1318: if (seslog == 0) {
1319: printf("?Session log wasn't open\n");
1320: return(0);
1321: }
1322: *sesfil = '\0';
1323: seslog = 0;
1324: return(zclose(ZSFILE));
1325:
1326: #ifdef TLOG
1327: case LOGT:
1328: if (tralog == 0) {
1329: printf("?Transaction log wasn't open\n");
1330: return(0);
1331: }
1332: *trafil = '\0';
1333: tralog = 0;
1334: return(zclose(ZTFILE));
1335: #endif /* TLOG */
1336:
1337: #ifndef NOSPL
1338: case LOGW:
1339: case LOGR:
1340: y = (x == LOGR) ? ZRFILE : ZWFILE;
1341: if (chkfn(y) < 1) {
1342: if (x == LOGW)
1343: printf("?No file to close\n");
1344: return(0);
1345: }
1346: y = zclose(y);
1347: return((x == LOGR) ? 1 : y);
1348: #endif /* NOSPL */
1349:
1350: default:
1351: printf("\n?Unexpected log designator - %ld\n", x);
1352: return(0);
1353: }
1354: }
1355:
1356: #ifndef NOSERVER
1357: #ifndef NOFRILLS
1358: static char *nm[] = { "disabled", "enabled" };
1359: #endif /* NOFRILLS */
1360: #endif /* NOSERVER */
1361:
1362: static int slc = 0; /* Screen line count */
1363:
1364: #ifndef NOFRILLS
1365: #define xxdiff(v,sys) strncmp(v,sys,strlen(sys))
1366: VOID
1367: shover() {
1368: printf("\nVersions:\n %s\n Numeric: %ld",versio,vernum);
1369: if (verwho) printf("-%d",verwho);
1370: printf(xxdiff(ckxv,ckxsys) ? "\n %s for%s\n" : "\n %s\n",ckxv,ckxsys);
1371: printf(xxdiff(ckzv,ckzsys) ? " %s for%s\n" : " %s\n",ckzv,ckzsys);
1372: printf(" %s\n",protv);
1373: printf(" %s\n",fnsv);
1374: printf(" %s\n %s\n",cmdv,userv);
1375: #ifndef NOCSETS
1376: printf(" %s\n",xlav);
1377: #endif /* NOCSETS */
1378: #ifndef MAC
1379: printf(" %s\n",connv);
1380: #endif /* MAC */
1381: #ifndef NODIAL
1382: printf(" %s\n",dialv);
1383: #endif /* NODIAL */
1384: #ifndef NOSCRIPT
1385: printf(" %s\n",loginv);
1386: #endif /* NOSCRIPT */
1387: #ifdef NETCONN
1388: printf(" %s\n",cknetv);
1389: #endif /* NETCONN */
1390:
1391: printf("\nSpecial features:\n");
1392: #ifdef NETCONN
1393: printf(" Network support (type SHOW NET for further info)\n");
1394: #endif /* NETCONN */
1395:
1396: #ifdef KANJI
1397: printf(" Kanji character-set translation\n");
1398: #endif /* KANJI */
1399:
1400: printf("\nFeatures not included:\n");
1401: #ifdef NOSERVER
1402: printf(" No server mode\n");
1403: #endif /* NOSERVER */
1404: #ifdef NODEBUG
1405: printf(" No debugging\n");
1406: #endif /* NODEBUG */
1407: #ifdef NOTLOG
1408: printf(" No transaction log\n");
1409: #endif /* NOTLOG */
1410: #ifdef NOHELP
1411: printf(" No built-in help\n");
1412: #endif /* NOHELP */
1413: #ifndef NETCONN
1414: printf(" No network support\n");
1415: #endif /* NETCONN */
1416: #ifdef NOMSEND
1417: printf(" No MSEND command\n");
1418: #endif /* NOMSEND */
1419: #ifdef NODIAL
1420: printf(" No DIAL command\n");
1421: #endif /* NODIAL */
1422: #ifdef NOXMIT
1423: printf(" No TRANSMIT command\n");
1424: #endif /* NOXMIT */
1425: #ifdef NOSCRIPT
1426: printf(" No SCRIPT command\n");
1427: #endif /* NOSCRIPT */
1428: #ifdef NOSPL
1429: printf(" No script programming features\n");
1430: #endif /* NOSPL */
1431: #ifdef NOCSETS
1432: printf(" No character-set translation\n");
1433: #else
1434: #ifdef NOCYRIL
1435: printf(" No Cyrillic character-set translation\n");
1436: #endif /* NOCYRIL */
1437: #ifndef KANJI
1438: printf(" No Kanji character-set translation\n");
1439: #endif /* KANJI */
1440: #endif /* NOCSETS */
1441: #ifdef NOCMDL
1442: printf(" No command-line arguments\n");
1443: #endif /* NOCMDL */
1444: #ifdef NOFRILLS
1445: printf(" No frills\n");
1446: #endif /* NOFRILLS */
1447: #ifdef NOPUSH
1448: printf(" No escape to system\n");
1449: #endif /* NOPUSH */
1450: #ifdef NOJC
1451: printf(" No UNIX job control\n");
1452: #endif /* NOJC */
1453: #ifdef NOSETKEY
1454: printf(" No SET KEY command\n");
1455: #endif /* NOSETKEY */
1456: #ifdef NOESCSEQ
1457: printf(" No ANSI escape sequence recognition\n");
1458: #endif /* NOESCSEQ */
1459: #ifndef PARSENSE
1460: printf(" No automatic parity detection\n");
1461: #endif /* PARSENSE */
1462: /*
1463: Print all of Kermit's compile-time options, as well as C preprocessor
1464: predefined symbols that might affect us...
1465: */
1466: printf("\nCompiler options:\n");
1467: #ifdef DEBUG
1468: #ifdef IFDEBUG
1469: prtopt(" IFDEBUG");
1470: #else
1471: prtopt(" DEBUG");
1472: #endif /* IFDEBUG */
1473: #endif /* DEBUG */
1474: #ifdef TLOG
1475: prtopt(" TLOG");
1476: #endif /* TLOG */
1477: #ifdef DYNAMIC
1478: prtopt(" DYNAMIC");
1479: #endif /* IFDEBUG */
1480: #ifdef UNIX
1481: prtopt(" UNIX");
1482: #endif /* UNIX */
1483: #ifdef VMS
1484: prtopt(" VMS");
1485: #endif /* VMS */
1486: #ifdef vms
1487: prtopt(" vms");
1488: #endif /* vms */
1489: #ifdef VMSSHARE
1490: prtopt(" VMSSHARE");
1491: #endif /* VMSSHARE */
1492: #ifdef datageneral
1493: prtopt(" datageneral");
1494: #endif /* datageneral */
1495: #ifdef apollo
1496: prtopt(" apollo");
1497: #endif /* apollo */
1498: #ifdef aegis
1499: prtopt(" aegis");
1500: #endif /* aegis */
1501: #ifdef A986
1502: prtopt(" A986");
1503: #endif /* A986 */
1504: #ifdef AMIGA
1505: prtopt(" AMIGA");
1506: #endif /* AMIGA */
1507: #ifdef MAC
1508: prtopt(" MAC");
1509: #endif /* MAC */
1510: #ifdef AUX
1511: prtopt(" AUX");
1512: #endif /* AUX */
1513: #ifdef OS2
1514: prtopt(" OS2");
1515: #endif /* OS2 */
1516: #ifdef OS9
1517: prtopt(" OS9");
1518: #endif /* OS9 */
1519: #ifdef MSDOS
1520: prtopt(" MSDOS");
1521: #endif /* MSDOS */
1522: #ifdef DIRENT
1523: prtopt(" DIRENT");
1524: #endif /* DIRENT */
1525: #ifdef SDIRENT
1526: prtopt(" SDIRENT");
1527: #endif /* SDIRENT */
1528: #ifdef NDIR
1529: prtopt(" NDIR");
1530: #endif /* NDIR */
1531: #ifdef XNDIR
1532: prtopt(" XNDIR");
1533: #endif /* XNDIR */
1534: #ifdef MATCHDOT
1535: prtopt(" MATCHDOT");
1536: #endif /* MATCHDOT */
1537: #ifdef SAVEDUID
1538: prtopt(" SAVEDUID");
1539: #endif /* SAVEDUID */
1540: #ifdef NOCCTRAP
1541: prtopt(" NOCCTRAP");
1542: #endif /* NOCCTRAP */
1543: #ifdef SUNX25
1544: prtopt(" SUNX25");
1545: #endif /* SUNX25 */
1546: #ifdef ATT7300
1547: prtopt(" ATT7300");
1548: #endif /* ATT7300 */
1549: #ifdef ATT6300
1550: prtopt(" ATT6300");
1551: #endif /* ATT6300 */
1552: #ifdef HDBUUCP
1553: prtopt(" HDBUUCP");
1554: #endif /* HDBUUCP */
1555: #ifdef NOUUCP
1556: prtopt(" NOUUCP");
1557: #endif /* NOUUCP */
1558: #ifdef LONGFN
1559: prtopt(" LONGFN");
1560: #endif /* LONGFN */
1561: #ifdef RDCHK
1562: prtopt(" RDCHK");
1563: #endif /* RDCHK */
1564: #ifdef NAP
1565: prtopt(" NAP");
1566: #endif /* NAP */
1567: #ifdef EXCELAN
1568: prtopt(" EXCELAN");
1569: #endif /* EXCELAN */
1570: #ifdef PARAMH
1571: prtopt(" PARAMH");
1572: #endif /* PARAMH */
1573: #ifdef INTERLAN
1574: prtopt(" INTERLAN");
1575: #endif /* INTERLAN */
1576: #ifdef NOFILEH
1577: prtopt(" NOFILEH");
1578: #endif /* NOFILEH */
1579: #ifdef NOSYSIOCTLH
1580: prtopt(" NOSYSIOCTLH");
1581: #endif /* NOSYSIOCTLH */
1582: #ifdef DCLPOPEN
1583: prtopt(" DCLPOPEN");
1584: #endif /* DCLPOPEN */
1585: #ifdef NOPOPEN
1586: prtopt(" NOPOPEN");
1587: #endif /* NOPOPEN */
1588: #ifdef NOPARTIAL
1589: prtopt(" NOPARTIAL");
1590: #endif /* NOPARTIAL */
1591: #ifdef NOSETREU
1592: prtopt(" NOSETREU");
1593: #endif /* NOSETREU */
1594: #ifdef _POSIX_SOURCE
1595: prtopt(" _POSIX_SOURCE");
1596: #endif /* _POSIX_SOURCE */
1597: #ifdef LCKDIR
1598: prtopt(" LCKDIR");
1599: #endif /* LCKDIR */
1600: #ifdef ACUCNTRL
1601: prtopt(" ACUCNTRL");
1602: #endif /* ACUCNTRL */
1603: #ifdef BSD4
1604: prtopt(" BSD4");
1605: #endif /* BSD4 */
1606: #ifdef BSD41
1607: prtopt(" BSD41");
1608: #endif /* BSD41 */
1609: #ifdef BSD43
1610: prtopt(" BSD43");
1611: #endif /* BSD43 */
1612: #ifdef BSD29
1613: prtopt(" BSD29");
1614: #endif /* BSD29 */
1615: #ifdef V7
1616: prtopt(" V7");
1617: #endif /* V7 */
1618: #ifdef AIX370
1619: prtopt(" AIX370");
1620: #endif /* AIX370 */
1621: #ifdef RTAIX
1622: prtopt(" RTAIX");
1623: #endif /* RTAIX */
1624: #ifdef HPUX
1625: prtopt(" HPUX");
1626: #endif /* HPUX */
1627: #ifdef HPUXPRE65
1628: prtopt(" HPUXPRE65");
1629: #endif /* HPUXPRE65 */
1630: #ifdef DGUX
1631: prtopt(" DGUX");
1632: #endif /* DGUX */
1633: #ifdef DGUX540
1634: prtopt(" DGUX540");
1635: #endif /* DGUX540 */
1636: #ifdef sony_news
1637: prtopt(" sony_news");
1638: #endif /* sony_news */
1639: #ifdef CIE
1640: prtopt(" CIE");
1641: #endif /* CIE */
1642: #ifdef XENIX
1643: prtopt(" XENIX");
1644: #endif /* XENIX */
1645: #ifdef SCO_XENIX
1646: prtopt(" SCO_XENIX");
1647: #endif /* SCO_XENIX */
1648: #ifdef ISIII
1649: prtopt(" ISIII");
1650: #endif /* ISIII */
1651: #ifdef I386IX
1652: prtopt(" I386IX");
1653: #endif /* I386IX */
1654: #ifdef RTU
1655: prtopt(" RTU");
1656: #endif /* RTU */
1657: #ifdef PROVX1
1658: prtopt(" PROVX1");
1659: #endif /* PROVX1 */
1660: #ifdef TOWER1
1661: prtopt(" TOWER1");
1662: #endif /* TOWER1 */
1663: #ifdef ZILOG
1664: prtopt(" ZILOG");
1665: #endif /* ZILOG */
1666: #ifdef TRS16
1667: prtopt(" TRS16");
1668: #endif /* TRS16 */
1669: #ifdef MINIX
1670: prtopt(" MINIX");
1671: #endif /* MINIX */
1672: #ifdef C70
1673: prtopt(" C70");
1674: #endif /* C70 */
1675: #ifdef AIXPS2
1676: prtopt(" AIXPS2");
1677: #endif /* AIXPS2 */
1678: #ifdef AIXRS
1679: prtopt(" AIXRS");
1680: #endif /* AIXRS */
1681: #ifdef UTSV
1682: prtopt(" UTSV");
1683: #endif /* UTSV */
1684: #ifdef ATTSV
1685: prtopt(" ATTSV");
1686: #endif /* ATTSV */
1687: #ifdef SVR3
1688: prtopt(" SVR3");
1689: #endif /* SVR3 */
1690: #ifdef SVR4
1691: prtopt(" SVR4");
1692: #endif /* SVR4 */
1693: #ifdef POSIX
1694: prtopt(" POSIX");
1695: #endif /* POSIX */
1696: #ifdef SUNOS4
1697: prtopt(" SUNOS4");
1698: #endif /* SUNOS4 */
1699: #ifdef SUN4S5
1700: prtopt(" SUN4S5");
1701: #endif /* SUN4S5 */
1702: #ifdef ENCORE
1703: prtopt(" ENCORE");
1704: #endif /* ENCORE */
1705: #ifdef ultrix
1706: prtopt(" ultrix");
1707: #endif
1708: #ifdef sxaE50
1709: prtopt(" sxaE50");
1710: #endif
1711: #ifdef mips
1712: prtopt(" mips");
1713: #endif
1714: #ifdef MIPS
1715: prtopt(" MIPS");
1716: #endif
1717: #ifdef vax
1718: prtopt(" vax");
1719: #endif
1720: #ifdef VAX
1721: prtopt(" VAX");
1722: #endif
1723: #ifdef sun
1724: prtopt(" sun");
1725: #endif
1726: #ifdef sun3
1727: prtopt(" sun3");
1728: #endif
1729: #ifdef sun386
1730: prtopt(" sun386");
1731: #endif
1732: #ifdef _SUN
1733: prtopt(" _SUN");
1734: #endif
1735: #ifdef sun4
1736: prtopt(" sun4");
1737: #endif
1738: #ifdef sparc
1739: prtopt(" sparc");
1740: #endif
1741: #ifdef NEXT
1742: prtopt(" NEXT");
1743: #endif
1744: #ifdef NeXT
1745: prtopt(" NeXT");
1746: #endif
1747: #ifdef sgi
1748: prtopt(" sgi");
1749: #endif
1750: #ifdef M_SYS5
1751: prtopt(" M_SYS5");
1752: #endif
1753: #ifdef __SYSTEM_FIVE
1754: prtopt(" __SYSTEM_FIVE");
1755: #endif
1756: #ifdef sysV
1757: prtopt(" sysV");
1758: #endif
1759: #ifdef M_XENIX /* SCO Xenix V and UNIX/386 */
1760: prtopt(" M_XENIX");
1761: #endif
1762: #ifdef M_UNIX
1763: prtopt(" M_UNIX");
1764: #endif
1765: #ifdef M_I386
1766: prtopt(" M_I386");
1767: #endif
1768: #ifdef i386
1769: prtopt(" i386");
1770: #endif
1771: #ifdef i286
1772: prtopt(" i286");
1773: #endif
1774: #ifdef M_I286
1775: prtopt(" M_I286");
1776: #endif
1777: #ifdef mc68000
1778: prtopt(" mc68000");
1779: #endif
1780: #ifdef mc68010
1781: prtopt(" mc68010");
1782: #endif
1783: #ifdef mc68020
1784: prtopt(" mc68020");
1785: #endif
1786: #ifdef mc68030
1787: prtopt(" mc68030");
1788: #endif
1789: #ifdef mc68040
1790: prtopt(" mc68040");
1791: #endif
1792: #ifdef M_68000
1793: prtopt(" M_68000");
1794: #endif
1795: #ifdef M_68010
1796: prtopt(" M_68010");
1797: #endif
1798: #ifdef M_68020
1799: prtopt(" M_68020");
1800: #endif
1801: #ifdef M_68030
1802: prtopt(" M_68030");
1803: #endif
1804: #ifdef M_68040
1805: prtopt(" M_68040");
1806: #endif
1807: #ifdef m68k
1808: prtopt(" m68k");
1809: #endif
1810: #ifdef m88k
1811: prtopt(" m88k");
1812: #endif
1813: #ifdef pdp11
1814: prtopt(" pdp11");
1815: #endif
1816: #ifdef iAPX
1817: prtopt(" iAPX");
1818: #endif
1819: #ifdef __hp9000s800
1820: prtopt(" __hp9000s800");
1821: #endif
1822: #ifdef __hp9000s500
1823: prtopt(" __hp9000s500");
1824: #endif
1825: #ifdef __hp9000s300
1826: prtopt(" __hp9000s300");
1827: #endif
1828: #ifdef __hp9000s200
1829: prtopt(" __hp9000s200");
1830: #endif
1831: #ifdef AIX
1832: prtopt(" AIX");
1833: #endif
1834: #ifdef _AIXFS
1835: prtopt(" _AIXFS");
1836: #endif
1837: #ifdef u370
1838: prtopt(" u370");
1839: #endif
1840: #ifdef u3b
1841: prtopt(" u3b");
1842: #endif
1843: #ifdef u3b2
1844: prtopt(" u3b2");
1845: #endif
1846: #ifdef multimax
1847: prtopt(" multimax");
1848: #endif
1849: #ifdef balance
1850: prtopt(" balance");
1851: #endif
1852: #ifdef ibmrt
1853: prtopt(" ibmrt");
1854: #endif
1855: #ifdef _IBMRT
1856: prtopt(" _IBMRT");
1857: #endif
1858: #ifdef ibmrs6000
1859: prtopt(" ibmrs6000");
1860: #endif
1861: #ifdef _AIX
1862: prtopt(" _AIX");
1863: #endif /* _AIX */
1864: #ifdef _IBMR2
1865: prtopt(" _IBMR2");
1866: #endif
1867: #ifdef __STRICT_BSD__
1868: prtopt(" __STRICT_BSD__");
1869: #endif
1870: #ifdef __STRICT_ANSI__
1871: prtopt(" __STRICT_ANSI__");
1872: #endif
1873: #ifdef _ANSI_C_SOURCE
1874: prtopt(" _ANSI_C_SOURCE");
1875: #endif
1876: #ifdef __STDC__
1877: prtopt(" __STDC__");
1878: #endif
1879: #ifdef __GNUC__ /* gcc in ansi mode */
1880: prtopt(" __GNUC__");
1881: #endif
1882: #ifdef GNUC /* gcc in traditional mode */
1883: prtopt(" GNUC");
1884: #endif
1885: #ifdef CK_ANSIC
1886: prtopt(" CK_ANSIC");
1887: #endif
1888: #ifdef CK_ANSILIBS
1889: prtopt(" CK_ANSILIBS");
1890: #endif
1891: #ifdef _XOPEN_SOURCE
1892: prtopt(" _XOPEN_SOURCE");
1893: #endif
1894: #ifdef _ALL_SOURCE
1895: prtopt(" _ALL_SOURCE");
1896: #endif
1897: #ifdef _SC_JOB_CONTROL
1898: prtopt(" _SC_JOB_CONTROL");
1899: #endif
1900: #ifdef _POSIX_JOB_CONTROL
1901: prtopt(" _POSIX_JOB_CONTROL");
1902: #endif
1903: #ifdef _BSD
1904: prtopt(" _BSD");
1905: #endif
1906: #ifdef TERMIOX
1907: prtopt(" TERMIOX");
1908: #endif /* TERMIOX */
1909: #ifdef STERMIOX
1910: prtopt(" STERMIOX");
1911: #endif /* STERMIOX */
1912: prtopt((char *)0);
1913: printf("\n\n");
1914: }
1915: #endif /* NOFRILLS */
1916:
1917: #ifdef VMS
1918: int
1919: sholbl() {
1920: printf("VMS Labeled File Features:\n");
1921: printf(" acl %s (ACL info %s)\n",
1922: lf_opts & LBL_ACL ? "on " : "off",
1923: lf_opts & LBL_ACL ? "preserved" : "discarded");
1924: printf(" backup-date %s (backup date/time %s)\n",
1925: lf_opts & LBL_BCK ? "on " : "off",
1926: lf_opts & LBL_BCK ? "preserved" : "discarded");
1927: printf(" name %s (original filename %s)\n",
1928: lf_opts & LBL_NAM ? "on " : "off",
1929: lf_opts & LBL_NAM ? "preserved" : "discarded");
1930: printf(" owner %s (original file owner id %s)\n",
1931: lf_opts & LBL_OWN ? "on " : "off",
1932: lf_opts & LBL_OWN ? "preserved" : "discarded");
1933: printf(" path %s (original file's disk:[directory] %s)\n",
1934: lf_opts & LBL_PTH ? "on " : "off",
1935: lf_opts & LBL_PTH ? "preserved" : "discarded");
1936: }
1937: #endif /* VMS */
1938:
1939: #ifndef NOSHOW
1940: int
1941: doshow(x) int x; {
1942: int y;
1943: char *s;
1944:
1945: #ifndef NOSETKEY
1946: if (x == SHKEY) { /* SHOW KEY */
1947: int c;
1948: KEY ch;
1949: CHAR *s;
1950:
1951: if ((y = cmcfm()) < 0) return(y);
1952: #ifdef MAC
1953: printf("Not implemented\n");
1954: return(0);
1955: #else /* Not MAC */
1956: printf(" Press key: ");
1957: conbin((char)escape); /* Put terminal in binary mode */
1958: c = congks(0); /* Get character or scan code */
1959: concb((char)escape); /* Restore terminal to cbreak mode */
1960: if (c < 0) { /* Check for error */
1961: printf("?Error reading key\n");
1962: return(0);
1963: }
1964: #ifndef OS2
1965: /*
1966: Do NOT mask when it can be a raw scan code, perhaps > 255
1967: */
1968: c &= cmdmsk; /* Apply command mask */
1969: #endif /* OS2 */
1970: printf("\n Key code \\%d => ",c);
1971: if (macrotab[c]) { /* See if there's a macro */
1972: printf("String: "); /* If so, display its definition */
1973: s = macrotab[c];
1974: while (ch = *s++)
1975: if (ch < 32 || ch == 127
1976: /*
1977: Systems whose native character sets have graphic characters in C1...
1978: */
1979: #ifndef NEXT /* NeXT */
1980: #ifndef AUX /* Macintosh */
1981: #ifndef XENIX /* IBM PC */
1982: #ifndef OS2 /* IBM PC */
1983: || (ch > 127 && ch < 160)
1984: #endif /* OS2 */
1985: #endif /* XENIX */
1986: #endif /* AUX */
1987: #endif /* NEXT */
1988: )
1989: printf("\\{%d}",ch); /* Display control characters */
1990: else putchar((char) ch); /* in backslash notation */
1991: printf("\n");
1992: } else { /* No macro, show single character */
1993: printf("Character: ");
1994: ch = keymap[c];
1995: if (ch < 32 || ch == 127 || ch > 255
1996: #ifndef NEXT
1997: #ifndef AUX
1998: #ifndef XENIX
1999: #ifndef OS2
2000: || (ch > 127 && ch < 160)
2001: #endif /* OS2 */
2002: #endif /* XENIX */
2003: #endif /* AUX */
2004: #endif /* NEXT */
2005: )
2006: printf("\\%d",(unsigned int) ch);
2007: else printf("%c \\%d",ch,(unsigned int) ch);
2008: }
2009: if (ch == (KEY) c)
2010: printf(" (self, no translation)\n");
2011: else printf("\n");
2012: return(1);
2013: #endif /* MAC */
2014: }
2015: #endif /* NOSETKEY */
2016:
2017: #ifndef NOSPL
2018: if (x == SHMAC) { /* SHOW MACRO */
2019: x = cmfld("Macro name, or carriage return to see them all","",&s,
2020: NULL);
2021: if (x == -3) /* This means they want see all */
2022: *line = '\0';
2023: else if (x < 0) /* Otherwise negative = parse error */
2024: return(x);
2025: else /* 0 or greater */
2026: strcpy(line,s); /* means they typed something */
2027: if ((y = cmcfm()) < 0) return(y); /* Get confirmation */
2028: if (*line) {
2029: slc = 0; /* Initial SHO MAC line number */
2030: x = mlook(mactab,s,nmac); /* Look up what they typed */
2031: switch (x) {
2032: case -3: /* Nothing to look up */
2033: return(0);
2034: case -1: /* Not found */
2035: printf("%s - not found\n",s);
2036: return(0);
2037: case -2: /* Ambiguous, matches more than one */
2038: y = (int)strlen(line);
2039: for (x = 0; x < nmac; x++)
2040: if (!strncmp(mactab[x].kwd,line,y))
2041: if (shomac(mactab[x].kwd,mactab[x].mval) < 0) break;
2042: return(1);
2043: default: /* Matches one exactly */
2044: shomac(mactab[x].kwd,mactab[x].mval);
2045: return(1);
2046: }
2047: } else { /* They want to see them all */
2048: printf("Macros:\n");
2049: slc = 1;
2050: for (y = 0; y < nmac; y++)
2051: if (shomac(mactab[y].kwd,mactab[y].mval) < 0) break;
2052: return(1);
2053: }
2054: }
2055: #endif /* NOSPL */
2056:
2057: /*
2058: Other SHOW commands only have two fields. Get command confirmation here,
2059: then handle with big switch() statement.
2060: */
2061: if ((y = cmcfm()) < 0) return(y);
2062: switch (x) {
2063:
2064: #ifdef SUNX25
2065: case SHPAD:
2066: shopad();
2067: break;
2068: #endif /* SUNX25 */
2069:
2070: #ifdef NETCONN
2071: case SHNET:
2072: shonet();
2073: break;
2074: #endif /* NETCONN */
2075:
2076: case SHPAR:
2077: shopar();
2078: break;
2079:
2080: case SHATT:
2081: shoatt();
2082: break;
2083:
2084: #ifndef NOSPL
2085: case SHCOU:
2086: printf(" %d\n",count[cmdlvl]);
2087: break;
2088: #endif /* NOSPL */
2089:
2090: #ifndef NOSERVER
2091: case SHSER: /* Show Server */
2092: #ifndef NOFRILLS
2093: printf("Function Status:\n");
2094: printf(" GET %s\n",nm[en_get]);
2095: printf(" SEND %s\n",nm[en_sen]);
2096: printf(" REMOTE CD/CWD %s\n",nm[en_cwd]);
2097: printf(" REMOTE DELETE %s\n",nm[en_del]);
2098: printf(" REMOTE DIRECTORY %s\n",nm[en_dir]);
2099: printf(" REMOTE HOST %s\n",nm[en_hos]);
2100: printf(" REMOTE SET %s\n",nm[en_set]);
2101: printf(" REMOTE SPACE %s\n",nm[en_spa]);
2102: printf(" REMOTE TYPE %s\n",nm[en_typ]);
2103: printf(" REMOTE WHO %s\n",nm[en_who]);
2104: printf(" BYE %s\n",nm[en_bye]);
2105: printf(" FINISH %s\n",nm[en_fin]);
2106: #endif /* NOFRILLS */
2107: printf("Server timeout: %d\n",srvtim);
2108: printf("Server display: %s\n\n", srvdis ? "on" : "off");
2109: break;
2110: #endif /* NOSERVER */
2111:
2112: case SHSTA: /* Status of last command */
2113: if (success) printf(" SUCCESS\n"); else printf(" FAILURE\n");
2114: break;
2115:
2116: #ifdef MAC
2117: case SHSTK: { /* Stack for MAC debugging */
2118: long sp;
2119:
2120: sp = -1;
2121: loadA0 ((char *)&sp); /* set destination address */
2122: SPtoaA0(); /* move SP to destination */
2123: printf("Stack at 0x%x\n", sp);
2124: show_queue(); /* more debugging */
2125: break;
2126: }
2127: #endif /* MAC */
2128:
2129: case SHTER:
2130: #ifdef OS2PM
2131: printf(" Terminal type: %s\n",
2132: (Term_mode == VT100) ? "VT100" : "Tektronix");
2133: #endif /* OS2PM */
2134: printf(" Command bytesize: %d bits\n",
2135: (cmdmsk == 0377) ? 8 : 7);
2136: printf(" Terminal bytesize: %d bits\n",
2137: (cmask == 0377) ? 8 : 7);
2138: printf(" Terminal locking-shift: %s\n", sosi ? "on" : "off");
2139: printf(" Terminal newline-mode: %s\n", tnlm ? "on" : "off");
2140: #ifndef NOCSETS
2141: printf(" Terminal character set");
2142: if (tcsl == tcsr) {
2143: printf(": transparent\n");
2144: } else {
2145: s = "unknown";
2146: for (y = 0; y <= nfilc; y++)
2147: if (fcstab[y].kwval == tcsr) {
2148: s = fcstab[y].kwd;
2149: break;
2150: }
2151: printf("s: remote: %s, local: ",s);
2152: s = "unknown";
2153: for (y = 0; y <= nfilc; y++)
2154: if (fcstab[y].kwval == tcsl) {
2155: s = fcstab[y].kwd;
2156: break;
2157: }
2158: printf("%s",s);
2159: if (tcsr != tcsl)
2160: printf(" (via %s)",
2161: #ifdef CYRILLIC
2162: (language == L_RUSSIAN) ? "latin-cyrillic" : "latin1"
2163: #else
2164: "latin1"
2165: #endif /* CYRILLIC */
2166: );
2167: printf("\n");
2168: }
2169: #endif /* NOCSETS */
2170: #ifdef UNIX
2171: printf(" Suspend: %s\n", suspend ? "on" : "off");
2172: #endif /* UNIX */
2173: break;
2174:
2175: #ifndef NOFRILLS
2176: case SHVER:
2177: shover();
2178: break;
2179: #endif /* NOFRILLS */
2180:
2181: #ifndef NOSPL
2182: case SHBUI: /* Built-in variables */
2183: for (y = 0; y < nvars; y++)
2184: printf(" \\v(%s) = %s\n",vartab[y].kwd,nvlook(vartab[y].kwd));
2185: break;
2186:
2187: case SHFUN: /* Functions */
2188: for (y = 0; y < nfuncs; y++)
2189: printf(" \\f%s()\n",fnctab[y].kwd);
2190: break;
2191:
2192: case SHVAR: /* Global variables */
2193: x = 0; /* Variable count */
2194: slc = 1; /* Screen line count for "more?" */
2195: for (y = 33; y < GVARS; y++)
2196: if (g_var[y]) {
2197: if (x++ == 0) printf("Global variables:\n");
2198: sprintf(line," \\%%%c",y);
2199: if (shomac(line,g_var[y]) < 0) break;
2200: }
2201: if (!x) printf(" No variables defined\n");
2202: break;
2203:
2204: case SHARG: /* Args */
2205: if (maclvl > -1) {
2206: printf("Macro arguments at level %d\n",maclvl);
2207: for (y = 0; y < 10; y++)
2208: if (m_arg[maclvl][y])
2209: printf(" \\%%%d = %s\n",y,m_arg[maclvl][y]);
2210: } else {
2211: printf(" No macro arguments at top level\n");
2212: }
2213: break;
2214:
2215: case SHARR: /* Arrays */
2216: x = 0;
2217: for (y = 0; y < 27; y++)
2218: if (a_ptr[y]) {
2219: if (x == 0) printf("Declared arrays:\n");
2220: x = 1;
2221: printf(" \\&%c[%d]\n",(y == 0) ? 64 : y + 96, a_dim[y]);
2222: }
2223: if (!x) printf(" No arrays declared\n");
2224: break;
2225: #endif /* NOSPL */
2226:
2227: case SHPRO: /* Protocol parameters */
2228: shoparp();
2229: printf("\n");
2230: break;
2231:
2232: case SHCOM: /* Communication parameters */
2233: printf("\n");
2234: shoparc();
2235: #ifndef NODIAL
2236: printf("\n");
2237: #ifdef NETCONN
2238: if (!network)
2239: #endif /* NETCONN */
2240: shodial();
2241: #endif /* NODIAL */
2242: printf("\n");
2243: shomdm();
2244: printf("\n");
2245: break;
2246:
2247: case SHFIL: /* File parameters */
2248: shoparf();
2249: printf("\n");
2250: break;
2251:
2252: #ifndef NOCSETS
2253: case SHLNG: /* Languages */
2254: shoparl();
2255: break;
2256: #endif /* NOCSETS */
2257:
2258: #ifndef NOSPL
2259: case SHSCR: /* Scripts */
2260: printf(" Take echo: %s\n", techo ? "On" : "Off");
2261: printf(" Take error: %s\n", terror ? "On" : "Off");
2262: printf(" Macro Echo: %s\n", mecho ? "On" : "Off");
2263: printf(" Macro Error: %s\n", merror ? "On" : "Off");
2264: printf(" Input Case: %s\n", incase ? "Observe" : "Ignore");
2265: printf(" Input Echo: %s\n", inecho ? "On" : "Off");
2266: printf(" Input Timeout: %s\n", intime ? "Quit" : "Proceed");
2267: #ifndef NOSCRIPT
2268: printf(" Script echo: %s\n", secho ? "On" : "Off");
2269: #endif /* NOSCRIPT */
2270: break;
2271: #endif /* NOSPL */
2272:
2273: #ifndef NOXMIT
2274: case SHXMI:
2275: printf(" File type: %s\n", binary ? "binary" : "text");
2276: printf(" Transmit EOF: ");
2277: if (*xmitbuf == NUL) {
2278: printf("none\n");
2279: } else {
2280: char *p;
2281: p = xmitbuf;
2282: while (*p) {
2283: if (*p < SP)
2284: printf("^%c",ctl(*p));
2285: else
2286: printf("%c",*p);
2287: p++;
2288: }
2289: printf("\n");
2290: }
2291: if (xmitf)
2292: printf(" Transmit Fill: %d (fill character for blank lines)\n",
2293: xmitf);
2294: else printf(" Transmit Fill: none\n");
2295: printf(" Transmit Linefeed: %s\n",
2296: xmitl ? "on (send linefeeds too)" : "off");
2297: if (xmitp)
2298: printf(" Transmit Prompt: %d (host line end character)\n",xmitp);
2299: else printf(" Transmit Prompt: none\n");
2300: printf(" Transmit Echo: %s\n",
2301: xmitx ? "on" : "off");
2302: printf(" Transmit Locking-Shift: %s\n",xmits ? "on" : "off");
2303: printf(" Transmit Pause: %d milliseconds\n", xmitw);
2304: break;
2305: #endif /* NOXMIT */
2306:
2307: case SHMOD: /* SHOW MODEM */
2308: shmdmlin();
2309: shomdm();
2310: break;
2311:
2312: #ifndef MAC
2313: case SHDFLT:
2314: zsyscmd(PWDCMD);
2315: break;
2316: #endif /* MAC */
2317:
2318: case SHESC:
2319: printf(" Escape character: %d (^%c)\n",escape,ctl(escape));
2320: break;
2321:
2322: #ifndef NODIAL
2323: case SHDIA:
2324: shmdmlin();
2325: doshodial();
2326: if (local
2327: #ifdef NETCONN
2328: && !network
2329: #endif /* NETCONN */
2330: ) {
2331: printf("%s modem signals:\n",ttname);
2332: shomdm();
2333: }
2334: break;
2335: #endif /* NODIAL */
2336:
2337: #ifdef VMS
2338: case SHLBL:
2339: sholbl();
2340: break;
2341: #endif /* VMS */
2342:
2343: default:
2344: printf("\nNothing to show...\n");
2345: return(-2);
2346: }
2347: return(success = 1);
2348: }
2349:
2350: VOID
2351: shmdmlin() { /* Briefly show modem & line */
2352: int i;
2353: if (local
2354: #ifdef NETCONN
2355: && !network
2356: #endif /* NETCONN */
2357: )
2358: printf("Line: %s, modem: ",ttname);
2359: else
2360: printf(" Communication device not yet selected with SET LINE\nModem: ");
2361: if (
2362: #ifdef NETCONN
2363: !network
2364: #else
2365: 1
2366: #endif /* NETCONN */
2367: ) {
2368: #ifndef NODIAL
2369: for (i = 0; i < nmdm; i++) {
2370: if (mdmtab[i].kwval == mdmtyp) {
2371: printf("%s\n",mdmtab[i].kwd);
2372: break;
2373: }
2374: }
2375: #else
2376: printf("(disabled)\n");
2377: #endif /* NODIAL */
2378: }
2379: }
2380:
2381: #ifndef NOSPL
2382: #define SCRNLEN 21
2383: #define SCRNWID 79
2384: int /* SHO MACROS */
2385: shomac(s1, s2) char *s1, *s2; {
2386: int x, n, pp;
2387: pp = 0;
2388:
2389: if (!s1)
2390: return(0);
2391: else
2392: printf("%s = ",s1); /* Print macro name */
2393: n = (int)strlen(s1) + 3;
2394: if (!s2) s2 = "(null definition)";
2395: while (x = *s2++) { /* Loop thru definition */
2396: if (x == '(') pp++; /* Treat commas within parens */
2397: if (x == ')') pp--; /* as ordinary text */
2398: if (pp < 0) pp = 0; /* Outside parens, */
2399: if (x == ',' && pp == 0) { /* comma becomes comma-dash-NL. */
2400: putchar(',');
2401: x = '\n';
2402: }
2403: putchar(x);
2404: if (x == '\n') {
2405: n = 0;
2406: slc++;
2407: } else if (++n > SCRNWID) {
2408: putchar(NL);
2409: n = 0;
2410: slc++;
2411: }
2412: if (slc > SCRNLEN) {
2413: if (!askmore()) return(-1);
2414: n = 0;
2415: slc = 0;
2416: }
2417: }
2418: putchar(NL);
2419: if (++slc > SCRNLEN) {
2420: if (!askmore()) return(-1);
2421: slc = 0;
2422: }
2423: return(0);
2424: }
2425: #endif /* NOSPL */
2426:
2427: int
2428: shoatt() {
2429: printf("Attributes: %s\n", atcapr ? "On" : "Off");
2430: if (!atcapr) return(0);
2431: printf(" Blocksize: %s\n", atblki ? "On" : "Off");
2432: printf(" Date: %s\n", atdati ? "On" : "Off");
2433: printf(" Disposition: %s\n", atdisi ? "On" : "Off");
2434: printf(" Encoding (Character Set): %s\n", atenci ? "On" : "Off");
2435: printf(" Length: %s\n", atleni ? "On" : "Off");
2436: printf(" Type (text/binary): %s\n", attypi ? "On" : "Off");
2437: printf(" System ID: %s\n", atsidi ? "On" : "Off");
2438: printf(" System Info: %s\n", atsysi ? "On" : "Off");
2439: return(0);
2440: }
2441: #endif /* NOSHOW */
2442:
2443: #ifndef NOSPL
2444: /* Evaluate an arithmetic expression. */
2445: /* Code adapted from ev, by Howie Kaye of Columbia U & others. */
2446:
2447: static int xerror;
2448: static char *cp;
2449: static long tokval;
2450: static char curtok;
2451: static long expval;
2452:
2453: #define LONGBITS (8*sizeof (long))
2454: #define NUMBER 'N'
2455: #define EOT 'E'
2456:
2457: /*
2458: Replacement for strchr() and index(), neither of which seem to be universal.
2459: */
2460:
2461: static char *
2462: #ifdef CK_ANSIC
2463: windex(char * s, char c)
2464: #else
2465: windex(s,c) char *s, c;
2466: #endif /* CK_ANSIC */
2467: /* windex */ {
2468: while (*s != NUL && *s != c) s++;
2469: if (*s == c) return(s); else return(NULL);
2470: }
2471:
2472: /*
2473: g e t t o k
2474:
2475: Returns the next token. If token is a NUMBER, sets tokval appropriately.
2476: */
2477: static char
2478: gettok() {
2479: while (isspace(*cp)) cp++ ;
2480: switch(*cp) {
2481: case '$': /* ??? */
2482: case '+': /* Add */
2483: case '-': /* Subtract or Negate */
2484: case '@': /* Greatest Common Divisor */
2485: case '*': /* Multiply */
2486: case '/': /* Divide */
2487: case '%': /* Modulus */
2488: case '<': /* Left shift */
2489: case '>': /* Right shift */
2490: case '&': /* And */
2491: case '|': /* Or */
2492: case '#': /* Exclusive Or */
2493: case '~': /* Not */
2494: case '^': /* Exponent */
2495: case '!': /* Factorial */
2496: case '(': /* Parens for grouping */
2497: case ')': return(*cp++); /* operator, just return it */
2498: case '\n':
2499: case '\0': return(EOT); /* end of line, return that */
2500: }
2501: if (isxdigit(*cp)) { /* digit, must be a number */
2502: char tbuf[80],*tp; /* buffer to accumulate number */
2503: int radix = 10; /* default radix */
2504: for (tp=tbuf; isxdigit(*cp); cp++)
2505: *tp++ = isupper(*cp) ? tolower(*cp) : *cp;
2506: *tp = '\0'; /* end number */
2507: switch(isupper(*cp) ? tolower(*cp) : *cp) { /* examine break char */
2508: case 'h':
2509: case 'x': radix = 16; cp++; break; /* if radix signifier... */
2510: case 'o':
2511: case 'q': radix = 8; cp++; break;
2512: case 't': radix = 2; cp++; break;
2513: }
2514: for (tp=tbuf,tokval=0; *tp != '\0'; tp++) {
2515: int dig;
2516: dig = *tp - '0'; /* convert number */
2517: if (dig > 10) dig -= 'a'-'0'-10;
2518: if (dig >= radix) {
2519: xerror = 1;
2520: if (cmdlvl == 0)
2521: printf("invalid digit '%c' in number\n",*tp);
2522: return(NUMBER);
2523: }
2524: tokval = radix*tokval + dig;
2525: }
2526: return(NUMBER);
2527: }
2528: if (cmdlvl == 0)
2529: printf("Invalid character '%c' in input\n",*cp);
2530: xerror = 1;
2531: cp++;
2532: return(gettok());
2533: }
2534:
2535: static long
2536: expon(x,y) long x,y; {
2537: long result = 1;
2538: int sign = 1;
2539: if (y < 0) return(0);
2540: if (x < 0) {
2541: x = -x;
2542: if (y & 1) sign = -1;
2543: }
2544: while (y != 0) {
2545: if (y & 1) result *= x;
2546: y >>= 1;
2547: if (y != 0) x *= x;
2548: }
2549: return(result * sign);
2550: }
2551:
2552: /*
2553: * factor ::= simple | simple ^ factor
2554: *
2555: */
2556: _PROTOTYP( static VOID simple, (void) );
2557:
2558: static VOID
2559: factor() {
2560: long oldval;
2561: simple();
2562: if (curtok == '^') {
2563: oldval = expval;
2564: curtok = gettok();
2565: factor();
2566: expval = expon(oldval,expval);
2567: }
2568: }
2569:
2570: /*
2571: * termp ::= NULL | {*,/,%,&} factor termp
2572: *
2573: */
2574: static VOID
2575: termp() {
2576: while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == '&') {
2577: long oldval;
2578: char op;
2579: op = curtok;
2580: curtok = gettok(); /* skip past operator */
2581: oldval = expval;
2582: factor();
2583: switch(op) {
2584: case '*': expval = oldval * expval; break;
2585: case '/': expval = oldval / expval; break;
2586: case '%': expval = oldval % expval; break;
2587: case '&': expval = oldval & expval; break;
2588: }
2589: }
2590: }
2591:
2592: static long
2593: fact(x) long x; { /* factorial */
2594: long result = 1;
2595: while (x > 1)
2596: result *= x--;
2597: return(result);
2598: }
2599:
2600: /*
2601: * term ::= factor termp
2602: *
2603: */
2604: static VOID
2605: term() {
2606: factor();
2607: termp();
2608: }
2609:
2610: static long
2611: gcd(x,y) long x,y; {
2612: int nshift = 0;
2613: if (x < 0) x = -x;
2614: if (y < 0) y = -y; /* validate arguments */
2615: if (x == 0 || y == 0) return(x + y); /* this is bogus */
2616:
2617: while (!((x & 1) | (y & 1))) { /* get rid of powers of 2 */
2618: nshift++;
2619: x >>= 1;
2620: y >>= 1;
2621: }
2622: while (x != 1 && y != 1 && x != 0 && y != 0) {
2623: while (!(x & 1)) x >>= 1; /* eliminate unnecessary */
2624: while (!(y & 1)) y >>= 1; /* powers of 2 */
2625: if (x < y) { /* force x to be larger */
2626: long t;
2627: t = x;
2628: x = y;
2629: y = t;
2630: }
2631: x -= y;
2632: }
2633: if (x == 0 || y == 0) return((x + y) << nshift); /* gcd is non-zero one */
2634: else return((long) 1 << nshift); /* else gcd is 1 */
2635: }
2636:
2637: /*
2638: * exprp ::= NULL | {+,-,|,...} term exprp
2639: *
2640: */
2641: static VOID
2642: exprp() {
2643: while (windex("+-|<>#@",curtok) != NULL) {
2644: long oldval;
2645: char op;
2646: op = curtok;
2647: curtok = gettok(); /* skip past operator */
2648: oldval = expval;
2649: term();
2650: switch(op) {
2651: case '+' : expval = oldval + expval; break;
2652: case '-' : expval = oldval - expval; break;
2653: case '|' : expval = oldval | expval; break;
2654: case '#' : expval = oldval ^ expval; break;
2655: case '@' : expval = gcd(oldval,expval); break;
2656: case '<' : expval = oldval << expval; break;
2657: case '>' : expval = oldval >> expval; break;
2658: }
2659: }
2660: }
2661:
2662: /*
2663: * expr ::= term exprp
2664: *
2665: */
2666: static VOID
2667: expr() {
2668: term();
2669: exprp();
2670: }
2671:
2672: static long
2673: xparse() {
2674: curtok = gettok();
2675: expr();
2676: #ifdef COMMENT
2677: if (curtok == '$') {
2678: curtok = gettok();
2679: if (curtok != NUMBER) {
2680: if (cmdlvl == 0) printf("illegal radix\n");
2681: return(0);
2682: }
2683: curtok = gettok();
2684: }
2685: #endif /* COMMENT */
2686: if (curtok != EOT) {
2687: if (cmdlvl == 0)
2688: printf("extra characters after expression\n");
2689: xerror = 1;
2690: }
2691: return(expval);
2692: }
2693:
2694: char *
2695: evala(s) char *s; {
2696: char *p; /* Return pointer */
2697: long v; /* Numeric value */
2698:
2699: xerror = 0; /* Start out with no error */
2700: cp = s; /* Make the argument global */
2701: v = xparse(); /* Parse the string */
2702: p = numbuf; /* Convert long number to string */
2703: sprintf(p,"%ld",v);
2704: return(xerror ? "" : p); /* Return empty string on error */
2705: }
2706:
2707: /*
2708: * simplest ::= NUMBER | ( expr )
2709: *
2710: */
2711: static VOID
2712: simplest() {
2713: if (curtok == NUMBER) expval = tokval;
2714: else if (curtok == '(') {
2715: curtok = gettok(); /* skip over paren */
2716: expr();
2717: if (curtok != ')') {
2718: if (cmdlvl == 0) printf("missing right parenthesis\n");
2719: xerror = 1;
2720: }
2721: }
2722: else {
2723: if (cmdlvl == 0) printf("operator unexpected\n");
2724: xerror = 1;
2725: }
2726: curtok = gettok();
2727: }
2728:
2729: /*
2730: * simpler ::= simplest | simplest !
2731: *
2732: */
2733: static VOID
2734: simpler() {
2735: simplest();
2736: if (curtok == '!') {
2737: curtok = gettok();
2738: expval = fact(expval);
2739: }
2740: }
2741:
2742: /*
2743: * simple ::= {-,~} simpler | simpler
2744: *
2745: */
2746:
2747: static VOID
2748: simple() {
2749: if (curtok == '-' || curtok == '~') {
2750: int op = curtok;
2751: curtok = gettok(); /* skip over - sign */
2752: simpler(); /* parse the factor again */
2753: expval = op == '-' ? -expval : ~expval;
2754: } else simpler();
2755: }
2756: #endif /* NOSPL */
2757:
2758: #ifndef NOSPL
2759: /* D C L A R R A Y -- Declare an array */
2760:
2761: int /* Declare an array of size n */
2762: #ifdef CK_ANSIC
2763: dclarray(char a, int n)
2764: #else
2765: dclarray(a,n) char a; int n;
2766: #endif /* CK_ANSIC */
2767: /* dclarray */ {
2768: char **p; int i, n2;
2769:
2770: if (a > 63 && a < 96) a += 32; /* Convert to lowercase */
2771: if (a < 96 || a > 122) return(-1); /* Verify name */
2772: a -= 96; /* Convert name to number */
2773: if ((p = a_ptr[a]) != NULL) { /* Delete old array of same name */
2774: n2 = a_dim[a];
2775: for (i = 0; i <= n2; i++) /* First delete its elements */
2776: if (p[i]) free(p[i]);
2777: free(a_ptr[a]); /* Then the element list */
2778: a_ptr[a] = (char **) NULL; /* Remove pointer to element list */
2779: a_dim[a] = 0; /* Set dimension at zero. */
2780: }
2781: if (n == 0) return(0); /* If dimension 0, just deallocate. */
2782:
2783: p = (char **) malloc((n+1) * sizeof(char **)); /* Allocate for new array */
2784: if (p == NULL) return(-1); /* Check */
2785: a_ptr[a] = p; /* Save pointer to member list */
2786: a_dim[a] = n; /* Save dimension */
2787: for (i = 0; i <= n; i++) /* Initialize members to null */
2788: p[i] = NULL;
2789: return(0);
2790: }
2791:
2792: /* A R R A Y N A M -- Parse an array name */
2793:
2794: /*
2795: Call with pointer to string that starts with the array reference.
2796: String may begin with either \& or just &.
2797: On success,
2798: Returns letter ID (always lowercase) in argument c,
2799: which can also be accent grave (` = 96; '@' is converted to grave);
2800: Dimension or subscript in argument n;
2801: IMPORTANT: These arguments must be provided by the caller as addresses
2802: of ints (not chars), for example:
2803: char *s; int x, y;
2804: arraynam(s,&x,&y);
2805: On failure, returns a negative number, with args n and c set to zero.
2806: */
2807: int
2808: arraynam(ss,c,n) char *ss; int *c; int *n; {
2809: int i, y, pp;
2810: char x;
2811: char *s, *p, *sx, *vnp;
2812: char vnbuf[VNAML+1]; /* On stack to allow for */
2813: char ssbuf[VNAML+1]; /* recursive calls... */
2814: char sxbuf[VNAML+1];
2815:
2816: *c = *n = 0; /* Initialize return values */
2817: strncpy(vnbuf,ss,VNAML);
2818: vnp = vnbuf;
2819: if (vnbuf[0] == CMDQ && vnbuf[1] == '&') vnp++;
2820: if (*vnp != '&') {
2821: printf("?Not an array - %s\n",vnbuf);
2822: return(-9);
2823: }
2824: x = *(vnp + 1); /* Fold case of array name */
2825: /* We don't use isupper & tolower here on purpose because these */
2826: /* would produce undesired effects with accented letters. */
2827: if (x > 63 && x < 91) x = *(vnp +1) = x + 32;
2828: if ((x < 96) || (x > 122) || (*(vnp+2) != '[')) {
2829: printf("?Invalid format for array name - %s\n",vnbuf);
2830: return(-9);
2831: }
2832: *c = x; /* Return the array name */
2833: s = vnp+3; /* Get dimension */
2834: p = ssbuf;
2835: pp = 1; /* Bracket counter */
2836: for (i = 0; i < VNAML && *s != NUL; i++) { /* Copy up to ] */
2837: if (*s == '[') pp++;
2838: if (*s == ']' && --pp == 0) break;
2839: *p++ = *s++;
2840: }
2841: if (*s != ']') {
2842: printf("?No closing bracket on array dimension - %s\n",vnbuf);
2843: return(-9);
2844: }
2845: *p = NUL; /* Terminate subscript with null */
2846: p = ssbuf; /* Point to beginning of subscript */
2847: sx = sxbuf; /* Where to put expanded subscript */
2848: y = VNAML-1;
2849: xxstring(p,&sx,&y); /* Convert variables, etc. */
2850: if (!chknum(sxbuf)) { /* Make sure it's all digits */
2851: printf("?Array dimension or subscript must be numeric - %s\n",sxbuf);
2852: return(-9);
2853: }
2854: if ((y = atoi(sxbuf)) < 0) {
2855: if (cmflgs == 0) printf("\n");
2856: printf("?Array dimension or subscript must be positive or zero - %s\n",
2857: sxbuf);
2858: return(-9);
2859: }
2860: *n = y; /* Return the subscript or dimension */
2861: return(0);
2862: }
2863:
2864: int
2865: chkarray(a,i) int a, i; { /* Check if array is declared */
2866: int x; /* and if subscript is in range */
2867: if (a == 64) a = 96; /* Convert atsign to grave accent */
2868: x = a - 96; /* Values must be in range 96-122 */
2869: if (x < 0 || x > 26) return(-2); /* Not in range */
2870: if (a_ptr[x] == NULL) return(-1); /* Not declared */
2871: if (i > a_dim[x]) return(-2); /* Declared but out of range. */
2872: return(a_dim[x]); /* All ok, return dimension */
2873: }
2874:
2875: char *
2876: arrayval(a,i) int a, i; { /* Return value of \&a[i] */
2877: int x; char **p; /* (possibly NULL) */
2878:
2879: if (a == 64) a = 96; /* Convert atsign to grave accent */
2880: x = a - 96; /* Values must be in range 96-122 */
2881: if (x < 0 || x > 26) return(NULL); /* Not in range */
2882: if ((p = a_ptr[x]) == NULL) /* Array not declared */
2883: return(NULL);
2884: if (i > a_dim[x]) /* Subscript out of range. */
2885: return(NULL);
2886: return(p[i]); /* All ok, return pointer to value. */
2887: }
2888: #endif /* NOSPL */
2889:
2890: #ifndef NOSPL
2891: /* P A R S E V A R -- Parse a variable name or array reference. */
2892: /*
2893: Call with:
2894: s = pointer to candidate variable name or array reference.
2895: *c = address of integer in which to return variable ID.
2896: *i = address of integer in which to return array subscript.
2897: Returns:
2898: -2: syntax error in variable name or array reference.
2899: 1: successful parse of a simple variable, with ID in c.
2900: 2: successful parse of an array reference, w/ID in c and subscript in i.
2901: */
2902: int
2903: parsevar(s,c,i) char *s; int *c, *i; {
2904: char *p;
2905: int x,y,z;
2906:
2907: p = s;
2908: if (*s == CMDQ) s++; /* Point after backslash */
2909:
2910: if (*s != '%' && *s != '&') { /* Make sure it's % or & */
2911: printf("?Not a variable name - %s\n",p);
2912: return(-9);
2913: }
2914: if ((int)strlen(s) < 2) {
2915: printf("?Incomplete variable name - %s\n",p);
2916: return(-9);
2917: }
2918: if (*s == '%' && *(s+2) != '\0') {
2919: printf("?Only one character after '%%' in variable name, please\n");
2920: return(-9);
2921: }
2922: if (*s == '&' && *(s+2) != '[') {
2923: printf("?Array subscript expected - %s\n",p);
2924: return(-9);
2925: }
2926: if (*s == '%') { /* Simple variable. */
2927: y = *(s+1); /* Get variable ID letter/char */
2928: if (isupper(y)) y -= ('a'-'A'); /* Convert upper to lower case */
2929: *c = y; /* Set the return values. */
2930: *i = -1; /* No array subscript. */
2931: return(1); /* Return 1 = simple variable */
2932: }
2933: if (*s == '&') { /* Array reference. */
2934: if (arraynam(s,&x,&z) < 0) { /* Go parse it. */
2935: printf("?Invalid array reference - %s\n",p);
2936: return(-9);
2937: }
2938: if (chkarray(x,z) < 0) { /* Check if declared, etc. */
2939: printf("?Array not declared or subscript out of range\n");
2940: return(-9);
2941: }
2942: *c = x; /* Return array letter */
2943: *i = z; /* and subscript. */
2944: return(2);
2945: }
2946: return(-2); /* None of the above. */
2947: }
2948:
2949: #define VALN 20
2950:
2951: /* Get the numeric value of a variable */
2952: /*
2953: Call with pointer to variable name, pointer to int for return value.
2954: Returns:
2955: 0 on success with second arg containing the value.
2956: -1 on failure (bad variable syntax, variable not defined or not numeric).
2957: */
2958: int
2959: varval(s,v) char *s; int *v; {
2960: char valbuf[VALN+1]; /* s is pointer to variable name */
2961: char *p;
2962: int y;
2963:
2964: p = valbuf; /* Expand variable into valbuf. */
2965: y = VALN;
2966: if (xxstring(s,&p,&y) < 0) return(-1);
2967: p = valbuf; /* Make sure value is numeric */
2968: if (!chknum(p)) return(-1);
2969: *v = atoi(p); /* Convert numeric string to int */
2970: return(0);
2971: }
2972:
2973: /* Increment or decrement a variable */
2974: /* Returns -1 on failure, 0 on success, with 4th argument set to result */
2975:
2976: int
2977: incvar(s,x,z,r) char *s; int x, z, *r; { /* Increment a numeric variable */
2978: char valbuf[VALN+1]; /* s is pointer to variable name */
2979: /* x is amount to increment by */
2980: int n; /* z != 0 means add */
2981: /* z = 0 means subtract */
2982:
2983: if (varval(s,&n) < 0) /* Convert numeric string to int */
2984: return(-1);
2985: if (z) /* Increment it by the given amount */
2986: n += x;
2987: else /* or decrement as requested. */
2988: n -= x;
2989: sprintf(valbuf,"%d",n); /* Convert back to numeric string */
2990: addmac(s,valbuf); /* Replace old variable */
2991: *r = n; /* Return the integer value */
2992: return(0);
2993: }
2994: #endif /* NOSPL */
2995:
2996: /* Functions moved here from ckuusr.c to even out the module sizes... */
2997:
2998: #ifndef NOSPL
2999: /* D O D O -- Do a macro */
3000:
3001: /*
3002: Call with x = macro table index, s = pointer to arguments.
3003: Returns 0 on failure, 1 on success.
3004: */
3005:
3006: int
3007: dodo(x,s) int x; char *s; {
3008: char *p;
3009: int b, y, z;
3010:
3011: debug(F101,"dodo maclvl","",maclvl);
3012: if (++maclvl > MACLEVEL) { /* Make sure we have storage */
3013: debug(F101,"dodo maclvl too deep","",maclvl);
3014: --maclvl;
3015: printf("Macros nested too deeply\n");
3016: return(0);
3017: }
3018: macp[maclvl] = mactab[x].mval; /* Point to the macro body */
3019: macx[maclvl] = mactab[x].mval; /* Remember where the beginning is */
3020: debug(F111,"do macro",macp[maclvl],maclvl);
3021:
3022: cmdlvl++; /* Entering a new command level */
3023: if (cmdlvl > CMDSTKL) { /* Too many macros + TAKE files? */
3024: debug(F101,"dodo cmdlvl too deep","",cmdlvl);
3025: cmdlvl--;
3026: printf("?TAKE files and DO commands nested too deeply\n");
3027: return(0);
3028: }
3029: #ifdef VMS
3030: conres(); /* So Ctrl-C, etc, will work. */
3031: #endif
3032: ifcmd[cmdlvl] = 0;
3033: iftest[cmdlvl] = 0;
3034: count[cmdlvl] = 0;
3035: cmdstk[cmdlvl].src = CMD_MD; /* Say we're in a macro */
3036: cmdstk[cmdlvl].lvl = maclvl; /* and remember the macro level */
3037: mrval[maclvl] = NULL; /* Initialize return value */
3038:
3039: debug(F110,"do macro",mactab[x].kwd,0);
3040:
3041: /* Clear old %0..%9 arguments */
3042:
3043: addmac("%0",mactab[x].kwd); /* Define %0 = name of macro */
3044: varnam[0] = '%';
3045: varnam[2] = '\0';
3046: for (y = 1; y < 10; y++) { /* Clear args %1..%9 */
3047: varnam[1] = y + '0';
3048: delmac(varnam);
3049: }
3050:
3051: /* Assign the new args one word per arg, allowing braces to group words */
3052:
3053: p = s; /* Pointer to beginning of arg */
3054: b = 0; /* Flag for outer brace removal */
3055: x = 0; /* Flag for in-word */
3056: y = 0; /* Brace nesting level */
3057: z = 0; /* Argument counter, 0 thru 9 */
3058:
3059: while (1) { /* Go thru argument list */
3060: if (!s || (*s == '\0')) { /* No more characters? */
3061: if (x != 0) {
3062: if (z == 9) break; /* Only go up to 9. */
3063: z++; /* Count it. */
3064: varnam[1] = z + '0'; /* Assign last argument */
3065: addmac(varnam,p);
3066: break; /* And get out. */
3067: } else break;
3068: }
3069: if (x == 0 && *s == ' ') { /* Eat leading blanks */
3070: s++;
3071: continue;
3072: } else if (*s == '{') { /* An opening brace */
3073: if (x == 0 && y == 0) { /* If leading brace */
3074: p = s+1; /* point past it */
3075: b = 1; /* and flag that we did this */
3076: }
3077: x = 1; /* Flag that we're in a word */
3078: y++; /* Count the brace. */
3079: } else if (*s == '}') { /* A closing brace. */
3080: y--; /* Count it. */
3081: if (y == 0 && b != 0) { /* If it matches the leading brace */
3082: *s = ' '; /* change it to a space */
3083: b = 0; /* and we're not in braces any more */
3084: } else if (y < 0) x = 1; /* otherwise just start a new word. */
3085: } else if (*s != ' ') { /* Nonspace means we're in a word */
3086: if (x == 0) p = s; /* Mark the beginning */
3087: x = 1; /* Set in-word flag */
3088: }
3089: /* If we're not inside a braced quantity, and we are in a word, and */
3090: /* we have hit a space, then we have an argument to assign. */
3091: if ((y < 1) && (x != 0) && (*s == ' ')) {
3092: *s = '\0'; /* terminate the arg with null */
3093: x = 0; /* say we're not in a word any more */
3094: y = 0; /* start braces off clean again */
3095: if (z == 9) break; /* Only go up to 9. */
3096: z++; /* count this arg */
3097: varnam[1] = z + '0'; /* compute its name */
3098: addmac(varnam,p); /* add it to the macro table */
3099: p = s+1;
3100: }
3101: s++; /* Point past this character */
3102: }
3103: if ((z == 0) && (y > 1)) { /* Extra closing brace(s) at end */
3104: z++;
3105: varnam[1] = z + '0'; /* compute its name */
3106: addmac(varnam,p); /* Add rest of line to last arg */
3107: }
3108: macargc[maclvl] = z + 1; /* For ARGC variable */
3109: return(1); /* DO command succeeded */
3110: }
3111:
3112: /* Insert "literal" quote around each comma-separated command to prevent */
3113: /* its premature expansion. Only do this if object command is surrounded */
3114: /* by braces. */
3115:
3116: static char* flit = "\\flit(";
3117:
3118: int
3119: litcmd(src,dest) char **src, **dest; {
3120: int bc = 0, pp = 0;
3121: char *s, *lp, *ss;
3122:
3123: s = *src;
3124: lp = *dest;
3125:
3126: while (*s == SP) s++; /* strip extra leading spaces */
3127: if (*s == '{') {
3128:
3129: pp = 0; /* paren counter */
3130: bc = 1; /* count leading brace */
3131: *lp++ = *s++; /* copy it */
3132: while (*s == SP) s++; /* strip interior leading spaces */
3133: ss = flit; /* point to "\flit(" */
3134: while (*lp++ = *ss++) ; /* copy it */
3135: lp--; /* back up over null */
3136: while (*s) { /* go thru rest of text */
3137: ss = flit; /* point back to start of "\flit(" */
3138: if (*s == '{') bc++; /* count brackets */
3139: if (*s == '(') pp++; /* and parens */
3140: if (*s == ')') pp--;
3141: if (*s == '}') { /* Closing brace. */
3142: if (--bc == 0) { /* Final one? */
3143: *lp++ = ')'; /* Add closing paren for "\flit()" */
3144: *lp++ = *s++;
3145: break;
3146: }
3147: }
3148: if (*s == ',' && pp == 0) { /* comma not inside of parens */
3149: *lp++ = ')'; /* closing ) of \flit( */
3150: *lp++ = ','; /* insert the comma */
3151: while (*lp++ = *ss++) ; /* start new "\flit(" */
3152: lp--; /* back up over null */
3153: s++; /* skip over comma in source string */
3154: while (*s++ == SP); /* eat leading spaces again. */
3155: s--; /* back up over nonspace */
3156: continue;
3157: }
3158: *lp++ = *s++; /* Copy anything but comma here. */
3159: }
3160: *lp = NUL;
3161: } else { /* No brackets around, */
3162: while (*lp++ = *s++) ; /* just copy. */
3163: lp--;
3164: }
3165: *src = s;
3166: *dest = lp;
3167: if (bc) return(-1);
3168: else return(0);
3169: }
3170: #endif /* NOSPL */
3171:
3172: int
3173: docd() { /* Do the CD command */
3174: int x;
3175: char *s;
3176:
3177: #ifdef AMIGA
3178: if ((x = cmtxt("Name of local directory, or carriage return","",&s,
3179: xxstring)) < 0)
3180: return(x);
3181: /* if no name, just print directory name */
3182: if (*s) {
3183: if (chdir(s)) {
3184: cwdf = success = 0;
3185: perror(s);
3186: }
3187: success = cwdf = 1;
3188: }
3189: if (getcwd(line, LINBUFSIZ) == NULL)
3190: printf("Current directory name not available.\n");
3191: else
3192: if (pflag &&
3193: #ifndef NOSPL
3194: cmdlvl == 0
3195: #else
3196: tlevel < 0
3197: #endif /* NOSPL */
3198: ) printf("%s\n", line);
3199: #else
3200: if ((x = cmdir("Name of local directory, or carriage return",homdir,&s,
3201: xxstring)) < 0 )
3202: return(x);
3203: if (x == 2) {
3204: printf("?Wildcards not allowed in directory name\n");
3205: return(-9);
3206: }
3207: #ifdef OS2
3208: if ( s!=NUL ) {
3209: if ((int)strlen(s)>=2 && s[1]==':') { /* Disk specifier */
3210: if (zchdsk(*s)) { /* Change disk successful */
3211: if ( (int)strlen(s)>=3 & ( s[2]==CMDQ || isalnum(s[2]) ) ) {
3212: if (chdir(s)) perror(s);
3213: }
3214: } else {
3215: cwdf = success = 0;
3216: perror(s);
3217: }
3218: } else if (chdir(s)) {
3219: cwdf = success = 0;
3220: perror(s);
3221: }
3222: }
3223: printf("%s\n", zgtdir());
3224: success = cwdf = 1;
3225: #else /* Not OS2 */
3226: if (! zchdir(s)) {
3227: cwdf = 0;
3228: perror(s);
3229: } else cwdf = 1;
3230: #ifndef MAC
3231: zsyscmd(PWDCMD); /* assume this works... */
3232: #endif /* MAC */
3233: #endif /* OS2 */
3234: #endif /* AMIGA */
3235: return(cwdf);
3236: }
3237:
3238: VOID
3239: fixcmd() { /* Fix command parser after interruption */
3240: dostop(); /* Back to top level (also calls conint()). */
3241: bgchk(); /* Check background status */
3242: if (*psave) { /* If old prompt saved, */
3243: cmsetp(psave); /* restore it. */
3244: *psave = NUL;
3245: }
3246: success = 0; /* Tell parser last command failed */
3247: }
3248:
3249: VOID
3250: prtopt(s) char *s; { /* Print an option */
3251: static int x = 0; /* (used by SHOW VER) */
3252: int y; /* Does word wrap. */
3253: if (!s) { x = 0; return; } /* Call with null pointer to */
3254: y = (int)strlen(s); /* reset horizontal position. */
3255: x += y;
3256: if (x > 79) {
3257: printf("\n%s",s);
3258: x = y;
3259: } else printf("%s",s);
3260: }
3261:
3262: #endif /* NOICP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.