Annotation of 43BSD/contrib/kermit/ckucmd.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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