Annotation of researchv10dc/lbin/kermit/ckucmd.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.