Annotation of coherent/e/bin/ckermit/ckucmd.c, revision 1.1

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

unix.superglobalmegacorp.com

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