|
|
1.1 ! root 1: int cmdmsk = 127; /* Command-terminal-to-C-Kermit character mask */ ! 2: ! 3: #include "ckcdeb.h" /* Formats for debug(), etc. */ ! 4: _PROTOTYP( int unhex, (char) ); ! 5: ! 6: #ifndef NOICP /* The rest only if interactive command parsing selected */ ! 7: ! 8: char *cmdv = "Command package 5A(048), 8 Feb 92"; ! 9: ! 10: /* C K U C M D -- Interactive command package for Unix */ ! 11: ! 12: /* ! 13: Author: Frank da Cruz ([email protected], [email protected]), ! 14: Columbia University Center for Computing Activities. ! 15: First released January 1985. ! 16: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New ! 17: York. Permission is granted to any individual or institution to use, copy, or ! 18: redistribute this software so long as it is not sold for profit, provided this ! 19: copyright notice is retained. ! 20: */ ! 21: ! 22: /* ! 23: Modelled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. ! 24: Features: ! 25: . parses and verifies keywords, filenames, text strings, numbers, other data ! 26: . displays appropriate menu or help message when user types "?" ! 27: . does keyword and filename completion when user types ESC or TAB ! 28: . does partial filename completion ! 29: . accepts any unique abbreviation for a keyword ! 30: . allows keywords to have attributes, like "invisible" and "abbreviation" ! 31: . can supply defaults for fields omitted by user ! 32: . provides command line editing (character, word, and line deletion) ! 33: . accepts input from keyboard, command files, or redirected stdin ! 34: . allows for full or half duplex operation, character or line input ! 35: . settable prompt, protected from deletion ! 36: ! 37: Functions: ! 38: cmsetp - Set prompt (cmprom is prompt string) ! 39: cmsavp - Save current prompt ! 40: prompt - Issue prompt ! 41: cmini - Clear the command buffer (before parsing a new command) ! 42: cmres - Reset command buffer pointers (before reparsing) ! 43: cmkey - Parse a keyword ! 44: cmnum - Parse a number ! 45: cmifi - Parse an input file name ! 46: cmofi - Parse an output file name ! 47: cmdir - Parse a directory name (UNIX only) ! 48: cmfld - Parse an arbitrary field ! 49: cmtxt - Parse a text string ! 50: cmcfm - Parse command confirmation (end of line) ! 51: ! 52: Return codes: ! 53: -3: no input provided when required ! 54: -2: input was invalid (e.g. not a number when a number was required) ! 55: -1: reparse required (user deleted into a preceding field) ! 56: 0 or greater: success ! 57: See individual functions for greater detail. ! 58: ! 59: Before using these routines, the caller should #include ckucmd.h, and set the ! 60: program's prompt by calling cmsetp(). If the file parsing functions cmifi, ! 61: cmofi, or cmdir are to be used, this module must be linked with a ck?fio file ! 62: system support module for the appropriate system, e.g. ckufio for Unix. If ! 63: the caller puts the terminal in character wakeup ("cbreak") mode with no echo, ! 64: then these functions will provide line editing -- character, word, and line ! 65: deletion, as well as keyword and filename completion upon ESC and help ! 66: strings, keyword, or file menus upon '?'. If the caller puts the terminal ! 67: into character wakeup/noecho mode, care should be taken to restore it before ! 68: exit from or interruption of the program. If the character wakeup mode is not ! 69: set, the system's own line editor may be used. ! 70: ! 71: NOTE: Contrary to expectations, many #ifdef's have been added to this module. ! 72: Any operation requiring an #ifdef (like clear screen, get character from ! 73: keyboard, erase character from screen, etc) should eventually be turned into a ! 74: call to a function that is defined in ck?tio.c, but then all the ck?tio.c ! 75: modules would have to be changed... ! 76: */ ! 77: ! 78: /* Includes */ ! 79: ! 80: #include "ckcker.h" /* (===OS2 addition===) */ ! 81: #include "ckcasc.h" /* ASCII character symbols */ ! 82: #include "ckucmd.h" /* Command parsing definitions */ ! 83: #include <errno.h> /* Error number symbols */ ! 84: ! 85: #ifdef OSK ! 86: #define cc ccount /* OS-9/68K compiler bug */ ! 87: #endif /* OSK */ ! 88: ! 89: #ifdef GEMDOS /* Atari ST */ ! 90: #ifdef putchar ! 91: #undef putchar ! 92: #endif /* putchar */ ! 93: #define putchar(x) conoc(x) /* Why doesn't everyone do this? */ ! 94: #endif /* GEMDOS */ ! 95: ! 96: /* Local variables */ ! 97: ! 98: int psetf = 0, /* Flag that prompt has been set */ ! 99: cc = 0, /* Character count */ ! 100: dpx = 0; /* Duplex (0 = full) */ ! 101: ! 102: int hw = HLPLW, /* Help line width */ ! 103: hc = HLPCW, /* Help line column width */ ! 104: hh, /* Current help column number */ ! 105: hx; /* Current help line position */ ! 106: ! 107: #define PROML 160 /* Maximum length for prompt */ ! 108: ! 109: char cmprom[PROML+1]; /* Program's prompt */ ! 110: char cmprxx[PROML+1]; /* Program's prompt, unevaluated */ ! 111: char *dfprom = "Command? "; /* Default prompt */ ! 112: ! 113: int cmflgs; /* Command flags */ ! 114: int cmfsav; /* A saved version of them */ ! 115: ! 116: #ifdef DCMDBUF ! 117: char *cmdbuf; /* Command buffer */ ! 118: char *savbuf; /* Help string buffer */ ! 119: char *hlpbuf; /* Atom buffer */ ! 120: char *atmbuf; /* File name buffer */ ! 121: char *atxbuf; /* For expanding the atom buffer */ ! 122: int atxn; /* Length of expansion buffer */ ! 123: char *atybuf; /* For copying atom buffer */ ! 124: char *filbuf; /* Buffer to save copy of command */ ! 125: #else ! 126: char cmdbuf[CMDBL+4]; /* Command buffer */ ! 127: char hlpbuf[HLPBL+4]; /* Help string buffer */ ! 128: char atmbuf[ATMBL+4]; /* Atom buffer */ ! 129: char filbuf[ATMBL+4]; /* File name buffer */ ! 130: char atxbuf[CMDBL+4]; /* For expanding the atom buffer */ ! 131: int atxn; /* Length of expansion buffer */ ! 132: char atybuf[ATMBL+4]; /* For copying atom buffer */ ! 133: char savbuf[CMDBL+4]; /* Buffer to save copy of command */ ! 134: #endif /* COMMENT */ ! 135: ! 136: /* Command buffer pointers */ ! 137: ! 138: static char *bp, /* Current command buffer position */ ! 139: *pp, /* Start of current field */ ! 140: *np; /* Start of next field */ ! 141: ! 142: static int ungw; /* For ungetting words */ ! 143: ! 144: _PROTOTYP( VOID addhlp, (char *) ); ! 145: _PROTOTYP( VOID clrhlp, (void) ); ! 146: _PROTOTYP( VOID dmphlp, (void) ); ! 147: _PROTOTYP( int gtword, (void) ); ! 148: _PROTOTYP( int addbuf, (char *) ); ! 149: _PROTOTYP( int setatm, (char *) ); ! 150: _PROTOTYP( int cmdgetc, (void) ); ! 151: _PROTOTYP( VOID cmdnewl, (char) ); ! 152: _PROTOTYP( VOID cmdchardel, (void) ); ! 153: _PROTOTYP( VOID cmdecho, (char, int) ); ! 154: _PROTOTYP( static int test, (int, int) ); ! 155: ! 156: /* T E S T -- Bit test */ ! 157: ! 158: static int ! 159: test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */ ! 160: return((x & m) ? 1 : 0); ! 161: } ! 162: ! 163: /* C M S E T U P -- Set up command buffers */ ! 164: ! 165: #ifdef DCMDBUF ! 166: int ! 167: cmsetup() { ! 168: if (!(cmdbuf = malloc(CMDBL + 4))) return(-1); ! 169: if (!(savbuf = malloc(CMDBL + 4))) return(-1); ! 170: savbuf[0] = '\0'; ! 171: if (!(hlpbuf = malloc(HLPBL + 4))) return(-1); ! 172: if (!(atmbuf = malloc(ATMBL + 4))) return(-1); ! 173: if (!(atxbuf = malloc(CMDBL + 4))) return(-1); ! 174: if (!(atybuf = malloc(ATMBL + 4))) return(-1); ! 175: if (!(filbuf = malloc(ATMBL + 4))) return(-1); ! 176: return(0); ! 177: } ! 178: #endif /* COMMENT */ ! 179: ! 180: /* C M S E T P -- Set the program prompt. */ ! 181: ! 182: VOID ! 183: cmsetp(s) char *s; { ! 184: strncpy(cmprxx,s,PROML - 1); ! 185: cmprxx[PROML] = NUL; ! 186: psetf = 1; /* Flag that prompt has been set. */ ! 187: } ! 188: /* C M S A V P -- Save a copy of the current prompt. */ ! 189: ! 190: VOID ! 191: #ifdef CK_ANSIC ! 192: cmsavp(char s[], int n) ! 193: #else ! 194: cmsavp(s,n) int n; char s[]; ! 195: #endif /* CK_ANSIC */ ! 196: /* cmsavp */ { ! 197: strncpy(s,cmprxx,n-1); ! 198: s[n-1] = NUL; ! 199: } ! 200: ! 201: /* P R O M P T -- Issue the program prompt. */ ! 202: ! 203: VOID ! 204: prompt(f) xx_strp f; { ! 205: char *sx, *sy; int n; ! 206: ! 207: if (psetf == 0) cmsetp(dfprom); /* If no prompt set, set default. */ ! 208: ! 209: sx = cmprxx; /* Unevaluated copy */ ! 210: if (f) { /* If conversion function given */ ! 211: sy = cmprom; /* Evaluate it */ ! 212: n = PROML; ! 213: if ((*f)(sx,&sy,&n) < 0) /* If evaluation failed */ ! 214: sx = cmprxx; /* revert to unevaluated copy */ ! 215: else ! 216: sx = cmprom; ! 217: } ! 218: #ifdef OSK ! 219: fputs(sx, stdout); ! 220: #else ! 221: #ifdef MAC ! 222: printf("%s", sx); ! 223: #else ! 224: printf("\r%s",sx); /* Print the prompt. */ ! 225: fflush(stdout); /* Now! */ ! 226: #endif /* MAC */ ! 227: #endif /* OSK */ ! 228: } ! 229: ! 230: #ifndef NOSPL ! 231: VOID ! 232: pushcmd() { /* For use with IF command. */ ! 233: strcpy(savbuf,np); /* Save the dependent clause, */ ! 234: cmres(); /* and clear the command buffer. */ ! 235: debug(F110, "pushcmd: savbuf:", savbuf, 0); ! 236: } ! 237: #endif /* NOSPL */ ! 238: ! 239: #ifdef COMMENT ! 240: /* no longer used... */ ! 241: VOID ! 242: popcmd() { ! 243: strcpy(cmdbuf,savbuf); /* Put back the saved material */ ! 244: *savbuf = '\0'; /* and clear the save buffer */ ! 245: cmres(); ! 246: } ! 247: #endif /* COMMENT */ ! 248: ! 249: /* C M R E S -- Reset pointers to beginning of command buffer. */ ! 250: ! 251: VOID ! 252: cmres() { ! 253: cc = 0; /* Reset character counter. */ ! 254: pp = np = bp = cmdbuf; /* Point to command buffer. */ ! 255: cmflgs = -5; /* Parse not yet started. */ ! 256: ungw = 0; /* Don't need to unget a word. */ ! 257: } ! 258: ! 259: /* C M I N I -- Clear the command and atom buffers, reset pointers. */ ! 260: ! 261: /* ! 262: The argument specifies who is to echo the user's typein -- ! 263: 1 means the cmd package echoes ! 264: 0 somebody else (system, front end, terminal) echoes ! 265: */ ! 266: VOID ! 267: cmini(d) int d; { ! 268: for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL; ! 269: *atmbuf = NUL; ! 270: dpx = d; ! 271: cmres(); ! 272: } ! 273: ! 274: #ifndef NOSPL ! 275: /* The following bits are to allow the command package to call itself */ ! 276: /* in the middle of a parse. To do this, begin by calling cmpush, and */ ! 277: /* end by calling cmpop. */ ! 278: ! 279: #ifdef DCMDBUF ! 280: struct cmp { ! 281: int i[5]; /* stack for integers */ ! 282: char *c[3]; /* stack for pointers */ ! 283: char *b[8]; /* stack for buffer contents */ ! 284: }; ! 285: struct cmp *cmp = 0; ! 286: #else ! 287: int cmp_i[CMDDEP+1][5]; /* Stack for integers */ ! 288: char *cmp_c[CMDDEP+1][5]; /* for misc pointers */ ! 289: char *cmp_b[CMDDEP+1][7]; /* for buffer contents pointers */ ! 290: #endif /* DCMDBUF */ ! 291: ! 292: int cmddep = -1; /* Current stack depth */ ! 293: ! 294: int ! 295: cmpush() { /* Save the command environment */ ! 296: char *cp; /* Character pointer */ ! 297: ! 298: if (++cmddep > CMDDEP) return(-1); /* Enter a new command depth */ ! 299: debug(F101,"&cmpush","",cmddep); ! 300: ! 301: #ifdef DCMDBUF ! 302: /* allocate memory for cmp if not already done */ ! 303: if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1)))) ! 304: fatal("cmpush: no memory for cmp"); ! 305: cmp[cmddep].i[0] = cmflgs; /* First do the global ints */ ! 306: cmp[cmddep].i[1] = cmfsav; ! 307: cmp[cmddep].i[2] = atxn; ! 308: cmp[cmddep].i[3] = ungw; ! 309: ! 310: cmp[cmddep].c[0] = bp; /* Then the global pointers */ ! 311: cmp[cmddep].c[1] = pp; ! 312: cmp[cmddep].c[2] = np; ! 313: #else ! 314: cmp_i[cmddep][0] = cmflgs; /* First do the global ints */ ! 315: cmp_i[cmddep][1] = cmfsav; ! 316: cmp_i[cmddep][2] = atxn; ! 317: cmp_i[cmddep][3] = ungw; ! 318: ! 319: cmp_c[cmddep][0] = bp; /* Then the global pointers */ ! 320: cmp_c[cmddep][1] = pp; ! 321: cmp_c[cmddep][2] = np; ! 322: #endif /* DCMDBUF */ ! 323: ! 324: /* Now the buffers themselves. A lot of repititious code... */ ! 325: ! 326: #ifdef DCMDBUF ! 327: cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */ ! 328: if (cp) strcpy(cp,cmdbuf); ! 329: cmp[cmddep].b[0] = cp; ! 330: if (cp == NULL) return(-1); ! 331: ! 332: cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */ ! 333: if (cp) strcpy(cp,savbuf); ! 334: cmp[cmddep].b[1] = cp; ! 335: if (cp == NULL) return(-1); ! 336: ! 337: cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */ ! 338: if (cp) strcpy(cp,hlpbuf); ! 339: cmp[cmddep].b[2] = cp; ! 340: if (cp == NULL) return(-1); ! 341: ! 342: cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */ ! 343: if (cp) strcpy(cp,atmbuf); ! 344: cmp[cmddep].b[3] = cp; ! 345: if (cp == NULL) return(-1); ! 346: ! 347: cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */ ! 348: if (cp) strcpy(cp,atxbuf); ! 349: cmp[cmddep].b[4] = cp; ! 350: if (cp == NULL) return(-1); ! 351: ! 352: cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */ ! 353: if (cp) strcpy(cp,atybuf); ! 354: cmp[cmddep].b[5] = cp; ! 355: if (cp == NULL) return(-1); ! 356: ! 357: cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */ ! 358: if (cp) strcpy(cp,filbuf); ! 359: cmp[cmddep].b[6] = cp; ! 360: if (cp == NULL) return(-1); ! 361: #else ! 362: cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */ ! 363: if (cp) strcpy(cp,cmdbuf); ! 364: cmp_b[cmddep][0] = cp; ! 365: if (cp == NULL) return(-1); ! 366: ! 367: cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */ ! 368: if (cp) strcpy(cp,savbuf); ! 369: cmp_b[cmddep][1] = cp; ! 370: if (cp == NULL) return(-1); ! 371: ! 372: cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */ ! 373: if (cp) strcpy(cp,hlpbuf); ! 374: cmp_b[cmddep][2] = cp; ! 375: if (cp == NULL) return(-1); ! 376: ! 377: cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */ ! 378: if (cp) strcpy(cp,atmbuf); ! 379: cmp_b[cmddep][3] = cp; ! 380: if (cp == NULL) return(-1); ! 381: ! 382: cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */ ! 383: if (cp) strcpy(cp,atxbuf); ! 384: cmp_b[cmddep][4] = cp; ! 385: if (cp == NULL) return(-1); ! 386: ! 387: cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */ ! 388: if (cp) strcpy(cp,atybuf); ! 389: cmp_b[cmddep][5] = cp; ! 390: if (cp == NULL) return(-1); ! 391: ! 392: cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */ ! 393: if (cp) strcpy(cp,filbuf); ! 394: cmp_b[cmddep][6] = cp; ! 395: if (cp == NULL) return(-1); ! 396: #endif /* DCMDBUF */ ! 397: ! 398: cmini(dpx); /* Initize the command parser */ ! 399: return(0); ! 400: } ! 401: ! 402: int ! 403: cmpop() { /* Restore the command environment */ ! 404: debug(F101,"&cmpop","",cmddep); ! 405: if (cmddep < 0) return(-1); /* Don't pop too much! */ ! 406: ! 407: #ifdef DCMDBUF ! 408: cmflgs = cmp[cmddep].i[0]; /* First do the global ints */ ! 409: cmfsav = cmp[cmddep].i[1]; ! 410: atxn = cmp[cmddep].i[2]; ! 411: ungw = cmp[cmddep].i[3]; ! 412: ! 413: bp = cmp[cmddep].c[0]; /* Then the global pointers */ ! 414: pp = cmp[cmddep].c[1]; ! 415: np = cmp[cmddep].c[2]; ! 416: #else ! 417: cmflgs = cmp_i[cmddep][0]; /* First do the global ints */ ! 418: cmfsav = cmp_i[cmddep][1]; ! 419: atxn = cmp_i[cmddep][2]; ! 420: ungw = cmp_i[cmddep][3]; ! 421: ! 422: bp = cmp_c[cmddep][0]; /* Then the global pointers */ ! 423: pp = cmp_c[cmddep][1]; ! 424: np = cmp_c[cmddep][2]; ! 425: #endif /* DCMDBUF */ ! 426: ! 427: /* Now the buffers themselves. */ ! 428: ! 429: #ifdef DCMDBUF ! 430: if (cmp[cmddep].b[0]) { ! 431: strcpy(cmdbuf,cmp[cmddep].b[0]); /* 0: Command buffer */ ! 432: free(cmp[cmddep].b[0]); ! 433: cmp[cmddep].b[0] = NULL; ! 434: } ! 435: if (cmp[cmddep].b[1]) { ! 436: strcpy(savbuf,cmp[cmddep].b[1]); /* 1: Save buffer */ ! 437: free(cmp[cmddep].b[1]); ! 438: cmp[cmddep].b[1] = NULL; ! 439: } ! 440: if (cmp[cmddep].b[2]) { ! 441: strcpy(hlpbuf,cmp[cmddep].b[2]); /* 2: Help buffer */ ! 442: free(cmp[cmddep].b[2]); ! 443: cmp[cmddep].b[2] = NULL; ! 444: } ! 445: if (cmp[cmddep].b[3]) { ! 446: strcpy(atmbuf,cmp[cmddep].b[3]); /* 3: Atomic buffer! */ ! 447: free(cmp[cmddep].b[3]); ! 448: cmp[cmddep].b[3] = NULL; ! 449: } ! 450: if (cmp[cmddep].b[4]) { ! 451: strcpy(atxbuf,cmp[cmddep].b[4]); /* 4: eXpansion buffer */ ! 452: free(cmp[cmddep].b[4]); ! 453: cmp[cmddep].b[4] = NULL; ! 454: } ! 455: if (cmp[cmddep].b[5]) { ! 456: strcpy(atybuf,cmp[cmddep].b[5]); /* 5: Atom buffer copY */ ! 457: free(cmp[cmddep].b[5]); ! 458: cmp[cmddep].b[5] = NULL; ! 459: } ! 460: if (cmp[cmddep].b[6]) { ! 461: strcpy(filbuf,cmp[cmddep].b[6]); /* 6: Filename buffer */ ! 462: free(cmp[cmddep].b[6]); ! 463: cmp[cmddep].b[6] = NULL; ! 464: } ! 465: #else ! 466: if (cmp_b[cmddep][0]) { ! 467: strcpy(cmdbuf,cmp_b[cmddep][0]); /* 0: Command buffer */ ! 468: free(cmp_b[cmddep][0]); ! 469: cmp_b[cmddep][0] = NULL; ! 470: } ! 471: if (cmp_b[cmddep][1]) { ! 472: strcpy(savbuf,cmp_b[cmddep][1]); /* 1: Save buffer */ ! 473: free(cmp_b[cmddep][1]); ! 474: cmp_b[cmddep][1] = NULL; ! 475: } ! 476: if (cmp_b[cmddep][2]) { ! 477: strcpy(hlpbuf,cmp_b[cmddep][2]); /* 2: Help buffer */ ! 478: free(cmp_b[cmddep][2]); ! 479: cmp_b[cmddep][2] = NULL; ! 480: } ! 481: if (cmp_b[cmddep][3]) { ! 482: strcpy(atmbuf,cmp_b[cmddep][3]); /* 3: Atomic buffer! */ ! 483: free(cmp_b[cmddep][3]); ! 484: cmp_b[cmddep][3] = NULL; ! 485: } ! 486: if (cmp_b[cmddep][4]) { ! 487: strcpy(atxbuf,cmp_b[cmddep][4]); /* 4: eXpansion buffer */ ! 488: free(cmp_b[cmddep][4]); ! 489: cmp_b[cmddep][4] = NULL; ! 490: } ! 491: if (cmp_b[cmddep][5]) { ! 492: strcpy(atybuf,cmp_b[cmddep][5]); /* 5: Atom buffer copY */ ! 493: free(cmp_b[cmddep][5]); ! 494: cmp_b[cmddep][5] = NULL; ! 495: } ! 496: if (cmp_b[cmddep][6]) { ! 497: strcpy(filbuf,cmp_b[cmddep][6]); /* 6: Filename buffer */ ! 498: free(cmp_b[cmddep][6]); ! 499: cmp_b[cmddep][6] = NULL; ! 500: } ! 501: #endif /* DCMDBUF */ ! 502: ! 503: cmddep--; /* Rise, rise */ ! 504: debug(F101,"&cmpop","",cmddep); ! 505: return(cmddep); ! 506: } ! 507: #endif /* NOSPL */ ! 508: ! 509: #ifdef COMMENT ! 510: VOID ! 511: stripq(s) char *s; { /* Function to strip '\' quotes */ ! 512: char *t; ! 513: while (*s) { ! 514: if (*s == CMDQ) { ! 515: for (t = s; *t != '\0'; t++) *t = *(t+1); ! 516: } ! 517: s++; ! 518: } ! 519: } ! 520: #endif /* COMMENT */ ! 521: ! 522: /* Convert tabs to spaces, one for one */ ! 523: VOID ! 524: untab(s) char *s; { ! 525: while (*s) { ! 526: if (*s == HT) *s = SP; ! 527: s++; ! 528: } ! 529: } ! 530: ! 531: /* C M N U M -- Parse a number in the indicated radix */ ! 532: ! 533: /* ! 534: The only radix allowed in unquoted numbers is 10. ! 535: Parses unquoted numeric strings in base 10. ! 536: Parses backslash-quoted numbers in the radix indicated by the quote: ! 537: \nnn = \dnnn = decimal, \onnn = octal, \xnn = Hexadecimal. ! 538: If these fail, then if a preprocessing function is supplied, that is applied ! 539: and then a second attempt is made to parse an unquoted decimal string. ! 540: ! 541: Returns: ! 542: -3 if no input present when required, ! 543: -2 if user typed an illegal number, ! 544: -1 if reparse needed, ! 545: 0 otherwise, with argument n set to the number that was parsed ! 546: */ ! 547: int ! 548: cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; { ! 549: int x; char *s, *zp, *zq; ! 550: ! 551: if (radix != 10) { /* Just do base 10 */ ! 552: printf("cmnum: illegal radix - %d\n",radix); ! 553: return(-1); ! 554: } ! 555: x = cmfld(xhlp,xdef,&s,(xx_strp)0); ! 556: debug(F101,"cmnum: cmfld","",x); ! 557: if (x < 0) return(x); /* Parse a field */ ! 558: zp = atmbuf; ! 559: ! 560: if (chknum(zp)) { /* Check for decimal number */ ! 561: *n = atoi(zp); /* Got one, we're done. */ ! 562: debug(F101,"cmnum 1st chknum ok","",*n); ! 563: return(0); ! 564: } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */ ! 565: *n = x; ! 566: debug(F101,"cmnum xxesc ok","",*n); ! 567: return(*zp ? -2 : 0); ! 568: } else if (f) { /* If conversion function given */ ! 569: zp = atmbuf; /* Try that */ ! 570: zq = atxbuf; ! 571: atxn = CMDBL; ! 572: (*f)(zp,&zq,&atxn); /* Convert */ ! 573: zp = atxbuf; ! 574: } ! 575: debug(F110,"cmnum zp",zp,0); ! 576: if (chknum(zp)) { /* Check again for decimal number */ ! 577: *n = atoi(zp); /* Got one, we're done. */ ! 578: debug(F101,"cmnum 2nd chknum ok","",*n); ! 579: return(0); ! 580: } else { /* Not numeric */ ! 581: return(-2); ! 582: } ! 583: } ! 584: ! 585: /* C M O F I -- Parse the name of an output file */ ! 586: ! 587: /* ! 588: Depends on the external function zchko(); if zchko() not available, use ! 589: cmfld() to parse output file names. ! 590: ! 591: Returns ! 592: -3 if no input present when required, ! 593: -2 if permission would be denied to create the file, ! 594: -1 if reparse needed, ! 595: 0 or 1 otherwise, with xp pointing to name. ! 596: */ ! 597: int ! 598: cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; { ! 599: int x; char *s, *zq; ! 600: #ifdef DTILDE ! 601: _PROTOTYP( char * tilde_expand, (char *) ); ! 602: char *dirp; ! 603: #endif ! 604: ! 605: if (*xhlp == NUL) xhlp = "Output file"; ! 606: *xp = ""; ! 607: ! 608: if ((x = cmfld(xhlp,xdef,&s,(xx_strp)0)) < 0) return(x); ! 609: ! 610: if (f) { /* If a conversion function is given */ ! 611: zq = atxbuf; ! 612: atxn = CMDBL; ! 613: if ((x = (*f)(s,&zq,&atxn)) < 0) return(-2); ! 614: s = atxbuf; ! 615: } ! 616: ! 617: #ifdef DTILDE ! 618: dirp = tilde_expand(s); /* Expand tilde, if any, */ ! 619: if (*dirp != '\0') setatm(dirp); /* right in the atom buffer. */ ! 620: s = atmbuf; ! 621: #endif ! 622: ! 623: if (iswild(s)) { ! 624: printf("?Wildcards not allowed - %s\n",s); ! 625: return(-2); ! 626: } ! 627: if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* ok to write to tty */ ! 628: printf("?Write permission denied - %s\n",s); ! 629: return(-9); ! 630: } else { ! 631: *xp = s; ! 632: return(x); ! 633: } ! 634: } ! 635: ! 636: ! 637: /* C M I F I -- Parse the name of an existing file */ ! 638: ! 639: /* ! 640: This function depends on the external functions: ! 641: zchki() - Check if input file exists and is readable. ! 642: zxpand() - Expand a wild file specification into a list. ! 643: znext() - Return next file name from list. ! 644: If these functions aren't available, then use cmfld() to parse filenames. ! 645: */ ! 646: /* ! 647: Returns ! 648: -4 EOF ! 649: -3 if no input present when required, ! 650: -2 if file does not exist or is not readable, ! 651: -1 if reparse needed, ! 652: 0 or 1 otherwise, with: ! 653: xp pointing to name, ! 654: wild = 1 if name contains '*' or '?', 0 otherwise. ! 655: */ ! 656: int ! 657: cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; { ! 658: int i, x, xc; long y; char *sp, *zq, *sv; ! 659: #ifdef DTILDE ! 660: char *tilde_expand(), *dirp; ! 661: #endif ! 662: ! 663: ! 664: #ifndef NOPARTIAL ! 665: extern char *mtchs[]; ! 666: #endif ! 667: ! 668: cc = xc = 0; /* Initialize counts & pointers */ ! 669: *xp = ""; ! 670: if ((x = cmflgs) != 1) { /* Already confirmed? */ ! 671: x = gtword(); /* No, get a word */ ! 672: } else { ! 673: cc = setatm(xdef); /* If so, use default, if any. */ ! 674: } ! 675: ! 676: *xp = atmbuf; /* Point to result. */ ! 677: ! 678: while (1) { ! 679: xc += cc; /* Count the characters. */ ! 680: debug(F111,"cmifi gtword",atmbuf,xc); ! 681: switch (x) { ! 682: case -4: /* EOF */ ! 683: case -2: /* Out of space. */ ! 684: case -1: /* Reparse needed */ ! 685: return(x); ! 686: case 0: /* SP or NL */ ! 687: case 1: ! 688: if (xc == 0) *xp = xdef; /* If no input, return default. */ ! 689: if (**xp == NUL) return(-3); /* If field empty, return -3. */ ! 690: ! 691: if (f) { /* If a conversion function is given */ ! 692: zq = atxbuf; /* ... */ ! 693: atxn = CMDBL; ! 694: if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); ! 695: *xp = atxbuf; ! 696: } ! 697: debug(F110,"cmifi atxbuf",atxbuf,0); ! 698: #ifdef COMMENT ! 699: /* don't need this stuff, zxpand does it now. */ ! 700: #ifdef DTILDE ! 701: ! 702: dirp = tilde_expand(*xp); /* Expand tilde, if any, */ ! 703: if (*dirp != '\0') setatm(dirp); /* right in atom buffer. */ ! 704: *xp = atmbuf; ! 705: #endif /* DTILDE */ ! 706: ! 707: /* If filespec is wild, see if there are any matches */ ! 708: ! 709: *wild = iswild(*xp); ! 710: debug(F101,"cmifi wild","",*wild); ! 711: if (*wild != 0) { ! 712: #endif /* COMMENT */ ! 713: sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */ ! 714: if (!sv) { ! 715: printf("?malloc error 73, cmifi\n"); ! 716: return(-9); ! 717: } ! 718: strcpy(sv,*xp); ! 719: debug(F110,"cmifi sv",sv,0); ! 720: y = zxpand(*xp); ! 721: *wild = (y > 1); ! 722: debug(F111,"cmifi sv wild",sv,*wild); ! 723: if (y == 0) { ! 724: printf("?No files match - %s\n",*xp); ! 725: return(-9); ! 726: } else if (y < 0) { ! 727: printf("?Too many files match - %s\n",*xp); ! 728: return(-9); ! 729: } else if (y > 1) return(x); ! 730: #ifdef COMMENT ! 731: } ! 732: #endif ! 733: /* If not wild, see if it exists and is readable. */ ! 734: ! 735: debug(F111,"cmifi sv not wild",sv,*wild); ! 736: ! 737: znext(*xp); /* Get first (only?) matching file */ ! 738: y = zchki(*xp); /* Check its accessibility */ ! 739: zxpand(sv); /* Rewind so next znext() gets 1st */ ! 740: free(sv); /* done with this */ ! 741: if (y == -3) { ! 742: printf("?Read permission denied - %s\n",*xp); ! 743: return(-9); ! 744: } else if (y == -2) { ! 745: printf("?File not readable - %s\n",*xp); ! 746: return(-9); ! 747: } else if (y < 0) { ! 748: printf("?File not found - %s\n",*xp); ! 749: return(-9); ! 750: } ! 751: return(x); ! 752: ! 753: #ifndef MAC ! 754: case 2: /* ESC */ ! 755: debug(F101,"cmifi esc, xc","",xc); ! 756: if (xc == 0) { ! 757: if (*xdef != '\0') { ! 758: printf("%s ",xdef); /* If at beginning of field, */ ! 759: #ifdef GEMDOS ! 760: fflush(stdout); ! 761: #endif /* GEMDOS */ ! 762: addbuf(xdef); /* supply default. */ ! 763: cc = setatm(xdef); ! 764: } else { /* No default */ ! 765: putchar(BEL); ! 766: } ! 767: break; ! 768: } ! 769: if (f) { /* If a conversion function is given */ ! 770: zq = atxbuf; /* ... */ ! 771: atxn = CMDBL; ! 772: if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); ! 773: /* reduce cc by number of \\ consumed by conversion */ ! 774: /* function (needed for OS/2, where \ is path separator) */ ! 775: cc -= (strlen(*xp) - strlen(atxbuf)); ! 776: *xp = atxbuf; ! 777: } ! 778: /* #ifdef COMMENT */ ! 779: #ifdef DTILDE ! 780: dirp = tilde_expand(*xp); /* Expand tilde, if any, */ ! 781: if (*dirp != '\0') setatm(dirp); /* in the atom buffer. */ ! 782: *xp = atmbuf; ! 783: #endif /* DTILDE */ ! 784: /* #endif */ ! 785: sp = *xp + cc; ! 786: #ifdef datageneral ! 787: *sp++ = '+'; /* Data General AOS wildcard */ ! 788: #else ! 789: *sp++ = '*'; /* Others */ ! 790: #endif /* datageneral */ ! 791: *sp-- = '\0'; ! 792: y = zxpand(*xp); /* Add wildcard and expand list. */ ! 793: if (y > 0) strcpy(filbuf,mtchs[0]); ! 794: else *filbuf = '\0'; ! 795: *sp = '\0'; /* Remove wildcard. */ ! 796: *wild = (y > 1); ! 797: if (y == 0) { ! 798: printf("?No files match - %s\n",atmbuf); ! 799: return(-9); ! 800: } else if (y < 0) { ! 801: printf("?Too many files match - %s\n",atmbuf); ! 802: return(-9); ! 803: } else if (y > 1) { /* Not unique. */ ! 804: #ifndef NOPARTIAL ! 805: /* Partial filename completion */ ! 806: int i, j, k; char c; ! 807: k = 0; ! 808: debug(F111,"cmifi partial",filbuf,cc); ! 809: for (i = cc; (c = filbuf[i]); i++) { ! 810: for (j = 1; j < y; j++) ! 811: if (mtchs[j][i] != c) break; ! 812: if (j == y) k++; ! 813: else filbuf[i] = filbuf[i+1] = NUL; ! 814: } ! 815: debug(F111,"cmifi partial k",filbuf,k); ! 816: if (k > 0) { /* Got more characters */ ! 817: sp = filbuf + cc; /* Point to new ones */ ! 818: #ifdef VMS ! 819: for (i = 0; i < cc; i++) { ! 820: cmdchardel(); /* Back up over old partial spec */ ! 821: bp--; ! 822: } ! 823: sp = filbuf; /* Point to new word start */ ! 824: debug(F100,"cmifi vms erase ok","",0); ! 825: #endif /* VMS */ ! 826: cc = k; /* How many new ones we just got */ ! 827: printf("%s",sp); /* Print them */ ! 828: while (*bp++ = *sp++) ; /* Copy to command buffer */ ! 829: bp--; /* Back up over NUL */ ! 830: debug(F110,"cmifi partial cmdbuf",cmdbuf,0); ! 831: setatm(filbuf); ! 832: debug(F111,"cmifi partial atmbuf",atmbuf,cc); ! 833: *xp = atmbuf; ! 834: } ! 835: #endif /* NOPARTIAL */ ! 836: putchar(BEL); /* Beep because not unique. */ ! 837: } else { /* Unique, complete it. */ ! 838: sp = filbuf + cc; /* Point past what user typed. */ ! 839: #ifdef VMS ! 840: for (i = 0; i < cc; i++) { ! 841: cmdchardel(); /* Back up over old partial spec */ ! 842: bp--; ! 843: } ! 844: sp = filbuf; /* Point to new word start */ ! 845: #endif /* VMS */ ! 846: printf("%s ",sp); /* Complete the name. */ ! 847: #ifdef GEMDOS ! 848: fflush(stdout); ! 849: #endif /* GEMDOS */ ! 850: addbuf(sp); /* Add the characters to cmdbuf. */ ! 851: setatm(filbuf); /* And to atmbuf. */ ! 852: *xp = atmbuf; /* Return pointer to atmbuf. */ ! 853: ! 854: return(cmflgs = 0); ! 855: } ! 856: break; ! 857: ! 858: case 3: /* Question mark */ ! 859: if (*xhlp == NUL) ! 860: printf(" Input file specification"); ! 861: else ! 862: printf(" %s",xhlp); ! 863: #ifdef GEMDOS ! 864: fflush(stdout); ! 865: #endif /* GEMDOS */ ! 866: if (xc > 0) { ! 867: if (f) { /* If a conversion function is given */ ! 868: zq = atxbuf; /* ... */ ! 869: atxn = CMDBL; ! 870: if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); ! 871: *xp = atxbuf; ! 872: } ! 873: #ifdef DTILDE ! 874: dirp = tilde_expand(*xp); /* Expand tilde, if any */ ! 875: if (*dirp != '\0') setatm(dirp); ! 876: *xp = atmbuf; ! 877: #endif ! 878: debug(F111,"cmifi ? *xp, cc",*xp,cc); ! 879: sp = *xp + cc; /* Insert "*" at end */ ! 880: #ifdef datageneral ! 881: *sp++ = '+'; /* Insert +, the DG wild card */ ! 882: #else ! 883: *sp++ = '*'; ! 884: #endif ! 885: *sp-- = '\0'; ! 886: debug(F110,"cmifi ? wild",*xp,0); ! 887: y = zxpand(*xp); ! 888: *sp = '\0'; ! 889: if (y == 0) { ! 890: printf("?No files match - %s\n",atmbuf); ! 891: return(-9); ! 892: } else if (y < 0) { ! 893: printf("?Too many files match - %s\n",atmbuf); ! 894: return(-9); ! 895: } else { ! 896: printf(", one of the following:\n"); ! 897: clrhlp(); ! 898: for (i = 0; i < y; i++) { ! 899: znext(filbuf); ! 900: #ifdef VMS ! 901: printf(" %s\n",filbuf); /* VMS names can be long */ ! 902: #else ! 903: addhlp(filbuf); ! 904: #endif /* VMS */ ! 905: } ! 906: dmphlp(); ! 907: } ! 908: } else printf("\n"); ! 909: printf("%s%s",cmprom,cmdbuf); ! 910: fflush(stdout); ! 911: break; ! 912: #endif /* MAC */ ! 913: } ! 914: x = gtword(); ! 915: *xp = atmbuf; ! 916: } ! 917: } ! 918: ! 919: /* C M D I R -- Parse a directory specification */ ! 920: ! 921: /* ! 922: This function depends on the external functions: ! 923: zchki() - Check if input file exists and is readable. ! 924: If these functions aren't available, then use cmfld() to parse dir names. ! 925: Note: this function quickly cobbled together, mainly by deleting lots of ! 926: lines from cmifi(). It seems to work, but various services are missing, ! 927: like completion, lists of matching directories on "?", etc. ! 928: */ ! 929: /* ! 930: Returns ! 931: -4 EOF ! 932: -3 if no input present when required, ! 933: -2 if out of space or other internal error, ! 934: -1 if reparse needed, ! 935: 0 or 1, with xp pointing to name, if directory specified, ! 936: 2 if a wildcard was included. ! 937: */ ! 938: int ! 939: cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; { ! 940: int x, xc; char *zq; ! 941: #ifdef DTILDE ! 942: char *tilde_expand(), *dirp; ! 943: #endif /* DTILDE */ ! 944: ! 945: cc = xc = 0; /* Initialize counts & pointers */ ! 946: *xp = ""; ! 947: if ((x = cmflgs) != 1) { /* Already confirmed? */ ! 948: x = gtword(); /* No, get a word */ ! 949: } else { ! 950: cc = setatm(xdef); /* If so, use default, if any. */ ! 951: } ! 952: *xp = atmbuf; /* Point to result. */ ! 953: while (1) { ! 954: xc += cc; /* Count the characters. */ ! 955: debug(F111,"cmdir gtword",atmbuf,xc); ! 956: switch (x) { ! 957: case -4: /* EOF */ ! 958: case -2: /* Out of space. */ ! 959: case -1: /* Reparse needed */ ! 960: return(x); ! 961: case 0: /* SP or NL */ ! 962: case 1: ! 963: if (xc == 0) *xp = xdef; /* If no input, return default. */ ! 964: else *xp = atmbuf; ! 965: if (**xp == NUL) return(-3); /* If field empty, return -3. */ ! 966: ! 967: if (f) { /* If a conversion function is given */ ! 968: zq = atxbuf; /* ... */ ! 969: atxn = CMDBL; ! 970: if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); ! 971: *xp = atxbuf; ! 972: cc = (int)strlen(atxbuf); ! 973: } ! 974: #ifdef DTILDE ! 975: /* ! 976: This is ugly, and for UNIX only. ! 977: Normally, we wouldn't call tilde_expand from a place like this anyway, ! 978: but rather let zxpand() take care of it. But in this case we might want ! 979: a hybrid result -- a string with the tilde expanded, but with wildcards ! 980: left unexpanded. ! 981: */ ! 982: dirp = tilde_expand(*xp); /* Expand tilde, if any, */ ! 983: if (*dirp == '~') { /* Still starts with tilde? */ ! 984: char *tp; /* Yes, convert to lowercase */ ! 985: tp = *xp; /* and try again. */ ! 986: while (*tp) { ! 987: if (isupper(*tp)) *tp = tolower(*tp); ! 988: tp++; ! 989: } ! 990: } ! 991: dirp = tilde_expand(*xp); /* Expand tilde, if any, */ ! 992: if (*dirp != '\0') setatm(dirp); /* in the atom buffer. */ ! 993: *xp = atmbuf; ! 994: #endif /* DTILDE */ ! 995: if (iswild(*xp)) return(2); ! 996: else return(x); ! 997: ! 998: case 2: /* ESC */ ! 999: putchar(BEL); ! 1000: break; ! 1001: ! 1002: case 3: /* Question mark */ ! 1003: if (*xhlp == NUL) ! 1004: printf(" Directory name"); ! 1005: else ! 1006: printf(" %s",xhlp); ! 1007: printf("\n%s%s",cmprom,cmdbuf); ! 1008: fflush(stdout); ! 1009: break; ! 1010: } ! 1011: x = gtword(); ! 1012: /* *xp = atmbuf; */ ! 1013: } ! 1014: } ! 1015: ! 1016: /* C M F L D -- Parse an arbitrary field */ ! 1017: /* ! 1018: Returns ! 1019: -3 if no input present when required, ! 1020: -2 if field too big for buffer, ! 1021: -1 if reparse needed, ! 1022: 0 otherwise, xp pointing to string result. ! 1023: */ ! 1024: int ! 1025: cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; { ! 1026: int x, xc; ! 1027: char *zq; ! 1028: ! 1029: cc = xc = 0; /* Initialize counts & pointers */ ! 1030: *xp = ""; ! 1031: if ((x = cmflgs) != 1) { /* Already confirmed? */ ! 1032: x = gtword(); /* No, get a word */ ! 1033: } else { ! 1034: cc = setatm(xdef); /* If so, use default, if any. */ ! 1035: } ! 1036: *xp = atmbuf; /* Point to result. */ ! 1037: ! 1038: while (1) { ! 1039: xc += cc; /* Count the characters. */ ! 1040: debug(F111,"cmfld: gtword",atmbuf,xc); ! 1041: debug(F101,"cmfld x","",x); ! 1042: switch (x) { ! 1043: case -4: /* EOF */ ! 1044: case -2: /* Out of space. */ ! 1045: case -1: /* Reparse needed */ ! 1046: return(x); ! 1047: case 0: /* SP or NL */ ! 1048: case 1: ! 1049: if (xc == 0) /* If no input, return default. */ ! 1050: cc = setatm(xdef); ! 1051: *xp = atmbuf; ! 1052: if (f) { /* If a conversion function is given */ ! 1053: zq = atxbuf; /* ... */ ! 1054: atxn = CMDBL; ! 1055: if ((*f)(*xp,&zq,&atxn) < 0) return(-2); ! 1056: cc = setatm(atxbuf); ! 1057: *xp = atmbuf; ! 1058: } ! 1059: if (**xp == NUL) { /* If variable evaluates to null */ ! 1060: cc = setatm(xdef); /* Stick in the default again. */ ! 1061: if (**xp == NUL) x = -3; /* If still empty, return -3. */ ! 1062: } ! 1063: #ifdef COMMENT ! 1064: /* The following is apparently not necessary. */ ! 1065: /* Remove it if nothing is broken, esp. TAKE file with trailing comments */ ! 1066: xx = *xp; ! 1067: debug(F111,"cmfld before trim",*xp,x); ! 1068: for (i = (int)strlen(xx) - 1; i > 0; i--) ! 1069: if (xx[i] != SP) /* Trim trailing blanks */ ! 1070: break; ! 1071: else ! 1072: xx[i] = NUL; ! 1073: debug(F111,"cmfld returns",*xp,x); ! 1074: #endif /* COMMENT */ ! 1075: debug(F101,"cmfld: returns","",x); ! 1076: return(x); ! 1077: case 2: /* ESC */ ! 1078: if (xc == 0 && *xdef != NUL) { ! 1079: printf("%s ",xdef); /* If at beginning of field, */ ! 1080: #ifdef GEMDOS ! 1081: fflush(stdout); ! 1082: #endif /* GEMDOS */ ! 1083: addbuf(xdef); /* supply default. */ ! 1084: cc = setatm(xdef); /* Return as if whole field */ ! 1085: return(0); /* typed, followed by space. */ ! 1086: } else { ! 1087: putchar(BEL); /* Beep if already into field. */ ! 1088: } ! 1089: break; ! 1090: case 3: /* Question mark */ ! 1091: if (*xhlp == NUL) ! 1092: printf(" Please complete this field"); ! 1093: else ! 1094: printf(" %s",xhlp); ! 1095: printf("\n%s%s",cmprom,cmdbuf); ! 1096: fflush(stdout); ! 1097: break; ! 1098: } ! 1099: x = gtword(); ! 1100: /* *xp = atmbuf; */ ! 1101: } ! 1102: } ! 1103: ! 1104: ! 1105: /* C M T X T -- Get a text string, including confirmation */ ! 1106: ! 1107: /* ! 1108: Print help message 'xhlp' if ? typed, supply default 'xdef' if null ! 1109: string typed. Returns ! 1110: ! 1111: -1 if reparse needed or buffer overflows. ! 1112: 1 otherwise. ! 1113: ! 1114: with cmflgs set to return code, and xp pointing to result string. ! 1115: */ ! 1116: int ! 1117: cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; { ! 1118: ! 1119: int x, i; ! 1120: char *xx, *zq; ! 1121: static int xc; ! 1122: ! 1123: debug(F101,"cmtxt, cmflgs","",cmflgs); ! 1124: cc = 0; /* Start atmbuf counter off at 0 */ ! 1125: if (cmflgs == -1) { /* If reparsing, */ ! 1126: xc = (int)strlen(*xp); /* get back the total text length, */ ! 1127: } else { /* otherwise, */ ! 1128: *xp = ""; /* start fresh. */ ! 1129: xc = 0; ! 1130: } ! 1131: *atmbuf = NUL; /* And empty the atom buffer. */ ! 1132: if ((x = cmflgs) != 1) { ! 1133: x = gtword(); /* Get first word. */ ! 1134: *xp = pp; /* Save pointer to it. */ ! 1135: } ! 1136: debug(F101,"cmtxt (*f)","", f); ! 1137: while (1) { /* Loop for each word in text. */ ! 1138: xc += cc; /* Char count for all words. */ ! 1139: debug(F111,"cmtxt: gtword",atmbuf,xc); ! 1140: debug(F101," x","",x); ! 1141: switch (x) { ! 1142: case -9: /* Buffer overflow */ ! 1143: case -4: /* EOF */ ! 1144: #ifdef MAC ! 1145: case -3: /* Quit/Timeout */ ! 1146: #endif /* MAC */ ! 1147: case -2: /* Overflow */ ! 1148: case -1: /* Deletion */ ! 1149: return(x); ! 1150: case 0: /* Space */ ! 1151: xc++; /* Just count it */ ! 1152: break; ! 1153: case 1: /* CR or LF */ ! 1154: if (xc == 0) *xp = xdef; ! 1155: if (f) { /* If a conversion function is given */ ! 1156: zq = atxbuf; /* Point to the expansion buffer */ ! 1157: atxn = CMDBL; /* specify its length */ ! 1158: debug(F110,"cmtxt calling (*f)",*xp,0); ! 1159: if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2); ! 1160: cc = (int)strlen(atxbuf); ! 1161: *xp = atxbuf; /* and return pointer to it. */ ! 1162: debug(F111,"cmtxt (*f) returns",*xp,cc); ! 1163: } ! 1164: xx = *xp; ! 1165: for (i = (int)strlen(xx) - 1; i > 0; i--) ! 1166: if (xx[i] != SP) /* Trim trailing blanks */ ! 1167: break; ! 1168: else ! 1169: xx[i] = NUL; ! 1170: return(x); ! 1171: case 2: /* ESC */ ! 1172: if (xc == 0) { ! 1173: printf("%s ",xdef); ! 1174: #ifdef GEMDOS ! 1175: fflush(stdout); ! 1176: #endif /* GEMDOS */ ! 1177: cc = addbuf(xdef); ! 1178: } else { ! 1179: putchar(BEL); ! 1180: } ! 1181: break; ! 1182: case 3: /* Question Mark */ ! 1183: if (*xhlp == NUL) ! 1184: printf(" Text string"); ! 1185: else ! 1186: printf(" %s",xhlp); ! 1187: printf("\n%s%s",cmprom,cmdbuf); ! 1188: fflush(stdout); ! 1189: break; ! 1190: default: ! 1191: printf("?Unexpected return code from gtword() - %d\n",x); ! 1192: return(-2); ! 1193: } ! 1194: x = gtword(); ! 1195: } ! 1196: } ! 1197: ! 1198: ! 1199: /* C M K E Y -- Parse a keyword */ ! 1200: ! 1201: /* ! 1202: Call with: ! 1203: table -- keyword table, in 'struct keytab' format; ! 1204: n -- number of entries in table; ! 1205: xhlp -- pointer to help string; ! 1206: xdef -- pointer to default keyword; ! 1207: ! 1208: Returns: ! 1209: -3 -- no input supplied and no default available ! 1210: -2 -- input doesn't uniquely match a keyword in the table ! 1211: -1 -- user deleted too much, command reparse required ! 1212: n >= 0 -- value associated with keyword ! 1213: */ ! 1214: int ! 1215: cmkey(table,n,xhlp,xdef,f) ! 1216: /* cmkey */ struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; { ! 1217: return(cmkey2(table,n,xhlp,xdef,"",f)); ! 1218: } ! 1219: int ! 1220: cmkey2(table,n,xhlp,xdef,tok,f) ! 1221: struct keytab table[]; int n; char *xhlp, *xdef; char *tok; xx_strp f; { ! 1222: ! 1223: int i, tl, y, z, zz, xc; ! 1224: char *xp, *zq; ! 1225: ! 1226: tl = (int)strlen(tok); ! 1227: xc = cc = 0; /* Clear character counters. */ ! 1228: ! 1229: if ((zz = cmflgs) == 1) /* Command already entered? */ ! 1230: setatm(xdef); /* Yes, copy default into atom buf */ ! 1231: else zz = gtword(); /* Otherwise get a command word */ ! 1232: ! 1233: debug(F101,"cmkey: table length","",n); ! 1234: debug(F101," cmflgs","",cmflgs); ! 1235: debug(F101," zz","",zz); ! 1236: while (1) { ! 1237: xc += cc; ! 1238: debug(F111,"cmkey: gtword",atmbuf,xc); ! 1239: ! 1240: switch(zz) { ! 1241: case -4: /* EOF */ ! 1242: #ifdef MAC ! 1243: case -3: /* Quit/Timeout */ ! 1244: #endif /* MAC */ ! 1245: case -2: /* Buffer overflow */ ! 1246: case -1: /* Or user did some deleting. */ ! 1247: return(zz); ! 1248: ! 1249: case 0: /* User terminated word with space */ ! 1250: case 1: /* or newline */ ! 1251: if (cc == 0) setatm(xdef); /* Supply default if user typed nada */ ! 1252: if (f) { /* If a conversion function is given */ ! 1253: zq = atxbuf; /* apply it */ ! 1254: atxn = CMDBL; ! 1255: if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); ! 1256: debug(F110,"cmkey atxbuf after *f",atxbuf,0); ! 1257: cc = setatm(atxbuf); ! 1258: } ! 1259: y = lookup(table,atmbuf,n,&z); /* Look up the word in the table */ ! 1260: switch (y) { ! 1261: case -2: /* Ambiguous */ ! 1262: printf("?Ambiguous - %s\n",atmbuf); ! 1263: cmflgs = -2; ! 1264: return(-9); ! 1265: case -1: /* Not found at all */ ! 1266: if (tl) { ! 1267: for (i = 0; i < tl; i++) /* Check for token */ ! 1268: if (tok[i] == *atmbuf) { /* Got one */ ! 1269: ungword(); /* Put back the following word */ ! 1270: return(-5); /* Special return code for token */ ! 1271: } ! 1272: } ! 1273: /* Kludge alert... only print error if */ ! 1274: /* we were called as cmkey2, but not cmkey... */ ! 1275: /* This doesn't seem to always work. */ ! 1276: if (tl == 0) { ! 1277: printf("?No keywords match - %s\n",atmbuf); /* cmkey */ ! 1278: return(cmflgs = -9); ! 1279: } else { ! 1280: if (cmflgs == 1) return(cmflgs = -6); /* cmkey2 */ ! 1281: else return(cmflgs = -2); ! 1282: /* The -6 code is to let caller try another table */ ! 1283: } ! 1284: default: ! 1285: break; ! 1286: } ! 1287: return(y); ! 1288: ! 1289: case 2: /* User terminated word with ESC */ ! 1290: if (cc == 0) { ! 1291: if (*xdef != NUL) { /* Nothing in atmbuf */ ! 1292: printf("%s ",xdef); /* Supply default if any */ ! 1293: #ifdef GEMDOS ! 1294: fflush(stdout); ! 1295: #endif /* GEMDOS */ ! 1296: addbuf(xdef); ! 1297: cc = setatm(xdef); ! 1298: debug(F111,"cmkey: default",atmbuf,cc); ! 1299: } else { ! 1300: putchar(BEL); /* No default, just beep */ ! 1301: break; ! 1302: } ! 1303: } ! 1304: if (f) { /* If a conversion function is given */ ! 1305: zq = atxbuf; /* apply it */ ! 1306: atxn = CMDBL; ! 1307: if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); ! 1308: cc = setatm(atxbuf); ! 1309: } ! 1310: y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */ ! 1311: debug(F111,"cmkey: esc",atmbuf,y); ! 1312: if (y == -2) { ! 1313: putchar(BEL); ! 1314: break; ! 1315: } ! 1316: if (y == -1) { ! 1317: /* if (tl == 0) */ printf("?No keywords match - %s\n",atmbuf); ! 1318: cmflgs = -2; ! 1319: return(-9); ! 1320: } ! 1321: xp = table[z].kwd + cc; ! 1322: printf("%s ",xp); ! 1323: #ifdef GEMDOS ! 1324: fflush(stdout); ! 1325: #endif /* GEMDOS */ ! 1326: addbuf(xp); ! 1327: debug(F110,"cmkey: addbuf",cmdbuf,0); ! 1328: return(y); ! 1329: ! 1330: case 3: /* User terminated word with "?" */ ! 1331: if (f) { /* If a conversion function is given */ ! 1332: zq = atxbuf; ! 1333: atxn = CMDBL; ! 1334: if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2); ! 1335: cc = setatm(atxbuf); ! 1336: } ! 1337: y = lookup(table,atmbuf,n,&z); ! 1338: ! 1339: if (y == -1) { ! 1340: /* if (tl == 0) */ printf(" No keywords match\n"); ! 1341: cmflgs = -2; ! 1342: return(-9); ! 1343: } else if (y > -1 && !test(table[z].flgs,CM_ABR)) { ! 1344: printf(" %s\n%s%s",table[z].kwd,cmprom,cmdbuf); ! 1345: fflush(stdout); ! 1346: break; ! 1347: } ! 1348: if (*xhlp == NUL) ! 1349: printf(" One of the following:\n"); ! 1350: else ! 1351: printf(" %s, one of the following:\n",xhlp); ! 1352: ! 1353: clrhlp(); ! 1354: for (i = 0; i < n; i++) { ! 1355: if (!strncmp(table[i].kwd,atmbuf,cc) ! 1356: && !test(table[i].flgs,CM_INV) ! 1357: ) ! 1358: addhlp(table[i].kwd); ! 1359: } ! 1360: dmphlp(); ! 1361: if (*atmbuf == NUL) { ! 1362: if (tl == 1) ! 1363: printf("or the token '%c'\n",*tok); ! 1364: else if (tl > 1) printf("or one of the tokens '%s'\n",tok); ! 1365: } ! 1366: printf("%s%s", cmprom, cmdbuf); ! 1367: fflush(stdout); ! 1368: break; ! 1369: ! 1370: default: ! 1371: printf("\n%d - Unexpected return code from gtword\n",zz); ! 1372: return(cmflgs = -2); ! 1373: } ! 1374: zz = gtword(); ! 1375: } ! 1376: } ! 1377: int ! 1378: chktok(tlist) char *tlist; { ! 1379: char *p; ! 1380: p = tlist; ! 1381: while (*p != NUL && *p != *atmbuf) p++; ! 1382: return((*p) ? (int) *p : 0); ! 1383: } ! 1384: ! 1385: /* C M C F M -- Parse command confirmation (end of line) */ ! 1386: ! 1387: /* ! 1388: Returns ! 1389: -2: User typed anything but whitespace or newline ! 1390: -1: Reparse needed ! 1391: 0: Confirmation was received ! 1392: */ ! 1393: int ! 1394: cmcfm() { ! 1395: int x, xc; ! 1396: ! 1397: debug(F101,"cmcfm: cmflgs","",cmflgs); ! 1398: ! 1399: xc = cc = 0; ! 1400: if (cmflgs == 1) return(0); ! 1401: ! 1402: while (1) { ! 1403: x = gtword(); ! 1404: xc += cc; ! 1405: debug(F111,"cmcfm: gtword",atmbuf,xc); ! 1406: switch (x) { ! 1407: case -4: /* EOF */ ! 1408: case -2: ! 1409: case -1: ! 1410: return(x); ! 1411: ! 1412: case 1: /* End of line */ ! 1413: if (xc > 0) { ! 1414: printf("?Not confirmed - %s\n",atmbuf); ! 1415: return(-9); ! 1416: } else return(0); ! 1417: case 2: /* ESC */ ! 1418: if (xc == 0) { ! 1419: putchar(BEL); /* beep & continue */ ! 1420: continue; /* or fall thru. */ ! 1421: } ! 1422: case 0: /* Space */ ! 1423: if (xc == 0) /* If no chars type, continue, */ ! 1424: continue; /* else fall thru. */ ! 1425: case 3: /* Question mark */ ! 1426: if (xc > 0) { ! 1427: printf("?Not confirmed - %s\n",atmbuf); ! 1428: return(-9); ! 1429: } ! 1430: printf("\n Type a carriage return to confirm the command\n"); ! 1431: printf("%s%s",cmprom,cmdbuf); ! 1432: fflush(stdout); ! 1433: continue; ! 1434: } ! 1435: } ! 1436: } ! 1437: ! 1438: /* Keyword help routines */ ! 1439: ! 1440: ! 1441: /* C L R H L P -- Initialize/Clear the help line buffer */ ! 1442: ! 1443: VOID ! 1444: clrhlp() { /* Clear the help buffer */ ! 1445: hlpbuf[0] = NUL; ! 1446: hh = hx = 0; ! 1447: } ! 1448: ! 1449: ! 1450: /* A D D H L P -- Add a string to the help line buffer */ ! 1451: ! 1452: VOID ! 1453: addhlp(s) char *s; { /* Add a word to the help buffer */ ! 1454: int j; ! 1455: ! 1456: hh++; /* Count this column */ ! 1457: ! 1458: for (j = 0; (j < hc) && (*s != NUL); j++) { /* Fill the column */ ! 1459: hlpbuf[hx++] = *s++; ! 1460: } ! 1461: if (*s != NUL) /* Still some chars left in string? */ ! 1462: hlpbuf[hx-1] = '+'; /* Mark as too long for column. */ ! 1463: ! 1464: if (hh < (hw / hc)) { /* Pad col with spaces if necessary */ ! 1465: for (; j < hc; j++) { ! 1466: hlpbuf[hx++] = SP; ! 1467: } ! 1468: } else { /* If last column, */ ! 1469: hlpbuf[hx++] = NUL; /* no spaces. */ ! 1470: dmphlp(); /* Print it. */ ! 1471: return; ! 1472: } ! 1473: } ! 1474: ! 1475: ! 1476: /* D M P H L P -- Dump the help line buffer */ ! 1477: ! 1478: VOID ! 1479: dmphlp() { /* Print the help buffer */ ! 1480: hlpbuf[hx++] = NUL; ! 1481: printf(" %s\n",hlpbuf); ! 1482: clrhlp(); ! 1483: } ! 1484: ! 1485: ! 1486: /* G T W O R D -- Gets a "word" from the command input stream */ ! 1487: ! 1488: /* ! 1489: Usage: retcode = gtword(); ! 1490: ! 1491: Returns: ! 1492: -4 if end of file (e.g. pipe broken) ! 1493: -2 if command buffer overflows ! 1494: -1 if user did some deleting ! 1495: 0 if word terminates with SP or tab ! 1496: 1 if ... CR ! 1497: 2 if ... ESC ! 1498: 3 if ... ? (question mark) ! 1499: ! 1500: With: ! 1501: pp pointing to beginning of word in buffer ! 1502: bp pointing to after current position ! 1503: atmbuf containing a copy of the word ! 1504: cc containing the number of characters in the word copied to atmbuf ! 1505: */ ! 1506: ! 1507: int ! 1508: ungword() { /* unget a word */ ! 1509: if (ungw) return(0); ! 1510: cmfsav = cmflgs; ! 1511: debug(F101,"ungword cmflgs","",cmflgs); ! 1512: ungw = 1; ! 1513: cmflgs = 0; ! 1514: return(0); ! 1515: } ! 1516: ! 1517: int ! 1518: gtword() { ! 1519: int c; /* Current char */ ! 1520: static int inword = 0; /* Flag for start of word found */ ! 1521: int quote = 0; /* Flag for quote character */ ! 1522: int echof = 0; /* Flag for whether to echo */ ! 1523: int chsrc = 0; /* Source of character, 1 = tty */ ! 1524: int comment = 0; /* Flag for in comment */ ! 1525: char *cp = NULL; /* Comment pointer */ ! 1526: ! 1527: #ifdef RTU ! 1528: extern int rtu_bug; ! 1529: #endif /* RTU */ ! 1530: ! 1531: #ifdef datageneral ! 1532: extern int termtype; /* DG terminal type flag */ ! 1533: extern int con_reads_mt; /* Console read asynch is active */ ! 1534: if (con_reads_mt) connoi_mt(); /* Task would interfere w/cons read */ ! 1535: #endif /* datageneral */ ! 1536: ! 1537: if (ungw) { /* Have a word saved? */ ! 1538: debug(F110,"gtword ungetting from pp",pp,0); ! 1539: while (*pp++ == SP) ; ! 1540: setatm(pp); ! 1541: ungw = 0; ! 1542: cmflgs = cmfsav; ! 1543: debug(F111,"gtword returning atmbuf",atmbuf,cmflgs); ! 1544: return(cmflgs); ! 1545: } ! 1546: pp = np; /* Start of current field */ ! 1547: ! 1548: #ifdef COMMENT ! 1549: debug(F111,"gtword: cmdbuf",cmdbuf,(int) cmdbuf); ! 1550: debug(F111," bp",bp,(int) bp); ! 1551: debug(F111," pp",pp,(int) pp); ! 1552: #endif /* COMMENT */ ! 1553: ! 1554: while (bp < cmdbuf+CMDBL) { /* Big get-a-character loop */ ! 1555: echof = 0; /* Assume we don't echo because */ ! 1556: chsrc = 0; /* character came from reparse buf. */ ! 1557: ! 1558: if ((c = *bp) == NUL) { /* If no char waiting in reparse buf */ ! 1559: if (dpx) echof = 1; /* must get from tty, set echo flag. */ ! 1560: c = cmdgetc(); /* Read a character from the tty. */ ! 1561: chsrc = 1; /* Remember character source is tty. */ ! 1562: #ifdef MAC ! 1563: if (c == -3) /* If null command... */ ! 1564: return(-3); ! 1565: #endif /* MAC */ ! 1566: if (c == EOF) { /* This can happen if stdin not tty. */ ! 1567: #ifdef EINTR ! 1568: if (errno == EINTR) /* This is for when bg'd process is */ ! 1569: continue; /* fg'd again. */ ! 1570: #endif /* EINTR */ ! 1571: return(-4); ! 1572: } ! 1573: c &= cmdmsk; /* Strip any parity bit */ ! 1574: } /* if desired. */ ! 1575: #ifndef MAC ! 1576: debug(F000,"gtword char","",c); ! 1577: #endif /* MAC */ ! 1578: ! 1579: /* Now we have the next character */ ! 1580: ! 1581: if (quote == 0) { /* If this is not a quoted character */ ! 1582: if (c == CMDQ) { /* Got the quote character itself */ ! 1583: if (!comment) quote = 1; /* Flag it if not in a comment */ ! 1584: } ! 1585: if (c == FF) { /* Formfeed. */ ! 1586: c = NL; /* Replace with newline */ ! 1587: #ifdef COMMENT ! 1588: /* No more screen clearing... */ ! 1589: cmdclrscn(); /* Clear the screen */ ! 1590: #endif ! 1591: } ! 1592: if (c == HT) { /* Tab */ ! 1593: if (comment) /* If in comment, */ ! 1594: c = SP; /* substitute space */ ! 1595: else /* otherwise */ ! 1596: c = ESC; /* substitute ESC (for completion) */ ! 1597: } ! 1598: if (c == ';' || c == '#') { /* Trailing comment */ ! 1599: if (inword == 0) { /* If we're not in a word */ ! 1600: comment = 1; /* start a comment. */ ! 1601: cp = bp; /* remember where it starts. */ ! 1602: } ! 1603: } ! 1604: if (!comment && c == SP) { /* Space */ ! 1605: *bp++ = c; /* deposit in buffer if not already */ ! 1606: if (echof) putchar(c); /* echo it. */ ! 1607: if (inword == 0) { /* If leading, gobble it. */ ! 1608: pp++; ! 1609: continue; ! 1610: } else { /* If terminating, return. */ ! 1611: np = bp; ! 1612: setatm(pp); ! 1613: inword = 0; ! 1614: return(cmflgs = 0); ! 1615: } ! 1616: } ! 1617: if (c == NL || c == CR) { /* CR or LF. */ ! 1618: if (echof) cmdnewl((char)c); /* Echo it. */ ! 1619: if (*(bp-1) == '-') { /* Is this line continued? */ ! 1620: if (chsrc) { /* If reading from tty, */ ! 1621: bp--; /* back up the buffer pointer, */ ! 1622: *bp = NUL; /* erase the dash, */ ! 1623: continue; /* and go back for next char now. */ ! 1624: } ! 1625: } else { /* No, a command has been entered. */ ! 1626: *bp = NUL; /* Terminate the command string. */ ! 1627: if (comment) { /* If we're in a comment, */ ! 1628: comment = 0; /* Say we're not any more, */ ! 1629: *cp = NUL; /* cut it off. */ ! 1630: } ! 1631: np = bp; /* Where to start next field. */ ! 1632: setatm(pp); /* Copy this field to atom buffer. */ ! 1633: inword = 0; /* Not in a word any more. */ ! 1634: return(cmflgs = 1); ! 1635: } ! 1636: } ! 1637: if (!comment && echof && (c == '?')) { /* Question mark */ ! 1638: putchar(c); ! 1639: *bp = NUL; ! 1640: setatm(pp); ! 1641: return(cmflgs = 3); ! 1642: } ! 1643: if (c == ESC) { /* ESC */ ! 1644: if (!comment) { ! 1645: *bp = NUL; ! 1646: setatm(pp); ! 1647: return(cmflgs = 2); ! 1648: } else { ! 1649: putchar(BEL); ! 1650: continue; ! 1651: } ! 1652: } ! 1653: if (c == BS || c == RUB) { /* Character deletion */ ! 1654: if (bp > cmdbuf) { /* If still in buffer... */ ! 1655: cmdchardel(); /* erase it. */ ! 1656: bp--; /* point behind it, */ ! 1657: if (*bp == SP) inword = 0; /* Flag if current field gone */ ! 1658: *bp = NUL; /* Erase character from buffer. */ ! 1659: } else { /* Otherwise, */ ! 1660: putchar(BEL); /* beep, */ ! 1661: cmres(); /* and start parsing a new command. */ ! 1662: } ! 1663: if (pp < bp) continue; ! 1664: else return(cmflgs = -1); ! 1665: } ! 1666: if (c == LDEL) { /* ^U, line deletion */ ! 1667: while ((bp--) > cmdbuf) { ! 1668: cmdchardel(); ! 1669: *bp = NUL; ! 1670: } ! 1671: cmres(); /* Restart the command. */ ! 1672: inword = 0; ! 1673: return(cmflgs = -1); ! 1674: } ! 1675: if (c == WDEL) { /* ^W, word deletion */ ! 1676: if (bp <= cmdbuf) { /* Beep if nothing to delete */ ! 1677: putchar(BEL); ! 1678: cmres(); ! 1679: return(cmflgs = -1); ! 1680: } ! 1681: bp--; ! 1682: for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) { ! 1683: cmdchardel(); ! 1684: *bp = NUL; ! 1685: } ! 1686: for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) { ! 1687: cmdchardel(); ! 1688: *bp = NUL; ! 1689: } ! 1690: bp++; ! 1691: inword = 0; ! 1692: return(cmflgs = -1); ! 1693: } ! 1694: if (c == RDIS) { /* ^R, redisplay */ ! 1695: *bp = NUL; ! 1696: printf("\n%s%s",cmprom,cmdbuf); ! 1697: fflush(stdout); ! 1698: continue; ! 1699: } ! 1700: if (c < SP && quote == 0) { /* Any other unquoted ctrl char */ ! 1701: if (!chsrc) bp++; /* If cmd file, point past it */ ! 1702: else putchar(BEL); /* otherwise just beep and */ ! 1703: continue; /* continue, don't put in buffer */ ! 1704: } ! 1705: } else { /* This character was quoted. */ ! 1706: quote = 0; /* Unset the quote flag. */ ! 1707: /* Quote character at this level is only for SP, ?, and controls */ ! 1708: /* If anything else was quoted, leave quote in, and let */ ! 1709: /* the command-specific parsing routines handle it, e.g. \007 */ ! 1710: if (c > 32 && c != '?' && c != RUB && chsrc != 0) ! 1711: *bp++ = CMDQ; /* Deposit \ if it came from tty */ ! 1712: debug(F110,"gtword quote",cmdbuf,0); ! 1713: } ! 1714: if (echof) cmdecho((char) c,quote); /* Echo what was typed. */ ! 1715: if (!comment) inword = 1; /* Flag we're in a word. */ ! 1716: if (quote) continue; /* Don't deposit quote character. */ ! 1717: if (c != NL) *bp++ = c; /* Deposit command character. */ ! 1718: /*** debug(F110,"gtword deposit",cmdbuf,0); ***/ ! 1719: } /* End of big while */ ! 1720: putchar(BEL); /* Get here if... */ ! 1721: printf("?Command too long, maximum length: %d.\n",CMDBL); ! 1722: cmflgs = -2; ! 1723: return(-9); ! 1724: } ! 1725: ! 1726: /* Utility functions */ ! 1727: ! 1728: /* A D D B U F -- Add the string pointed to by cp to the command buffer */ ! 1729: ! 1730: int ! 1731: addbuf(cp) char *cp; { ! 1732: int len = 0; ! 1733: while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) { ! 1734: *bp++ = *cp++; /* Copy and */ ! 1735: len++; /* count the characters. */ ! 1736: } ! 1737: *bp++ = SP; /* Put a space at the end */ ! 1738: *bp = NUL; /* Terminate with a null */ ! 1739: np = bp; /* Update the next-field pointer */ ! 1740: return(len); /* Return the length */ ! 1741: } ! 1742: ! 1743: /* S E T A T M -- Deposit a token in the atom buffer. */ ! 1744: /* Break on space, newline, carriage return, or null. */ ! 1745: /* Null-terminate the result. */ ! 1746: /* If the source pointer is the atom buffer itself, do nothing. */ ! 1747: /* Return length of token, and also set global "cc" to this length. */ ! 1748: ! 1749: int ! 1750: setatm(cp) char *cp; { ! 1751: char *ap, *xp; ! 1752: ! 1753: cc = 0; /* Character counter */ ! 1754: ap = atmbuf; /* Address of atom buffer */ ! 1755: ! 1756: if (cp == ap) { /* In case source is atom buffer */ ! 1757: xp = atybuf; /* make a copy */ ! 1758: strcpy(xp,ap); /* so we can copy it back, edited. */ ! 1759: cp = xp; ! 1760: } ! 1761: *ap = NUL; /* Zero the atom buffer */ ! 1762: ! 1763: while (*cp == SP) cp++; /* Trim leading spaces */ ! 1764: while ((*cp != SP) && (*cp != NL) && (*cp != NUL) && (*cp != CR)) { ! 1765: *ap++ = *cp++; /* Copy up to SP, NL, CR, or end */ ! 1766: cc++; /* and count */ ! 1767: } ! 1768: *ap = NUL; /* Terminate the string. */ ! 1769: return(cc); /* Return length. */ ! 1770: } ! 1771: ! 1772: /* R D I G I T S -- Verify that all the characters in line ARE DIGITS */ ! 1773: ! 1774: int ! 1775: rdigits(s) char *s; { ! 1776: while (*s) { ! 1777: if (!isdigit(*s)) return(0); ! 1778: s++; ! 1779: } ! 1780: return(1); ! 1781: } ! 1782: ! 1783: /* These functions attempt to hide system dependencies from the mainline */ ! 1784: /* code in gtword(). Ultimately they should be moved to ck?tio.c, where */ ! 1785: /* ? = each and every system supported by C-Kermit. */ ! 1786: ! 1787: int ! 1788: cmdgetc() { /* Get a character from the tty. */ ! 1789: int c; ! 1790: ! 1791: #ifdef datageneral ! 1792: { ! 1793: char ch; ! 1794: c = dgncinb(0,&ch,1); /* -1 is EOF, -2 TO, ! 1795: * -c is AOS/VS error */ ! 1796: if (c == -2) { /* timeout was enabled? */ ! 1797: resto(channel(0)); /* reset timeouts */ ! 1798: c = dgncinb(0,&ch,1); /* retry this now! */ ! 1799: } ! 1800: if (c < 0) return(-4); /* EOF or some error */ ! 1801: else c = (int) ch & 0177; /* Get char without parity */ ! 1802: /* echof = 1; */ ! 1803: } ! 1804: #else /* Not datageneral */ ! 1805: #ifdef GEMDOS ! 1806: c = isatty(0) ? coninc(0) : getchar(); ! 1807: #else ! 1808: #ifdef OS2 ! 1809: c = isatty(0) ? coninc(0) : getchar(); ! 1810: if (c < 0) return(-4); ! 1811: #else /* Not OS2 */ ! 1812: c = getchar(); /* or from tty. */ ! 1813: #ifdef RTU ! 1814: if (rtu_bug) { ! 1815: c = getchar(); /* RTU doesn't discard the ^Z */ ! 1816: rtu_bug = 0; ! 1817: } ! 1818: #endif /* RTU */ ! 1819: #endif /* OS2 */ ! 1820: #endif /* GEMDOS */ ! 1821: #endif /* datageneral */ ! 1822: return(c); /* Return what we got */ ! 1823: } ! 1824: ! 1825: ! 1826: #ifdef COMMENT ! 1827: /* ! 1828: No more screen clearing. If you wanna clear the screen, define a macro ! 1829: to do it, like "define cls write screen \27[;H\27[2J". ! 1830: */ ! 1831: cmdclrscn() { /* Clear the screen */ ! 1832: ! 1833: #ifdef aegis ! 1834: putchar(FF); ! 1835: #else ! 1836: #ifdef AMIGA ! 1837: putchar(FF); ! 1838: #else ! 1839: #ifdef OSK ! 1840: putchar(FF); ! 1841: #else ! 1842: #ifdef datageneral ! 1843: putchar(FF); ! 1844: #else ! 1845: #ifdef OS2 ! 1846: zsystem("cls"); ! 1847: #else ! 1848: zsystem("clear"); ! 1849: #endif /* OS2 */ ! 1850: #endif /* datageneral */ ! 1851: #endif /* OSK */ ! 1852: #endif /* AMIGA */ ! 1853: #endif /* aegis */ ! 1854: } ! 1855: #endif /* COMMENT */ ! 1856: ! 1857: VOID /* What to echo at end of command */ ! 1858: #ifdef CK_ANSIC ! 1859: cmdnewl(char c) ! 1860: #else ! 1861: cmdnewl(c) char c; ! 1862: #endif /* CK_ANSIC */ ! 1863: /* cmdnewl */ { ! 1864: putchar(c); /* c is the terminating character */ ! 1865: #ifdef OS2 ! 1866: if (c == CR) putchar(NL); ! 1867: #endif /* OS2 */ ! 1868: #ifdef aegis ! 1869: if (c == CR) putchar(NL); ! 1870: #endif /* aegis */ ! 1871: #ifdef AMIGA ! 1872: if (c == CR) putchar(NL); ! 1873: #endif /* AMIGA */ ! 1874: #ifdef datageneral ! 1875: if (c == CR) putchar(NL); ! 1876: #endif /* datageneral */ ! 1877: #ifdef GEMDOS ! 1878: if (c == CR) putchar(NL); ! 1879: #endif /* GEMDOS */ ! 1880: } ! 1881: ! 1882: VOID ! 1883: cmdchardel() { /* Erase a character from the screen */ ! 1884: #ifdef datageneral ! 1885: /* DG '\b' is EM (^y or \031) */ ! 1886: if (termtype == 1) ! 1887: /* Erase a character from non-DG screen, */ ! 1888: dgncoub(1,"\010 \010",3); ! 1889: else ! 1890: #endif ! 1891: printf("\b \b"); ! 1892: #ifdef GEMDOS ! 1893: fflush(stdout); ! 1894: #endif /* GEMDOS */ ! 1895: } ! 1896: ! 1897: VOID ! 1898: #ifdef CK_ANSIC ! 1899: cmdecho(char c, int quote) ! 1900: #else ! 1901: cmdecho(c,quote) char c; int quote; ! 1902: #endif /* CK_ANSIC */ ! 1903: { /* cmdecho */ ! 1904: /* Echo tty input character c */ ! 1905: putchar(c); ! 1906: #ifdef OS2 ! 1907: if (quote==1 && c==CR) putchar(NL); ! 1908: #endif /* OS2 */ ! 1909: } ! 1910: ! 1911: #endif /* NOICP */ ! 1912: ! 1913: #ifdef NOICP ! 1914: #include "ckcdeb.h" ! 1915: #include "ckucmd.h" ! 1916: #include "ckcasc.h" ! 1917: /*** #include <ctype.h> (ckcdeb.h already includes this) ***/ ! 1918: #endif /* NOICP */ ! 1919: ! 1920: /* X X E S C -- Interprets backslash codes */ ! 1921: /* Returns the int value of the backslash code if it is > -1 and < 256 */ ! 1922: /* and updates the string pointer to first character after backslash code. */ ! 1923: /* If the argument is invalid, leaves pointer unchanged and returns -1. */ ! 1924: ! 1925: int ! 1926: xxesc(s) char **s; { /* Expand backslash escapes */ ! 1927: int x, y, brace, radix; /* Returns the int value */ ! 1928: char hd = '9'; /* Highest digit in radix */ ! 1929: char *p; ! 1930: ! 1931: p = *s; /* pointer to beginning */ ! 1932: if (!p) return(-1); /* watch out for null pointer */ ! 1933: x = *p++; /* character at beginning */ ! 1934: if (x != CMDQ) return(-1); /* make sure it's a backslash code */ ! 1935: ! 1936: x = *p; /* it is, get the next character */ ! 1937: if (x == '{') { /* bracketed quantity? */ ! 1938: p++; /* begin past bracket */ ! 1939: x = *p; ! 1940: brace = 1; ! 1941: } else brace = 0; ! 1942: switch (x) { /* Start interpreting */ ! 1943: case 'd': /* Decimal radix indicator */ ! 1944: case 'D': ! 1945: p++; /* Just point past it and fall thru */ ! 1946: case '0': /* Starts with digit */ ! 1947: case '1': ! 1948: case '2': case '3': case '4': case '5': ! 1949: case '6': case '7': case '8': case '9': ! 1950: radix = 10; /* Decimal */ ! 1951: hd = '9'; /* highest valid digit */ ! 1952: break; ! 1953: case 'o': /* Starts with o or O */ ! 1954: case 'O': ! 1955: radix = 8; /* Octal */ ! 1956: hd = '7'; /* highest valid digit */ ! 1957: p++; /* point past radix indicator */ ! 1958: break; ! 1959: case 'x': /* Starts with x or X */ ! 1960: case 'X': ! 1961: radix = 16; /* Hexadecimal */ ! 1962: p++; /* point past radix indicator */ ! 1963: break; ! 1964: default: /* All others */ ! 1965: #ifdef COMMENT ! 1966: *s = p+1; /* Treat as quote of next char */ ! 1967: return(*p); ! 1968: #else ! 1969: return(-1); ! 1970: #endif /* COMMENT */ ! 1971: } ! 1972: /* For OS/2, there are "wide" characters required for the keyboard ! 1973: * binding, i.e \644 and similar codes larger than 255 (byte). ! 1974: * For this purpose, give up checking for < 256. If someone means ! 1975: * \266 should result in \26 followed by a "6" character, he should ! 1976: * always write \{26}6 anyway. Now, return only the lower byte of ! 1977: * the result, i.e. 10, but eat up the whole \266 sequence and ! 1978: * put the wide result 266 into a global variable. Yes, that's not ! 1979: * the most beautiful programming style but requires the least ! 1980: * amount of changes to other routines. ! 1981: */ ! 1982: if (radix <= 10) { /* Number in radix 8 or 10 */ ! 1983: for ( x = y = 0; ! 1984: (*p) && (*p >= '0') && (*p <= hd) ! 1985: #ifdef OS2 ! 1986: && (y < 4) && (x*radix < 768); ! 1987: /* the maximum needed value \767 is still only 3 digits long */ ! 1988: /* while as octal it requires \1377, i.e. 4 digits */ ! 1989: #else ! 1990: && (y < 3) && (x*radix < 256); ! 1991: #endif /* OS2 */ ! 1992: p++,y++) { ! 1993: x = x * radix + (int) *p - 48; ! 1994: } ! 1995: #ifdef OS2 ! 1996: wideresult = x; /* Remember wide result */ ! 1997: x &= 255; ! 1998: #endif /* OS2 */ ! 1999: if (y == 0 || x > 255) { /* No valid digits? */ ! 2000: *s = p; /* point after it */ ! 2001: return(-1); /* return failure. */ ! 2002: } ! 2003: } else if (radix == 16) { /* Special case for hex */ ! 2004: if ((x = unhex(*p++)) < 0) { *s = p - 1; return(-1); } ! 2005: if ((y = unhex(*p++)) < 0) { *s = p - 2; return(-1); } ! 2006: x = ((x << 4) & 0xF0) | (y & 0x0F); ! 2007: #ifdef OS2 ! 2008: if ((y = unhex(*p)) >= 0) { ! 2009: p++; ! 2010: wideresult = ((x << 4) & 0xFF0) | (y & 0x0F); ! 2011: x = wideresult & 255; ! 2012: } ! 2013: #endif /* OS2 */ ! 2014: } else x = -1; ! 2015: if (brace && *p == '}' && x > -1) /* Point past closing brace, if any */ ! 2016: p++; ! 2017: *s = p; /* Point to next char after sequence */ ! 2018: return(x); /* Return value of sequence */ ! 2019: } ! 2020: ! 2021: int /* Convert hex string to int */ ! 2022: #ifdef CK_ANSIC ! 2023: unhex(char x) ! 2024: #else ! 2025: unhex(x) char x; ! 2026: #endif /* CK_ANSIC */ ! 2027: /* unhex */ { ! 2028: ! 2029: if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */ ! 2030: return(x - 0x30); ! 2031: else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */ ! 2032: return(x - 0x37); ! 2033: else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */ ! 2034: return(x - 0x57); /* (obviously ASCII dependent) */ ! 2035: else return(-1); ! 2036: } ! 2037: ! 2038: /* See if argument string is numeric */ ! 2039: /* Returns 1 if OK, zero if not OK */ ! 2040: /* If OK, string should be acceptable to atoi() */ ! 2041: /* Allows leading space, sign */ ! 2042: ! 2043: int ! 2044: chknum(s) char *s; { /* Check Numeric String */ ! 2045: int x = 0; /* Flag for past leading space */ ! 2046: int y = 0; /* Flag for digit seen */ ! 2047: char c; ! 2048: debug(F110,"chknum",s,0); ! 2049: while (c = *s++) { /* For each character in the string */ ! 2050: switch (c) { ! 2051: case SP: /* Allow leading spaces */ ! 2052: case HT: ! 2053: if (x == 0) continue; ! 2054: else return(0); ! 2055: case '+': /* Allow leading sign */ ! 2056: case '-': ! 2057: if (x == 0) x = 1; ! 2058: else return(0); ! 2059: break; ! 2060: default: /* After that, only decimal digits */ ! 2061: if (c >= '0' && c <= '9') { ! 2062: x = y = 1; ! 2063: continue; ! 2064: } else return(0); ! 2065: } ! 2066: } ! 2067: return(y); ! 2068: } ! 2069: ! 2070: /* L O W E R -- Lowercase a string */ ! 2071: ! 2072: int ! 2073: lower(s) char *s; { ! 2074: int n = 0; ! 2075: while (*s) { ! 2076: if (isupper(*s)) *s = tolower(*s); ! 2077: s++, n++; ! 2078: } ! 2079: return(n); ! 2080: } ! 2081: ! 2082: /* L O O K U P -- Lookup the string in the given array of strings */ ! 2083: ! 2084: /* ! 2085: Call this way: v = lookup(table,word,n,&x); ! 2086: ! 2087: table - a 'struct keytab' table. ! 2088: word - the target string to look up in the table. ! 2089: n - the number of elements in the table. ! 2090: x - address of an integer for returning the table array index. ! 2091: ! 2092: The keyword table must be arranged in ascending alphabetical order, and ! 2093: all letters must be lowercase. ! 2094: ! 2095: Returns the keyword's associated value ( zero or greater ) if found, ! 2096: with the variable x set to the array index, or: ! 2097: ! 2098: -3 if nothing to look up (target was null), ! 2099: -2 if ambiguous, ! 2100: -1 if not found. ! 2101: ! 2102: A match is successful if the target matches a keyword exactly, or if ! 2103: the target is a prefix of exactly one keyword. It is ambiguous if the ! 2104: target matches two or more keywords from the table. ! 2105: */ ! 2106: ! 2107: int ! 2108: lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; { ! 2109: ! 2110: int i, v, cmdlen; ! 2111: ! 2112: /* Lowercase & get length of target, if it's null return code -3. */ ! 2113: ! 2114: if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3); ! 2115: ! 2116: /* Not null, look it up */ ! 2117: ! 2118: for (i = 0; i < n-1; i++) { ! 2119: if (!strcmp(table[i].kwd,cmd) || ! 2120: ((v = !strncmp(table[i].kwd,cmd,cmdlen)) && ! 2121: strncmp(table[i+1].kwd,cmd,cmdlen))) { ! 2122: *x = i; ! 2123: return(table[i].kwval); ! 2124: } ! 2125: if (v) return(-2); ! 2126: } ! 2127: ! 2128: /* Last (or only) element */ ! 2129: ! 2130: if (!strncmp(table[n-1].kwd,cmd,cmdlen)) { ! 2131: *x = n-1; ! 2132: return(table[n-1].kwval); ! 2133: } else return(-1); ! 2134: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.