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 (fdc@columbia.edu, FDCCU@CUVMA.BITNET), 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 */