Annotation of researchv10dc/lbin/kermit/ckucmd.c, revision 1.1.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.