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

unix.superglobalmegacorp.com

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