|
|
1.1 root 1: #ifndef NOICP
2:
3: /* C K U U S 4 -- "User Interface" for Unix Kermit, part 4 */
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 this
11: software as long as it is not sold for profit. This copyright notice must be
12: retained. This software may not be included in commercial products without
13: written permission of Columbia University.
14: */
15:
16: /*
17: File ckuus4.c -- Functions moved from other ckuus*.c modules to even
18: out their sizes.
19: */
20: #include "ckcdeb.h"
21: #include "ckcasc.h"
22: #include "ckcker.h"
23: #include "ckuusr.h"
24: #include "ckuver.h"
25: #include "ckcnet.h" /* Network symbols */
26:
27: #ifndef NOCSETS /* Character sets */
28: #include "ckcxla.h"
29: #endif /* NOCSETS */
30:
31: #ifndef AMIGA
32: #ifndef MAC
33: #include <signal.h>
34: #include <setjmp.h>
35: #endif /* MAC */
36: #endif /* AMIGA */
37:
38: #ifdef SUNX25
39: extern int revcall, closgr, cudata, npadx3;
40: int x25ver;
41: extern char udata[MAXCUDATA];
42: extern CHAR padparms[MAXPADPARMS+1];
43: extern struct keytab padx3tab[];
44: #endif /* SUNX25 */
45:
46: #ifdef NETCONN
47: extern char ipaddr[];
48: #ifdef TNCODE
49: extern int tn_duplex, tn_nlm;
50: extern char *tn_term;
51: #endif /* TNCODE */
52: #endif /* NETCONN */
53:
54: #ifndef NOSPL
55: /* This needs to be internationalized... */
56: static
57: char *months[] = {
58: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
59: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
60: };
61:
62: static
63: char *wkdays[] = {
64: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
65: };
66: #endif /* NOSPL */
67:
68: #ifdef UNIX
69: extern int ttyfd;
70: #endif /* UNIX */
71: #ifdef OS2
72: extern int ttyfd;
73: #endif /* OS2 */
74:
75: _PROTOTYP( static VOID shods, (char *) );
76:
77: extern struct keytab colxtab[];
78:
79: extern CHAR
80: eol, mypadc, mystch, padch, seol, stchr;
81:
82: extern char
83: kermrc[], ttname[],
84: *ckxsys, *versio, **xargv, *zinptr;
85:
86: extern int
87: atcapr, autopar, bctr, bctu, bgset, bigrbsiz, bigsbsiz, binary, carrier,
88: cdtimo, cmask, crunched, delay, duplex, ebq, ebqflg, escape, flow, fmask,
89: fncact, fncnv, incase, inecho, keep, local, lscapr, lscapu,
90: maxrps, maxsps, maxtry, mdmspd, mdmtyp, mypadn, ncolx,
91: nettype, network, nmac, noinit, npad, parity, pktlog, pkttim, rcflag,
92: retrans, rpackets, rptflg, rptq, rtimo, seslog, sessft, sosi, spackets,
93: spsiz, spsizf, spsizr, srvtim, stayflg, success, timeouts, tralog,
94: tsecs, ttnproto, turn, turnch, urpsiz, wmax, wslotn, wslotr, xargc, xargs,
95: zincnt, fdispla, tlevel, xitsta, spmax, insilence, cmdmsk, timint, timef;
96:
97: #ifdef VMS
98: extern int frecl;
99: #endif /* VMS */
100:
101: extern long
102: ffc, filcnt, rptn, speed, tfc, tlci, tlco, vernum;
103:
104: #ifndef NOSPL
105: extern char fspec[], myhost[];
106: #endif /* NOSPL */
107:
108: extern char *tfnam[]; /* Command file names */
109:
110: #ifdef DCMDBUF
111: extern struct cmdptr *cmdstk;
112: extern char *line;
113: #else
114: extern struct cmdptr cmdstk[];
115: extern char line[];
116: #endif /* DCMDBUF */
117:
118: extern char pktfil[], /* Packet log file name */
119: #ifdef DEBUG
120: debfil[], /* Debug log file name */
121: #endif /* DEBUG */
122: #ifdef TLOG
123: trafil[], /* Transaction log file name */
124: #endif /* TLOG */
125: sesfil[]; /* Session log file name */
126:
127: #ifndef NOXMIT /* TRANSMIT command variables */
128: extern char xmitbuf[];
129: extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw;
130: #endif /* NOXMIT */
131:
132: #ifndef NOSPL
133: /* Script programming language items */
134: extern char **a_ptr[]; /* Arrays */
135: extern int a_dim[];
136: extern char inpbuf[], inchar[]; /* Buffers for INPUT and REINPUT */
137: extern char *inpbp; /* And pointer to same */
138: static char *inpbps = inpbuf; /* And another */
139: extern int incount; /* INPUT character count */
140: extern int maclvl; /* Macro invocation level */
141: extern struct mtab *mactab; /* Macro table */
142: extern char *mrval[];
143: extern int macargc[], cmdlvl;
144: extern char *m_arg[MACLEVEL][10]; /* You have to put in the dimensions */
145: extern char *g_var[GVARS]; /* for external 2-dimensional arrays. */
146: #ifdef DCMDBUF
147: extern int *count;
148: #else
149: extern int count[];
150: #endif /* DCMDBUF */
151: #endif /* NOSPL */
152:
153: #ifdef UNIX
154: extern int haslock; /* For UUCP locks */
155: extern char flfnam[];
156: extern int maxnam, maxpath; /* Longest name, path length */
157: #endif /* UNIX */
158:
159: #ifndef NODIAL
160: /* DIAL-related variables */
161: extern int nmdm, dialhng, dialtmo, dialksp, dialdpy, dialmnp, dialmhu;
162: extern char *dialnum, *dialdir, *dialnpr;
163: extern struct keytab mdmtab[];
164: #endif /* NODIAL */
165:
166: #ifndef NOCSETS
167: /* Translation stuff */
168: extern int fcharset, tcharset, tslevel, language, nlng, tcsr, tcsl;
169: extern struct keytab lngtab[];
170: extern struct csinfo fcsinfo[], tcsinfo[];
171: extern struct langinfo langs[];
172: #ifdef CK_ANSIC
173: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
174: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
175: #else
176: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
177: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
178: #endif /* CK_ANSIC */
179: #endif /* NOCSETS */
180:
181: #ifndef NOSPL
182: /* Built-in variable names, maximum length VNAML (20 characters) */
183:
184: struct keytab vartab[] = {
185: "argc", VN_ARGC, 0,
186: "args", VN_ARGS, 0,
187: "cmdfile", VN_CMDF, 0,
188: "cmdlevel", VN_CMDL, 0,
189: "cmdsource", VN_CMDS, 0,
190: "count", VN_COUN, 0,
191: "cpu", VN_CPU, 0,
192: "date", VN_DATE, 0,
193: "day", VN_DAY, 0, /* Edit 181 */
194: "directory", VN_DIRE, 0,
195: "exitstatus",VN_EXIT, 0,
196: "filespec", VN_FILE, 0,
197: "fsize", VN_FFC, 0,
198: "home", VN_HOME, 0,
199: "host", VN_HOST, 0,
200: "input", VN_IBUF, 0,
201: "inchar", VN_ICHR, 0,
202: "incount", VN_ICNT, 0,
203: "line", VN_LINE, 0,
204: "local", VN_LCL, 0,
205: "macro", VN_MAC, 0,
206: "ndate", VN_NDAT, 0,
207: "nday", VN_NDAY, 0,
208: "ntime", VN_NTIM, 0,
209: "platform", VN_SYSV, 0,
210: "program", VN_PROG, 0,
211: "return", VN_RET, 0,
212: "speed", VN_SPEE, 0,
213: "status", VN_SUCC, 0,
214: "system", VN_SYST, 0,
215: "tfsize", VN_TFC, 0,
216: "time", VN_TIME, 0,
217: #ifdef UNIX
218: "ttyfd", VN_TTYF, 0,
219: #endif /* UNIX */
220: #ifdef OS2
221: "ttyfd", VN_TTYF, 0,
222: #endif /* OS2 */
223: "version", VN_VERS, 0
224: };
225: int nvars = (sizeof(vartab) / sizeof(struct keytab));
226: #endif /* NOSPL */
227:
228: #ifndef NOSPL
229: struct keytab fnctab[] = { /* Function names */
230: "character", FN_CHR, 0, /* Character from code */
231: "code", FN_COD, 0, /* Code from character */
232: "contents", FN_CON, 0, /* Definition (contents) of variable */
233: "definition", FN_DEF, 0, /* Return definition of given macro */
234: "evaluate", FN_EVA, 0, /* Evaluate given arith expression */
235: "execute", FN_EXE, 0, /* Execute given macro */
236: "files", FN_FC, 0, /* File count */
237: "index", FN_IND, 0, /* Index (string search) */
238: "length", FN_LEN, 0, /* Return length of argument */
239: "literal", FN_LIT, 0, /* Return argument literally */
240: "lower", FN_LOW, 0, /* Return lowercased argument */
241: "lpad", FN_LPA, 0, /* Return left-padded argument */
242: "maximum", FN_MAX, 0, /* Return maximum of two arguments */
243: "minimim", FN_MIN, 0, /* Return minimum of two arguments */
244: #ifdef COMMENT
245: /* not needed because \feval() has it */
246: "modulus", FN_MOD, 0, /* Return modulus of two arguments */
247: #endif /* COMMENT */
248: "nextfile", FN_FIL, 0, /* Next file in list */
249: "repeat", FN_REP, 0, /* Repeat argument given # of times */
250: #ifndef NOFRILLS
251: "reverse", FN_REV, 0, /* Reverse the argument string */
252: #endif /* NOFRILLS */
253: "right", FN_RIG, 0, /* Rightmost n characters */
254: "rpad", FN_RPA, 0, /* Right-pad the argument */
255: "substring", FN_SUB, 0, /* Extract substring from argument */
256: "upper", FN_UPP, 0 /* Return uppercased argument */
257: };
258: int nfuncs = (sizeof(fnctab) / sizeof(struct keytab));
259: #endif /* NOSPL */
260:
261: #ifndef NOSPL /* Buffer for expansion of */
262: #define VVBUFL 60 /* built-in variables. */
263: char vvbuf[VVBUFL];
264: #endif /* NOSPL */
265:
266: struct keytab disptb[] = { /* Log file disposition */
267: "append", 1, 0,
268: "new", 0, 0
269: };
270:
271: /* P R E S C A N -- Quick look thru command-line args for init file name */
272: /* Also for -d (debug), -z (force foreground), -S (stay) */
273:
274: VOID
275: prescan() {
276: int yargc; char **yargv;
277: char x;
278:
279: yargc = xargc;
280: yargv = xargv;
281: strcpy(kermrc,KERMRC); /* Default init file name */
282: #ifndef NOCMDL
283: while (--yargc > 0) { /* Look for -y on command line */
284: yargv++;
285: if (**yargv == '-') { /* Option starting with dash */
286: x = *(*yargv+1); /* Get option letter */
287: if (x == 'Y') { /* Is it Y (= no init file?) */
288: noinit = 1;
289: continue;
290: } else if (x == 'y') { /* Is it y? */
291: yargv++, yargc--; /* Yes, count and check argument */
292: if (yargc < 1) fatal("missing name in -y");
293: strcpy(kermrc,*yargv); /* Replace init file name */
294: rcflag = 1; /* Flag that this has been done */
295: continue;
296: } else if (x == 'd') { /* Do this early as possible! */
297: debopn("debug.log",0);
298: continue;
299: } else if (x == 'z') { /* = SET BACKGROUND OFF */
300: bgset = 0;
301: continue;
302: } else if (x == 'S') {
303: stayflg = 1;
304: continue;
305: }
306: }
307: }
308: #endif /* NOCMDL */
309: }
310:
311: static int tr_int; /* Flag if TRANSMIT interrupted */
312:
313: #ifndef MAC
314: SIGTYP
315: trtrap(foo) int foo; { /* TRANSMIT interrupt trap */
316: #ifdef __EMX__
317: signal(SIGINT, SIG_ACK);
318: #endif
319: tr_int = 1; /* (Need arg for ANSI C) */
320: SIGRETURN;
321: }
322: #endif /* MAC */
323: /* G E T T C S -- Get Transfer (Intermediate) Character Set */
324:
325: /*
326: Given two file character sets, this routine picks out the appropriate
327: "transfer" character set to use for translating between them.
328: The transfer character set number is returned.
329:
330: Translation between two file character sets is done, for example,
331: by the CONNECT, TRANSMIT, and TRANSLATE commands.
332:
333: Translation between Kanji character sets is not yet supported.
334: */
335: int
336: gettcs(cs1,cs2) int cs1, cs2; {
337: #ifdef NOCSETS /* No character-set support */
338: return(0); /* so no translation */
339: #else
340: int tcs = TC_TRANSP;
341: #ifdef KANJI
342: /* Kanji not supported yet */
343: if (fcsinfo[cs1].alphabet == AL_JAPAN ||
344: fcsinfo[cs2].alphabet == AL_JAPAN )
345: tcs = TC_TRANSP;
346: else
347: #endif /* KANJI */
348: #ifdef CYRILLIC
349: /*
350: I can't remember why we don't test both sets here, but I think there
351: must have been a reason...
352: */
353: if (fcsinfo[cs2].alphabet == AL_CYRIL)
354: tcs = TC_CYRILL;
355: else
356: #endif /* CYRILLIC */
357: #ifdef LATIN2
358: if (cs1 == FC_2LATIN || cs1 == FC_2LATIN ||
359: cs1 == FC_CP852 || cs1 == FC_CP852 )
360: tcs = TC_2LATIN;
361: else
362: #endif /* LATIN2 */
363: tcs = TC_1LATIN;
364: return(tcs);
365: #endif /* NOCSETS */
366: }
367:
368: #ifndef NOXMIT
369: /* T R A N S M I T -- Raw upload */
370:
371: /* Obey current line, duplex, parity, flow, text/binary settings. */
372: /* Returns 0 upon apparent success, 1 on obvious failure. */
373:
374: /***
375: Things to add:
376: . Make both text and binary mode obey set file bytesize.
377: . Maybe allow user to specify terminators other than CR?
378: . Maybe allow user to specify prompts other than single characters?
379: ***/
380:
381: /* T R A N S M I T -- Raw upload */
382:
383: /* s is the filename, t is the turnaround (prompt) character */
384:
385: /*
386: Maximum number of characters to buffer.
387: Must be less than LINBUFSIZ
388: */
389: #define XMBUFS 120
390:
391: int
392: #ifdef CK_ANSIC
393: transmit(char * s, char t)
394: #else
395: transmit(s,t) char *s; char t;
396: #endif /* CK_ANSIC */
397: /* transmit */ {
398: #ifdef MAC
399: extern char sstate;
400: int count = 100;
401: #else
402: SIGTYP (* oldsig)(); /* For saving old interrupt trap. */
403: #endif /* MAC */
404: long zz;
405: int z = 1; /* Return code. 0=fail, 1=succeed. */
406: int x, c, i; /* Workers... */
407: int myflow;
408: CHAR csave;
409: char *p;
410:
411: #ifndef NOCSETS
412: int tcs = TC_TRANSP; /* Intermediate (xfer) char set */
413: int langsv = L_USASCII; /* Save current language */
414:
415: _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
416: _PROTOTYP ( CHAR (*rxo), (CHAR) ) = NULL;
417: _PROTOTYP ( CHAR (*sxi), (CHAR) ) = NULL;
418: _PROTOTYP ( CHAR (*rxi), (CHAR) ) = NULL;
419: #endif /* NOCSETS */
420:
421: if (zopeni(ZIFILE,s) == 0) { /* Open the file to be transmitted */
422: printf("?Can't open file %s\n",s);
423: return(0);
424: }
425: x = -1; /* Open the communication line */
426: if (ttopen(ttname,&x,mdmtyp,cdtimo) < 0) { /* (no harm if already open) */
427: printf("Can't open device %s\n",ttname);
428: return(0);
429: }
430: zz = x ? speed : -1L;
431: if (binary) { /* Binary file transmission */
432: myflow = (flow == FLO_XONX) ? FLO_NONE : flow;
433: if (ttvt(zz,myflow) < 0) { /* So no Xon/Xoff! */
434: printf("Can't condition line\n");
435: return(0);
436: }
437: } else {
438: if (ttpkt(zz,flow,parity) < 0) { /* Put the line in "packet mode" */
439: printf("Can't condition line\n"); /* so Xon/Xoff will work, etc. */
440: return(0);
441: }
442: }
443:
444: #ifndef NOCSETS
445: tcs = gettcs(tcsr,tcsl); /* Get intermediate set. */
446:
447: /* Set up character set translations */
448: if (binary == 0) {
449:
450: if (tcsr == tcsl || binary) { /* Remote and local sets the same? */
451: sxo = rxo = NULL; /* Or file type is not text? */
452: sxi = rxi = NULL;
453: } else { /* Otherwise, set up */
454: sxo = xls[tcs][tcsl]; /* translation function */
455: rxo = xlr[tcs][tcsr]; /* pointers for output functions */
456: sxi = xls[tcs][tcsr]; /* and for input functions. */
457: rxi = xlr[tcs][tcsl];
458: }
459: /*
460: This is to prevent use of zmstuff() and zdstuff() by translation functions.
461: They only work with disk i/o, not with communication i/o. Luckily Russian
462: translation functions don't do any stuffing...
463: */
464: langsv = language;
465: language = L_USASCII;
466: }
467: #endif /* NOCSETS */
468:
469: i = 0; /* Beginning of buffer. */
470: #ifndef MAC
471: #ifndef AMIGA
472: oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
473: #endif /* AMIGA */
474: #endif /* MAC */
475: tr_int = 0; /* Have not been interrupted (yet). */
476: z = 1; /* Return code presumed good. */
477: #ifdef VMS
478: conres();
479: #endif /* VMS */
480:
481: c = 0; /* Initial condition */
482: while (c > -1) { /* Loop for all characters in file */
483: #ifdef MAC
484: /*
485: * It is expensive to run the miniparser so don't do it for
486: * every character.
487: */
488: if (--count < 0) {
489: count = 100;
490: miniparser(1);
491: if (sstate == 'a') {
492: sstate = '\0';
493: z = 0;
494: break;
495: }
496: }
497: #else /* Not MAC */
498: if (tr_int) { /* Interrupted? */
499: printf("^C...\n"); /* Print message */
500: z = 0;
501: break;
502: }
503: #endif /* MAC */
504: c = zminchar(); /* Get a file character */
505: debug(F101,"transmit char","",c);
506: if (c == -1) /* Test for end-of-file */
507: break;
508: c &= fmask; /* Apply SET FILE BYTESIZE mask */
509:
510: if (binary) { /* If binary file, */
511: if (ttoc(dopar((char) c)) < 0) { /* else just send the char */
512: printf("?Can't transmit character\n");
513: z = 0;
514: break;
515: }
516: if (xmitw) msleep(xmitw); /* Pause if requested */
517: if (xmitx) { /* SET TRANSMIT ECHO ON? */
518: if (duplex) { /* Yes, for half duplex */
519: conoc((char)(c & cmdmsk)); /* echo locally. */
520: } else { /* For full duplex, */
521: int i, n; /* display whatever is there. */
522: n = ttchk(); /* How many chars are waiting? */
523: for (i = 0; i < n; i++) { /* Read and echo that many. */
524: x = ttinc(1); /* Timed read just in case. */
525: if (x > -1) { /* If no timeout */
526: if (parity) x &= 0x7f;
527: conoc((char)(x & cmdmsk)); /* display the char, */
528: } else break; /* otherwise stop reading. */
529: }
530: }
531: } else ttflui(); /* Not echoing, just flush input. */
532:
533: } else { /* Text mode, line at a time. */
534:
535: if (c == '\n') { /* Got a line */
536: if (i == 0) { /* Blank line? */
537: if (xmitf) /* Yes, insert fill if asked. */
538: line[i++] = dopar((char) xmitf);
539: }
540: if (i == 0 || line[i-1] != dopar(CR))
541: line[i++] = dopar(CR); /* Terminate it with CR */
542: if (
543: xmitl
544: #ifdef TNCODE
545: || (network && ttnproto == NP_TELNET && tn_nlm)
546: #endif /* TNCODE */
547: )
548: line[i++] = dopar(LF); /* Include LF if asked */
549:
550: } else if (c != -1) { /* Not a newline, regular character */
551: csave = c; /* Remember untranslated version */
552: #ifndef NOCSETS
553: /* Translate character sets */
554: if (sxo) c = (*sxo)((CHAR)c); /* From local to intermediate */
555: if (rxo) c = (*rxo)((CHAR)c); /* From intermediate to remote */
556: #endif /* NOCSETS */
557:
558: if (xmits && parity && (c & 0200)) { /* If shifting */
559: line[i++] = dopar(SO); /* needs to be done, */
560: line[i++] = dopar((char)c); /* do it here, */
561: line[i++] = dopar(SI); /* crudely. */
562: } else {
563: line[i++] = dopar((char)c); /* else, just char itself */
564: }
565: }
566:
567: /* Send characters if buffer full, or at end of line, or at end of file */
568:
569: if (i >= XMBUFS || c == '\n' || c == -1) {
570: p = line;
571: line[i] = '\0';
572: debug(F111,"transmit buf",p,i);
573: if (ttol((CHAR *)p,i) < 0) { /* try to send it. */
574: printf("Can't send buffer\n");
575: z = 0;
576: break;
577: }
578: i = 0; /* Reset buffer pointer. */
579:
580: /* Worry about echoing here. "xmitx" is SET TRANSMIT ECHO flag. */
581:
582: if (duplex && xmitx) { /* If local echo, echo it */
583: if (parity || cmdmsk == 0x7f) { /* Strip off high bits */
584: char *s = p; /* if necessary */
585: while (*s) {
586: *s &= 0x7f;
587: s++;
588: }
589: conoll(p);
590: }
591: }
592: if (xmitw) /* Give receiver time to digest. */
593: msleep(xmitw);
594: if (t != 0 && c == '\n') { /* Want a turnaround character */
595: x = 0; /* Wait for it */
596: while (x != t) {
597: if ((x = ttinc(1)) < 0) break;
598: if (xmitx && !duplex) { /* Echo any echoes */
599: if (parity) x &= 0x7f;
600: #ifndef NOCSETS
601: if (sxi) x = (*sxi)((CHAR)x); /* But translate */
602: if (rxi) x = (*rxi)((CHAR)x); /* them first... */
603: #endif /* NOCSETS */
604: conoc((char) x);
605: }
606: }
607: } else if (xmitx && !duplex) { /* Otherwise, */
608: while (ttchk() > 0) { /* echo for as long as */
609: if ((x = ttinc(0)) < 0) break; /* anything is there. */
610: if (parity) x &= 0x7f;
611: #ifndef NOCSETS
612: if (sxi) x = (*sxi)((CHAR)x); /* Translate first */
613: if (rxi) x = (*rxi)((CHAR)x);
614: #endif /* NOCSETS */
615: conoc((char)x);
616: }
617: } else ttflui(); /* Otherwise just flush input buffer */
618: } /* End of buffer-dumping block */
619: } /* End of text mode */
620: } /* End of character-reading loop */
621:
622: if (*xmitbuf) { /* Anything to send at EOF? */
623: p = xmitbuf; /* Yes, point to string. */
624: while (*p) /* Send it. */
625: ttoc(dopar(*p++)); /* Don't worry about echo here. */
626: }
627:
628: #ifndef AMIGA
629: #ifndef MAC
630: signal(SIGINT,oldsig); /* Put old signal action back. */
631: #endif /* MAC */
632: #endif /* AMIGA */
633: #ifdef VMS
634: concb(escape); /* Put terminal back, */
635: #endif /* VMS */
636: zclose(ZIFILE); /* Close file, */
637: #ifndef NOCSETS
638: language = langsv; /* restore language, */
639: #endif /* NOCSETS */
640: return(z); /* and return successfully. */
641: }
642: #endif /* NOXMIT */
643:
644: #ifdef MAC
645: /*
646: This code is not used any more, except on the Macintosh. Instead we call
647: system to do the typing. Revive this code if your system can't be called
648: to do this.
649: */
650:
651: /* D O T Y P E -- Type a file */
652:
653: int
654: dotype(s) char *s; {
655:
656: #ifdef MAC
657: extern char sstate;
658: int count = 100;
659: #else
660: SIGTYP (* oldsig)(); /* For saving old interrupt trap. */
661: #endif /* MAC */
662: int z; /* Return code. */
663: int c; /* Worker. */
664:
665: if (zopeni(ZIFILE,s) == 0) { /* Open the file to be typed */
666: printf("?Can't open %s\n",s);
667: return(0);
668: }
669: #ifndef AMIGA
670: #ifndef MAC
671: oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
672: #endif /* MAC */
673: #endif /* AMIGA */
674:
675: tr_int = 0; /* Have not been interrupted (yet). */
676: z = 1; /* Return code presumed good. */
677:
678: #ifdef VMS
679: conoc(CR); /* On VMS, display blank line first */
680: conoc(LF);
681: conres(); /* So Ctrl-C/Y will work */
682: #endif /* VMS */
683: while ((c = zminchar()) != -1) { /* Loop for all characters in file */
684: #ifdef MAC
685: /*
686: * It is expensive to run the miniparser so don't do it for
687: * every character.
688: */
689: if (--count < 0) {
690: count = 100;
691: miniparser(1);
692: if (sstate == 'a') {
693: sstate = '\0';
694: z = 0;
695: break;
696: }
697: }
698: putchar(c);
699: #else /* Not MAC */
700: if (tr_int) { /* Interrupted? */
701: printf("^C...\n"); /* Print message */
702: z = 0;
703: break;
704: }
705: conoc(c); /* Echo character on screen */
706: #endif /* MAC */
707: }
708: #ifndef AMIGA
709: #ifndef MAC
710: signal(SIGINT,oldsig); /* put old signal action back. */
711: #endif /* MAC */
712: #endif /* AMIGA */
713:
714: tr_int = 0;
715: #ifdef VMS
716: concb(escape); /* Get back in command-parsing mode, */
717: #endif /* VMS */
718: zclose(ZIFILE); /* close file, */
719: return(z); /* and return successfully. */
720: }
721: #endif /* MAC */
722:
723: #ifndef NOCSETS
724:
725: _PROTOTYP( CHAR (*sxx), (CHAR) ); /* Local translation function */
726: _PROTOTYP( CHAR (*rxx), (CHAR) ); /* Local translation function */
727: _PROTOTYP( CHAR zl1as, (CHAR) ); /* Latin-1 to ascii */
728: _PROTOTYP( CHAR xl1as, (CHAR) ); /* ditto */
729:
730: /* X L A T E -- Translate a local file from one character set to another */
731:
732: /*
733: Translates input file (fin) from character set csin to character set csout
734: and puts the result in the output file (fout). The two character sets are
735: file character sets from fcstab.
736: */
737:
738: int
739: xlate(fin, fout, csin, csout) char *fin, *fout; int csin, csout; {
740:
741: #ifndef MAC
742: SIGTYP (* oldsig)(); /* For saving old interrupt trap. */
743: #endif /* MAC */
744: int filecode; /* Code for output file */
745:
746: int z = 1; /* Return code. */
747: int c, tcs; /* Workers */
748:
749: if (zopeni(ZIFILE,fin) == 0) { /* Open the file to be translated */
750: printf("?Can't open input file %s\n",fin);
751: return(0);
752: }
753: #ifdef MAC
754: /*
755: If user specified no output file, it goes to the screen. For the Mac,
756: this must be done a special way (result goes to a new window); the Mac
757: doesn't have a "controlling terminal" device name.
758: */
759: filecode = !strcmp(fout,CTTNAM) ? ZCTERM : ZOFILE;
760: #else
761: filecode = ZOFILE;
762: #endif /* MAC */
763:
764: if (zopeno(filecode,fout,NULL,NULL) == 0) { /* And the output file */
765: printf("?Can't open output file %s\n",fout);
766: return(0);
767: }
768: #ifndef AMIGA
769: #ifndef MAC
770: oldsig = signal(SIGINT, trtrap); /* Save current interrupt trap. */
771: #endif /* MAC */
772: #endif /* AMIGA */
773:
774: tr_int = 0; /* Have not been interrupted (yet). */
775: z = 1; /* Return code presumed good. */
776:
777: tcs = gettcs(csin,csout); /* Get intermediate set. */
778:
779: printf("%s (%s) => %s (%s)\n", /* Say what we're doing. */
780: fin, fcsinfo[csin].name,
781: fout,fcsinfo[csout].name
782: );
783: printf("via %s", tcsinfo[tcs].name);
784: if (language)
785: printf(", language: %s\n",langs[language].description);
786: printf("\n\n");
787:
788: if (csin == csout) { /* Input and output sets the same? */
789: sxx = rxx = NULL; /* If so, no translation. */
790: } else { /* Otherwise, set up */
791: sxx = xls[tcs][csin]; /* translation function */
792: rxx = xlr[tcs][csout]; /* pointers. */
793: if (rxx == zl1as) rxx = xl1as;
794: }
795: while ((c = zminchar()) != -1) { /* Loop for all characters in file */
796: if (tr_int) { /* Interrupted? */
797: printf("^C...\n"); /* Print message */
798: z = 0;
799: break;
800: }
801: if (sxx) c = (*sxx)((CHAR)c); /* From fcs1 to tcs */
802: if (rxx) c = (*rxx)((CHAR)c); /* from tcs to fcs2 */
803:
804: if (zchout(ZOFILE,(char)c) < 0) { /* Output the translated character */
805: printf("File output error\n");
806: z = 0;
807: break;
808: }
809: }
810: #ifndef AMIGA
811: #ifndef MAC
812: signal(SIGINT,oldsig); /* put old signal action back. */
813: #endif /* MAC */
814: #endif /* AMIGA */
815:
816: tr_int = 0;
817: zclose(ZIFILE); /* close files, */
818: zclose(ZOFILE);
819: return(z); /* and return successfully. */
820: }
821: #endif /* NOCSETS */
822:
823: /* D O L O G -- Do the log command */
824:
825: int
826: dolog(x) int x; {
827: int y, disp; char *s;
828:
829: switch (x) {
830:
831: #ifdef DEBUG
832: case LOGD:
833: y = cmofi("Name of debugging log file","debug.log",&s,xxstring);
834: break;
835: #endif /* DEBUG */
836:
837: case LOGP:
838: y = cmofi("Name of packet log file","packet.log",&s,xxstring);
839: break;
840:
841: case LOGS:
842: y = cmofi("Name of session log file","session.log",&s,xxstring);
843: break;
844:
845: #ifdef TLOG
846: case LOGT:
847: y = cmofi("Name of transaction log file","transact.log",&s,
848: xxstring);
849: break;
850: #endif /* TLOG */
851:
852: default:
853: printf("\n?Unknown log designator - %d\n",x);
854: return(-2);
855: }
856: if (y < 0) return(y);
857:
858: strcpy(line,s);
859: s = line;
860: if ((y = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
861: return(y);
862: disp = y;
863: if ((y = cmcfm()) < 0) return(y);
864:
865: switch (x) {
866:
867: #ifdef DEBUG
868: case LOGD:
869: return(deblog = debopn(s,disp));
870: #endif /* DEBUG */
871:
872: case LOGP:
873: return(pktlog = pktopn(s,disp));
874:
875: case LOGS:
876: return(seslog = sesopn(s,disp));
877:
878: #ifdef TLOG
879: case LOGT:
880: return(tralog = traopn(s,disp));
881: #endif /* TLOG */
882:
883: default:
884: return(-2);
885: }
886: }
887:
888: int
889: pktopn(s,disp) char *s; int disp; {
890: extern char pktfil[];
891: static struct filinfo xx;
892: int y;
893:
894: zclose(ZPFILE);
895: if(s[0] == '\0') return(0);
896: if (disp) {
897: xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
898: xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
899: xx.lblopts = 0;
900: y = zopeno(ZPFILE,s,NULL,&xx);
901: } else y = zopeno(ZPFILE,s,NULL,NULL);
902: if (y > 0)
903: strcpy(pktfil,s);
904: else
905: *pktfil = '\0';
906: return(y);
907: }
908:
909: int
910: traopn(s,disp) char *s; int disp; {
911: #ifdef TLOG
912: extern char trafil[];
913: static struct filinfo xx;
914: int y;
915:
916: zclose(ZTFILE);
917: if(s[0] == '\0') return(0);
918: if (disp) {
919: xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
920: xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
921: xx.lblopts = 0;
922: y = zopeno(ZTFILE,s,NULL,&xx);
923: } else y = zopeno(ZTFILE,s,NULL,NULL);
924: if (y > 0) {
925: strcpy(trafil,s);
926: tlog(F110,"Transaction Log:",versio,0L);
927: #ifndef MAC
928: tlog(F100,ckxsys,"",0L);
929: #endif /* MAC */
930: ztime(&s);
931: tlog(F100,s,"",0L);
932: } else *trafil = '\0';
933: return(y);
934: #else
935: return(0);
936: #endif
937: }
938:
939: int
940: sesopn(s,disp) char * s; int disp; {
941: extern char sesfil[];
942: static struct filinfo xx;
943: int y;
944:
945: zclose(ZSFILE);
946: if(s[0] == '\0') return(0);
947: if (disp) {
948: xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
949: xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
950: xx.lblopts = 0;
951: y = zopeno(ZSFILE,s,NULL,&xx);
952: } else y = zopeno(ZSFILE,s,NULL,NULL);
953: if (y > 0)
954: strcpy(sesfil,s);
955: else
956: *sesfil = '\0';
957: return(y);
958: }
959:
960: int
961: debopn(s,disp) char *s; int disp; {
962: #ifdef DEBUG
963: char *tp;
964: static struct filinfo xx;
965:
966: zclose(ZDFILE);
967:
968: if (disp) {
969: xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
970: xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = '\0';
971: xx.lblopts = 0;
972: deblog = zopeno(ZDFILE,s,NULL,&xx);
973: } else deblog = zopeno(ZDFILE,s,NULL,NULL);
974: if (deblog > 0) {
975: strcpy(debfil,s);
976: debug(F110,"Debug Log ",versio,0);
977: #ifndef MAC
978: debug(F100,ckxsys,"",0);
979: #endif /* MAC */
980: ztime(&tp);
981: debug(F100,tp,"",0);
982: } else *debfil = '\0';
983: return(deblog);
984: #else
985: return(0);
986: #endif
987: }
988:
989: #ifndef NOSHOW
990:
991: /* S H O P A R -- Show Parameters */
992:
993: #ifdef SUNX25
994: VOID
995: shox25() {
996: if (nettype == NET_SX25) {
997: printf("SunLink X.25 V%d.%d",x25ver / 10,x25ver % 10);
998: if (ttnproto == NP_X3) printf(", PAD X.3, X.28, X.29 protocol,");
999: printf("\n Reverse charge call %s",
1000: revcall ? "selected" : "not selected");
1001: printf (", Closed user group ");
1002: if (closgr > -1)
1003: printf ("%d",closgr);
1004: else
1005: printf ("not selected");
1006: printf (",");
1007: printf("\n Call user data %s.\n", cudata ? udata : "not selected");
1008: }
1009: }
1010: #endif /* SUNX25 */
1011:
1012: VOID
1013: shoparc() {
1014: int i; char *s;
1015: long zz;
1016:
1017: puts("Communications Parameters:");
1018:
1019: if (network) {
1020: printf(" Host: %s",ttname);
1021: } else {
1022: printf(" Line: %s, speed: ",ttname);
1023: if ((zz = ttgspd()) < 0) {
1024: printf("unknown");
1025: } else {
1026: if (speed == 8880) printf("75/1200"); else printf("%ld",zz);
1027: }
1028: }
1029: printf(", mode: ");
1030: if (local) printf("local"); else printf("remote");
1031: if (network == 0) {
1032: #ifndef NODIAL
1033: for (i = 0; i < nmdm; i++) {
1034: if (mdmtab[i].kwval == mdmtyp) {
1035: printf(", modem: %s",mdmtab[i].kwd);
1036: break;
1037: }
1038: }
1039: #endif /* NODIAL */
1040: } else {
1041: if (nettype == NET_TCPA) printf(", TCP/IP");
1042: if (nettype == NET_TCPB) printf(", TCP/IP");
1043: if (nettype == NET_DEC) {
1044: if ( ttnproto == NP_LAT ) printf(", DECnet LAT");
1045: else if ( ttnproto == NP_CTERM ) printf(", DECnet CTERM");
1046: else printf(", DECnet");
1047: }
1048: if (nettype == NET_PIPE) printf(", Named Pipe");
1049: #ifdef SUNX25
1050: shox25();
1051: #endif /* SUNX25 */
1052: if (ttnproto == NP_TELNET) printf(", telnet protocol");
1053: }
1054: if (local) {
1055: i = parity ? 7 : 8;
1056: if (i == 8) i = (cmask == 0177) ? 7 : 8;
1057: printf("\n Terminal bits: %d, p",i);
1058: } else printf("\n P");
1059: printf("arity: %s",parnam((char)parity));
1060: printf(", duplex: ");
1061: if (duplex) printf("half, "); else printf("full, ");
1062: printf("flow: ");
1063: if (flow == FLO_KEEP) printf("keep");
1064: else if (flow == FLO_XONX) printf("xon/xoff");
1065: else if (flow == FLO_NONE) printf("none");
1066: else if (flow == FLO_DTRT) printf("dtr/cts");
1067: else if (flow == FLO_RTSC) printf("rts/cts");
1068: else if (flow == FLO_DTRC) printf("dtr/cd");
1069: else printf("%d",flow);
1070: printf(", handshake: ");
1071: if (turn) printf("%d\n",turnch); else printf("none\n");
1072: if (local && !network) { /* Lockfile & carrier stuff */
1073: if (carrier == CAR_OFF) s = "off";
1074: else if (carrier == CAR_ON) s = "on";
1075: else if (carrier == CAR_AUT) s = "auto";
1076: else s = "unknown";
1077: printf(" Carrier: %s", s);
1078: if (carrier == CAR_ON) {
1079: if (cdtimo) printf(", timeout: %d sec", cdtimo);
1080: else printf(", timeout: none");
1081: }
1082: #ifdef UNIX
1083: if (haslock && *flfnam) { /* Lockfiles only apply to UNIX... */
1084: printf(", lockfile: %s",flfnam);
1085: }
1086: #endif /* UNIX */
1087: printf("\n Escape character: %d (^%c)\n",escape,ctl(escape));
1088: }
1089: }
1090:
1091: #ifdef TNCODE
1092: static VOID
1093: shotel() {
1094: printf("SET TELNET parameters:\n echo: %s\n newline-mode: %s\n",
1095: tn_duplex ? "local" : "remote", tn_nlm ? "on" : "off");
1096: printf(" terminal-type: ");
1097: if (tn_term) printf("%s\n",tn_term);
1098: else {
1099: char *p;
1100: p = getenv("TERM");
1101: if (p)
1102: printf("none (%s will be used)\n",p);
1103: else printf("none\n");
1104: }
1105: }
1106: #endif /* TNCODE */
1107:
1108: VOID
1109: shonet() {
1110: #ifndef NETCONN
1111: printf("\nNo networks are supported in this version of C-Kermit\n");
1112: #else
1113: printf("\nSupported networks:\n");
1114:
1115: #ifdef VMS
1116:
1117: #ifdef MULTINET
1118: printf(" TGV MultiNet TCP/IP");
1119: #else
1120: #ifdef WINTCP
1121: printf(" WOLLONGONG WIN/TCP");
1122: #else
1123: #ifdef DEC_TCPIP
1124: printf(" DEC TCP/IP Services for (Open)VMS");
1125: #else
1126: printf(" None");
1127: #endif /* DEC_TCPIP */
1128: #endif /* WINTCP */
1129: #endif /* MULTINET */
1130: #ifdef TNCODE
1131: printf(", TELNET protocol\n\n");
1132: shotel();
1133: #endif /* TNCODE */
1134: printf("\n");
1135:
1136: #else /* Not VMS */
1137:
1138: #ifdef SUNX25
1139: printf(" SunLink X.25\n");
1140: #endif /* SUNX25 */
1141: #ifdef DECNET
1142: printf(" DECnet\n");
1143: #endif /* DECNET */
1144: #ifdef NPIPE
1145: printf(" LAN Manager Named Pipe\n");
1146: #endif /* DECNET */
1147: #ifdef TCPSOCKET
1148: printf(" TCP/IP");
1149: #ifdef TNCODE
1150: printf(", TELNET protocol\n\n");
1151: shotel();
1152: #endif /* TNCODE */
1153: #endif /* TCPSOCKET */
1154: printf("\n");
1155:
1156: #endif /* VMS */
1157:
1158: printf("Current network type:\n");
1159: if (nettype == NET_TCPA || nettype == NET_TCPB)
1160: printf(" TCP/IP\n");
1161: #ifdef SUNX25
1162: else if (nettype == NET_SX25) printf(" X.25\n");
1163: #endif /* SUNX25 */
1164: #ifdef DECNET
1165: else if (nettype == NET_DEC) printf(" DECnet\n");
1166: #endif /* DECNET */
1167:
1168: printf("\nActive SET HOST connection:\n");
1169: if (network) {
1170: printf(" %s",ttname);
1171: if (*ipaddr) printf(" [%s]",ipaddr);
1172: printf("\n Via: ");
1173: if (nettype == NET_TCPA || nettype == NET_TCPB) printf("TCP/IP\n");
1174: else if (nettype == NET_SX25) printf("SunLink X.25\n");
1175: else if (nettype == NET_DEC) {
1176: if ( ttnproto == NP_LAT ) printf("DECnet LAT\n");
1177: else if ( ttnproto == NP_CTERM ) printf("DECnet CTERM\n");
1178: else printf("DECnet\n");
1179: }
1180: else if (nettype == NET_PIPE) printf("LAN Manager Named Pipe\n");
1181: #ifdef SUNX25
1182: if (nettype == NET_SX25) shox25();
1183: #endif /* SUNX25 */
1184: #ifdef TNCODE
1185: if (ttnproto == NP_TELNET) {
1186: printf(" TELNET protocol\n");
1187: printf(" Echoing is currently %s\n",duplex ? "local" : "remote");
1188: }
1189: #endif /* TNCODE */
1190: } else printf(" None\n");
1191: printf("\n");
1192: #endif /* NETCONN */
1193: }
1194:
1195: #ifndef NODIAL
1196:
1197: VOID
1198: shodial() {
1199: if (mdmtyp >= 0 || local != 0) doshodial();
1200: }
1201:
1202: static VOID
1203: shods(s) char *s; { /* Show a dial-related string */
1204: char c;
1205: if (s == NULL || !(*s)) { /* Empty? */
1206: printf("(none)\n");
1207: } else { /* Not empty. */
1208: while (c = *s++) /* Can contain controls */
1209: if (c > 31 && c < 127) { putchar(c); } /* so display them */
1210: else printf("\\{%d}",c); /* in backslash notation */
1211: printf("\n");
1212: }
1213: }
1214:
1215: int
1216: doshodial() {
1217: printf(" Dial directory: %s\n",dialdir ? dialdir : "(none)");
1218: printf(" Dial hangup: %s, dial modem-hangup: %s\n",
1219: dialhng ? "on" : "off", dialmhu ? "on" : "off") ;
1220: printf(" Dial kermit-spoof: %s",dialksp ? "on" : "off");
1221: printf(", dial display: %s\n",dialdpy ? "on" : "off");
1222: printf(" Dial speed-matching: %s",mdmspd ? "on" : "off");
1223: printf(", dial mnp-enable: %s\n",dialmnp ? "on" : "off");
1224: printf(" Dial init-string: ");
1225: shods(getdws(mdmtyp)); /* Ask dial module for it */
1226: printf(" Dial dial-command: ");
1227: shods(getdcs(mdmtyp)); /* Ask dial module for it */
1228: printf(" Dial prefix: ");
1229: shods(dialnpr);
1230: printf(" Dial timeout: ");
1231: if (dialtmo > 0)
1232: printf("%d sec", dialtmo);
1233: else
1234: printf("0 (auto)");
1235: printf(", Redial number: %s\n",dialnum ? dialnum : "(none)");
1236: return(0);
1237: }
1238: #endif /* NODIAL */
1239:
1240: #ifdef SUNX25
1241: VOID
1242: shopad() {
1243: int i;
1244: printf("\nX.3 PAD Parameters:\n");
1245: for (i = 0; i < npadx3; i++)
1246: printf(" [%d] %s %d\n",padx3tab[i].kwval,padx3tab[i].kwd,
1247: padparms[padx3tab[i].kwval]);
1248: }
1249: #endif /* SUNX25 */
1250:
1251: /* Show File Parameters */
1252:
1253: VOID
1254: shoparf() {
1255: char *s; int i;
1256: printf("\nFile parameters: ");
1257: #ifdef COMMENT
1258: printf("Blocksize: %5d ",fblksiz);
1259: #endif /* COMMENT */
1260: printf(" Attributes: ");
1261: if (atcapr) printf("on"); else printf("off");
1262: #ifdef VMS
1263: printf(" Record-Length: %5d",frecl);
1264: #endif /* VMS */
1265: printf("\n Names: ");
1266: printf("%-12s",(fncnv) ? "converted" : "literal");
1267: #ifdef DEBUG
1268: #ifndef MAC
1269: printf(" Debugging Log: ");
1270: if (deblog) printf("%s",debfil); else printf("none");
1271: #endif /* MAC */
1272: #endif /* DEBUG */
1273:
1274: printf("\n Type: ");
1275: switch (binary) {
1276: case XYFT_T: s = "text"; break;
1277: #ifdef VMS
1278: case XYFT_B: s = "binary fixed"; break;
1279: case XYFT_I: s = "image"; break;
1280: case XYFT_L: s = "labeled"; break;
1281: case XYFT_U: s = "binary undef"; break;
1282: #else
1283: case XYFT_B: s = "binary"; break;
1284: #endif /* VMS */
1285: default: s = "?"; break;
1286: }
1287: printf("%-12s",s);
1288: #ifdef COMMENT
1289: printf(" Organization: ");
1290: switch (forg) {
1291: case XYFO_I: printf("%-10s","indexed"); break;
1292: case XYFO_R: printf("%-10s","relative"); break;
1293: case XYFO_S: printf("%-10s","sequential"); break;
1294: }
1295: #endif /* COMMENT */
1296: #ifndef MAC
1297: printf(" Packet Log: ");
1298: if (pktlog) printf(pktfil); else printf("none");
1299: #endif /* MAC */
1300: #ifdef UNIX
1301: printf(" Longest filename: %d",maxnam);
1302: #endif /* UNIX */
1303: printf("\n Collide: ");
1304: for (i = 0; i < ncolx; i++)
1305: if (colxtab[i].kwval == fncact) break;
1306: printf("%-12s", (i == ncolx) ? "unknown" : colxtab[i].kwd);
1307:
1308: #ifdef COMMENT
1309: printf(" Format: ");
1310: switch (frecfm) {
1311: case XYFF_F: printf("%-10s","fixed"); break;
1312: case XYFF_VB: printf("%-10s","rcw"); break;
1313: case XYFF_S: printf("%-10s","stream"); break;
1314: case XYFF_U: printf("%-10s","undefined"); break;
1315: case XYFF_V: printf("%-10s","variable"); break;
1316: }
1317: #endif /* COMMENT */
1318: #ifndef MAC
1319: printf(" Session Log: ");
1320: if (seslog) printf(sesfil); else printf("none");
1321: #endif /* MAC */
1322: #ifdef UNIX
1323: printf(" Longest pathname: %d",maxpath);
1324: #endif /* UNIX */
1325: printf("\n Display: ");
1326: switch (fdispla) {
1327: case XYFD_N: printf("%-12s","none"); break;
1328: case XYFD_R: printf("%-12s","serial"); break;
1329: case XYFD_C: printf("%-12s","fullscreen"); break;
1330: case XYFD_S: printf("%-12s","crt"); break;
1331: }
1332: #ifdef COMMENT
1333: printf("Carriage-Control: ");
1334: switch (fcctrl) {
1335: case XYFP_F: printf("%-10s","fortran"); break;
1336: case XYFP_N: printf("%-10s","newline"); break;
1337: case XYFP_P: printf("%-10s","machine"); break;
1338: case XYFP_X: printf("%-10s","none"); break;
1339: }
1340: #endif /* COMMENT */
1341: #ifdef TLOG
1342: #ifndef MAC
1343: printf(" Transaction Log: ");
1344: if (tralog) printf(trafil); else printf("none");
1345: #endif /* MAC */
1346: #endif /* TLOG */
1347: #ifndef NOCSETS
1348: if (binary == XYFT_T) {
1349: shocharset();
1350: } else
1351: #endif /* NOCSETS */
1352: printf("\n");
1353: printf("\nFile Byte Size: %d",(fmask == 0177) ? 7 : 8);
1354: printf(", Incomplete Files: ");
1355: if (keep) printf("keep"); else printf("discard");
1356: #ifdef KERMRC
1357: printf(", Init file: %s",kermrc);
1358: #endif /* KERMRC */
1359: printf("\n");
1360: }
1361:
1362: VOID
1363: shoparp() {
1364: printf("\nProtocol Parameters: Send Receive");
1365: if (timef)
1366: printf("\n Timeout (used=%2d):%7d*%8d ", timint, rtimo, pkttim);
1367: else
1368: printf("\n Timeout (used=%2d):%7d%9d ", timint, rtimo, pkttim);
1369: #ifndef NOSERVER
1370: printf(" Server Timeout:%4d\n",srvtim);
1371: #endif /* NOSERVER */
1372: printf( " Padding: %11d%9d", npad, mypadn);
1373: if (bctr == 4)
1374: printf(" Block Check: blank-free-2\n");
1375: else
1376: printf(" Block Check: %6d\n",bctr);
1377: printf( " Pad Character:%11d%9d", padch, mypadc);
1378: printf(" Delay: %6d\n",delay);
1379: printf( " Packet Start: %11d%9d", mystch, stchr);
1380: printf(" Max Retries: %6d\n",maxtry);
1381: printf( " Packet End: %11d%9d", seol, eol);
1382: if (ebqflg)
1383: printf(" 8th-Bit Prefix: '%c'",ebq);
1384: #ifdef COMMENT
1385: /*
1386: This is confusing.
1387: */
1388: printf( "\n Packet Length:%11d", spsizf ? spsizr : spsiz);
1389: printf( spsizf ? "*" : " " ); printf("%8d", urpsiz);
1390: printf( (urpsiz > 94) ? " (94)" : " ");
1391: #else
1392: printf( "\n Packet Length:%11d ", spmax);
1393: printf("%8d ", urpsiz);
1394: #endif /* COMMENT */
1395: if (rptflg)
1396: printf(" Repeat Prefix: '%c'",rptq);
1397: printf( "\n Maximum Length: %9d%9d", maxsps, maxrps);
1398: printf(" Window Size:%7d set, %d used\n",wslotr,wmax);
1399: printf( " Buffer Size: %11d%9d", bigsbsiz, bigrbsiz);
1400: printf(" Locking-Shift: ");
1401: if (lscapu == 2) {
1402: printf("forced\n");
1403: } else {
1404: printf("%s", (lscapr ? "enabled" : "disabled"));
1405: if (lscapr) printf(",%s%s", (lscapu ? " " : " not "), "used");
1406: printf("\n");
1407: }
1408: }
1409:
1410: #ifndef NOCSETS
1411: VOID
1412: shoparl() {
1413: #ifdef COMMENT
1414: int i;
1415: /* Misleading... */
1416: printf("\nAvailable Languages:\n");
1417: for (i = 0; i < MAXLANG; i++) {
1418: printf(" %s\n",langs[i].description);
1419: }
1420: #else
1421: printf("\nLanguage-specific translation rules: %s\n",
1422: language == L_USASCII ? "none" : langs[language].description);
1423: shocharset();
1424: printf("\n\n");
1425: #endif /* COMMENT */
1426: }
1427:
1428: VOID
1429: shocharset() {
1430: int x;
1431: printf("\n File Character-Set: %s (",fcsinfo[fcharset].name);
1432: if ((x = fcsinfo[fcharset].size) == 128) printf("7-bit)");
1433: else if (x == 256) printf("8-bit)");
1434: else printf("(multibyte)");
1435: printf("\n Transfer Character-Set");
1436: #ifdef COMMENT
1437: if (tslevel == TS_L2)
1438: printf(": (international)");
1439: else
1440: #endif /* COMMENT */
1441: if (tcharset == TC_TRANSP)
1442: printf(": Transparent");
1443: else
1444: printf(": %s",tcsinfo[tcharset].name);
1445: }
1446: #endif /* NOCSETS */
1447:
1448: VOID
1449: shopar() {
1450: #ifndef MAC
1451: printf("\n%s,%s\n",versio,ckxsys);
1452: #endif /* MAC */
1453: shoparc();
1454: shoparp();
1455: shoparf();
1456: }
1457: #endif /* NOSHOW */
1458:
1459: /* D O S T A T -- Display file transfer statistics. */
1460:
1461: int
1462: dostat() {
1463: printf("\nMost recent transaction --\n");
1464: printf("\n files: %ld\n",filcnt);
1465: printf(" characters last file : %ld\n",ffc);
1466: printf(" total file characters : %ld\n",tfc);
1467: printf(" communication line in : %ld\n",tlci);
1468: printf(" communication line out : %ld\n",tlco);
1469: printf(" packets sent : %d\n", spackets);
1470: printf(" packets received : %d\n", rpackets);
1471: printf(" damaged packets rec'd : %d\n", crunched);
1472: printf(" timeouts : %d\n", timeouts);
1473: printf(" retransmissions : %d\n", retrans);
1474: if (filcnt > 0) {
1475: printf(" parity : %s",parnam((char)parity));
1476: if (autopar) printf(" (detected automatically)");
1477: printf("\n 8th bit prefixing : ");
1478: if (ebqflg) printf("yes [%c]\n",ebq); else printf("no\n");
1479: printf(" locking shifts : %s\n", lscapu ? "yes" : "no");
1480: printf(" window slots used : %d of %d\n", wmax, wslotr);
1481: printf(" packet length : %d (send), %d (receive)\n",
1482: spmax, urpsiz);
1483: printf(" compression : ");
1484: if (rptflg) printf("yes [%c] (%d)\n",rptq,rptn); else printf("no\n");
1485: if (bctu == 4)
1486: printf(" block check type used : blank-free-2\n");
1487: else
1488: printf(" block check type used : %d\n",bctu);
1489: printf(" elapsed time : %d sec\n",tsecs);
1490: if (speed <= 0L) speed = ttgspd();
1491: if (speed > 0L) {
1492: if (speed == 8880)
1493: printf(" transmission rate : 75/1200 bps\n");
1494: else
1495: printf(" transmission rate : %ld bps\n",speed);
1496: }
1497: if (tsecs > 0) {
1498: long lx;
1499: lx = (tfc * 10L) / (long) tsecs;
1500: printf(" effective data rate : %ld cps\n",lx/10L);
1501: if (speed > 0L && speed != 8880L && network == 0) {
1502: lx = (lx * 100L) / speed;
1503: printf(" efficiency (percent) : %ld\n",lx);
1504: }
1505: #ifdef COMMENT
1506: lx = (tlci * 10L) / (long) tsecs;
1507: printf(" throughput (in) : %ld cps\n",lx/10l);
1508: lx = (tlco * 10L) / (long) tsecs;
1509: printf(" throughput (out) : %ld cps\n",lx/10l);
1510: #endif /* COMMENT */
1511: }
1512: }
1513: return(1);
1514: }
1515:
1516: /* D O C O N E C T -- Do the connect command */
1517:
1518: /* Note, we don't call this directly from dial, because we need to give */
1519: /* the user a chance to change parameters (e.g. parity) after the */
1520: /* connection is made. */
1521:
1522: int
1523: doconect() {
1524: int x;
1525: conres(); /* Put console back to normal */
1526: x = conect(); /* Connect */
1527: concb((char)escape); /* Put console into cbreak mode, */
1528: return(x); /* for more command parsing. */
1529: }
1530:
1531: #ifndef NOSPL
1532: /* The INPUT command */
1533:
1534: #ifdef NETCONN
1535: extern int tn_init;
1536: #ifndef IAC
1537: #define IAC 255
1538: #endif /* IAC */
1539: #endif /* NETCONN */
1540:
1541: int
1542: doinput(timo,s) int timo; char *s; {
1543: int x, y, i, t, icn, anychar;
1544: int lastchar = 0;
1545: char *xp, *xq = (char *)0;
1546: CHAR c;
1547:
1548: if (local) { /* Put line in "ttvt" mode */
1549: y = ttvt(speed,flow); /* if not already. */
1550: if (y < 0) {
1551: printf("?Can't condition line for INPUT\n");
1552: return(0); /* Watch out for failure. */
1553: }
1554: }
1555: if (!s) s = "";
1556: y = (int)strlen(s); /* If search string is empty */
1557: anychar = (y < 1); /* any input character will do. */
1558: debug(F111,"doinput",s,y);
1559: if (timo <= 0) timo = 1; /* Give at least 1 second timeout */
1560:
1561: x = 0; /* Return code, assume failure */
1562: i = 0; /* String pattern match position */
1563:
1564: if (!incase) { /* INPUT CASE = IGNORE? */
1565: xp = malloc(y+2); /* Make a separate copy of the */
1566: if (!xp) { /* input string for editing. */
1567: printf("?malloc error 5\n");
1568: return(x);
1569: } else xq = xp; /* Save pointer to beginning */
1570:
1571: while (*s) { /* Convert to lowercase */
1572: *xp = *s;
1573: if (isupper(*xp)) *xp = tolower(*xp);
1574: xp++; s++;
1575: }
1576: *xp = NUL; /* Terminate the search string. */
1577: s = xq; /* Point back to beginning. */
1578: }
1579: inpbps = inpbp; /* Save current pointer. */
1580: rtimer(); /* Reset timer. */
1581: t = 0; /* Time is 0. */
1582: incount = 0; /* Character counter */
1583: while (1) { /* Character-getting loop */
1584: if (local) { /* One case for local */
1585: y = ttinc(1); /* Get character from comm line. */
1586: debug(F101,"input ttinc(1) returns","",y);
1587: if (icn = conchk()) { /* Interrupted from keyboard? */
1588: debug(F101,"input interrupted from keyboard","",icn);
1589: while (icn--) coninc(0); /* Yes, read what was typed. */
1590: break; /* And fail. */
1591: }
1592: } else { /* Another for remote */
1593: y = coninc(1);
1594: debug(F101,"input coninc(1) returns","",y);
1595: }
1596: if (y > -1) { /* A character arrived */
1597: #ifdef TNCODE
1598: /* Check for telnet protocol negotiation */
1599: if (network && (ttnproto == NP_TELNET) && ((y & 0xff) == IAC)) {
1600: switch (tn_doop((CHAR)(y & 0xff),duplex,ttinc)) {
1601: case 2: duplex = 0; continue;
1602: case 1: duplex = 1;
1603: default: continue;
1604: }
1605: }
1606: #endif /* TNCODE */
1607:
1608: /* Real input character to be checked */
1609:
1610: c = cmask & (CHAR) y; /* Mask off parity */
1611:
1612: inchar[0] = c; /* Remember character for \v(inchar) */
1613: lastchar = gtimer(); /* Remember when it came. */
1614:
1615: if (c == '\0') { /* NUL, we can't use it */
1616: if (anychar) { /* Any character will do? */
1617: x = 1; /* Yes, done. */
1618: incount = 1; /* This must be the first and only. */
1619: break;
1620: } else continue; /* Otherwise continue INPUTting */
1621: }
1622:
1623: *inpbp++ = c; /* Store char in circular buffer */
1624: incount++; /* Count it for \v(incount) */
1625:
1626: if (inpbp >= inpbuf + INPBUFSIZ) { /* Time to wrap around? */
1627: inpbp = inpbuf; /* Yes. */
1628: *(inpbp+INPBUFSIZ) = NUL; /* Make sure it's null-terminated. */
1629: }
1630: #ifdef MAC
1631: {
1632: extern char *ttermw; /* fake pointer cast */
1633: if (inecho) {
1634: outchar(ttermw, c); /* echo to terminal window */
1635: /* this might be too much overhead to do here ? */
1636: updatecommand(ttermw);
1637: }
1638: }
1639: #else /* Not MAC */
1640: if (inecho) conoc(c); /* Echo and log the input character */
1641: #endif /* MAC */
1642: if (seslog) {
1643: #ifdef UNIX
1644: if (sessft != 0 || c != '\r')
1645: #endif /* UNIX */
1646: if (zchout(ZSFILE,c) < 0) seslog = 0;
1647: }
1648: if (anychar) { /* Any character will do? */
1649: x = 1;
1650: break;
1651: }
1652: if (!incase) { /* Ignore alphabetic case? */
1653: if (isupper(c)) c = tolower(c); /* Yes */
1654: }
1655: debug(F000,"doinput char","",c);
1656: debug(F000,"compare char","",s[i]);
1657: if (c == s[i]) { /* Check for match */
1658: i++; /* Got one, go to next character */
1659: } else { /* Don't have a match */
1660: int j, size;
1661: for (j = i; i-- > 0; ) { /* [jrs] search backwards */
1662: if (c == s[i]) {
1663: size = j - i;
1664: if (strncmp(s,&s[j-i],i-size)== 0)
1665: break;
1666: }
1667: }
1668: i++; /* [jrs] count last char matched */
1669: } /* [jrs] or return to zero from -1 */
1670: if (s[i] == '\0') { /* Matched all the way to end? */
1671: x = 1; /* Yes, */
1672: break; /* done. */
1673: }
1674: }
1675: if ((t = gtimer()) > timo) /* Did not match, timer exceeded? */
1676: break;
1677: else if (insilence > 0 && (t - lastchar) > insilence)
1678: break;
1679: } /* Still have time left, continue. */
1680: if (!incase) if (xq) free(xq); /* Done, free dynamic memory. */
1681: return(x); /* Return the return code. */
1682: }
1683: #endif /* NOSPL */
1684:
1685: #ifndef NOSPL
1686: /* REINPUT Command */
1687:
1688: /* Note, the timeout parameter is required, but ignored. */
1689: /* Syntax is compatible with MS-DOS Kermit except timeout can't be omitted. */
1690: /* This function only looks at the characters already received */
1691: /* and does not read any new characters from the communication line. */
1692:
1693: int
1694: doreinp(timo,s) int timo; char *s; {
1695: int x, y, i;
1696: char *xx, *xp, *xq = (char *)0;
1697: CHAR c;
1698:
1699: y = (int)strlen(s);
1700: debug(F111,"doreinput",s,y);
1701:
1702: x = 0; /* Return code, assume failure */
1703: i = 0; /* String pattern match position */
1704:
1705: if (!incase) { /* INPUT CASE = IGNORE? */
1706: xp = malloc(y+2); /* Make a separate copy of the */
1707: if (!xp) { /* search string. */
1708: printf("?malloc error 6\n");
1709: return(x);
1710: } else xq = xp; /* Keep pointer to beginning. */
1711: while (*s) { /* Yes, convert to lowercase */
1712: *xp = *s;
1713: if (isupper(*xp)) *xp = tolower(*xp);
1714: xp++; s++;
1715: }
1716: *xp = NUL; /* Terminate it! */
1717: s = xq; /* Move search pointer to it. */
1718: }
1719: xx = inpbp; /* Current INPUT buffer pointer */
1720: do {
1721: c = *xx++; /* Get next character */
1722: if (xx >= inpbuf + INPBUFSIZ) xx = inpbuf; /* Wrap around */
1723: if (!incase) { /* Ignore alphabetic case? */
1724: if (isupper(c)) c = tolower(c); /* Yes */
1725: }
1726: debug(F000,"doreinp char","",c);
1727: debug(F000,"compare char","",s[i]);
1728: if (c == s[i]) { /* Check for match */
1729: i++; /* Got one, go to next character */
1730: } else { /* Don't have a match */
1731: int j, size;
1732: for (j = i; i-- > 0; ) { /* [jrs] search backwards for it */
1733: if (c == s[i]) {
1734: size = j - i;
1735: if (strncmp(s,&s[j-i],i-size)== 0)
1736: break;
1737: }
1738: }
1739: i++; /* [jrs] count last char matched */
1740: } /* [jrs] or return to zero from -1 */
1741: if (s[i] == '\0') { /* Matched all the way to end? */
1742: x = 1; /* Yes, */
1743: break; /* done. */
1744: }
1745: } while (xx != inpbp); /* Until back where we started. */
1746:
1747: if (!incase) if (xq) free(xq); /* Free this if it was malloc'd. */
1748: return(x); /* Return search result. */
1749: }
1750: #ifndef NOSPL
1751:
1752: #endif /* NOSPL */
1753: /* X X S T R I N G -- Interpret strings containing backslash escapes */
1754:
1755: /*
1756: Copies result to new string.
1757: strips enclosing braces or doublequotes.
1758: interprets backslash escapes.
1759: returns 0 on success, nonzero on failure.
1760: tries to be compatible with MS-DOS Kermit.
1761:
1762: Syntax of input string:
1763: string = chars | "chars" | {chars}
1764: chars = (c*e*)*
1765: where c = any printable character, ascii 32-126
1766: and e = a backslash escape
1767: and * means 0 or more repetitions of preceding quantity
1768: backslash escape = \operand
1769: operand = {number} | number | fname(operand) | v(name) | $(name) | m(name)
1770: number = [r]n[n[n]]], i.e. an optional radix code followed by 1-3 digits
1771: radix code is oO (octal), hHxX (hex), dD or none (decimal).
1772: */
1773:
1774: #ifndef NOFRILLS
1775: int
1776: yystring(s,s2) char *s; char **s2; { /* Reverse a string */
1777: int x;
1778: static char *new;
1779: new = *s2;
1780: if (!s || !new) return(-1); /* Watch out for null pointers. */
1781: if ((x = (int)strlen(s)) == 0) { /* Recursion done. */
1782: *new = '\0';
1783: return(0);
1784: }
1785: x--; /* Otherwise, call self */
1786: *new++ = s[x]; /* to reverse rest of string. */
1787: s[x] = 0;
1788: return(yystring(s,&new));
1789: }
1790: #endif /* NOFRILLS */
1791:
1792: #define FNVALL 1000
1793: char fnval[FNVALL+2]; /* Return value */
1794:
1795: char * /* Evaluate builtin function */
1796: fneval(fn,argp,argn) char *fn, *argp[]; int argn; {
1797: int i, j, k, len1, len2, n, x, y;
1798: char *bp[FNARGS]; /* Pointers to malloc'd strings */
1799: char *p, *s;
1800:
1801: if (!fn) fn = ""; /* Paranoia */
1802: debug(F111,"fneval",fn,argn);
1803: debug(F110,"fneval",argp[0],0);
1804: y = lookup(fnctab,fn,nfuncs,&x);
1805: if (y < 0) /* bad function name */
1806: return(""); /* so value is null */
1807:
1808: #ifdef DEBUG
1809: if (deblog) {
1810: int j;
1811: for (j = 0; j < argn; j++)
1812: debug(F111,"fneval function arg",argp[j],j);
1813: }
1814: #endif /* DEBUG */
1815:
1816: if (y == FN_LIT) /* literal(arg1) */
1817: return(argp[0] ? argp[0] : ""); /* return a pointer to arg itself */
1818:
1819: if (y == FN_CON) { /* Contents of variable, unexpanded. */
1820: char c;
1821: if (!(p = argp[0]) || !*p) return("");
1822: if (*p == CMDQ) p++;
1823: if ((c = *p) == '%') { /* Scalar variable. */
1824: c = *++p; /* Get ID character. */
1825: p = ""; /* Assume definition is empty */
1826: if (!c) return(p); /* Double paranoia */
1827: if (c >= '0' && c <= '9') { /* Digit for macro arg */
1828: c -= '0'; /* convert character to integer */
1829: if (maclvl < 0) /* Digit variables are global */
1830: p = g_var[c]; /* if no macro is active */
1831: else /* otherwise */
1832: p = m_arg[maclvl][c]; /* they're on the stack */
1833: } else {
1834: if (isupper(c)) c -= ('a'-'A');
1835: p = g_var[c]; /* Letter for global variable */
1836: }
1837: return(p ? p : "");
1838: }
1839: if (c == '&') { /* Array reference. */
1840: int vbi, d;
1841: if (arraynam(p,&vbi,&d) < 0) /* Get name and subscript */
1842: return("");
1843: if (chkarray(vbi,d) > 0) { /* Array is declared? */
1844: vbi -= 'a'; /* Convert name to index */
1845: if (a_dim[vbi] >= d) { /* If subscript in range */
1846: char **ap;
1847: ap = a_ptr[vbi]; /* get data pointer */
1848: if (ap) { /* and if there is one */
1849: return(ap[d]); /* return what it points to */
1850: }
1851: }
1852: }
1853: return(p ? p : ""); /* Otherwise its enexpanded value. */
1854: }
1855: }
1856:
1857: for (i = 0; i < argn; i++) { /* Not literal, expand the args */
1858: n = 1024; /* allow 1K per expanded arg, yow! */
1859: bp[i] = s = malloc(n); /* get the new space */
1860: if (bp[i] == NULL) { /* handle failure to get space */
1861: for (k = 0; k < i; k++) if (bp[k]) free(bp[k]);
1862: debug(F101,"fneval malloc failure, arg","",i);
1863: return("");
1864: }
1865: p = argp[i] ? argp[i] : ""; /* Point to this argument */
1866:
1867: /*
1868: Trim leading and trailing spaces from the original argument, before
1869: evaluation. This code new to edit 184.
1870: */
1871: if (y != FN_REP || i != 0) { /* Don't trim 1st REPEAT argument */
1872: int j; /* All others... */
1873: while (*p == SP || *p == HT) /* Point past leading whitespace */
1874: p++;
1875: j = (int) strlen(p) - 1; /* Trim trailing whitespace */
1876: while (j > 0 && (*(p + j) == SP || *(p + j) == HT))
1877: *(p + j--) = NUL;
1878: }
1879:
1880: /* Now evaluate the argument */
1881:
1882: if (xxstring(p,&s,&n) < 0) { /* Expand arg into new space */
1883: debug(F101,"fneval xxstring fails, arg","",i);
1884: for (k = 0; k <= i; k++) /* Free up previous space on error */
1885: if (bp[k]) free(bp[k]);
1886: return(""); /* and return null string. */
1887: }
1888: debug(F111,"fneval arg",bp[i],i);
1889: }
1890:
1891: #ifdef DEBUG
1892: if (deblog) {
1893: int j;
1894: for (j = 0; j < argn; j++) {
1895: debug(F111,"fneval arg post eval",argp[j],j);
1896: debug(F111,"fneval evaluated arg",bp[j],j);
1897: }
1898: }
1899: #endif /* DEBUG */
1900:
1901: switch (y) { /* Do function on expanded args */
1902:
1903: case FN_DEF:
1904: k = mlook(mactab,bp[0],nmac); /* def(arg1) - Return a macro def */
1905: p = (k > -1) ? mactab[k].mval : "";
1906: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
1907: return(p ? p : "");
1908:
1909: case FN_EVA: /* eval(arg1) */
1910: p = evala(bp[0]);
1911: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
1912: return(p ? p : "");
1913:
1914: case FN_EXE: /* execute(arg1) */
1915: j = (int)strlen(s = bp[0]); /* Length of macro invocation */
1916: p = ""; /* Initialize return value to null */
1917: if (j) { /* If there is a macro to execute */
1918: while (*s == SP) s++,j--; /* strip leading spaces */
1919: p = s; /* remember beginning of macro name */
1920: for (i = 0; i < j; i++) { /* find end of macro name */
1921: if (*s == SP) break;
1922: s++;
1923: }
1924: if (*s == SP) { /* if there was a space after */
1925: *s++ = NUL; /* terminate the macro name */
1926: while (*s == SP) s++; /* skip past any extra spaces */
1927: } else s = ""; /* maybe there are no arguments */
1928: if (p && *p)
1929: k = mlook(mactab,p,nmac); /* Look up the macro name */
1930: else k = -1;
1931:
1932: p = ""; /* Initialize return value */
1933: if (k >= 0) { /* If macro found in table */
1934: if ((j = dodo(k,s)) > 0) { /* Go set it up (like DO cmd) */
1935: if (cmpush() > -1) { /* Push command parser state */
1936: extern int ifc;
1937: int ifcsav = ifc; /* Push IF condition on stack */
1938: k = parser(1); /* Call parser to execute the macro */
1939: cmpop(); /* Pop command parser */
1940: ifc = ifcsav; /* Restore IF condition */
1941: if (k == 0) { /* No errors, ignore action cmds. */
1942: p = mrval[maclvl+1]; /* If OK, set return value. */
1943: if (p == NULL) p = "";
1944: }
1945: } else { /* Can't push any more */
1946: debug(F100,"fexec pushed too deep","",0);
1947: printf("\n?\\fexec() too deeply nested\n");
1948: while (cmpop() > -1) ;
1949: p = "";
1950: }
1951: }
1952: }
1953: }
1954: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
1955: return(p ? p : "");
1956:
1957: case FN_FC: /* File count. */
1958: p = fnval;
1959: *p = NUL;
1960: if (argn > 0) {
1961: k = zxpand(bp[0]);
1962: sprintf(fnval,"%d",k);
1963: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
1964: }
1965: return(p);
1966:
1967: case FN_FIL: /* Next file in list. */
1968: p = fnval; /* (no args) */
1969: *p = NUL;
1970: znext(p);
1971: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
1972: return(p ? p : "");
1973:
1974: case FN_IND: /* index(arg1,arg2) */
1975: if (argn > 1) { /* Only works if we have 2 args */
1976: int start;
1977: len1 = (int)strlen(bp[0]); /* length of string to look for */
1978: len2 = (int)strlen(s = bp[1]); /* length of string to look in */
1979: if (len1 < 0) return(""); /* paranoia */
1980: if (len2 < 0) return("");
1981: j = len2 - len1; /* length difference */
1982: start = 0; /* starting position */
1983: if (argn > 2) {
1984: if (chknum(bp[2])) {
1985: start = atoi(bp[2]) - 1;
1986: if (start < 0) start = 0;
1987: }
1988: }
1989: if (j < 0 || start > j) { /* search string is longer */
1990: p = "0";
1991: } else {
1992: if (!incase) { /* input case ignore? */
1993: lower(bp[0]);
1994: lower(bp[1]);
1995: }
1996: s = bp[1] + start; /* Point to beginning of target */
1997: p = "0";
1998: for (i = 0; i <= (j - start); i++) { /* Now compare */
1999: if (!strncmp(bp[0],s++,len1)) {
2000: sprintf(fnval,"%d",i+1+start);
2001: p = fnval;
2002: break;
2003: }
2004: }
2005: }
2006: } else p = "0";
2007: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2008: return(p);
2009:
2010: case FN_CHR: /* character(arg1) */
2011: if (chknum(bp[0])) { /* Must be numeric */
2012: i = atoi(bp[0]);
2013: if (i >= 0 && i < 256) { /* Must be an 8-bit value */
2014: p = fnval;
2015: *p++ = i;
2016: *p = NUL;
2017: p = fnval;
2018: } else p = ""; /* Otherwise return null */
2019: } else p = ""; /* Otherwise return null */
2020: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2021: return(p);
2022:
2023: case FN_COD: /* code(char) */
2024: p = "";
2025: if ((int)strlen(bp[0]) > 0) {
2026: p = fnval;
2027: i = *bp[0];
2028: sprintf(p,"%d",(i & 0xff));
2029: }
2030: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2031: return(p);
2032:
2033: case FN_LEN: /* length(arg1) */
2034: p = fnval;
2035: sprintf(p,"%d",(int)strlen(bp[0]));
2036: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2037: return(p);
2038:
2039: case FN_LOW: /* lower(arg1) */
2040: s = bp[0];
2041: p = fnval;
2042:
2043: while (*s) {
2044: if (isupper(*s))
2045: *p = tolower(*s);
2046: else
2047: *p = *s;
2048: p++; s++;
2049: }
2050: *p = NUL;
2051: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2052: p = fnval;
2053: return(p);
2054:
2055: case FN_MAX: /* max(arg1,arg2) */
2056: case FN_MIN: /* min(arg1,arg2) */
2057: case FN_MOD: /* mod(arg1,arg2) */
2058: if (chknum(bp[0]) && chknum(bp[1])) {
2059: i = atoi(bp[0]);
2060: j = atoi(bp[1]);
2061: switch (y) {
2062: case FN_MAX:
2063: if (j < i) j = i;
2064: break;
2065: case FN_MIN:
2066: if (j > i) j = i;
2067: break;
2068: case FN_MOD:
2069: j = i % j;
2070: break;
2071: }
2072: p = fnval;
2073: sprintf(p,"%d",j);
2074: } else p = "";
2075: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2076: return(p);
2077:
2078: case FN_SUB: /* substr(arg1,arg2,arg3) */
2079: case FN_RIG: /* right(arg1,arg2) */
2080: if (((argn > 1) && (int)strlen(bp[1]) && !rdigits(bp[1])) ||
2081: ((y == FN_SUB) &&
2082: ((argn > 2) && (int)strlen(bp[2]) && !rdigits(bp[2])))) {
2083: p = ""; /* if either, return null */
2084: } else {
2085: int lx;
2086: p = fnval; /* pointer to result */
2087: lx = strlen(bp[0]); /* length of arg1 */
2088: if (y == FN_SUB) { /* substring */
2089: k = (argn > 2) ? atoi(bp[2]) : 1023; /* length */
2090: j = (argn > 1) ? atoi(bp[1]) : 1; /* start pos for substr */
2091: } else { /* right */
2092: k = (argn > 1) ? atoi(bp[1]) : lx; /* length */
2093: j = lx - k + 1; /* start pos for right */
2094: if (j < 1) j = 1;
2095: }
2096: if (k > 0 && j <= lx) { /* if start pos in range */
2097: s = bp[0]+j-1; /* point to source string */
2098: for (i = 0; (i < k) && (*p++ = *s++); i++) ; /* copy */
2099: }
2100: *p = NUL; /* terminate the result */
2101: p = fnval; /* and point to it. */
2102: }
2103: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]); /* Free temp mem */
2104: return(p);
2105:
2106: case FN_UPP: /* upper(arg1) */
2107: s = bp[0];
2108: p = fnval;
2109: while (*s) {
2110: if (islower(*s))
2111: *p = toupper(*s);
2112: else
2113: *p = *s;
2114: p++; s++;
2115: }
2116: *p = NUL;
2117: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2118: p = fnval;
2119: return(p);
2120:
2121: case FN_REP: /* Repeat */
2122: p = ""; /* Return value */
2123: if (chknum(bp[1])) { /* Repeat count */
2124: n = atoi(bp[1]);
2125: if (n > 0) { /* Make n copies */
2126: p = fnval;
2127: *p = '\0';
2128: k = (int)strlen(bp[0]); /* Make sure string has some length */
2129: if (k > 0) {
2130: for (i = 0; i < n; i++) {
2131: s = bp[0];
2132: for (j = 0; j < k; j++) {
2133: if ((p - fnval) >= FNVALL) { /* Protect against */
2134: p = ""; /* core dumps... */
2135: break;
2136: } else *p++ = *s++;
2137: }
2138: }
2139: *p = NUL;
2140: }
2141: }
2142: }
2143: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2144: p = fnval;
2145: return(p);
2146:
2147: #ifndef NOFRILLS
2148: case FN_REV:
2149: p = fnval;
2150: yystring(bp[0],&p);
2151: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2152: return(p);
2153: #endif /* NOFRILLS */
2154:
2155: case FN_RPA: /* RPAD and LPAD */
2156: case FN_LPA:
2157: *fnval = NUL; /* Return value */
2158: if (argn == 1) { /* If a number wasn't given */
2159: p = fnval; /* just return the original string */
2160: strncpy(p,bp[0],FNVALL);
2161: } else if (chknum(bp[1])) { /* Repeat count */
2162: char pc;
2163: n = atoi(bp[1]);
2164: if (n >= 0) { /* Pad it out */
2165: p = fnval;
2166: k = (int)strlen(bp[0]); /* Length of string to be padded */
2167: pc = (argn < 3) ? SP : *bp[2]; /* Padding character */
2168: if (n > FNVALL) n = FNVALL-1; /* protect against overruns */
2169: if (k > FNVALL) k = FNVALL-1; /* and silly args. */
2170: if (k > n) k = n;
2171: if (y == FN_RPA) { /* RPAD */
2172: strncpy(p,bp[0],k);
2173: p += k;
2174: for (i = k; i < n; i++)
2175: *p++ = pc;
2176: } else { /* LPAD */
2177: n -= k;
2178: for (i = 0; i < n; i++)
2179: *p++ = pc;
2180: strncpy(p,bp[0],k);
2181: p += k;
2182: }
2183: *p = NUL;
2184: }
2185: }
2186: for (k = 0; k < argn; k++) if (bp[k]) free(bp[k]);
2187: p = fnval;
2188: return(p);
2189:
2190: default:
2191: return("");
2192: }
2193: }
2194: #endif /* NOSPL */
2195:
2196: #ifndef NOSPL
2197:
2198: char * /* Evaluate builtin variable */
2199: nvlook(s) char *s; {
2200: int x, y;
2201: long z;
2202: char *p;
2203:
2204: x = 30;
2205: p = vvbuf;
2206: if (xxstring(s,&p,&x) < 0) {
2207: y = -1;
2208: } else {
2209: s = vvbuf;
2210: if ((y = lookup(vartab,s,nvars,&x)) < 0) return(NULL);
2211: }
2212: switch (y) {
2213: case VN_ARGC: /* ARGC */
2214: sprintf(vvbuf,"%d",macargc[maclvl]);
2215: return(vvbuf);
2216:
2217: case VN_ARGS: /* ARGS */
2218: sprintf(vvbuf,"%d",xargs);
2219: return(vvbuf);
2220:
2221: case VN_COUN: /* COUNT */
2222: sprintf(vvbuf,"%d",count[cmdlvl]);
2223: return(vvbuf);
2224:
2225: case VN_DATE: /* DATE */
2226: ztime(&p); /* Get "asctime" string */
2227: if (p == NULL || *p == NUL) return(NULL);
2228: vvbuf[0] = p[8]; /* dd */
2229: vvbuf[1] = p[9];
2230: vvbuf[2] = SP;
2231: vvbuf[3] = p[4]; /* mmm */
2232: vvbuf[4] = p[5];
2233: vvbuf[5] = p[6];
2234: vvbuf[6] = SP;
2235: for (x = 20; x < 24; x++) /* yyyy */
2236: vvbuf[x - 13] = p[x];
2237: vvbuf[11] = NUL;
2238: return(vvbuf);
2239:
2240: case VN_NDAT: /* Numeric date */
2241: ztime(&p); /* Get "asctime" string */
2242: if (p == NULL || *p == NUL) return(NULL);
2243: for (x = 20; x < 24; x++) /* yyyy */
2244: vvbuf[x - 20] = p[x];
2245: vvbuf[6] = (p[8] == ' ') ? '0' : p[8]; vvbuf[7] = p[9]; /* dd */
2246: for (x = 0; x < 12; x++) /* mm */
2247: if (!strncmp(p+4,months[x],3)) break;
2248: if (x == 12) {
2249: vvbuf[4] = vvbuf[5] = '?';
2250: } else {
2251: x++;
2252: vvbuf[4] = (x < 10) ? '0' : '1';
2253: vvbuf[5] = (x % 10) + 48;
2254: }
2255: vvbuf[8] = NUL;
2256: return(vvbuf);
2257:
2258: case VN_DIRE: /* DIRECTORY */
2259: return(zgtdir());
2260:
2261: case VN_FILE: /* filespec */
2262: return(fspec);
2263:
2264: case VN_HOST: /* host name */
2265: if (*myhost) { /* If known */
2266: return(myhost); /* return it. */
2267: } else { /* Otherwise */
2268: strcpy(vvbuf,"unknown"); /* just say "unknown" */
2269: return(vvbuf);
2270: }
2271:
2272: case VN_SYST: /* System type */
2273: #ifdef UNIX
2274: strcpy(vvbuf,"UNIX");
2275: #else
2276: #ifdef VMS
2277: strcpy(vvbuf,"VMS");
2278: #else
2279: #ifdef OSK
2280: strcpy(vvbuf,"OS9/68K");
2281: #else
2282: #ifdef AMIGA
2283: strcpy(vvbuf,"Amiga");
2284: #else
2285: #ifdef MAC
2286: strcpy(vvbuf,"Macintosh");
2287: #else
2288: #ifdef OS2
2289: strcpy(vvbuf,"OS/2");
2290: #else
2291: #ifdef datageneral
2292: strcpy(vvbuf,"AOS/VS");
2293: #else
2294: #ifdef GEMDOS
2295: strcpy(vvbuf,"Atari_ST");
2296: #else
2297: strcpy(vvbuf,"unknown");
2298: #endif /* GEMDOS */
2299: #endif /* datageneral */
2300: #endif /* OS2 */
2301: #endif /* MAC */
2302: #endif /* AMIGA */
2303: #endif /* OSK */
2304: #endif /* VMS */
2305: #endif /* UNIX */
2306: return(vvbuf);
2307:
2308: case VN_SYSV: /* System herald */
2309: for (x = y = 0; x < VVBUFL; x++) {
2310: if (ckxsys[x] == SP && y == 0) continue;
2311: vvbuf[y++] = (ckxsys[x] == SP) ? '_' : ckxsys[x];
2312: }
2313: vvbuf[y] = NUL;
2314: return(vvbuf);
2315:
2316: case VN_TIME: /* TIME. Assumes that ztime returns */
2317: ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
2318: if (p == NULL || *p == NUL) /* like asctime()! */
2319: return(NULL);
2320: for (x = 11; x < 19; x++) /* copy hh:mm:ss */
2321: vvbuf[x - 11] = p[x]; /* to vvbuf */
2322: vvbuf[8] = NUL; /* terminate */
2323: return(vvbuf); /* and return it */
2324:
2325: case VN_NTIM: /* Numeric time */
2326: ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
2327: if (p == NULL || *p == NUL) /* like asctime()! */
2328: return(NULL);
2329: z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2330: sprintf(vvbuf,"%ld",z);
2331: return(vvbuf);
2332:
2333: #ifdef UNIX
2334: case VN_TTYF: /* TTY file descriptor */
2335: sprintf(vvbuf,"%d",ttyfd);
2336: return(vvbuf);
2337: #else
2338: #ifdef OS2
2339: case VN_TTYF: /* TTY file descriptor */
2340: sprintf(vvbuf,"%d",ttyfd);
2341: return(vvbuf);
2342: #endif /* OS2 */
2343: #endif /* UNIX */
2344:
2345: case VN_VERS: /* Numeric Kermit version number */
2346: sprintf(vvbuf,"%ld",vernum);
2347: return(vvbuf);
2348:
2349: case VN_HOME: /* Home directory */
2350: #ifdef UNIX
2351: sprintf(vvbuf,"%s/",zhome());
2352: return(vvbuf);
2353: #else
2354: return(zhome());
2355: #endif /* UNIX */
2356:
2357: case VN_IBUF: /* INPUT buffer */
2358: return(inpbuf);
2359:
2360: case VN_ICHR: /* INPUT character */
2361: inchar[1] = NUL;
2362: return((char *)inchar);
2363:
2364: case VN_ICNT: /* INPUT character count */
2365: sprintf(vvbuf,"%d",incount);
2366: return(vvbuf);
2367:
2368: case VN_SPEE: { /* Transmission SPEED */
2369: long t;
2370: t = ttgspd();
2371: if (t < 0L)
2372: sprintf(vvbuf,"unknown");
2373: else
2374: sprintf(vvbuf,"%ld",t);
2375: return(vvbuf);
2376: }
2377: case VN_SUCC: /* SUCCESS flag */
2378: sprintf(vvbuf,"%d",(success == 0) ? 1 : 0);
2379: return(vvbuf);
2380:
2381: case VN_LINE: /* LINE */
2382: p = (char *) ttname;
2383: return(p);
2384:
2385: case VN_PROG: /* Program name */
2386: #ifdef MAC
2387: return("Mac-Kermit");
2388: #else
2389: return("C-Kermit");
2390: #endif /* MAC */
2391:
2392: case VN_RET: /* Value of most recent RETURN */
2393: p = mrval[maclvl+1];
2394: if (p == NULL) p = "";
2395: return(p);
2396:
2397: case VN_FFC: /* Size of most recent file */
2398: sprintf(vvbuf, "%ld", ffc);
2399: return(vvbuf);
2400:
2401: case VN_TFC: /* Size of most recent file group */
2402: sprintf(vvbuf, "%ld", tfc);
2403: return(vvbuf);
2404:
2405: case VN_CPU: /* CPU type */
2406: #ifdef CKCPU
2407: return(CKCPU);
2408: #else
2409: return("unknown");
2410: #endif /* CKCPU */
2411:
2412: case VN_CMDL: /* Command level */
2413: sprintf(vvbuf, "%d", cmdlvl);
2414: return(vvbuf);
2415:
2416: case VN_DAY: /* Day of week */
2417: case VN_NDAY:
2418: /*
2419: Depends on ztime() returning ENGLISH asctime()-format string!
2420: asctime() format is: "Thu Feb 8 12:00:00 1990".
2421: Needs updating to accommodate non-English asctime() strings.
2422: */
2423: ztime(&p);
2424: if (p != NULL && *p != NUL) { /* ztime() succeeded. */
2425: if (y == VN_DAY) { /* String day. */
2426: strncpy(vvbuf,p,3);
2427: } else { /* Numeric day. */
2428: for (x = 0; x < 7; x++) /* Look up day string in table */
2429: if (!strncmp(p,wkdays[x],3))
2430: break;
2431: if (x > 6) x = -1; /* Not found */
2432: sprintf(vvbuf,"%d",x); /* Return the number */
2433: }
2434: } else vvbuf[0] = NUL; /* ztime() failed. */
2435: return(vvbuf); /* Return what we got. */
2436:
2437: case VN_LCL: /* Local (vs remote) mode */
2438: strcpy(vvbuf, local ? "1" : "0");
2439: return(vvbuf);
2440:
2441: case VN_CMDS: /* Command source */
2442: if (cmdstk[cmdlvl].src == CMD_KB)
2443: strcpy(vvbuf,"prompt");
2444: else if (cmdstk[cmdlvl].src == CMD_MD)
2445: strcpy(vvbuf,"macro");
2446: else if (cmdstk[cmdlvl].src == CMD_TF)
2447: strcpy(vvbuf,"file");
2448: else strcpy(vvbuf,"unknown");
2449: return(vvbuf);
2450:
2451: case VN_CMDF: /* Current command file name */
2452: return(tfnam[tlevel] ? tfnam[tlevel] : "");
2453:
2454: case VN_MAC: /* Current macro name */
2455: return((maclvl > -1) ? m_arg[maclvl][0] : "");
2456:
2457: case VN_EXIT:
2458: sprintf(vvbuf,"%d",xitsta);
2459: return(vvbuf);
2460:
2461: default:
2462: return(NULL);
2463: }
2464: }
2465: #endif /* NOSPL */
2466:
2467: /*
2468: X X S T R I N G -- Expand variables and backslash codes.
2469:
2470: int xxtstring(s,&s2,&n);
2471:
2472: Expands \ escapes via recursive descent.
2473: Argument s is a pointer to string to expand (source).
2474: Argument s2 is the address of where to put result (destination).
2475: Argument n is the length of the destination string (to prevent overruns).
2476: Returns -1 on failure, 0 on success,
2477: with destination string null-terminated and s2 pointing to the
2478: terminating null, so that subsequent characters can be added.
2479: */
2480:
2481: #define XXDEPLIM 100 /* Recursion depth limit */
2482:
2483: int
2484: xxstring(s,s2,n) char *s; char **s2; int *n; {
2485: int x, /* Current character */
2486: y, /* Worker */
2487: pp, /* Paren level */
2488: argn, /* Function argument counter */
2489: n2, /* Local copy of n */
2490: d, /* Array dimension */
2491: vbi, /* Variable id (integer form) */
2492: argl; /* String argument length */
2493:
2494: char vb, /* Variable id (char form) */
2495: *vp, /* Pointer to variable definition */
2496: *new, /* Local pointer to target string */
2497: *p, /* Worker */
2498: *q; /* Worker */
2499: char *r = (char *)0; /* For holding function args */
2500: char *r2 = (char *)0;
2501:
2502: #ifndef NOSPL
2503: char vnambuf[VNAML]; /* Buffer for variable/function name */
2504: char *argp[FNARGS]; /* Pointers to function args */
2505: #endif /* NOSPL */
2506:
2507: static int depth = 0; /* Call depth, avoid overflow */
2508:
2509: n2 = *n; /* Make local copies of args */
2510: new = *s2; /* for one less level of indirection */
2511:
2512: depth++; /* Sink to a new depth */
2513: if (depth > XXDEPLIM) { /* Too deep? */
2514: printf("?definition is circular or too deep\n");
2515: depth = 0;
2516: *new = NUL;
2517: return(-1);
2518: }
2519: if (!s || !new) { /* Watch out for null pointers */
2520: depth = 0;
2521: *new = NUL;
2522: return(-1);
2523: }
2524: argl = (int)strlen(s); /* Get length of source string */
2525: debug(F111,"xxstring",s,argl);
2526: if (argl < 0) { /* Watch out for garbage */
2527: depth = 0;
2528: *new = NUL;
2529: return(-1);
2530: }
2531: while ( x = *s ) { /* Loop for all characters */
2532: if (x != CMDQ) { /* Is it the command-quote char? */
2533: *new++ = *s++; /* No, normal char, just copy */
2534: if (n2-- < 0) { /* and count it, careful of overflow */
2535: return(-1);
2536: }
2537: continue;
2538: }
2539:
2540: /* We have the command-quote character. */
2541:
2542: x = *(s+1); /* Get the following character. */
2543: switch (x) { /* Act according to variable type */
2544: #ifndef NOSPL
2545: case '%': /* Variable */
2546: s += 2; /* Get the letter or digit */
2547: vb = *s++; /* and move source pointer past it */
2548: vp = NULL; /* Assume definition is empty */
2549: if (vb >= '0' && vb <= '9') { /* Digit for macro arg */
2550: if (maclvl < 0) /* Digit variables are global */
2551: vp = g_var[vb]; /* if no macro is active */
2552: else /* otherwise */
2553: vp = m_arg[maclvl][vb - '0']; /* they're on the stack */
2554: } else {
2555: if (isupper(vb)) vb -= ('a'-'A');
2556: vp = g_var[vb]; /* Letter for global variable */
2557: }
2558: if (vp) { /* If definition not empty */
2559: if (xxstring(vp,&new,&n2) < 0) { /* call self to evaluate it */
2560: return(-1); /* Pass along failure */
2561: }
2562: }
2563: break;
2564: case '&': /* An array reference */
2565: if (arraynam(s,&vbi,&d) < 0) { /* Get name and subscript */
2566: return(-1);
2567: }
2568: pp = 0; /* Bracket counter */
2569: while (*s) { /* Advance source pointer */
2570: if (*s == '[') pp++;
2571: if (*s == ']' && --pp == 0) break;
2572: s++;
2573: }
2574: if (*s == ']') s++; /* past the closing bracket. */
2575: if (chkarray(vbi,d) > 0) { /* Array is declared? */
2576: vbi -= 96; /* Convert name to index */
2577: if (a_dim[vbi] >= d) { /* If subscript in range */
2578: char **ap;
2579: ap = a_ptr[vbi]; /* get data pointer */
2580: if (ap) { /* and if there is one */
2581: if (ap[d]) { /* If definition not empty */
2582: if (xxstring(ap[d],&new,&n2) < 0) { /* evaluate */
2583: return(-1); /* Pass along failure */
2584: }
2585: }
2586: }
2587: }
2588: }
2589: break;
2590:
2591: case 'F': /* A builtin function */
2592: case 'f':
2593: q = vnambuf; /* Copy the name */
2594: y = 0; /* into a separate buffer */
2595: s+=2; /* point past 'F' */
2596: while (y++ < VNAML) {
2597: if (*s == '(') { s++; break; } /* Look for open paren */
2598: if ((*q = *s) == NUL) break; /* or end of string */
2599: s++; q++;
2600: }
2601: *q = NUL; /* Terminate function name */
2602: if (y >= VNAML) { /* Handle pathological case */
2603: while (*s && (*s != '(')) /* of very long string entered */
2604: s++; /* as function name. */
2605: if (*s == ')') s++; /* Skip past it. */
2606: }
2607: r = r2 = malloc(argl+2); /* And make a place to copy args */
2608: debug(F101,"xxstring r2","",r2);
2609: if (!r2) { /* Watch out for malloc failure */
2610: depth = 0;
2611: *new = NUL;
2612: return(-1);
2613: }
2614: argn = 0; /* Argument counter */
2615: argp[argn++] = r; /* Point to first argument */
2616: y = 0; /* Completion flag */
2617: pp = 1; /* Paren level (already have one). */
2618: while (*r = *s) { /* Copy each argument, char by char. */
2619: if (*r == '(') pp++; /* Count an opening paren. */
2620: if (*r == ')') { /* Closing paren, count it. */
2621: if (--pp == 0) { /* Final one? */
2622: *r = NUL; /* Make it a terminating null */
2623: s++;
2624: y = 1; /* Flag we've got all the args */
2625: break;
2626: }
2627: }
2628: if (*r == ',') { /* Comma */
2629: if (pp == 1) { /* If not within ()'s, */
2630: *r = NUL; /* new arg, skip past it, */
2631: argp[argn++] = r+1; /* point to new arg. */
2632: if (argn == FNARGS) /* Too many args */
2633: break;
2634: } /* Otherwise just skip past */
2635: }
2636: s++; r++; /* Advance pointers */
2637: }
2638: debug(F110,"xxstring function name",vnambuf,0);
2639: if (!y) { /* If we didn't find closing paren */
2640: debug(F101,"xxstring r2 before free","",r2);
2641: if (r2) free(r2); /* free the temporary storage */
2642: return(-1); /* and return failure. */
2643: }
2644: #ifdef DEBUG
2645: if (deblog)
2646: for (y = 0; y < argn; y++)
2647: debug(F111,"xxstring function arg",argp[y],y);
2648: #endif /* DEBUG */
2649: vp = fneval(vnambuf,argp,argn); /* Evaluate the function. */
2650: if (vp) { /* If definition not empty */
2651: while (*new++ = *vp++) /* copy it to output string */
2652: if (n2-- < 0) return(-1); /* mindful of overflow */
2653: new--; /* Back up over terminating null */
2654: n2++; /* to allow for further deposits. */
2655: }
2656: if (r2) {
2657: debug(F101,"xxstring freeing r2","",r2);
2658: free(r2); /* Now free the temporary storage */
2659: r2 = NULL;
2660: }
2661: break;
2662: case '$': /* An environment variable */
2663: case 'V': /* Or a named builtin variable. */
2664: case 'v':
2665: case 'M': /* Or a macro = long variable */
2666: case 'm':
2667: p = s+2; /* $/V/M must be followed by (name) */
2668: if (*p != '(') { /* as in \$(HOME) or \V(count) */
2669: *new++ = *s++; /* If not, just copy it */
2670: if (n2-- < 0) {
2671: return(-1);
2672: }
2673: break;
2674: }
2675: p++; /* Point to 1st char of name */
2676: q = vnambuf; /* Copy the name */
2677: y = 0; /* into a separate buffer */
2678: while (y++ < VNAML) { /* Watch out for name too long */
2679: if (*p == ')') { /* Name properly terminated with ')' */
2680: p++; /* Move source pointer past ')' */
2681: break;
2682: }
2683: if ((*q = *p) == NUL) /* String ends before ')' */
2684: break;
2685: p++; q++; /* Advance pointers */
2686: }
2687: *q = NUL; /* Terminate the variable name */
2688: if (y >= VNAML) { /* Handle pathological case */
2689: while (*p && (*p != ')')) /* of very long string entered */
2690: p++; /* as variable name. */
2691: if (*p == ')') p++; /* Skip ahead to the end of it. */
2692: }
2693: s = p; /* Adjust global source pointer */
2694: p = malloc((int)strlen(vnambuf) + 1); /* Make temporary space */
2695: if (p) { /* If we got the space */
2696: vp = vnambuf; /* Point to original */
2697: strcpy(p,vp); /* Make a copy of it */
2698: y = VNAML; /* Length of name buffer */
2699: xxstring(p,&vp,&y); /* Evaluate the copy */
2700: free(p); /* Free the temporary space */
2701: }
2702: debug(F110,"xxstring vname",vnambuf,0);
2703: if (x == '$') { /* Look up its value */
2704: vp = getenv(vnambuf); /* This way for environment variable */
2705: } else if (x == 'm' || x == 'M') { /* or this way for macro */
2706: y = mlook(mactab,vnambuf,nmac); /* contents (= long variable */
2707: vp = (y > -1) ? mactab[y].mval : ""; /* name)... */
2708: } else { /* or */
2709: vp = nvlook(vnambuf); /* this way for builtin variable */
2710: }
2711: if (vp) { /* If definition not empty */
2712: while (*new++ = *vp++) /* copy it to output string. */
2713: if (n2-- < 0) {
2714: return(-1);
2715: }
2716: new--; /* Back up over terminating null */
2717: n2++; /* to allow for further deposits. */
2718: }
2719: break;
2720: #endif /* NOSPL */ /* Handle \nnn even if NOSPL. */
2721: default: /* Maybe it's a backslash code */
2722: y = xxesc(&s); /* Go interpret it */
2723: if (y < 0) { /* Upon failure */
2724: *new++ = x; /* Just quote the next character */
2725: s += 2; /* Move past the pair */
2726: n2 -= 2;
2727: if (n2 < 0) {
2728: return(-1);
2729: }
2730: continue; /* and go back for more */
2731: } else {
2732: *new++ = y; /* else deposit interpreted value */
2733: if (n2-- < 0) {
2734: return(-1);
2735: }
2736: }
2737: }
2738: }
2739: *new = NUL; /* Terminate the new string */
2740: depth--; /* Adjust stack depth gauge */
2741: *s2 = new; /* Copy results back into */
2742: *n = n2; /* the argument addresses */
2743: return(0); /* and return. */
2744: }
2745: #endif /* NOICP */
2746:
2747:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.