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