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