|
|
1.1 ! root 1: char *cmdv = "Unix cmd package V1A(021), 19 Jun 85"; ! 2: ! 3: /* C K U C M D -- Interactive command package for Unix */ ! 4: /* ! 5: Modelled after the DECSYSTEM-20 command parser (the COMND JSYS) ! 6: ! 7: Features: ! 8: . parses and verifies keywords, text strings, numbers, and other data ! 9: . displays appropriate menu or help message when user types "?" ! 10: . does keyword and filename completion when user types ESC ! 11: . accepts any unique abbreviation for a keyword ! 12: . allows keywords to have attributes, like "invisible" ! 13: . can supply defaults for fields omitted by user ! 14: . provides command line editing (character, word, and line deletion) ! 15: . accepts input from keyboard, command files, or redirected stdin ! 16: . allows for full or half duplex operation, character or line input ! 17: . settable prompt, protected from deletion ! 18: ! 19: Functions: ! 20: cmsetp - Set prompt (cmprom is prompt string, cmerrp is error msg prefix) ! 21: cmsavp - Save current prompt ! 22: prompt - Issue prompt ! 23: cmini - Clear the command buffer (before parsing a new command) ! 24: cmres - Reset command buffer pointers (before reparsing) ! 25: cmkey - Parse a keyword ! 26: cmnum - Parse a number ! 27: cmifi - Parse an input file name ! 28: cmofi - Parse an output file name ! 29: cmfld - Parse an arbitrary field ! 30: cmtxt - Parse a text string ! 31: cmcfm - Parse command confirmation (end of line) ! 32: stripq - Strip out backslash quotes from a string. ! 33: ! 34: Return codes: ! 35: -3: no input provided when required ! 36: -2: input was invalid ! 37: -1: reparse required (user deleted into a preceding field) ! 38: 0 or greater: success ! 39: See individual functions for greater detail. ! 40: ! 41: Before using these routines, the caller should #include ckucmd.h, and ! 42: set the program's prompt by calling cmsetp(). If the file parsing ! 43: functions cmifi and cmofi are to be used, this module must be linked ! 44: with a ck?fio file system support module for the appropriate system, ! 45: e.g. ckufio for Unix. If the caller puts the terminal in ! 46: character wakeup ("cbreak") mode with no echo, then these functions will ! 47: provide line editing -- character, word, and line deletion, as well as ! 48: keyword and filename completion upon ESC and help strings, keyword, or ! 49: file menus upon '?'. If the caller puts the terminal into character ! 50: wakeup/noecho mode, care should be taken to restore it before exit from ! 51: or interruption of the program. If the character wakeup mode is not ! 52: set, the system's own line editor may be used. ! 53: ! 54: Author: Frank da Cruz (SY.FDC@CU20B), ! 55: Columbia University Center for Computing Activities, January 1985. ! 56: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 57: Permission is granted to any individual or institution to use, copy, or ! 58: redistribute this software so long as it is not sold for profit, provided this ! 59: copyright notice is retained. ! 60: */ ! 61: ! 62: /* Includes */ ! 63: ! 64: #include <stdio.h> /* Standard C I/O package */ ! 65: #include <ctype.h> /* Character types */ ! 66: #include "ckucmd.h" /* Command parsing definitions */ ! 67: #include "ckcdeb.h" /* Formats for debug() */ ! 68: ! 69: /* Local variables */ ! 70: ! 71: int psetf = 0, /* Flag that prompt has been set */ ! 72: cc = 0, /* Character count */ ! 73: dpx = 0; /* Duplex (0 = full) */ ! 74: ! 75: int hw = HLPLW, /* Help line width */ ! 76: hc = HLPCW, /* Help line column width */ ! 77: hh, /* Current help column number */ ! 78: hx; /* Current help line position */ ! 79: ! 80: #define PROML 60 /* Maximum length for prompt */ ! 81: ! 82: char cmprom[PROML+1]; /* Program's prompt */ ! 83: char *dfprom = "Command? "; /* Default prompt */ ! 84: ! 85: char cmerrp[PROML+1]; /* Program's error message prefix */ ! 86: ! 87: int cmflgs; /* Command flags */ ! 88: ! 89: char cmdbuf[CMDBL+4]; /* Command buffer */ ! 90: char hlpbuf[HLPBL+4]; /* Help string buffer */ ! 91: char atmbuf[ATMBL+4]; /* Atom buffer */ ! 92: char filbuf[ATMBL+4]; /* File name buffer */ ! 93: ! 94: /* Command buffer pointers */ ! 95: ! 96: static char *bp, /* Current command buffer position */ ! 97: *pp, /* Start of current field */ ! 98: *np; /* Start of next field */ ! 99: ! 100: long zchki(); /* From ck?fio.c. */ ! 101: ! 102: ! 103: /* C M S E T P -- Set the program prompt. */ ! 104: ! 105: cmsetp(s) char *s; { ! 106: char *sx, *sy, *strncpy(); ! 107: psetf = 1; /* Flag that prompt has been set. */ ! 108: strncpy(cmprom,s,PROML - 1); /* Copy the string. */ ! 109: cmprom[PROML] = NUL; /* Ensure null terminator. */ ! 110: sx = cmprom; sy = cmerrp; /* Also use as error message prefix. */ ! 111: while (*sy++ = *sx++) ; /* Copy. */ ! 112: sy -= 2; if (*sy == '>') *sy = NUL; /* Delete any final '>'. */ ! 113: } ! 114: /* C M S A V P -- Save a copy of the current prompt. */ ! 115: ! 116: cmsavp(s,n) int n; char s[]; { ! 117: extern char *strncpy(); /* +1 */ ! 118: strncpy(s,cmprom,n-1); ! 119: s[n] = NUL; ! 120: } ! 121: ! 122: /* P R O M P T -- Issue the program prompt. */ ! 123: ! 124: prompt() { ! 125: if (psetf == 0) cmsetp(dfprom); /* If no prompt set, set default. */ ! 126: printf("\r%s",cmprom); /* Print the prompt. */ ! 127: } ! 128: ! 129: ! 130: /* C M R E S -- Reset pointers to beginning of command buffer. */ ! 131: ! 132: cmres() { ! 133: cc = 0; /* Reset character counter. */ ! 134: pp = np = bp = cmdbuf; /* Point to command buffer. */ ! 135: cmflgs = -5; /* Parse not yet started. */ ! 136: } ! 137: ! 138: ! 139: /* C M I N I -- Clear the command and atom buffers, reset pointers. */ ! 140: ! 141: /* ! 142: The argument specifies who is to echo the user's typein -- ! 143: 1 means the cmd package echoes ! 144: 0 somebody else (system, front end, terminal) echoes ! 145: */ ! 146: cmini(d) int d; { ! 147: for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL; ! 148: *atmbuf = NUL; ! 149: dpx = d; ! 150: cmres(); ! 151: } ! 152: ! 153: stripq(s) char *s; { /* Function to strip '\' quotes */ ! 154: char *t; ! 155: while (*s) { ! 156: if (*s == '\\') { ! 157: for (t = s; *t != '\0'; t++) *t = *(t+1); ! 158: } ! 159: s++; ! 160: } ! 161: } ! 162: ! 163: ! 164: /* C M N U M -- Parse a number in the indicated radix */ ! 165: ! 166: /* For now, only works for positive numbers in base 10. */ ! 167: ! 168: /* ! 169: Returns ! 170: -3 if no input present when required, ! 171: -2 if user typed an illegal number, ! 172: -1 if reparse needed, ! 173: 0 otherwise, with n set to number that was parsed ! 174: */ ! 175: cmnum(xhlp,xdef,radix,n) char *xhlp, *xdef; int radix, *n; { ! 176: int x; char *s; ! 177: ! 178: if (radix != 10) { /* Just do base 10 for now */ ! 179: printf("cmnum: illegal radix - %d\n",radix); ! 180: return(-1); ! 181: } ! 182: ! 183: x = cmfld(xhlp,xdef,&s); ! 184: debug(F101,"cmnum: cmfld","",x); ! 185: if (x < 0) return(x); /* Parse a field */ ! 186: ! 187: if (digits(atmbuf)) { /* Convert to number */ ! 188: *n = atoi(atmbuf); ! 189: return(x); ! 190: } else { ! 191: printf("\n?not a number - %s\n",s); ! 192: return(-2); ! 193: } ! 194: } ! 195: ! 196: ! 197: /* C M O F I -- Parse the name of an output file */ ! 198: ! 199: /* ! 200: Depends on the external function zchko(); if zchko() not available, use ! 201: cmfld() to parse output file names. ! 202: ! 203: Returns ! 204: -3 if no input present when required, ! 205: -2 if permission would be denied to create the file, ! 206: -1 if reparse needed, ! 207: 0 or 1 otherwise, with xp pointing to name. ! 208: */ ! 209: cmofi(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { ! 210: int x; char *s; ! 211: ! 212: if (*xhlp == NUL) xhlp = "Output file"; ! 213: *xp = ""; ! 214: ! 215: if ((x = cmfld(xhlp,xdef,&s)) < 0) return(x); ! 216: ! 217: if (chkwld(s)) { ! 218: printf("\n?Wildcards not allowed - %s\n",s); ! 219: return(-2); ! 220: } ! 221: if (zchko(s) < 0) { ! 222: printf("\n?Write permission denied - %s\n",s); ! 223: return(-2); ! 224: } else { ! 225: *xp = s; ! 226: return(x); ! 227: } ! 228: } ! 229: ! 230: ! 231: /* C M I F I -- Parse the name of an existing file */ ! 232: ! 233: /* ! 234: This function depends on the external functions: ! 235: zchki() - Check if input file exists and is readable. ! 236: zxpand() - Expand a wild file specification into a list. ! 237: znext() - Return next file name from list. ! 238: If these functions aren't available, then use cmfld() to parse filenames. ! 239: */ ! 240: /* ! 241: Returns ! 242: -4 EOF ! 243: -3 if no input present when required, ! 244: -2 if file does not exist or is not readable, ! 245: -1 if reparse needed, ! 246: 0 or 1 otherwise, with: ! 247: xp pointing to name, ! 248: wild = 1 if name contains '*' or '?', 0 otherwise. ! 249: */ ! 250: cmifi(xhlp,xdef,xp,wild) char *xhlp, *xdef, **xp; int *wild; { ! 251: int i, x, xc; long y; char *sp; ! 252: ! 253: cc = xc = 0; /* Initialize counts & pointers */ ! 254: *xp = ""; ! 255: if ((x = cmflgs) != 1) { /* Already confirmed? */ ! 256: x = getwd(); /* No, get a word */ ! 257: } else { ! 258: cc = setatm(xdef); /* If so, use default, if any. */ ! 259: } ! 260: *xp = atmbuf; /* Point to result. */ ! 261: *wild = chkwld(*xp); ! 262: ! 263: while (1) { ! 264: xc += cc; /* Count the characters. */ ! 265: debug(F111,"cmifi: getwd",atmbuf,xc); ! 266: switch (x) { ! 267: case -4: /* EOF */ ! 268: case -2: /* Out of space. */ ! 269: case -1: /* Reparse needed */ ! 270: return(x); ! 271: ! 272: /* cont'd... */ ! 273: ! 274: ! 275: /* ...cmifi(), cont'd */ ! 276: ! 277: ! 278: case 0: /* SP or NL */ ! 279: case 1: ! 280: if (xc == 0) *xp = xdef; /* If no input, return default. */ ! 281: else *xp = atmbuf; ! 282: if (**xp == NUL) return(-3); /* If field empty, return -3. */ ! 283: ! 284: /* If filespec is wild, see if there are any matches */ ! 285: ! 286: *wild = chkwld(*xp); ! 287: debug(F101," *wild","",*wild); ! 288: if (*wild != 0) { ! 289: y = zxpand(*xp); ! 290: if (y == 0) { ! 291: printf("\n?No files match - %s\n",*xp); ! 292: return(-2); ! 293: } else if (y < 0) { ! 294: printf("\n?Too many files match - %s\n",*xp); ! 295: return(-2); ! 296: } else return(x); ! 297: } ! 298: ! 299: /* If not wild, see if it exists and is readable. */ ! 300: ! 301: y = zchki(*xp); ! 302: if (y == -3) { ! 303: printf("\n?Read permission denied - %s\n",*xp); ! 304: return(-2); ! 305: } else if (y == -2) { ! 306: printf("\n?File not readable - %s\n",*xp); ! 307: return(-2); ! 308: } else if (y < 0) { ! 309: printf("\n?File not found - %s\n",*xp); ! 310: return(-2); ! 311: } ! 312: return(x); ! 313: /* cont'd... */ ! 314: ! 315: ! 316: /* ...cmifi(), cont'd */ ! 317: ! 318: ! 319: case 2: /* ESC */ ! 320: if (xc == 0) { ! 321: if (*xdef != '\0') { ! 322: printf("%s ",xdef); /* If at beginning of field, */ ! 323: addbuf(xdef); /* supply default. */ ! 324: cc = setatm(xdef); ! 325: } else { /* No default */ ! 326: putchar(BEL); ! 327: } ! 328: break; ! 329: } ! 330: if (*wild = chkwld(*xp)) { /* No completion if wild */ ! 331: putchar(BEL); ! 332: break; ! 333: } ! 334: sp = atmbuf + cc; ! 335: *sp++ = '*'; ! 336: *sp-- = '\0'; ! 337: y = zxpand(atmbuf); /* Add * and expand list. */ ! 338: *sp = '\0'; /* Remove *. */ ! 339: ! 340: if (y == 0) { ! 341: printf("\n?No files match - %s\n",atmbuf); ! 342: return(-2); ! 343: } else if (y < 0) { ! 344: printf("\n?Too many files match - %s\n",atmbuf); ! 345: return(-2); ! 346: } else if (y > 1) { /* Not unique, just beep. */ ! 347: putchar(BEL); ! 348: } else { /* Unique, complete it. */ ! 349: znext(filbuf); /* Get whole name of file. */ ! 350: sp = filbuf + cc; /* Point past what user typed. */ ! 351: printf("%s ",sp); /* Complete the name. */ ! 352: addbuf(sp); /* Add the characters to cmdbuf. */ ! 353: setatm(pp); /* And to atmbuf. */ ! 354: *xp = atmbuf; /* Return pointer to atmbuf. */ ! 355: return(cmflgs = 0); ! 356: } ! 357: break; ! 358: ! 359: /* cont'd... */ ! 360: ! 361: ! 362: /* ...cmifi(), cont'd */ ! 363: ! 364: ! 365: case 3: /* Question mark */ ! 366: if (*xhlp == NUL) ! 367: printf(" Input file specification"); ! 368: else ! 369: printf(" %s",xhlp); ! 370: if (xc > 0) { ! 371: sp = atmbuf + cc; /* Insert * at end */ ! 372: *sp++ = '*'; ! 373: *sp-- = '\0'; ! 374: y = zxpand(atmbuf); ! 375: *sp = '\0'; ! 376: if (y == 0) { ! 377: printf("\n?No files match - %s\n",atmbuf); ! 378: return(-2); ! 379: } else if (y < 0) { ! 380: printf("\n?Too many file match - %s\n",atmbuf); ! 381: return(-2); ! 382: } else { ! 383: printf(", one of the following:\n"); ! 384: clrhlp(); ! 385: for (i = 0; i < y; i++) { ! 386: znext(filbuf); ! 387: addhlp(filbuf); ! 388: } ! 389: dmphlp(); ! 390: } ! 391: } else printf("\n"); ! 392: printf("%s%s",cmprom,cmdbuf); ! 393: break; ! 394: } ! 395: x = getwd(); ! 396: } ! 397: } ! 398: ! 399: ! 400: ! 401: /* C H K W L D -- Check for wildcard characters '*' or '?' */ ! 402: ! 403: chkwld(s) char *s; { ! 404: ! 405: for ( ; *s != '\0'; s++) { ! 406: if ((*s == '*') || (*s == '?')) ! 407: return(1); ! 408: } ! 409: return(0); ! 410: } ! 411: ! 412: ! 413: /* C M F L D -- Parse an arbitrary field */ ! 414: /* ! 415: Returns ! 416: -3 if no input present when required, ! 417: -2 if field too big for buffer, ! 418: -1 if reparse needed, ! 419: 0 otherwise, xp pointing to string result. ! 420: */ ! 421: cmfld(xhlp,xdef,xp) char *xhlp, *xdef, **xp; { ! 422: int x, xc; ! 423: ! 424: cc = xc = 0; /* Initialize counts & pointers */ ! 425: *xp = ""; ! 426: if ((x = cmflgs) != 1) { /* Already confirmed? */ ! 427: x = getwd(); /* No, get a word */ ! 428: } else { ! 429: cc = setatm(xdef); /* If so, use default, if any. */ ! 430: } ! 431: *xp = atmbuf; /* Point to result. */ ! 432: ! 433: while (1) { ! 434: xc += cc; /* Count the characters. */ ! 435: debug(F111,"cmfld: getwd",atmbuf,xc); ! 436: debug(F101," x","",x); ! 437: switch (x) { ! 438: case -4: /* EOF */ ! 439: case -2: /* Out of space. */ ! 440: case -1: /* Reparse needed */ ! 441: return(x); ! 442: case 0: /* SP or NL */ ! 443: case 1: ! 444: if (xc == 0) *xp = xdef; /* If no input, return default. */ ! 445: else *xp = atmbuf; ! 446: if (**xp == NUL) x = -3; /* If field empty, return -3. */ ! 447: return(x); ! 448: case 2: /* ESC */ ! 449: if (xc == 0) { ! 450: printf("%s ",xdef); /* If at beginning of field, */ ! 451: addbuf(xdef); /* supply default. */ ! 452: cc = setatm(xdef); /* Return as if whole field */ ! 453: return(0); /* typed, followed by space. */ ! 454: } else { ! 455: putchar(BEL); /* Beep if already into field. */ ! 456: } ! 457: break; ! 458: case 3: /* Question mark */ ! 459: if (*xhlp == NUL) ! 460: printf(" Please complete this field"); ! 461: else ! 462: printf(" %s",xhlp); ! 463: printf("\n%s%s",cmprom,cmdbuf); ! 464: break; ! 465: } ! 466: x = getwd(); ! 467: } ! 468: } ! 469: ! 470: ! 471: /* C M T X T -- Get a text string, including confirmation */ ! 472: ! 473: /* ! 474: Print help message 'xhlp' if ? typed, supply default 'xdef' if null ! 475: string typed. Returns ! 476: ! 477: -1 if reparse needed or buffer overflows. ! 478: 1 otherwise. ! 479: ! 480: with cmflgs set to return code, and xp pointing to result string. ! 481: */ ! 482: ! 483: cmtxt(xhlp,xdef,xp) char *xhlp; char *xdef; char **xp; { ! 484: ! 485: int x; ! 486: static int xc; ! 487: ! 488: debug(F101,"cmtxt, cmflgs","",cmflgs); ! 489: cc = 0; /* Start atmbuf counter off at 0 */ ! 490: if (cmflgs == -1) { /* If reparsing, */ ! 491: xc = strlen(*xp); /* get back the total text length, */ ! 492: } else { /* otherwise, */ ! 493: *xp = ""; /* start fresh. */ ! 494: xc = 0; ! 495: } ! 496: *atmbuf = NUL; /* And empty atom buffer. */ ! 497: if ((x = cmflgs) != 1) { ! 498: x = getwd(); /* Get first word. */ ! 499: *xp = pp; /* Save pointer to it. */ ! 500: } ! 501: while (1) { ! 502: xc += cc; /* Char count for all words. */ ! 503: debug(F111,"cmtxt: getwd",atmbuf,xc); ! 504: debug(F101," x","",x); ! 505: switch (x) { ! 506: case -4: /* EOF */ ! 507: case -2: /* Overflow */ ! 508: case -1: /* Deletion */ ! 509: return(x); ! 510: case 0: /* Space */ ! 511: xc++; /* Just count it */ ! 512: break; ! 513: case 1: /* CR or LF */ ! 514: if (xc == 0) *xp = xdef; ! 515: return(x); ! 516: case 2: /* ESC */ ! 517: if (xc == 0) { ! 518: printf("%s ",xdef); ! 519: cc = addbuf(xdef); ! 520: } else { ! 521: putchar(BEL); ! 522: } ! 523: break; ! 524: case 3: /* Question Mark */ ! 525: if (*xhlp == NUL) ! 526: printf(" Text string"); ! 527: else ! 528: printf(" %s",xhlp); ! 529: printf("\n%s%s",cmprom,cmdbuf); ! 530: break; ! 531: default: ! 532: printf("\n?Unexpected return code from getwd() - %d\n",x); ! 533: return(-2); ! 534: } ! 535: x = getwd(); ! 536: } ! 537: } ! 538: ! 539: ! 540: /* C M K E Y -- Parse a keyword */ ! 541: ! 542: /* ! 543: Call with: ! 544: table -- keyword table, in 'struct keytab' format; ! 545: n -- number of entries in table; ! 546: xhlp -- pointer to help string; ! 547: xdef -- pointer to default keyword; ! 548: ! 549: Returns: ! 550: -3 -- no input supplied and no default available ! 551: -2 -- input doesn't uniquely match a keyword in the table ! 552: -1 -- user deleted too much, command reparse required ! 553: n >= 0 -- value associated with keyword ! 554: */ ! 555: ! 556: cmkey(table,n,xhlp,xdef) struct keytab table[]; int n; char *xhlp, *xdef; { ! 557: int i, y, z, zz, xc; ! 558: char *xp; ! 559: ! 560: xc = cc = 0; /* Clear character counters. */ ! 561: ! 562: if ((zz = cmflgs) == 1) /* Command already entered? */ ! 563: setatm(xdef); ! 564: else zz = getwd(); ! 565: ! 566: debug(F101,"cmkey: table length","",n); ! 567: debug(F101," cmflgs","",cmflgs); ! 568: debug(F101," zz","",zz); ! 569: while (1) { ! 570: xc += cc; ! 571: debug(F111,"cmkey: getwd",atmbuf,xc); ! 572: ! 573: switch(zz) { ! 574: case -4: /* EOF */ ! 575: case -2: /* Buffer overflow */ ! 576: case -1: /* Or user did some deleting. */ ! 577: return(zz); ! 578: ! 579: case 0: /* User terminated word with space */ ! 580: case 1: /* or newline */ ! 581: if (cc == 0) setatm(xdef); ! 582: y = lookup(table,atmbuf,n,&z); ! 583: switch (y) { ! 584: case -2: ! 585: printf("\n?Ambiguous - %s\n",atmbuf); ! 586: return(cmflgs = -2); ! 587: case -1: ! 588: printf("\n?Invalid - %s\n",atmbuf); ! 589: return(cmflgs = -2); ! 590: default: ! 591: break; ! 592: } ! 593: return(y); ! 594: ! 595: /* cont'd... */ ! 596: ! 597: ! 598: /* ...cmkey(), cont'd */ ! 599: ! 600: case 2: /* User terminated word with ESC */ ! 601: if (cc == 0) { ! 602: if (*xdef != NUL) { /* Nothing in atmbuf */ ! 603: printf("%s ",xdef); /* Supply default if any */ ! 604: addbuf(xdef); ! 605: cc = setatm(xdef); ! 606: debug(F111,"cmkey: default",atmbuf,cc); ! 607: } else { ! 608: putchar(BEL); /* No default, just beep */ ! 609: break; ! 610: } ! 611: } ! 612: y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */ ! 613: debug(F111,"cmkey: esc",atmbuf,y); ! 614: if (y == -2) { ! 615: putchar(BEL); ! 616: break; ! 617: } ! 618: if (y == -1) { ! 619: printf("\n?Invalid - %s\n",atmbuf); ! 620: return(cmflgs = -2); ! 621: } ! 622: xp = table[z].kwd + cc; ! 623: printf("%s ",xp); ! 624: addbuf(xp); ! 625: debug(F110,"cmkey: addbuf",cmdbuf,0); ! 626: return(y); ! 627: ! 628: /* cont'd... */ ! 629: ! 630: ! 631: /* ...cmkey(), cont'd */ ! 632: ! 633: case 3: /* User terminated word with "?" */ ! 634: y = lookup(table,atmbuf,n,&z); ! 635: if (y > -1) { ! 636: printf(" %s\n%s%s",table[z].kwd,cmprom,cmdbuf); ! 637: break; ! 638: } else if (y == -1) { ! 639: printf("\n?Invalid\n"); ! 640: return(cmflgs = -2); ! 641: } ! 642: ! 643: if (*xhlp == NUL) ! 644: printf(" One of the following:\n"); ! 645: else ! 646: printf(" %s, one of the following:\n",xhlp); ! 647: ! 648: clrhlp(); ! 649: for (i = 0; i < n; i++) { ! 650: if (!strncmp(table[i].kwd,atmbuf,cc) ! 651: && !test(table[i].flgs,CM_INV)) ! 652: addhlp(table[i].kwd); ! 653: } ! 654: dmphlp(); ! 655: printf("%s%s", cmprom, cmdbuf); ! 656: break; ! 657: ! 658: default: ! 659: printf("\n%d - Unexpected return code from getwd\n",zz); ! 660: return(cmflgs = -2); ! 661: } ! 662: zz = getwd(); ! 663: } ! 664: } ! 665: ! 666: ! 667: /* C M C F M -- Parse command confirmation (end of line) */ ! 668: ! 669: /* ! 670: Returns ! 671: -2: User typed anything but whitespace or newline ! 672: -1: Reparse needed ! 673: 0: Confirmation was received ! 674: */ ! 675: ! 676: cmcfm() { ! 677: int x, xc; ! 678: ! 679: debug(F101,"cmcfm: cmflgs","",cmflgs); ! 680: ! 681: xc = cc = 0; ! 682: if (cmflgs == 1) return(0); ! 683: ! 684: while (1) { ! 685: x = getwd(); ! 686: xc += cc; ! 687: debug(F111,"cmcfm: getwd",atmbuf,xc); ! 688: switch (x) { ! 689: case -4: /* EOF */ ! 690: case -2: ! 691: case -1: ! 692: return(x); ! 693: ! 694: case 0: /* Space */ ! 695: continue; ! 696: case 1: /* End of line */ ! 697: if (xc > 0) { ! 698: printf("?Not confirmed - %s\n",atmbuf); ! 699: return(-2); ! 700: } else return(0); ! 701: case 2: ! 702: putchar(BEL); ! 703: continue; ! 704: ! 705: case 3: ! 706: if (xc > 0) { ! 707: printf("\n?Not confirmed - %s\n",atmbuf); ! 708: return(-2); ! 709: } ! 710: printf("\n Type a carriage return to confirm the command\n"); ! 711: printf("%s%s",cmprom,cmdbuf); ! 712: continue; ! 713: } ! 714: } ! 715: } ! 716: ! 717: ! 718: /* Keyword help routines */ ! 719: ! 720: ! 721: /* C L R H L P -- Initialize/Clear the help line buffer */ ! 722: ! 723: clrhlp() { /* Clear the help buffer */ ! 724: hlpbuf[0] = NUL; ! 725: hh = hx = 0; ! 726: } ! 727: ! 728: ! 729: /* A D D H L P -- Add a string to the help line buffer */ ! 730: ! 731: addhlp(s) char *s; { /* Add a word to the help buffer */ ! 732: int j; ! 733: ! 734: hh++; /* Count this column */ ! 735: ! 736: for (j = 0; (j < hc) && (*s != NUL); j++) { /* Fill the column */ ! 737: hlpbuf[hx++] = *s++; ! 738: } ! 739: if (*s != NUL) /* Still some chars left in string? */ ! 740: hlpbuf[hx-1] = '+'; /* Mark as too long for column. */ ! 741: ! 742: if (hh < (hw / hc)) { /* Pad col with spaces if necessary */ ! 743: for (; j < hc; j++) { ! 744: hlpbuf[hx++] = SP; ! 745: } ! 746: } else { /* If last column, */ ! 747: hlpbuf[hx++] = NUL; /* no spaces. */ ! 748: dmphlp(); /* Print it. */ ! 749: return; ! 750: } ! 751: } ! 752: ! 753: ! 754: /* D M P H L P -- Dump the help line buffer */ ! 755: ! 756: dmphlp() { /* Print the help buffer */ ! 757: hlpbuf[hx++] = NUL; ! 758: printf(" %s\n",hlpbuf); ! 759: clrhlp(); ! 760: } ! 761: ! 762: ! 763: /* L O O K U P -- Lookup the string in the given array of strings */ ! 764: ! 765: /* ! 766: Call this way: v = lookup(table,word,n,&x); ! 767: ! 768: table - a 'struct keytab' table. ! 769: word - the target string to look up in the table. ! 770: n - the number of elements in the table. ! 771: x - address of an integer for returning the table array index. ! 772: ! 773: The keyword table must be arranged in ascending alphabetical order, and ! 774: all letters must be lowercase. ! 775: ! 776: Returns the keyword's associated value ( zero or greater ) if found, ! 777: with the variable x set to the array index, or: ! 778: ! 779: -3 if nothing to look up (target was null), ! 780: -2 if ambiguous, ! 781: -1 if not found. ! 782: ! 783: A match is successful if the target matches a keyword exactly, or if ! 784: the target is a prefix of exactly one keyword. It is ambiguous if the ! 785: target matches two or more keywords from the table. ! 786: */ ! 787: ! 788: lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; { ! 789: ! 790: int i, v, cmdlen; ! 791: ! 792: /* Lowercase & get length of target, if it's null return code -3. */ ! 793: ! 794: if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3); ! 795: ! 796: /* Not null, look it up */ ! 797: ! 798: for (i = 0; i < n-1; i++) { ! 799: if (!strcmp(table[i].kwd,cmd) || ! 800: ((v = !strncmp(table[i].kwd,cmd,cmdlen)) && ! 801: strncmp(table[i+1].kwd,cmd,cmdlen))) { ! 802: *x = i; ! 803: return(table[i].val); ! 804: } ! 805: if (v) return(-2); ! 806: } ! 807: ! 808: /* Last (or only) element */ ! 809: ! 810: if (!strncmp(table[n-1].kwd,cmd,cmdlen)) { ! 811: *x = n-1; ! 812: return(table[n-1].val); ! 813: } else return(-1); ! 814: } ! 815: ! 816: ! 817: /* G E T W D -- Gets a "word" from the command input stream */ ! 818: ! 819: /* ! 820: Usage: retcode = getwd(); ! 821: ! 822: Returns: ! 823: -4 if end of file (e.g. pipe broken) ! 824: -2 if command buffer overflows ! 825: -1 if user did some deleting ! 826: 0 if word terminates with SP or tab ! 827: 1 if ... CR ! 828: 2 if ... ESC ! 829: 3 if ... ? ! 830: ! 831: With: ! 832: pp pointing to beginning of word in buffer ! 833: bp pointing to after current position ! 834: atmbuf containing a copy of the word ! 835: cc containing the number of characters in the word copied to atmbuf ! 836: */ ! 837: getwd() { ! 838: ! 839: int c; /* Current char */ ! 840: static int inword = 0; /* Flag for start of word found */ ! 841: int quote = 0; /* Flag for quote character */ ! 842: int echof = 0; /* Flag for whether to echo */ ! 843: int ignore = 0; ! 844: ! 845: pp = np; /* Start of current field */ ! 846: debug(F101,"getwd: cmdbuf","",(int) cmdbuf); ! 847: debug(F101," bp","",(int) bp); ! 848: debug(F101," pp","",(int) pp); ! 849: debug(F110," cmdbuf",cmdbuf,0); ! 850: ! 851: while (bp < cmdbuf+CMDBL) { /* Loop */ ! 852: ! 853: ignore = echof = 0; /* Flag for whether to echo */ ! 854: ! 855: if ((c = *bp) == NUL) { /* Get next character */ ! 856: if (dpx) echof = 1; /* from reparse buffer */ ! 857: c = getchar(); /* or from tty. */ ! 858: if (c == EOF) return(-4); ! 859: } else ignore = 1; ! 860: ! 861: if (quote == 0) { ! 862: ! 863: if (!ignore && (c == '\\')) { /* Quote character */ ! 864: quote = 1; ! 865: continue; ! 866: } ! 867: if (c == FF) { /* Formfeed. */ ! 868: c = NL; /* Replace with newline */ ! 869: system("clear"); /* and clear the screen. */ ! 870: } ! 871: ! 872: if (c == HT) c = SP; /* Substitute space for tab. */ ! 873: ! 874: /* cont'd... */ ! 875: ! 876: ! 877: /* ...getwd(), cont'd */ ! 878: ! 879: if (c == SP) { /* If space */ ! 880: *bp++ = c; /* deposit it in buffer. */ ! 881: if (echof) putchar(c); /* echo it. */ ! 882: if (inword == 0) { /* If leading, gobble it. */ ! 883: pp++; ! 884: continue; ! 885: } else { /* If terminating, return. */ ! 886: np = bp; ! 887: setatm(pp); ! 888: inword = 0; ! 889: return(cmflgs = 0); ! 890: } ! 891: } ! 892: if (c == NL || c == CR) { /* CR, LF */ ! 893: *bp = NUL; /* End the string */ ! 894: if (echof) { /* If echoing, */ ! 895: putchar(c); /* echo the typein */ ! 896: #ifdef aegis ! 897: if (c == CR) putchar(NL); ! 898: #endif ! 899: } ! 900: np = bp; /* Where to start next field. */ ! 901: setatm(pp); /* Copy this field to atom buffer. */ ! 902: inword = 0; ! 903: return(cmflgs = 1); ! 904: } ! 905: if (!ignore && (c == '?')) { /* Question mark */ ! 906: putchar(c); ! 907: *bp = NUL; ! 908: setatm(pp); ! 909: return(cmflgs = 3); ! 910: } ! 911: if (c == ESC) { /* ESC */ ! 912: *bp = NUL; ! 913: setatm(pp); ! 914: return(cmflgs = 2); ! 915: } ! 916: if (c == BS || c == RUB) { /* Character deletion */ ! 917: if (bp > cmdbuf) { /* If still in buffer... */ ! 918: printf("\b \b"); /* erase character from screen, */ ! 919: bp--; /* point behind it, */ ! 920: if (*bp == SP) inword = 0; /* Flag if current field gone */ ! 921: *bp = NUL; /* Erase character from buffer. */ ! 922: } else { /* Otherwise, */ ! 923: putchar(BEL); /* beep, */ ! 924: cmres(); /* and start parsing a new command. */ ! 925: } ! 926: if (pp < bp) continue; ! 927: else return(cmflgs = -1); ! 928: } ! 929: if (c == LDEL) { /* ^U, line deletion */ ! 930: while ((bp--) > cmdbuf) { ! 931: printf("\b \b"); ! 932: *bp = NUL; ! 933: } ! 934: cmres(); /* Restart the command. */ ! 935: inword = 0; ! 936: return(cmflgs = -1); ! 937: } ! 938: ! 939: /* cont'd... */ ! 940: ! 941: ! 942: /* ...getwd(), cont'd */ ! 943: ! 944: if (c == WDEL) { /* ^W, word deletion */ ! 945: if (bp <= cmdbuf) { /* Beep if nothing to delete */ ! 946: putchar(BEL); ! 947: cmres(); ! 948: return(cmflgs = -1); ! 949: } ! 950: bp--; ! 951: for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) { ! 952: printf("\b \b"); ! 953: *bp = NUL; ! 954: } ! 955: for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) { ! 956: printf("\b \b"); ! 957: *bp = NUL; ! 958: } ! 959: bp++; ! 960: inword = 0; ! 961: return(cmflgs = -1); ! 962: } ! 963: if (c == RDIS) { /* ^R, redisplay */ ! 964: *bp = NUL; ! 965: printf("\n%s%s",cmprom,cmdbuf); ! 966: continue; ! 967: } ! 968: } ! 969: if (echof) putchar(c); /* If tty input, echo. */ ! 970: inword = 1; /* Flag we're in a word. */ ! 971: if (quote == 0 || c != NL) *bp++ = c; /* And deposit it. */ ! 972: quote = 0; /* Turn off quote. */ ! 973: } /* end of big while */ ! 974: putchar(BEL); /* Get here if... */ ! 975: printf("\n?Buffer full\n"); ! 976: return(cmflgs = -2); ! 977: } ! 978: ! 979: ! 980: /* Utility functions */ ! 981: ! 982: /* A D D B U F -- Add the string pointed to by cp to the command buffer */ ! 983: ! 984: addbuf(cp) char *cp; { ! 985: int len = 0; ! 986: while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) { ! 987: *bp++ = *cp++; /* Copy and */ ! 988: len++; /* count the characters. */ ! 989: } ! 990: *bp++ = SP; /* Put a space at the end */ ! 991: *bp = NUL; /* Terminate with a null */ ! 992: np = bp; /* Update the next-field pointer */ ! 993: return(len); /* Return the length */ ! 994: } ! 995: ! 996: /* S E T A T M -- Deposit a string in the atom buffer */ ! 997: ! 998: setatm(cp) char *cp; { ! 999: char *ap; ! 1000: cc = 0; ! 1001: ap = atmbuf; ! 1002: *ap = NUL; ! 1003: while (*cp == SP) cp++; ! 1004: while ((*cp != SP) && (*cp != NL) && (*cp != NUL) && (*cp != CR)) { ! 1005: *ap++ = *cp++; ! 1006: cc++; ! 1007: } ! 1008: *ap++ = NUL; ! 1009: return(cc); /* Return length */ ! 1010: } ! 1011: ! 1012: /* D I G I T S -- Verify that all the characters in line are digits */ ! 1013: ! 1014: digits(s) char *s; { ! 1015: while (*s) { ! 1016: if (!isdigit(*s)) return(0); ! 1017: s++; ! 1018: } ! 1019: return(1); ! 1020: } ! 1021: ! 1022: /* L O W E R -- Lowercase a string */ ! 1023: ! 1024: lower(s) char *s; { ! 1025: int n = 0; ! 1026: while (*s) { ! 1027: if (isupper(*s)) *s = tolower(*s); ! 1028: s++, n++; ! 1029: } ! 1030: return(n); ! 1031: } ! 1032: ! 1033: /* T E S T -- Bit test */ ! 1034: ! 1035: test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */ ! 1036: return((x & m) ? 1 : 0); ! 1037: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.