Annotation of coherent/g/usr/bin/ckermit/ckucmd.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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