source: trunk/third/kermit/ckucmd.c @ 10780

Revision 10780, 112.5 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
Line 
1#include "ckcsym.h"
2
3char *cmdv = "Command package 6.0.088, 6 Sep 96";
4
5#ifdef OS2
6int cmdmsk = 255; /* Command-terminal-to-C-Kermit character mask */
7#else
8int cmdmsk = 127; /* Command-terminal-to-C-Kermit character mask */
9#endif /* OS2 */
10
11#ifdef BS_DIRSEP                        /* Directory separator is backslash */
12#undef BS_DIRSEP
13#endif /* BS_DIRSEP */
14
15#ifdef OS2
16#define BS_DIRSEP
17#endif /* BS_DIRSEP */
18
19#include "ckcdeb.h"                     /* Formats for debug(), etc. */
20#include "ckcker.h"                     /* Needed for BIGBUFOK definition */
21#include "ckucmd.h"                     /* Needed for xx_strp prototype */
22#include "ckuusr.h"                     /* Needed for prompt length */
23
24_PROTOTYP( int unhex, (char) );
25_PROTOTYP( static int filhelp, (int, char *, char *, int) );
26_PROTOTYP( VOID sh_sort, (char **, int) );
27_PROTOTYP( static VOID cmdclrscn, (void) );
28
29#ifndef NOICP     /* The rest only if interactive command parsing selected */
30
31#ifndef NOSPL
32_PROTOTYP( int chkvar, (char *) );
33#endif /* NOSPL */
34
35static int blocklvl = 0;              /* "Block" level */
36static int linebegin = 0;             /* Flag for at start of a line */
37static int quoting = 1;
38
39#ifdef BS_DIRSEP
40static int cmdirflg = 0;
41#endif /* BS_DIRSEP */
42
43/*  C K U C M D  --  Interactive command package for Unix  */
44
45/*
46  Author: Frank da Cruz (fdc@columbia.edu),
47  Columbia University Academic Information Systems, New York City.
48
49  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
50  York.  The C-Kermit software may not be, in whole or in part, licensed or
51  sold for profit as a software product itself, nor may it be included in or
52  distributed with commercial products or otherwise distributed by commercial
53  concerns to their clients or customers without written permission of the
54  Office of Kermit Development and Distribution, Columbia University.  This
55  copyright notice must not be removed, altered, or obscured.
56*/
57
58/*
59Modeled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. Features:
60
61. parses and verifies keywords, filenames, text strings, numbers, other data
62. displays appropriate menu or help message when user types "?"
63. does keyword and filename completion when user types ESC or TAB
64. does partial filename completion
65. accepts any unique abbreviation for a keyword
66. allows keywords to have attributes, like "invisible" and "abbreviation"
67. can supply defaults for fields omitted by user
68. provides command retry and recall
69. provides command line editing (character, word, and line deletion)
70. accepts input from keyboard, command files, macros, or redirected stdin
71. allows for full or half duplex operation, character or line input
72. allows \-escapes for hard-to-type characters
73. allows specification of a user exit to expand variables, etc.
74. settable prompt, protected from deletion, dynamically re-evaluated each time.
75
76Functions:
77 cmsetp - Set prompt (cmprom is prompt string)
78 cmsavp - Save current prompt
79 prompt - Issue prompt
80 cmini - Clear the command buffer (before parsing a new command)
81 cmres - Reset command buffer pointers (before reparsing)
82 cmkey - Parse a keyword or token
83 cmnum - Parse a number
84 cmifi - Parse an input file name
85 cmofi - Parse an output file name
86 cmdir - Parse a directory name
87 cmfld - Parse an arbitrary field
88 cmtxt - Parse a text string
89 cmcfm - Parse command confirmation (end of line)
90
91Return codes:
92 -9: like -2 except this module already printed the error message
93 -3: no input provided when required
94 -2: input was invalid (e.g. not a number when a number was required)
95 -1: reparse required (user deleted into a preceding field)
96  0 or greater: success
97See individual functions for greater detail.
98
99Before using these routines, the caller should #include ckucmd.h, and set the
100program's prompt by calling cmsetp().  If the file parsing functions cmifi,
101cmofi, or cmdir are to be used, this module must be linked with a ck?fio file
102system support module for the appropriate system, e.g. ckufio for Unix.  If
103the caller puts the terminal in character wakeup ("cbreak") mode with no echo,
104then these functions will provide line editing -- character, word, and line
105deletion, as well as keyword and filename completion upon ESC and help
106strings, keyword, or file menus upon '?'.  If the caller puts the terminal
107into character wakeup/noecho mode, care should be taken to restore it before
108exit from or interruption of the program.  If the character wakeup mode is not
109set, the system's own line editor may be used.
110
111NOTE: Contrary to expectations, many #ifdef's have been added to this module.
112Any operation requiring an #ifdef (like clear screen, get character from
113keyboard, erase character from screen, etc) should eventually be turned into a
114call to a function that is defined in ck?tio.c, but then all the ck?tio.c
115modules would have to be changed...
116*/
117
118/* Includes */
119
120#include "ckcker.h"
121#include "ckcasc.h"                     /* ASCII character symbols */
122#include "ckucmd.h"                     /* Command parsing definitions */
123#include <errno.h>                      /* Error number symbols */
124
125#ifdef OS2
126#ifndef NT
127#define INCL_NOPM
128#define INCL_VIO                        /* Needed for ckocon.h */
129#include <os2.h>
130#undef COMMENT
131#else
132#define APIRET ULONG
133#include <windows.h>
134#endif /* NT */
135#include "ckocon.h"
136#include <io.h>
137#endif /* OS2 */
138
139#ifdef NT
140#define stricmp _stricmp
141#endif /* NT */
142
143#ifdef OSK
144#define cc ccount                       /* OS-9/68K compiler bug */
145#endif /* OSK */
146
147#ifdef GEMDOS                           /* Atari ST */
148#ifdef putchar
149#undef putchar
150#endif /* putchar */
151#define putchar(x) conoc(x)
152#endif /* GEMDOS */
153
154/* Local variables */
155
156static
157int psetf = 0,                          /* Flag that prompt has been set */
158    cc = 0,                             /* Character count */
159    dpx = 0,                            /* Duplex (0 = full) */
160    inword = 0;                         /* In the middle of getting a word */
161
162static
163int hw = HLPLW,                         /* Help line width */
164    hc = HLPCW,                         /* Help line column width */
165    hh,                                 /* Current help column number */
166    hx;                                 /* Current help line position */
167
168char *dfprom = "Command? ";             /* Default prompt */
169
170int cmflgs;                             /* Command flags */
171int cmfsav;                             /* A saved version of them */
172
173#ifdef DCMDBUF
174char *cmdbuf;                           /* Command buffer */
175char *savbuf;                           /* Buffer to save copy of command */
176char *atmbuf;                           /* Atom buffer - for current field */
177char *atxbuf;                           /* For expanding the atom buffer */
178#ifdef OLDHELP
179static char *hlpbuf;                    /* Help string buffer */
180#endif /* OLDHELP */
181static char *atybuf;                    /* For copying atom buffer */
182static char *filbuf;                    /* File name buffer */
183static char *cmprom;                    /* Program's prompt */
184static char *cmprxx;                    /* Program's prompt, unevaluated */
185
186#ifdef CK_RECALL
187/*
188  Command recall is available only if we can make profligate use of malloc().
189*/
190#define R_MAX 10                        /* Max number of commands to save */
191int cm_recall = R_MAX;                  /* Size of command recall buffer */
192int on_recall = 1;                      /* Recall feature is ON */
193int in_recall = 0;                      /* Recall buffers are init'd */
194static int
195  current = -1,                         /* Pointer to current command */
196  rlast = -1;                           /* Index of last command in buffer */
197static char **recall = NULL;            /* Array of recall buffer pointers */
198#endif /* CK_RECALL */
199#else
200char cmdbuf[CMDBL+4];                   /* Command buffer */
201char savbuf[CMDBL+4];                   /* Buffer to save copy of command */
202char atmbuf[ATMBL+4];                   /* Atom buffer */
203char atxbuf[CMDBL+4];                   /* For expanding the atom buffer */
204#ifdef OLDHELP
205static char hlpbuf[HLPBL+4];            /* Help string buffer */
206#endif /* OLDHELP */
207static char atybuf[ATMBL+4];            /* For copying atom buffer */
208static char filbuf[ATMBL+4];            /* File name buffer */
209static char cmprom[PROMPTL+1];          /* Program's prompt */
210static char cmprxx[PROMPTL+1];          /* Program's prompt, unevaluated */
211#endif /* DCMDBUF */
212
213/* Command buffer pointers */
214
215static char *bp,                        /* Current command buffer position */
216    *pp,                                /* Start of current field */
217    *np;                                /* Start of next field */
218
219static int ungw,                        /* For ungetting words */
220    atxn;                               /* Expansion buffer (atxbuf) length */
221
222#ifdef OS2
223extern int wideresult;
224#endif /* OS2 */
225
226extern int cmd_cols, cmd_rows;
227
228#ifdef OLDHELP
229_PROTOTYP( static VOID addhlp, (char *) );
230_PROTOTYP( static VOID clrhlp, (void) );
231_PROTOTYP( static VOID dmphlp, (void) );
232#endif /* OLDHELP */
233_PROTOTYP( static int gtword, (void) );
234_PROTOTYP( static int addbuf, (char *) );
235_PROTOTYP( static int setatm, (char *, int) );
236_PROTOTYP( static int cmdgetc, (void) );
237_PROTOTYP( static VOID cmdnewl, (char) );
238_PROTOTYP( static VOID cmdchardel, (void) );
239_PROTOTYP( static VOID cmdecho, (char, int) );
240_PROTOTYP( static int test, (int, int) );
241#ifdef GEMDOS
242_PROTOTYP( extern char *strchr, (char *, int) );
243#endif /* GEMDOS */
244
245/*  T E S T  --  Bit test  */
246
247static int
248test(x,m) int x, m; { /*  Returns 1 if any bits from m are on in x, else 0  */
249    return((x & m) ? 1 : 0);
250}
251
252/*  K W D H E L P  --  Given a keyword table, print keywords in columns.  */
253/*
254  Call with:
255    s     - keyword table
256    n     - number of entries
257    pat   - pattern (left substring) that must match for each keyword
258    pre   - prefix to add to each keyword
259    post  - suffix to add to each keyword
260    off   - offset on first screenful, allowing room for introductory text
261
262  Arranges keywords in columns with width based on longest keyword.
263  Does "more?" prompting at end of screen. 
264  Uses global cmd_rows and cmd_cols for screen size.
265*/
266VOID
267kwdhelp(s,n,pat,pre,post,off)
268    struct keytab s[]; int n, off; char *pat, *pre, *post;
269/* kwdhelp */ {
270
271    int width = 0;
272    int cc;
273    int cols, height, i, j, k, lc, n2 = 0;
274    char *b = NULL, *p, *q;
275    char *pa, *px;
276    char **s2 = NULL;
277   
278    cc = strlen(pat);
279
280    if (!s) return;                     /* Nothing to do */
281    if (n < 1) return;                  /* Ditto */
282    if (off < 0) off = 0;               /* Offset for first page */
283    if (!pre) pre = "";                 /* Handle null string pointers */
284    if (!post) post = "";
285    lc = off;                           /* Screen-line counter */
286
287    if (s2 = (char **) malloc(n * sizeof(char *))) {
288        for (i = 0; i < n; i++) {       /* Find longest keyword */
289            s2[i] = NULL;
290            if (/* (cc > 0) && */
291                (xxstrcmp(s[i].kwd,pat,cc)) || (s[i].flgs & CM_INV)
292                )
293              continue;
294            s2[n2++] = s[i].kwd;        /* Copy pointers to visible ones */
295            j = strlen(s[i].kwd);
296            if (j > width)
297              width = j;
298        }
299        /* Column width */
300        n = n2;
301    }
302    if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer   */
303        char * bx;
304        bx = b + cmd_cols;
305        width += (int)strlen(pre) + (int)strlen(post) + 2;
306        cols = cmd_cols / width;        /* How many columns? */
307        if (cols < 1) cols = 1;
308        height = n / cols;              /* How long is each column? */
309        if (n % cols) height++;         /* Add one for remainder, if any */
310
311        for (i = 0; i < height; i++) {      /* Loop for each row */
312            for (j = 0; j < cmd_cols; j++)  /* First fill row with blanks */
313              b[j] = SP;
314            for (j = 0; j < cols; j++) {    /* Loop for each column in row */
315                k = i + (j * height);       /* Index of next keyword */
316                if (k < n) {                /* In range? */
317                    pa = pre;
318                    px = post;
319                    p = s2[k];              /* Point to verb name */
320                    q = b + (j * width) + 1; /* Where to copy it to */
321                    while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
322                    q--;                                 /* Back up over NUL */
323                    while ((q < bx) && (*q++ = *p++)) ;  /* Copy filename */
324                    q--;                                 /* Back up over NUL */
325                    while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
326                    if (j < cols - 1) {
327                        q--;
328                        *q = SP;        /* Replace the space */
329                    }
330                }
331            }
332            p = b + cmd_cols - 1;       /* Last char in line */
333            while (*p-- == SP) ;        /* Trim */
334            *(p+2) = NUL;
335            printf("%s\n",b);           /* Print the line */
336            if (++lc > (cmd_rows - 2)) { /* Screen full? */
337                if (!askmore())         /* Do more-prompting... */
338                  goto xkwdhelp;
339                else
340                  lc = 0;
341            }
342        }
343        /* printf("\n"); */             /* Blank line at end of report */
344    } else {                            /* Malloc failure, no columns */
345        for (i = 0; i < n; i++) {
346            if (s[i].flgs & CM_INV)     /* Use original keyword table */
347              continue;                 /* skipping invisible entries */
348            printf("%s%s%s\n",pre,s[i].kwd,post);
349            if (++lc > (cmd_rows - 2)) { /* Screen full? */
350                if (!askmore())         /* Do more-prompting... */
351                  goto xkwdhelp;
352                else
353                  lc = 0;
354            }       
355        }
356    }
357  xkwdhelp:
358    if (s2) free(s2);                   /* Free array copy */
359    if (b) free(b);                     /* Free line buffer */
360    return;
361}
362
363VOID
364sh_sort(s,n) char **s; int n; {         /* Shell sort */
365    int m, i, j;                        /* Much faster than bubble sort */
366    char *t;                            /* Not as fast as Quicksort */
367    if (n < 2)                          /* but less code, and fast enough */
368      return;
369    m = n;                              /* Initial group size is whole array */
370    while (1) {
371        m = m / 2;                      /* Divide group size in half */
372        if (m < 1)                      /* Small as can be, so done */
373          break;
374        for (j = 0; j < n-m; j++) {     /* Sort each group */
375            t = s[j+m];
376            for (i = j; i >= 0; i -= m) {
377                if (strcmp(s[i],t) < 0)
378                  break;
379                s[i+m] = s[i];
380            }
381            s[i+m] = t;
382        }
383    }
384}
385
386/*  F I L H E L P  --  Given a file list, print names in columns.  */
387/*
388  Call with:
389    s     - file list
390    n     - number of entries
391    pat   - pattern (left substring) that must match for each filename
392    pre   - prefix to add to each filename
393    post  - suffix to add to each filename
394    off   - offset on first screenful, allowing room for introductory text
395
396  Arranges filenames in columns with width based on longest filename.
397  Does "more?" prompting at end of screen. 
398  Uses global cmd_rows and cmd_cols for screen size.
399*/
400#ifndef MAXPATHLEN
401#define MAXPATHLEN 1024
402#endif /* MAXPATHLEN */
403
404static int
405filhelp(n,pre,post,off) int n, off; char *pre, *post; {
406    char filbuf[MAXPATHLEN + 1];        /* Temp buffer for one filename */
407    int width = 0;
408    int cols, height, i, j, k, lc, n2 = 0, rc = 0;
409    char *b = NULL, *p, *q;
410    char *pa, *px;
411    char **s2 = NULL;
412
413    if (n < 1) return(0);
414    if (off < 0) off = 0;               /* Offset for first page */
415    if (!pre) pre = "";                 /* Handle null string pointers */
416    if (!post) post = "";
417    lc = off;                           /* Screen-line counter */
418
419    if (s2 = (char **) malloc(n * sizeof(char *))) {
420        for (i = 0; i < n; i++) {       /* Loop through filenames */
421            s2[i] = NULL;               /* Initialize each pointer to NULL */
422            znext(filbuf);              /* Get next filename */
423            if (!filbuf[0])             /* Shouldn't happen */
424              break;
425            if (!(s2[n2] = malloc((j = (int) strlen(filbuf)) + 1))) {
426                printf("?Memory allocation failure\n");
427                rc = -9;
428                goto xfilhelp;
429            }
430            if (j <= MAXPATHLEN) {
431                strcpy(s2[n2],filbuf);
432                n2++;
433            } else {
434                printf("?Name too long - %s\n", filbuf);
435                rc = -9;
436                goto xfilhelp;
437            }           
438            if (j > width)              /* Get width of widest one */
439              width = j;
440        }
441        n = n2;                         /* How many we actually got */
442    }
443    sh_sort(s2,n);                      /* Alphabetize the list */
444
445    if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
446        char * bx;
447        bx = b + cmd_cols;
448        width += (int)strlen(pre) + (int)strlen(post) + 2;
449        cols = cmd_cols / width;        /* How many columns? */
450        if (cols < 1) cols = 1;
451        height = n / cols;              /* How long is each column? */
452        if (n % cols) height++;         /* Add one for remainder, if any */
453
454        for (i = 0; i < height; i++) {      /* Loop for each row */
455            for (j = 0; j < cmd_cols; j++)  /* First fill row with blanks */
456              b[j] = SP;
457            for (j = 0; j < cols; j++) {    /* Loop for each column in row */
458                k = i + (j * height);       /* Index of next filename */
459                if (k < n) {                /* In range? */
460                    pa = pre;
461                    px = post;
462                    p = s2[k];                         /* Point to filename */
463                    q = b + (j * width) + 1;             /* and destination */
464                    while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
465                    q--;                                 /* Back up over NUL */
466                    while ((q < bx) && (*q++ = *p++)) ;  /* Copy filename */
467                    q--;                                 /* Back up over NUL */
468                    while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
469                    if (j < cols - 1) {
470                        q--;
471                        *q = SP;        /* Replace the space */
472                    }
473                }
474            }
475            p = b + cmd_cols - 1;       /* Last char in line */
476            while (*p-- == SP) ;        /* Trim */
477            *(p+2) = NUL;
478            printf("%s\n",b);           /* Print the line */
479            if (++lc > (cmd_rows - 2)) { /* Screen full? */
480                if (!askmore()) {       /* Do more-prompting... */
481                    rc = 0;
482                    goto xfilhelp;
483                } else
484                  lc = 0;
485            }
486        }
487        printf("\n");                   /* Blank line at end of report */
488        rc = 0;
489        goto xfilhelp;
490    } else {                            /* Malloc failure, no columns */
491        for (i = 0; i < n; i++) {
492            znext(filbuf);
493            printf("%s%s%s\n",pre,filbuf,post);
494            if (++lc > (cmd_rows - 2)) { /* Screen full? */
495                if (!askmore()) {        /* Do more-prompting... */
496                    rc = 0;
497                    goto xfilhelp;
498                } else lc = 0;
499            }       
500        }
501xfilhelp:
502        if (b) free(b);
503        for (i = 0; i < n2; i++)
504          if (s2[i]) free(s2[i]);
505        if (s2) free(s2);
506        return(rc);
507    }
508}
509
510/*  C M S E T U P  --  Set up command buffers  */
511
512#ifdef DCMDBUF
513int
514cmsetup() {
515    if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
516    if (!(savbuf = malloc(CMDBL + 4))) return(-1);
517    savbuf[0] = '\0';
518#ifdef OLDHELP
519    if (!(hlpbuf = malloc(HLPBL + 4))) return(-1);
520#endif /* OLDHELP */
521    if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
522    if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
523    if (!(atybuf = malloc(ATMBL + 4))) return(-1);
524    if (!(filbuf = malloc(ATMBL + 4))) return(-1);
525    if (!(cmprom = malloc(PROMPTL + 4))) return(-1);
526    if (!(cmprxx = malloc(PROMPTL + 4))) return(-1);
527#ifdef CK_RECALL
528    cmrini(cm_recall);
529#endif /* CK_RECALL */
530    return(0);
531}
532
533#ifdef CK_RECALL
534/* Initialize or change size of command recall buffer */
535int
536cmrini(n) int n; {
537    int i;
538    if (recall && in_recall) {          /* Free old storage, if any */
539        for (i = 0; i < cm_recall; i++) {
540            if (recall[i]) {
541                free(recall[i]);
542                recall[i] = NULL;
543            }
544        }
545        free(recall);
546        recall = NULL;
547    }
548    cm_recall = n;                      /* Set new size */
549    rlast = current = -1;               /* Initialize pointers */
550    if (n > 0) {
551        recall = (char **)malloc((cm_recall + 1) * sizeof(char *));
552        if (!recall)
553          return(1);
554        for (i = 0; i < cm_recall; i++) {
555            recall[i] = NULL;
556        }
557        in_recall = 1;                  /* Recall buffers init'd */
558    }
559    return(0);
560}
561#endif /* CK_RECALL */
562#endif /* DCMDBUF */
563
564/*  C M S E T P  --  Set the program prompt.  */
565
566VOID
567cmsetp(s) char *s; {
568    strncpy(cmprxx,s,PROMPTL - 1);
569    cmprxx[PROMPTL] = NUL;
570    psetf = 1;                          /* Flag that prompt has been set. */
571}
572
573/*  C M S A V P  --  Save a copy of the current prompt.  */
574
575VOID
576#ifdef CK_ANSIC
577cmsavp(char s[], int n)
578#else
579cmsavp(s,n) char s[]; int n;
580#endif /* CK_ANSIC */
581/* cmsavp */ {
582    strncpy(s,cmprxx,n-1);
583    s[n-1] = NUL;
584}
585
586/*  P R O M P T  --  Issue the program prompt.  */
587
588VOID
589prompt(f) xx_strp f; {
590    char *sx, *sy; int n;
591
592    if (psetf == 0) cmsetp(dfprom);     /* If no prompt set, set default. */
593
594    sx = cmprxx;                        /* Unevaluated copy */
595    if (f) {                            /* If conversion function given */
596        sy = cmprom;                    /* Evaluate it */
597        debug(F101,"PROMPT sx","",sx);
598        debug(F101,"PROMPT sy","",sy);
599        n = PROMPTL;
600        if ((*f)(sx,&sy,&n) < 0)        /* If evaluation failed */
601          sx = cmprxx;                  /* revert to unevaluated copy */
602        else
603          sx = cmprom;
604    } else strcpy(cmprom,sx);
605#ifdef OSK
606    fputs(sx, stdout);
607#else
608#ifdef MAC
609    printf("%s", sx);
610#else
611    printf("\r%s",sx);                  /* Print the prompt. */
612    fflush(stdout);                     /* Now! */
613#endif /* MAC */
614#endif /* OSK */
615}
616
617#ifndef NOSPL
618VOID
619pushcmd() {                             /* For use with IF command. */
620    strncpy(savbuf,np,CMDBL);           /* Save the dependent clause,  */
621    cmres();                            /* and clear the command buffer. */
622    debug(F110, "pushcmd: savbuf:", savbuf, 0);
623}
624#endif /* NOSPL */
625
626#ifdef COMMENT
627/* no longer used... */
628VOID
629popcmd() {
630    strncpy(cmdbuf,savbuf,CMDBL);       /* Put back the saved material */
631    *savbuf = '\0';                     /* and clear the save buffer */
632    cmres();
633}
634#endif /* COMMENT */
635
636/*  C M R E S  --  Reset pointers to beginning of command buffer.  */
637
638VOID
639cmres() {
640    inword = 0;                         /* We're not in a word */
641    cc = 0;                             /* Character count is zero */
642
643/* Initialize pointers */
644
645    pp = cmdbuf;                        /* Beginning of current field */
646    bp = cmdbuf;                        /* Current position within buffer */
647    np = cmdbuf;                        /* Where to start next field */
648
649    cmflgs = -5;                        /* Parse not yet started. */
650    ungw = 0;                           /* Don't need to unget a word. */
651}
652
653/*  C M I N I  --  Clear the command and atom buffers, reset pointers.  */
654
655/*
656The argument specifies who is to echo the user's typein --
657  1 means the cmd package echoes
658  0 somebody else (system, front end, terminal) echoes
659*/
660VOID
661cmini(d) int d; {
662    for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL;
663    *atmbuf = *savbuf = *atxbuf = *atybuf = *filbuf = NUL;
664#ifdef OLDHELP
665    *hlpbuf = NUL;
666#endif /* OLDHELP */
667    blocklvl = 0;               /* Block level is 0 */
668    linebegin = 1;              /* And we're at the beginning of a line */
669    dpx = d;                    /* Make a global copy of the echo flag */
670    cmres();
671}
672
673#ifndef NOSPL
674/* The following bits are to allow the command package to call itself */
675/* in the middle of a parse.  To do this, begin by calling cmpush, and */
676/* end by calling cmpop. */
677
678#ifdef DCMDBUF
679struct cmp {
680    int i[5];                           /* stack for integers */
681    char *c[3];                         /* stack for pointers */
682    char *b[8];                         /* stack for buffer contents */
683};
684struct cmp *cmp = 0;
685#else
686int cmp_i[CMDDEP+1][5];                 /* Stack for integers */
687char *cmp_c[CMDDEP+1][5];               /* for misc pointers */
688char *cmp_b[CMDDEP+1][7];               /* for buffer contents pointers */
689#endif /* DCMDBUF */
690
691int cmddep = -1;                        /* Current stack depth */
692
693int
694cmpush() {                              /* Save the command environment */
695    char *cp;                           /* Character pointer */
696
697    if (cmddep >= CMDDEP)               /* Enter a new command depth */
698      return(-1);
699    cmddep++;
700    debug(F101,"&cmpush","",cmddep);
701
702#ifdef DCMDBUF
703    /* allocate memory for cmp if not already done */
704    if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1))))
705      fatal("cmpush: no memory for cmp");
706    cmp[cmddep].i[0] = cmflgs;          /* First do the global ints */
707    cmp[cmddep].i[1] = cmfsav;
708    cmp[cmddep].i[2] = atxn;
709    cmp[cmddep].i[3] = ungw;
710
711    cmp[cmddep].c[0] = bp;              /* Then the global pointers */
712    cmp[cmddep].c[1] = pp;
713    cmp[cmddep].c[2] = np;
714#else
715    cmp_i[cmddep][0] = cmflgs;          /* First do the global ints */
716    cmp_i[cmddep][1] = cmfsav;
717    cmp_i[cmddep][2] = atxn;
718    cmp_i[cmddep][3] = ungw;
719
720    cmp_c[cmddep][0] = bp;              /* Then the global pointers */
721    cmp_c[cmddep][1] = pp;
722    cmp_c[cmddep][2] = np;
723#endif /* DCMDBUF */
724
725    /* Now the buffers themselves.  A lot of repititious code... */
726
727#ifdef DCMDBUF
728    cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
729    if (cp) strcpy(cp,cmdbuf);
730    cmp[cmddep].b[0] = cp;
731    if (cp == NULL) return(-1);
732
733    cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
734    if (cp) strcpy(cp,savbuf);
735    cmp[cmddep].b[1] = cp;
736    if (cp == NULL) return(-1);
737
738#ifdef OLDHELP
739    cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */
740    if (cp) strcpy(cp,hlpbuf);
741    cmp[cmddep].b[2] = cp;
742    if (cp == NULL) return(-1);
743#else
744    cmp[cmddep].b[2] = NULL;
745#endif /* OLDHELP */
746
747    cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
748    if (cp) strcpy(cp,atmbuf);
749    cmp[cmddep].b[3] = cp;
750    if (cp == NULL) return(-1);
751
752    cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
753    if (cp) strcpy(cp,atxbuf);
754    cmp[cmddep].b[4] = cp;
755    if (cp == NULL) return(-1);
756
757    cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
758    if (cp) strcpy(cp,atybuf);
759    cmp[cmddep].b[5] = cp;
760    if (cp == NULL) return(-1);
761
762    cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
763    if (cp) strcpy(cp,filbuf);
764    cmp[cmddep].b[6] = cp;
765    if (cp == NULL) return(-1);
766#else
767    cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
768    if (cp) strcpy(cp,cmdbuf);
769    cmp_b[cmddep][0] = cp;
770    if (cp == NULL) return(-1);
771
772    cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
773    if (cp) strcpy(cp,savbuf);
774    cmp_b[cmddep][1] = cp;
775    if (cp == NULL) return(-1);
776
777#ifdef OLDHELP
778    cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */
779    if (cp) strcpy(cp,hlpbuf);
780    cmp_b[cmddep][2] = cp;
781    if (cp == NULL) return(-1);
782#else
783    cmp_b[cmddep][2] = NULL;   
784#endif /* OLDHELP */
785
786    cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
787    if (cp) strcpy(cp,atmbuf);
788    cmp_b[cmddep][3] = cp;
789    if (cp == NULL) return(-1);
790
791    cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
792    if (cp) strcpy(cp,atxbuf);
793    cmp_b[cmddep][4] = cp;
794    if (cp == NULL) return(-1);
795
796    cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
797    if (cp) strcpy(cp,atybuf);
798    cmp_b[cmddep][5] = cp;
799    if (cp == NULL) return(-1);
800
801    cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
802    if (cp) strcpy(cp,filbuf);
803    cmp_b[cmddep][6] = cp;
804    if (cp == NULL) return(-1);
805#endif /* DCMDBUF */
806
807    cmini(dpx);                         /* Initize the command parser */
808    return(0);
809}
810
811int
812cmpop() {                               /* Restore the command environment */
813    debug(F101,"&cmpop","",cmddep);
814    if (cmddep < 0) return(-1);         /* Don't pop too much! */
815
816#ifdef DCMDBUF
817    cmflgs = cmp[cmddep].i[0];          /* First do the global ints */
818    cmfsav = cmp[cmddep].i[1];
819    atxn = cmp[cmddep].i[2];
820    ungw = cmp[cmddep].i[3];
821
822    bp = cmp[cmddep].c[0];              /* Then the global pointers */
823    pp = cmp[cmddep].c[1];
824    np = cmp[cmddep].c[2];
825#else
826    cmflgs = cmp_i[cmddep][0];          /* First do the global ints */
827    cmfsav = cmp_i[cmddep][1];
828    atxn = cmp_i[cmddep][2];
829    ungw = cmp_i[cmddep][3];
830
831    bp = cmp_c[cmddep][0];              /* Then the global pointers */
832    pp = cmp_c[cmddep][1];
833    np = cmp_c[cmddep][2];
834#endif /* DCMDBUF */
835
836    /* Now the buffers themselves. */
837
838#ifdef DCMDBUF
839    if (cmp[cmddep].b[0]) {
840        strncpy(cmdbuf,cmp[cmddep].b[0],CMDBL); /* 0: Command buffer */
841        free(cmp[cmddep].b[0]);
842        cmp[cmddep].b[0] = NULL;
843    }
844    if (cmp[cmddep].b[1]) {
845        strncpy(savbuf,cmp[cmddep].b[1],CMDBL); /* 1: Save buffer */
846        free(cmp[cmddep].b[1]);
847        cmp[cmddep].b[1] = NULL;
848    }
849#ifdef OLDHELP
850    if (cmp[cmddep].b[2]) {
851        strncpy(hlpbuf,cmp[cmddep].b[2],HLPBL); /* 2: Help buffer */
852        free(cmp[cmddep].b[2]);
853        cmp[cmddep].b[2] = NULL;
854    }
855#endif /* OLDHELP */
856    if (cmp[cmddep].b[3]) {
857        strncpy(atmbuf,cmp[cmddep].b[3],ATMBL); /* 3: Atomic buffer! */
858        free(cmp[cmddep].b[3]);
859        cmp[cmddep].b[3] = NULL;
860    }
861    if (cmp[cmddep].b[4]) {
862        strncpy(atxbuf,cmp[cmddep].b[4],ATMBL); /* 4: eXpansion buffer */
863        free(cmp[cmddep].b[4]);
864        cmp[cmddep].b[4] = NULL;
865    }
866    if (cmp[cmddep].b[5]) {
867        strncpy(atybuf,cmp[cmddep].b[5],ATMBL); /* 5: Atom buffer copY */
868        free(cmp[cmddep].b[5]);
869        cmp[cmddep].b[5] = NULL;
870    }
871    if (cmp[cmddep].b[6]) {
872        strncpy(filbuf,cmp[cmddep].b[6],ATMBL); /* 6: Filename buffer */
873        free(cmp[cmddep].b[6]);
874        cmp[cmddep].b[6] = NULL;
875    }
876#else
877    if (cmp_b[cmddep][0]) {
878        strncpy(cmdbuf,cmp_b[cmddep][0],CMDBL); /* 0: Command buffer */
879        free(cmp_b[cmddep][0]);
880        cmp_b[cmddep][0] = NULL;
881    }
882    if (cmp_b[cmddep][1]) {
883        strncpy(savbuf,cmp_b[cmddep][1],CMDBL); /* 1: Save buffer */
884        free(cmp_b[cmddep][1]);
885        cmp_b[cmddep][1] = NULL;
886    }
887#ifdef OLDHELP
888    if (cmp_b[cmddep][2]) {
889        strncpy(hlpbuf,cmp_b[cmddep][2],HLPBL); /* 2: Help buffer */
890        free(cmp_b[cmddep][2]);
891        cmp_b[cmddep][2] = NULL;
892    }
893#endif /* OLDHELP */
894    if (cmp_b[cmddep][3]) {
895        strncpy(atmbuf,cmp_b[cmddep][3],ATMBL); /* 3: Atomic buffer! */
896        free(cmp_b[cmddep][3]);
897        cmp_b[cmddep][3] = NULL;
898    }
899    if (cmp_b[cmddep][4]) {
900        strncpy(atxbuf,cmp_b[cmddep][4],ATMBL); /* 4: eXpansion buffer */
901        free(cmp_b[cmddep][4]);
902        cmp_b[cmddep][4] = NULL;
903    }
904    if (cmp_b[cmddep][5]) {
905        strncpy(atybuf,cmp_b[cmddep][5],ATMBL); /* 5: Atom buffer copY */
906        free(cmp_b[cmddep][5]);
907        cmp_b[cmddep][5] = NULL;
908    }
909    if (cmp_b[cmddep][6]) {
910        strncpy(filbuf,cmp_b[cmddep][6],ATMBL); /* 6: Filename buffer */
911        free(cmp_b[cmddep][6]);
912        cmp_b[cmddep][6] = NULL;
913    }
914#endif /* DCMDBUF */
915
916    cmddep--;                           /* Rise, rise */
917    debug(F101,"&cmpop","",cmddep);
918    return(cmddep);
919}
920#endif /* NOSPL */
921
922#ifdef COMMENT
923VOID
924stripq(s) char *s; {                    /* Function to strip '\' quotes */
925    char *t;
926    while (*s) {
927        if (*s == CMDQ) {
928            for (t = s; *t != '\0'; t++) *t = *(t+1);
929        }
930        s++;
931    }
932}
933#endif /* COMMENT */
934
935/* Convert tabs to spaces, one for one */
936VOID
937untab(s) char *s; {
938    while (*s) {
939        if (*s == HT) *s = SP;
940        s++;
941    }
942}
943
944/*  C M N U M  --  Parse a number in the indicated radix  */
945
946/*
947 The only radix allowed in unquoted numbers is 10.
948 Parses unquoted numeric strings in base 10.
949 Parses backslash-quoted numbers in the radix indicated by the quote:
950   \nnn = \dnnn = decimal, \onnn = octal, \xnn = Hexadecimal.
951 If these fail, then if a preprocessing function is supplied, that is applied
952 and then a second attempt is made to parse an unquoted decimal string.
953 And if that fails, the preprocessed string is passed to an arithmetic
954 expression evaluator.
955
956 Returns:
957   -3 if no input present when required,
958   -2 if user typed an illegal number,
959   -1 if reparse needed,
960    0 otherwise, with argument n set to the number that was parsed
961*/
962int
963cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
964    int x; char *s, *zp, *zq;
965
966    if (radix != 10) {                  /* Just do base 10 */
967        printf("cmnum: illegal radix - %d\n",radix);
968        return(-1);
969    } /* Easy to add others but there has never been a need for it. */
970    x = cmfld(xhlp,xdef,&s,(xx_strp)0);
971    debug(F101,"cmnum: cmfld","",x);
972    if (x < 0) return(x);               /* Parse a field */
973    zp = atmbuf;
974/*   
975  Edit 192 - Allow any number field to be braced.  This lets us included
976  spaces in expressions, but perhaps more important lets us have user-defined
977  functions in numeric fields, since these always have spaces in them.
978*/
979    if (*zp == '{') {                   /* Braced field, strip braces */
980        x = (int) strlen(atmbuf);
981        if (x > 0) {                    /* The "if" is to shut up optimizers */
982            *(atmbuf+x-1) = NUL;        /* that complain about a possible */
983            zp++;                       /* reference to atbmbuf[-1] even */
984        }                               /* though we know that x > 0. */
985    }
986
987    if (chknum(zp)) {                   /* Check for decimal number */
988        *n = atoi(zp);                  /* Got one, we're done. */
989        debug(F101,"cmnum 1st chknum ok","",*n);
990        return(0);
991    } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
992
993#ifndef OS2
994        *n = x;
995#else
996        *n = wideresult;
997#endif /* OS2 */
998
999        debug(F101,"cmnum xxesc ok","",*n);
1000        return(*zp ? -2 : 0);
1001    } else if (f) {                     /* If conversion function given */
1002        zq = atxbuf;                    /* Try that */
1003        atxn = CMDBL;
1004        (*f)(zp,&zq,&atxn);             /* Convert */
1005        zp = atxbuf;
1006    }
1007    debug(F110,"cmnum zp",zp,0);
1008    if (chknum(zp)) {                   /* Check again for decimal number */
1009        *n = atoi(zp);                  /* Got one, we're done. */
1010        debug(F101,"cmnum 2nd chknum ok","",*n);
1011        return(0);
1012#ifndef NOSPL
1013    }  else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
1014#ifndef OS2
1015        *n = x;
1016#else
1017        *n = wideresult;
1018#endif /* OS2 */
1019        debug(F101,"cmnum xxesc 2 ok","",*n);
1020        return(*zp ? -2 : 0);
1021    } else if (f) {                     /* Not numeric, maybe an expression */
1022        char *p; _PROTOTYP(char * evala, (char *));
1023        p = evala(zp);
1024        if (chknum(p)) {
1025            *n = atoi(p);
1026            debug(F101,"cmnum exp eval ok","",*n);
1027            return(0);
1028        } else return(-2);
1029#endif /* NOSPL */
1030    } else {                            /* Not numeric */
1031        return(-2);
1032    }
1033}
1034
1035/*  C M O F I  --  Parse the name of an output file  */
1036
1037/*
1038 Depends on the external function zchko(); if zchko() not available, use
1039 cmfld() to parse output file names.
1040
1041 Returns:
1042   -9 like -2, except message already printed,
1043   -3 if no input present when required,
1044   -2 if permission would be denied to create the file,
1045   -1 if reparse needed,
1046    0 or 1 if file can be created, with xp pointing to name.
1047    2 if given the name of an existing directory.
1048*/
1049int
1050cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
1051    int x; char *s, *zq;
1052#ifdef OS2
1053    int tries;
1054#endif /* OS2 */
1055#ifdef DTILDE
1056    _PROTOTYP( char * tilde_expand, (char *) );
1057    char *dirp;
1058#endif /* DTILDE */
1059
1060    if (*xhlp == NUL) xhlp = "Output file";
1061    *xp = "";
1062
1063    if ((x = cmfld(xhlp,xdef,&s,(xx_strp)0)) < 0) return(x);
1064    debug(F111,"cmofi 1",s,x);
1065
1066    if (*s == '{') {                    /* Strip enclosing braces */
1067        int n;
1068        n = strlen(s);
1069        if (s[n-1] == '}') {
1070            s[n-1] = NUL;
1071            s++;
1072        }
1073    }
1074    debug(F110,"cmofi 1.5",s,0);
1075
1076#ifdef OS2
1077    tries = 0;
1078    {
1079        char *p = s, q;
1080    /*
1081      This is really ugly.  If we skip conversion the first time through,
1082      then variable names like \%a will be used as filenames (e.g. creating
1083      a file called %A in the root directory).  If we DON'T skip conversion
1084      the first time through, then single backslashes used as directory
1085      separators in filenames will be misinterpreted as variable lead-ins.
1086      So we prescan to see if it has any variable references.  But this
1087      module is not supposed to know anything about variables, functions,
1088      etc, so this code does not really belong here, but rather it should
1089      be at the same level as zzstring().
1090    */
1091        while ( (tries == 0) && (p = strchr(p,CMDQ)) ) {
1092            q = *(p+1);                 /* Char after backslash */
1093            if (!q)                     /* None, quit */
1094              break;
1095            if (isupper(q))             /* If letter, convert to lowercase */
1096              q = tolower(q);
1097            if (isdigit(q)) {           /* If it's a digit, */
1098                tries = 1;              /* assume it's a backslash code  */
1099                break;
1100            }
1101            switch (q) {
1102              case CMDQ:                /* Double backslash */
1103                tries = 1;              /* so call the conversion function */
1104                break;
1105              case '%':                 /* Variable or array reference */
1106              case '&':                 /* must be followed by letter */
1107                if (isalpha(*(p+2)) || (*(p+2) >= '0' && *(p+2) <= '9'))
1108                  tries = 1;
1109                break;
1110              case 'm': case 'v': case '$': /* \m(), \v(), \$() */
1111                if (*(p+2) == '(')
1112                  if (strchr(p+2,')'))
1113                    tries = 1;
1114                break;
1115              case 'f':                 /* \Fname() */
1116                if (strchr(p+2,'('))
1117                  if (strchr(p+2,')'))
1118                      tries = 1;
1119                break;
1120              case '{':                 /* \{...} */
1121                if (strchr(p+2,'}'))
1122                  tries = 1;
1123                break;
1124              case 'd': case 'o':       /* Decimal or Octal number */
1125                if (isdigit(*(p+2)))
1126                  tries = 1;
1127                break;
1128              case 'x':                 /* Hex number */
1129                if (isdigit(*(p+2)) ||
1130                    ((*(p+2) >= 'a' && *(p+2) <= 'f') ||
1131                     ((*(p+2) >= 'A' && *(p+2) <= 'F'))))
1132                  tries = 1;
1133              default:
1134                break;
1135            }
1136            p++;
1137        }
1138    }
1139o_again:
1140    if (tries == 1)
1141#endif /* OS2 */
1142    if (f) {                            /* If a conversion function is given */
1143        zq = atxbuf;                    /* do the conversion. */
1144        atxn = CMDBL;
1145        if ((x = (*f)(s,&zq,&atxn)) < 0)
1146          return(-2);
1147        s = atxbuf;
1148    }
1149    debug(F111,"cmofi 2",s,x);
1150
1151#ifdef DTILDE
1152    dirp = tilde_expand(s);             /* Expand tilde, if any, */
1153    if (*dirp != '\0') {                /* right in the atom buffer. */
1154        if (setatm(dirp,1) < 0) {
1155            printf("?Name too long\n");
1156            return(-9);
1157        }
1158    }
1159    s = atmbuf;
1160    debug(F110,"cmofi 3",s,0);
1161#endif /* DTILDE */
1162
1163    if (iswild(s)) {
1164        printf("?Wildcards not allowed - %s\n",s);
1165        return(-2);
1166    }
1167    debug(F110,"cmofi 4",s,0);
1168
1169#ifdef CK_TMPDIR
1170    /* isdir() function required for this! */
1171    if (isdir(s)) {
1172        debug(F110,"cmofi 5: is directory",s,0);
1173        *xp = s;
1174        return(2);
1175    }
1176#endif /* CK_TMPDIR */
1177
1178    if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* OK to write to console */
1179#ifdef COMMENT
1180#ifdef OS2
1181/*
1182  We don't try again because we already prescanned the string to see if
1183  if contained anything that could be used by zzstring().
1184*/
1185        if (tries++ < 1)
1186          goto o_again;
1187#endif /* OS2 */
1188#endif /* COMMENT */
1189        debug(F110,"cmofi 6: failure",s,0);
1190        printf("?Write permission denied - %s\n",s);
1191        return(-9);
1192    } else {
1193        debug(F110,"cmofi 7: ok",s,0);
1194        *xp = s;
1195        return(x);
1196    }
1197}
1198
1199/*  C M I F I  --  Parse the name of an existing file  */
1200
1201/*
1202 This function depends on the external functions:
1203   zchki()  - Check if input file exists and is readable.
1204   zxpand() - Expand a wild file specification into a list.
1205   znext()  - Return next file name from list.
1206 If these functions aren't available, then use cmfld() to parse filenames.
1207*/
1208/*
1209 Returns
1210   -4 EOF
1211   -3 if no input present when required,
1212   -2 if file does not exist or is not readable,
1213   -1 if reparse needed,
1214    0 or 1 otherwise, with:
1215        xp pointing to name,
1216        wild = 1 if name contains '*' or '?', 0 otherwise.
1217*/
1218int
1219cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
1220    return(cmifi2(xhlp,xdef,xp,wild,0,NULL,f));
1221}
1222/*
1223  cmifip() is called when we want to supply a path or path list to search
1224  in case the filename that the user gives is (a) not absolute, and (b) can't
1225  be found as given.  The path string can be the name of a single directory,
1226  or a list of directories separated by the PATHSEP character, defined in
1227  ckucmd.h.  Look in ckuusr.c and ckuus3.c for examples of usage.
1228*/
1229int
1230cmifip(xhlp,xdef,xp,wild,d,path,f)
1231    char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
1232    return(cmifi2(xhlp,xdef,xp,wild,0,path,f));
1233}
1234
1235/*
1236  cmifi2() is for use when you also want to parse a directory or device
1237  name as an input file, as in the DIRECTORY command.
1238*/
1239int
1240cmifi2(xhlp,xdef,xp,wild,d,path,f)
1241    char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
1242#define NEWCMIFI
1243#ifdef NEWCMIFI
1244    /* New version... */
1245    int i, x, xc; long y; char *sp, *zq;
1246    char *sv = NULL;
1247#ifdef DTILDE
1248    char *tilde_expand(), *dirp;
1249#endif /* DTILDE */
1250
1251#ifndef NOPARTIAL
1252#ifndef OS2
1253#ifdef OSK
1254    /* This large array is dynamic for OS-9 -- should do for others too... */
1255    extern char **mtchs;
1256#else
1257#ifdef UNIX
1258    /* OK, for UNIX too */
1259    extern char **mtchs;
1260#else
1261    extern char *mtchs[];
1262#endif /* UNIX */
1263#endif /* OSK */
1264#endif /* OS2 */
1265#endif /* NOPARTIAL */
1266
1267    inword = 0;                         /* Initialize counts & pointers */
1268    cc = 0;
1269    xc = 0;
1270    *xp = "";
1271    if ((x = cmflgs) != 1) {            /* Already confirmed? */
1272#ifdef BS_DIRSEP
1273        cmdirflg = 1;
1274        x = gtword();                   /* No, get a word */
1275        cmdirflg = 0;
1276#else
1277        x = gtword();                   /* No, get a word */
1278#endif /* BS_DIRSEP */
1279    } else {                            /* If so, use default, if any. */
1280        if (setatm(xdef,0) < 0) {
1281            printf("?Default input filename too long\n");
1282            return(-9);
1283        }
1284    }
1285  i_path:
1286    *xp = atmbuf;                       /* Point to result. */
1287
1288    while (1) {
1289        xc += cc;                       /* Count this character. */
1290        debug(F111,"cmifi gtword",atmbuf,xc);
1291        debug(F101,"cmifi switch x","",x);
1292        switch (x) {
1293            case -9:
1294               printf("Command or field too long\n");
1295            case -4:                    /* EOF */
1296            case -2:                    /* Out of space. */
1297            case -1:                    /* Reparse needed */
1298                return(x);
1299            case 0:                     /* SP or NL */
1300            case 1:
1301                if (xc == 0) *xp = xdef;     /* If no input, return default. */
1302                if (**xp == NUL) return(-3); /* If field empty, return -3. */
1303
1304                if (**xp == '{') {      /* Strip enclosing braces first  */
1305                    char *s = *xp;      /* which might have been used if */
1306                    int n;              /* a filespec included spaces... */
1307                    n = strlen(s);
1308                    if (s[n-1] == '}') {
1309                        s[n-1] = NUL;
1310                        s++;
1311                        *xp = s;
1312                    }
1313                }
1314#ifdef OS2
1315/* In OS/2 and Windows, if we're parsing directory name, allow a disk name */
1316
1317                if (d && ((int)strlen(*xp) == 2))
1318                  if (isalpha(**xp) && *(*xp + 1) == ':')
1319                    return(x);
1320#endif /* OS2 */
1321#ifndef NOSPL
1322                if (f) {                /* If a conversion function is given */
1323                    char *s = *xp;      /* See if there are any variables in */
1324                    while (*s) {        /* the string and if so, expand them */
1325                        if (chkvar(s)) {
1326                            zq = atxbuf;
1327                            atxn = CMDBL;
1328                            if ((y = (*f)(*xp,&zq,&atxn)) < 0)
1329                              return(-2);
1330                            if ((int) strlen(atxbuf) > 0) {
1331                                *xp = atxbuf;
1332                                break;
1333                            }
1334                        }
1335                        s++;
1336                    }
1337                }
1338#endif /* NOSPL */
1339                debug(F110,"cmifi atxbuf",atxbuf,0);
1340                if (!sv) {                           /* Only do this once */
1341                    sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */
1342                    if (!sv) {
1343                        printf("?malloc error 73, cmifi\n");
1344                        return(-9);
1345                    }
1346                    strcpy(sv,*xp);
1347                    debug(F110,"cmifi sv",sv,0);
1348                }
1349                y = zxpand(*xp);
1350                *wild = (y > 1);
1351                debug(F111,"cmifi sv wild",sv,*wild);
1352                if (y == 0) {
1353                    if (path && !isabsolute(sv)) {
1354                        char * ptr = path;
1355                        char c;
1356                        while (1) {
1357                            c = *ptr;
1358                            if (c == PATHSEP || c == NUL) {
1359                                if (!*path) {
1360                                    path = NULL;
1361                                    break;
1362                                }
1363                                *ptr = NUL;
1364                                strcpy(atmbuf,path);
1365                                strcat(atmbuf,sv);
1366                                debug(F110,"cmifip add path",atmbuf,0);
1367                                if (c == PATHSEP) ptr++;
1368                                path = ptr;
1369                                break;
1370                            }
1371                            ptr++;
1372                        }
1373                        x = 1;
1374                        inword = 0;
1375                        cc = 0;
1376                        xc = (int) strlen(atmbuf);
1377                        *xp = "";
1378                        goto i_path;
1379                    }
1380                   if (d) {
1381                      if (sv) free(sv);
1382                      return(-2);
1383                    } else {
1384                       printf("?No files match - %s\n",sv);
1385                       if (sv) free(sv);
1386                       return(-9);
1387                    }
1388                } else if (y < 0) {
1389                    printf("?Too many files match - %s\n",sv);
1390                    if (sv) free(sv);
1391                    return(-9);
1392                } else if (y > 1) {
1393                    if (sv) free(sv);
1394                    return(x);
1395                }
1396
1397                /* If not wild, see if it exists and is readable. */
1398 
1399                debug(F111,"cmifi sv not wild",sv,*wild);
1400
1401                znext(*xp);             /* Get first (only?) matching file */
1402                y = zchki(*xp);         /* Check its accessibility */
1403                zxpand(sv);             /* Rewind so next znext() gets 1st */
1404                free(sv);               /* done with this */
1405                sv = NULL;
1406                if (y == -3) {
1407                    printf("?Read permission denied - %s\n",*xp);
1408                    return(-9);
1409                } else if (y == -2) {
1410                    if (d) return(0);
1411                    printf("?File not readable - %s\n",*xp);
1412                    return(-9);
1413                } else if (y < 0) {
1414                    printf("?File not found - %s\n",*xp);
1415                    return(-9);
1416                }
1417                return(x);
1418
1419#ifndef MAC
1420            case 2:                     /* ESC */
1421                debug(F101,"cmifi esc, xc","",xc);
1422                if (xc == 0) {
1423                    if (*xdef != '\0') {
1424                        printf("%s ",xdef); /* If at beginning of field, */
1425#ifdef GEMDOS
1426                        fflush(stdout);
1427#endif /* GEMDOS */
1428                        inword = cmflgs = 0;
1429                        addbuf(xdef);   /* Supply default. */
1430                        if (setatm(xdef,0) < 0) {
1431                            printf("Default input filename too long\n");
1432                            return(-9);
1433                        }
1434                    } else {            /* No default */
1435                        bleep(BP_WARN);
1436                    }
1437                    break;
1438                }
1439#ifndef NOSPL
1440                if (f) {                /* If a conversion function is given */
1441                    char *s = *xp;      /* See if there are any variables in */
1442                    while (*s) {        /* the string and if so, expand it.  */
1443                        if (chkvar(s)) {
1444                            zq = atxbuf;
1445                            atxn = CMDBL;
1446                            if ((x = (*f)(*xp,&zq,&atxn)) < 0)
1447                              return(-2);
1448                    /* reduce cc by number of \\ consumed by conversion */
1449                    /* function (needed for OS/2, where \ is path separator) */
1450                            if ((int) strlen(atxbuf) > 0) {
1451                                cc -= (strlen(*xp) - strlen(atxbuf));
1452                                *xp = atxbuf;
1453                                break;
1454                            }
1455                        }
1456                        s++;
1457                    }
1458                }
1459#endif /* NOSPL */
1460#ifdef DTILDE
1461                dirp = tilde_expand(*xp); /* Expand tilde, if any, */
1462                if (*dirp != '\0') {    /* in the atom buffer. */
1463                    if (setatm(dirp,0) < 0) {
1464                        printf("Expanded input filename too long\n");
1465                        return(-9);
1466                    }
1467                }
1468                *xp = atmbuf;
1469#endif /* DTILDE */
1470                sp = *xp + cc;
1471#ifdef datageneral
1472                *sp++ = '+';            /* Data General AOS wildcard */
1473#else
1474                *sp++ = '*';            /* Others */
1475#endif /* datageneral */
1476                *sp-- = '\0';
1477#ifdef GEMDOS
1478                if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */
1479                  strcat(*xp, ".*");    /* abc -> abc*.* */
1480#endif /* GEMDOS */
1481                y = zxpand(*xp);        /* Add wildcard and expand list. */
1482                if (y > 0) {
1483#ifdef OS2
1484                    znext(filbuf);
1485                    zxpand(*xp);        /* Must "rewind" */
1486#else
1487                    strcpy(filbuf,mtchs[0]);
1488#endif /* OS2 */
1489                } else
1490                  *filbuf = '\0';
1491                *sp = '\0';             /* Remove wildcard. */
1492                *wild = (y > 1);
1493                if (y == 0) {
1494                    printf("?No files match - %s\n",atmbuf);
1495                    return(-9);
1496                } else if (y < 0) {
1497                    printf("?Too many files match - %s\n",atmbuf);
1498                    return(-9);
1499                } else if (y > 1) {     /* Not unique. */
1500#ifndef NOPARTIAL
1501/* Partial filename completion */
1502                    int i, j, k; char c;
1503                    k = 0;
1504                    debug(F111,"cmifi partial",filbuf,cc);
1505#ifdef OS2
1506                    {
1507                        int cur = 0,
1508                          len = 0,
1509                          len2 = 0,
1510                          min = strlen(filbuf);
1511                        char localfn[257];
1512
1513                        len = min;
1514                        for (j = 1; j < y; j++) {
1515                            znext(localfn);
1516                            len2 = strlen(localfn);
1517                            for (cur = cc;
1518                                 cur < len && cur < len2 && cur <= min;
1519                                 cur++
1520                                 ) {
1521                                if (tolower(filbuf[cur]) !=
1522                                    tolower(localfn[cur])
1523                                    )
1524                                  break;
1525                            }
1526                            if (cur < min)
1527                              min = cur;
1528                        }
1529                        filbuf[min] = NUL;
1530                        if (min > cc)
1531                          k++;
1532                    }
1533#else /* OS2 */
1534                    for (i = cc; (c = filbuf[i]); i++) {
1535                        for (j = 1; j < y; j++)
1536                          if (mtchs[j][i] != c) break;
1537                        if (j == y) k++;
1538                        else filbuf[i] = filbuf[i+1] = NUL;
1539                    }
1540#endif /* OS2 */
1541                    debug(F111,"cmifi partial k",filbuf,k);
1542                    if (k > 0) {        /* Got more characters */
1543                        sp = filbuf + cc; /* Point to new ones */
1544#ifdef VMS
1545                        for (i = 0; i < cc; i++) {
1546                            cmdchardel(); /* Back up over old partial spec */
1547                            bp--;
1548                        }
1549                        sp = filbuf;    /* Point to new word start */
1550                        debug(F100,"cmifi vms erase ok","",0);
1551#endif /* VMS */
1552                        cc = k;         /* How many new ones we just got */
1553                        printf("%s",sp);        /* Print them */
1554                        while (*bp++ = *sp++) ; /* Copy to command buffer */
1555                        bp--;                   /* Back up over NUL */
1556                        debug(F110,"cmifi partial cmdbuf",cmdbuf,0);
1557                        if (setatm(filbuf,0) < 0) {
1558                            printf("?Partial filename too long\n");
1559                            return(-9);
1560                        }
1561                        debug(F111,"cmifi partial atmbuf",atmbuf,cc);
1562                        *xp = atmbuf;
1563                    }
1564#endif /* NOPARTIAL */
1565                    bleep(BP_WARN);
1566                } else {                /* Unique, complete it.  */
1567#ifndef VMS
1568#ifdef CK_TMPDIR   
1569                    /* isdir() function required for this! */
1570                    if (isdir(filbuf)) {
1571#ifdef UNIX
1572                        strcat(filbuf,"/");
1573#endif
1574#ifdef OS2
1575                        strcat(filbuf,"/");
1576#endif
1577#ifdef AMIGA
1578                        strcat(filbuf,"/");
1579#endif
1580#ifdef OSK
1581                        strcat(filbuf,"/");
1582#endif
1583#ifdef datageneral
1584                        strcat(filbuf,":");
1585#endif
1586#ifdef MAC
1587                        strcat(filbuf,":");
1588#endif
1589#ifdef STRATUS
1590                        strcat(filbuf,">");
1591#endif
1592#ifdef GEMDOS
1593                        strcat(filbuf,"\\");
1594#endif
1595                        sp = filbuf + cc;
1596                        bleep(BP_WARN);
1597                        printf("%s",sp);
1598                        cc++;
1599                        while (*bp++ = *sp++) ;
1600                        bp--;
1601                        if (setatm(filbuf,0) < 0) {
1602                            printf("?Directory name too long\n");
1603                            return(-9);
1604                        }
1605                        debug(F111,"cmifi directory atmbuf",atmbuf,cc);
1606                        *xp = atmbuf;
1607                    } else { /* Not a directory... */
1608#endif /* CK_TMPDIR */
1609#endif /* VMS */
1610                        sp = filbuf + cc; /* Point past what user typed. */
1611#ifdef VMS
1612                        for (i = 0; i < cc; i++) {
1613                            cmdchardel(); /* Back up over old partial spec */
1614                            bp--;
1615                        }
1616                        sp = filbuf;    /* Point to new word start */
1617#endif /* VMS */
1618                        printf("%s ",sp); /* Complete the name. */
1619#ifdef GEMDOS
1620                        fflush(stdout);
1621#endif /* GEMDOS */
1622                        addbuf(sp);     /* Add the characters to cmdbuf. */
1623                        if (setatm(filbuf,0) < 0) { /* And to atmbuf. */
1624                            printf("?Completed filename too long\n");
1625                            return(-9);
1626                        }
1627                        inword = cmflgs = 0;
1628                        *xp = atmbuf;   /* Return pointer to atmbuf. */
1629                        return(0);
1630#ifndef VMS
1631#ifdef CK_TMPDIR
1632                    }
1633#endif /* CK_TMPDIR */
1634#endif /* VMS */
1635                }
1636                break;
1637 
1638            case 3:                     /* Question mark - file menu wanted */
1639                if (*xhlp == NUL)
1640                  printf(" Input file specification");
1641                else
1642                  printf(" %s",xhlp);
1643#ifdef GEMDOS
1644                fflush(stdout);
1645#endif /* GEMDOS */
1646#ifdef OLDHELP
1647                if (xc > 0) {
1648#endif /* OLDHELP */
1649#ifndef NOSPL
1650                    if (f) {            /* If a conversion function is given */
1651                        char *s = *xp;  /* See if there are any variables in */
1652                        while (*s) {    /* the string and if so, expand them */
1653                            if (chkvar(s)) {
1654                                zq = atxbuf;
1655                                atxn = CMDBL;
1656                                if ((x = (*f)(*xp,&zq,&atxn)) < 0)
1657                                  return(-2);
1658                                if ((int) strlen(atxbuf) > 0) {
1659                                    *xp = atxbuf;
1660                                    break;
1661                                }
1662                            }
1663                            s++;
1664                        }
1665                    }
1666#endif /* NOSPL */
1667#ifdef DTILDE
1668                    dirp = tilde_expand(*xp);    /* Expand tilde, if any */
1669                    if (*dirp != '\0') {
1670                        if (setatm(dirp,0) < 0) {
1671                            printf("?Expanded filename too long\n");
1672                            return(-9);
1673                        }
1674                    }
1675                    *xp = atmbuf;
1676#endif /* DTILDE */
1677                    debug(F111,"cmifi ? *xp, cc",*xp,cc);
1678                    sp = *xp + cc;      /* Insert "*" at end */
1679#ifdef datageneral
1680                    *sp++ = '+';        /* Insert +, the DG wild card */
1681#else
1682                    *sp++ = '*';
1683#endif /* datageneral */
1684                    *sp-- = '\0';
1685#ifdef GEMDOS
1686                    if (! strchr(*xp, '.'))     /* abde.e -> abcde.e* */
1687                      strcat(*xp, ".*");        /* abc -> abc*.* */
1688#endif /* GEMDOS */
1689                    debug(F110,"cmifi ? wild",*xp,0);
1690                    y = zxpand(*xp);
1691                    *sp = '\0';
1692                    if (y == 0) {
1693                        printf("?No files match - %s\n",atmbuf);
1694                        return(-9);
1695                    } else if (y < 0) {
1696                        printf("?Too many files match - %s\n",atmbuf);
1697                        return(-9);
1698                    } else {
1699                        printf(", one of the following:\n");
1700#ifdef OLDHELP
1701                        clrhlp();
1702                        for (i = 0; i < y; i++) {
1703                            znext(filbuf);
1704#ifdef VMS
1705                            printf(" %s\n",filbuf); /* VMS names can be long */
1706#else
1707                            addhlp(filbuf);
1708#endif /* VMS */
1709                        }
1710                        dmphlp();
1711#else  /* New way... */
1712                        if (filhelp(y,"","",1) < 0)
1713                          return(-9);
1714#endif /* OLDHELP */
1715                    }
1716#ifdef OLDHELP
1717                } else
1718                  printf("\n");
1719#endif /* OLDHELP */
1720                printf("%s%s",cmprom,cmdbuf);
1721                fflush(stdout);
1722                break;
1723#endif /* MAC */
1724        }
1725#ifdef BS_DIRSEP
1726        cmdirflg = 1;
1727        x = gtword();                   /* No, get a word */
1728        cmdirflg = 0;
1729#else
1730        x = gtword();                   /* No, get a word */
1731#endif /* BS_DIRSEP */
1732    *xp = atmbuf;
1733    }
1734
1735#else /* Not NEWCMIFI ... */
1736
1737    int i, x, xc; long y; char *sp, *zq;
1738    char *sv = NULL;
1739#ifdef DTILDE
1740    char *tilde_expand(), *dirp;
1741#endif /* DTILDE */
1742#ifdef OS2
1743    int tries;
1744#endif /* OS2 */
1745
1746#ifndef NOPARTIAL
1747#ifndef OS2
1748#ifdef OSK
1749    extern char **mtchs; /* This large array is dynamic for OS-9 */
1750#else
1751    extern char *mtchs[];
1752#endif /* OSK */
1753#endif /* OS2 */
1754#endif /* NOPARTIAL */
1755
1756    inword = 0;                         /* Initialize counts & pointers */
1757    cc = 0;
1758    xc = 0;     
1759    *xp = "";
1760    if ((x = cmflgs) != 1) {            /* Already confirmed? */
1761#ifdef BS_DIRSEP
1762        cmdirflg = 1;
1763        x = gtword();                   /* No, get a word */
1764        cmdirflg = 0;
1765#else
1766        x = gtword();                   /* No, get a word */
1767#endif /* BS_DIRSEP */
1768    } else {                            /* If so, use default, if any. */
1769        if (setatm(xdef,0) < 0) {
1770            printf("?Default input filename too long\n");
1771            return(-9);
1772        }
1773    }
1774  i_path:
1775    *xp = atmbuf;                       /* Point to result. */
1776
1777    while (1) {
1778        xc += cc;                       /* Count the characters. */
1779        debug(F111,"cmifi gtword",atmbuf,xc);
1780        debug(F101,"cmifi switch x","",x);
1781        switch (x) {
1782            case -9:
1783               printf("Command or field too long\n");
1784            case -4:                    /* EOF */
1785            case -2:                    /* Out of space. */
1786            case -1:                    /* Reparse needed */
1787                return(x);
1788            case 0:                     /* SP or NL */
1789            case 1:
1790                if (xc == 0) *xp = xdef;     /* If no input, return default. */
1791                if (**xp == NUL) return(-3); /* If field empty, return -3. */
1792
1793                if (**xp == '{') {      /* Strip enclosing braces first */
1794                    char *s = *xp;
1795                    int n;
1796                    n = strlen(s);
1797                    if (s[n-1] == '}') {
1798                        s[n-1] = NUL;
1799                        s++;
1800                        *xp = s;
1801                    }
1802                }
1803#ifdef OS2
1804                if (d && ((int)strlen(*xp) == 2))
1805                  if (isalpha(**xp) && *(*xp + 1) == ':')
1806                    return(x);
1807                tries = 0;
1808i_again:
1809                if (tries > 0)
1810#endif /* OS2 */
1811                if (f) {                /* If a conversion function is given */
1812                    zq = atxbuf;        /* ... */
1813                    atxn = CMDBL;
1814                    if ((y = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
1815                    *xp = atxbuf;
1816                }
1817                debug(F110,"cmifi atxbuf",atxbuf,0);
1818                if (!sv) {                           /* Only do this once */
1819                    sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */
1820                    if (!sv) {
1821                        printf("?malloc error 73, cmifi\n");
1822                        return(-9);
1823                    }
1824                    strcpy(sv,*xp);
1825                    debug(F110,"cmifi sv",sv,0);
1826                }
1827                y = zxpand(*xp);
1828                *wild = (y > 1);
1829                debug(F111,"cmifi sv wild",sv,*wild);
1830                if (y == 0) {
1831                    if (path && !isabsolute(sv)) {
1832                        char * ptr = path;
1833                        char c;
1834                        while (1) {
1835                            c = *ptr;
1836                            if (c == PATHSEP || c == NUL) {
1837                                if (!*path) {
1838                                    path = NULL;
1839                                    break;
1840                                }
1841                                *ptr = NUL;
1842                                strcpy(atmbuf,path);
1843                                strcat(atmbuf,sv);
1844                                debug(F110,"cmifip add path",atmbuf,0);
1845                                if (c == PATHSEP) ptr++;
1846                                path = ptr;
1847                                break;
1848                            }
1849                            ptr++;
1850                        }
1851                        x = 1;
1852                        inword = 0;
1853                        cc = 0;
1854                        xc = (int) strlen(atmbuf);
1855                        *xp = "";
1856                        goto i_path;
1857                    }
1858#ifdef OS2
1859                    if (tries++ < 1)
1860                      goto i_again;
1861#endif /* OS2 */
1862                    if (sv) free(sv);
1863                    if (d) {
1864                        return(-2);
1865                    } else {
1866                        printf("?No files match - %s\n",*xp);
1867                        return(-9);
1868                    }
1869                } else if (y < 0) {
1870                    printf("?Too many files match - %s\n",*xp);
1871                    if (sv) free(sv);
1872                    return(-9);
1873                } else if (y > 1) {
1874                    if (sv) free(sv);
1875                    return(x);
1876                }
1877
1878                /* If not wild, see if it exists and is readable. */
1879 
1880                debug(F111,"cmifi sv not wild",sv,*wild);
1881
1882                znext(*xp);             /* Get first (only?) matching file */
1883                y = zchki(*xp);         /* Check its accessibility */
1884                zxpand(sv);             /* Rewind so next znext() gets 1st */
1885                free(sv);               /* done with this */
1886                sv = NULL;
1887                if (y == -3) {
1888                    printf("?Read permission denied - %s\n",*xp);
1889                    return(-9);
1890                } else if (y == -2) {
1891                    if (d) return(0);
1892                    printf("?File not readable - %s\n",*xp);
1893                    return(-9);
1894                } else if (y < 0) {
1895                    printf("?File not found - %s\n",*xp);
1896                    return(-9);
1897                }
1898                return(x);
1899
1900#ifndef MAC
1901            case 2:                     /* ESC */
1902                debug(F101,"cmifi esc, xc","",xc);
1903#ifdef OS2
1904                tries = 0;
1905#endif /* OS2 */
1906                if (xc == 0) {
1907                    if (*xdef != '\0') {
1908                        printf("%s ",xdef); /* If at beginning of field, */
1909#ifdef GEMDOS
1910                        fflush(stdout);
1911#endif /* GEMDOS */
1912                        inword = cmflgs = 0;
1913                        addbuf(xdef);   /* Supply default. */
1914                        if (setatm(xdef,0) < 0) {
1915                            printf("Default input filename too long\n");
1916                            return(-9);
1917                        }
1918                    } else {            /* No default */
1919                        bleep(BP_WARN);
1920                    }
1921                    break;
1922                }
1923#ifdef OS2
1924e_again:
1925                if (tries > 0)
1926#endif /* OS2 */
1927                if (f) {                /* If a conversion function is given */
1928                    zq = atxbuf;        /* ... */
1929                    atxn = CMDBL;
1930                    if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
1931                    /* reduce cc by number of \\ consumed by conversion */
1932                    /* function (needed for OS/2, where \ is path separator) */
1933                    cc -= (strlen(*xp) - strlen(atxbuf));
1934                    *xp = atxbuf;
1935                }
1936#ifdef DTILDE
1937                dirp = tilde_expand(*xp); /* Expand tilde, if any, */
1938                if (*dirp != '\0') {    /* in the atom buffer. */
1939                    if (setatm(dirp,0) < 0) {
1940                        printf("Expanded input filename too long\n");
1941                        return(-9);
1942                    }
1943                }
1944                *xp = atmbuf;
1945#endif /* DTILDE */
1946                sp = *xp + cc;
1947#ifdef datageneral
1948                *sp++ = '+';            /* Data General AOS wildcard */
1949#else
1950                *sp++ = '*';            /* Others */
1951#endif /* datageneral */
1952                *sp-- = '\0';
1953#ifdef GEMDOS
1954                if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */
1955                  strcat(*xp, ".*");    /* abc -> abc*.* */
1956#endif /* GEMDOS */
1957                y = zxpand(*xp);        /* Add wildcard and expand list. */
1958                if (y > 0)
1959#ifdef OS2
1960                  znext(filbuf);
1961else
1962                  strcpy(filbuf,mtchs[0]);
1963#endif /* OS2 */
1964                else
1965                  *filbuf = NUL;
1966                *sp = '\0';             /* Remove wildcard. */
1967                *wild = (y > 1);
1968                if (y == 0) {
1969#ifdef OS2
1970                    if (tries++ < 1)
1971                      goto e_again;
1972                    else
1973#endif /* OS2 */
1974                      printf("?No files match - %s\n",atmbuf);
1975                    return(-9);
1976                } else if (y < 0) {
1977                    printf("?Too many files match - %s\n",atmbuf);
1978                    return(-9);
1979                } else if (y > 1) {     /* Not unique. */
1980#ifndef NOPARTIAL
1981/* Partial filename completion */
1982                    int i, j, k; char c;
1983                    k = 0;
1984                    debug(F111,"cmifi partial",filbuf,cc);
1985#ifdef OS2
1986                    {
1987                        int cur = 0,
1988                        len = 0,
1989                        len2 = 0,
1990                        min = strlen(filbuf);
1991                        char localfn[257];
1992
1993                        len = min;
1994                        for (j = 1; j < y; j++) {
1995                            znext(localfn);
1996                            len2 = strlen(localfn);
1997                            for (cur=cc;
1998                                 cur < len && cur < len2 && cur <= min;
1999                                 cur++
2000                                 ) {
2001                                if (tolower(filbuf[cur]) !=
2002                                    tolower(localfn[cur])
2003                                    )
2004                                  break;
2005                            }
2006                            if (cur < min)
2007                              min = cur;
2008                        }
2009                        filbuf[min] = NUL;
2010                        if (min > cc)
2011                          k++;
2012                    }
2013#else /* OS2 */
2014                    for (i = cc; (c = filbuf[i]); i++) {
2015                        for (j = 1; j < y; j++)
2016                          if (mtchs[j][i] != c) break;
2017                        if (j == y) k++;
2018                        else filbuf[i] = filbuf[i+1] = NUL;
2019                    }
2020#endif /* OS2 */
2021                    debug(F111,"cmifi partial k",filbuf,k);
2022                    if (k > 0) {        /* Got more characters */
2023                        sp = filbuf + cc; /* Point to new ones */
2024#ifdef VMS
2025                        for (i = 0; i < cc; i++) {
2026                            cmdchardel(); /* Back up over old partial spec */
2027                            bp--;
2028                        }
2029                        sp = filbuf;    /* Point to new word start */
2030                        debug(F100,"cmifi vms erase ok","",0);
2031#endif /* VMS */
2032                        cc = k;         /* How many new ones we just got */
2033                        printf("%s",sp);        /* Print them */
2034                        while (*bp++ = *sp++) ; /* Copy to command buffer */
2035                        bp--;                   /* Back up over NUL */
2036                        debug(F110,"cmifi partial cmdbuf",cmdbuf,0);
2037                        if (setatm(filbuf,0) < 0) {
2038                            printf("?Partial filename too long\n");
2039                            return(-9);
2040                        }
2041                        debug(F111,"cmifi partial atmbuf",atmbuf,cc);
2042                        *xp = atmbuf;
2043                    }
2044#endif /* NOPARTIAL */
2045                    bleep(BP_WARN);
2046                } else {                /* Unique, complete it.  */
2047#ifndef VMS
2048#ifdef CK_TMPDIR   
2049                    /* isdir() function required for this! */
2050                    if (isdir(filbuf)) {
2051#ifdef UNIX
2052                        strcat(filbuf,"/");
2053#endif
2054#ifdef OS2
2055                        strcat(filbuf,"/");
2056#endif
2057#ifdef AMIGA
2058                        strcat(filbuf,"/");
2059#endif
2060#ifdef OSK
2061                        strcat(filbuf,"/");
2062#endif
2063#ifdef datageneral
2064                        strcat(filbuf,":");
2065#endif
2066#ifdef MAC
2067                        strcat(filbuf,":");
2068#endif
2069#ifdef STRATUS
2070                        strcat(filbuf,">");
2071#endif
2072#ifdef GEMDOS
2073                        strcat(filbuf,"\\");
2074#endif
2075                        sp = filbuf + cc;
2076                        bleep(BP_WARN);
2077                        printf("%s",sp);
2078                        cc++;
2079                        while (*bp++ = *sp++) ;
2080                        bp--;
2081                        if (setatm(filbuf,0) < 0) {
2082                            printf("?Directory name too long\n");
2083                            return(-9);
2084                        }
2085                        debug(F111,"cmifi directory atmbuf",atmbuf,cc);
2086                        *xp = atmbuf;
2087                    } else { /* Not a directory... */
2088#endif /* CK_TMPDIR */
2089#endif /* VMS */
2090                        sp = filbuf + cc; /* Point past what user typed. */
2091#ifdef VMS
2092                        for (i = 0; i < cc; i++) {
2093                            cmdchardel(); /* Back up over old partial spec */
2094                            bp--;
2095                        }
2096                        sp = filbuf;    /* Point to new word start */
2097#endif /* VMS */
2098                        printf("%s ",sp); /* Complete the name. */
2099#ifdef GEMDOS
2100                        fflush(stdout);
2101#endif /* GEMDOS */
2102                        addbuf(sp);     /* Add the characters to cmdbuf. */
2103                        if (setatm(filbuf,0) < 0) { /* And to atmbuf. */
2104                            printf("?Completed filename too long\n");
2105                            return(-9);
2106                        }
2107                        inword = cmflgs = 0;
2108                        *xp = atmbuf;   /* Return pointer to atmbuf. */
2109                        return(0);
2110#ifndef VMS
2111#ifdef CK_TMPDIR
2112                    }
2113#endif /* CK_TMPDIR */
2114#endif /* VMS */
2115                }
2116                break;
2117 
2118            case 3:                     /* Question mark */
2119#ifdef OS2
2120                tries = 0;
2121#endif /* OS2 */
2122                if (*xhlp == NUL)
2123                  printf(" Input file specification");
2124                else
2125                  printf(" %s",xhlp);
2126#ifdef GEMDOS
2127                fflush(stdout);
2128#endif /* GEMDOS */
2129                if (xc > 0) {
2130#ifdef OS2
2131q_again:
2132                    if (tries > 0)
2133#endif /* OS2 */
2134                    if (f) {            /* If a conversion function is given */
2135                        zq = atxbuf;    /* ... */
2136                        atxn = CMDBL;
2137                        if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
2138                        *xp = atxbuf;
2139                    }
2140#ifdef DTILDE
2141                    dirp = tilde_expand(*xp);    /* Expand tilde, if any */
2142                    if (*dirp != '\0') {
2143                        if (setatm(dirp,0) < 0) {
2144                            printf("?Expanded filename too long\n");
2145                            return(-9);
2146                        }
2147                    }
2148                    *xp = atmbuf;
2149#endif /* DTILDE */
2150                    debug(F111,"cmifi ? *xp, cc",*xp,cc);
2151                    sp = *xp + cc;      /* Insert "*" at end */
2152#ifdef datageneral
2153                    *sp++ = '+';        /* Insert +, the DG wild card */
2154#else
2155                    *sp++ = '*';
2156#endif /* datageneral */
2157                    *sp-- = '\0';
2158#ifdef GEMDOS
2159                    if (! strchr(*xp, '.'))     /* abde.e -> abcde.e* */
2160                      strcat(*xp, ".*");        /* abc -> abc*.* */
2161#endif /* GEMDOS */
2162                    debug(F110,"cmifi ? wild",*xp,0);
2163                    y = zxpand(*xp);
2164                    *sp = '\0';
2165                    if (y == 0) {
2166#ifdef OS2
2167                        if (tries++ < 1)
2168                          goto q_again;
2169                        else
2170#endif /* OS2 */
2171                          printf("?No files match - %s\n",atmbuf);
2172                        return(-9);
2173                    } else if (y < 0) {
2174                        printf("?Too many files match - %s\n",atmbuf);
2175                        return(-9);
2176                    } else {
2177                        printf(", one of the following:\n");
2178                        clrhlp();
2179                        for (i = 0; i < y; i++) {
2180                            znext(filbuf);
2181#ifdef VMS
2182                            printf(" %s\n",filbuf); /* VMS names can be long */
2183#else
2184                            addhlp(filbuf);
2185#endif /* VMS */
2186                        }
2187                        dmphlp();
2188                    }
2189                } else printf("\n");
2190                printf("%s%s",cmprom,cmdbuf);
2191                fflush(stdout);
2192                break;
2193#endif /* MAC */
2194        }
2195#ifdef BS_DIRSEP
2196        cmdirflg = 1;
2197        x = gtword();                   /* No, get a word */
2198        cmdirflg = 0;
2199#else
2200        x = gtword();                   /* No, get a word */
2201#endif /* BS_DIRSEP */
2202    *xp = atmbuf;
2203    }
2204#endif /* NEWCMIFI */
2205}
2206
2207/*  C M D I R  --  Parse a directory specification  */
2208
2209/*
2210 This function depends on the external functions:
2211   zchki()  - Check if input file exists and is readable.
2212 If these functions aren't available, then use cmfld() to parse dir names.
2213 Note: this function quickly cobbled together, mainly by deleting lots of
2214 lines from cmifi().  It seems to work, but various services are missing,
2215 like completion, lists of matching directories on "?", etc.
2216*/
2217/*
2218 Returns
2219   -4 EOF
2220   -3 if no input present when required,
2221   -2 if out of space or other internal error,
2222   -1 if reparse needed,
2223    0 or 1, with xp pointing to name, if directory specified,
2224    2 if a wildcard was included.
2225*/
2226int
2227cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
2228    int x, xc; char *zq;
2229#ifdef DTILDE
2230    char *tilde_expand(), *dirp;
2231#endif /* DTILDE */
2232
2233    inword = 0;                         /* Initialize counts & pointers */
2234    cc = 0;
2235    xc = 0;
2236    *xp = "";
2237    if ((x = cmflgs) != 1) {            /* Already confirmed? */
2238#ifdef BS_DIRSEP
2239        cmdirflg = 1;
2240        x = gtword();                   /* No, get a word */
2241        cmdirflg = 0;
2242#else
2243        x = gtword();                   /* No, get a word */
2244#endif /* BS_DIRSEP */
2245    } else {
2246        if (setatm(xdef,0) < 0) {       /* If so, use default, if any. */
2247            printf("?Default directory name too long\n");
2248            return(-9);
2249        }
2250    }
2251    *xp = atmbuf;                       /* Point to result. */
2252    while (1) {
2253        xc += cc;                       /* Count the characters. */
2254        debug(F111,"cmdir gtword",atmbuf,xc);
2255        switch (x) {
2256            case -9:
2257               printf("Command or field too long\n");
2258            case -4:                    /* EOF */
2259            case -2:                    /* Out of space. */
2260            case -1:                    /* Reparse needed */
2261                return(x);
2262            case 0:                     /* SP or NL */
2263            case 1:
2264                if (xc == 0) *xp = xdef;     /* If no input, return default. */
2265                else *xp = atmbuf;
2266                if (**xp == NUL) return(-3); /* If field empty, return -3. */
2267
2268                if (**xp == '{') {      /* Strip enclosing braces first */
2269                    char *s = *xp;
2270                    int n;
2271                    n = strlen(s);
2272                    if (s[n-1] == '}') {
2273                        s[n-1] = NUL;
2274                        s++;
2275                        *xp = s;
2276                    }
2277                }
2278#ifndef OS2
2279                if (f) {                /* If a conversion function is given */
2280                    zq = atxbuf;        /* ... */
2281                    atxn = CMDBL;
2282                    if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
2283                    *xp = atxbuf;
2284                    cc = (int)strlen(atxbuf);
2285                }
2286                if (cc == 0) {
2287                    xc = 0;
2288                    continue;
2289                }
2290#ifdef DTILDE
2291                dirp = tilde_expand(*xp); /* Expand tilde, if any, */
2292                if (*dirp == '~') {     /* Still starts with tilde? */
2293                    char *tp;           /* Yes, convert to lowercase */
2294                    tp = *xp;           /* and try again. */
2295                    while (*tp) {
2296                        if (isupper(*tp)) *tp = (char) tolower(*tp);
2297                        tp++;
2298                    }
2299                }
2300                dirp = tilde_expand(*xp); /* Expand tilde, if any, */
2301#ifdef COMMENT
2302                if (*dirp != '\0') {    /* in the atom buffer. */
2303                    if (setatm(dirp,0) < 0) {
2304                        printf("Expanded name too long\n");
2305                        return(-9);
2306                    }
2307                }
2308#else
2309                /* This allows for directory names that contain spaces. */
2310                if (*dirp != '\0')
2311                  strcpy(atmbuf,dirp);
2312                *xp = atmbuf;
2313#endif /* COMMENT */
2314#endif /* DTILDE */
2315#else  /* OS2 */
2316                if (isdir(*xp)) {       /* OS/2 version has this function */
2317                    return(x);
2318                } else {
2319                    if (f) {            /* If a conversion function is given */
2320                        zq = atxbuf;    /* ... */
2321                        atxn = CMDBL;
2322                        if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
2323                        *xp = atxbuf;
2324                        cc = (int)strlen(atxbuf);
2325                    }
2326                }
2327                if (cc == 0) {
2328                    xc = 0;
2329                    continue;
2330                }
2331#endif /* OS2 */
2332                if (iswild(*xp)) return(2);
2333                else return(x);
2334
2335            case 2:                     /* ESC */
2336                bleep(BP_WARN);
2337                break;
2338
2339            case 3:                     /* Question mark */
2340                if (*xhlp == NUL)
2341                  printf(" Directory name");
2342                else
2343                  printf(" %s",xhlp);
2344                printf("\n%s%s",cmprom,cmdbuf);
2345                fflush(stdout);
2346                break;
2347        }
2348#ifdef BS_DIRSEP
2349        cmdirflg = 1;
2350        x = gtword();
2351        cmdirflg = 0;
2352#else
2353        x = gtword();
2354#endif /* BS_DIRSEP */
2355
2356    }
2357}
2358
2359/*  C M F L D  --  Parse an arbitrary field  */
2360/*
2361 Returns
2362   -3 if no input present when required,
2363   -2 if field too big for buffer,
2364   -1 if reparse needed,
2365    0 otherwise, xp pointing to string result.
2366*/
2367int
2368cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
2369    int x, xc;
2370    char *zq;
2371
2372    inword = 0;                         /* Initialize counts & pointers */
2373    cc = 0;
2374    xc = 0;     
2375    *xp = "";
2376    if ((x = cmflgs) != 1) {            /* Already confirmed? */
2377        x = gtword();                   /* No, get a word */
2378    } else {
2379        if (setatm(xdef,0) < 0) {       /* If so, use default, if any. */
2380            printf("?Default too long\n");
2381            return(-9);
2382        }
2383    }
2384    *xp = atmbuf;                       /* Point to result. */
2385
2386    while (1) {
2387        xc += cc;                       /* Count the characters. */
2388        debug(F111,"cmfld: gtword",atmbuf,xc);
2389        debug(F101,"cmfld x","",x);
2390        switch (x) {
2391            case -9:
2392               printf("Command or field too long\n");
2393            case -4:                    /* EOF */
2394            case -2:                    /* Out of space. */
2395            case -1:                    /* Reparse needed */
2396                return(x);
2397            case 0:                     /* SP or NL */
2398            case 1:
2399                if (xc == 0) {          /* If no input, return default. */
2400                    if (setatm(xdef,0) < 0) {
2401                        printf("?Default too long\n");
2402                        return(-9);
2403                    }
2404                }
2405                *xp = atmbuf;
2406                if (f) {                /* If a conversion function is given */
2407                    zq = atxbuf;        /* employ it now. */
2408                    atxn = CMDBL;
2409                    if ((*f)(*xp,&zq,&atxn) < 0)
2410                      return(-2);
2411                    if (setatm(atxbuf,0) < 0) {
2412                        printf("Value too long\n");
2413                        return(-9);
2414                    }
2415                    *xp = atmbuf;
2416                }
2417                if (**xp == NUL) {      /* If variable evaluates to null */
2418                    if (setatm(xdef,0) < 0) {
2419                        printf("?Default too long\n");
2420                        return(-9);
2421                    }
2422                    if (**xp == NUL) x = -3; /* If still empty, return -3. */
2423                }
2424#ifdef COMMENT
2425/* The following is apparently not necessary. */
2426/* Remove it if nothing is broken, esp. TAKE file with trailing comments */
2427                xx = *xp;
2428                debug(F111,"cmfld before trim",*xp,x);
2429                for (i = (int)strlen(xx) - 1; i > 0; i--)
2430                  if (xx[i] != SP)      /* Trim trailing blanks */
2431                    break;
2432                  else
2433                    xx[i] = NUL;
2434#endif /* COMMENT */
2435                debug(F111,"cmfld returns",*xp,x);
2436                return(x);
2437            case 2:                     /* ESC */
2438                if (xc == 0 && *xdef != NUL) {
2439                    printf("%s ",xdef); /* If at beginning of field, */
2440#ifdef GEMDOS
2441                    fflush(stdout);
2442#endif /* GEMDOS */
2443                    addbuf(xdef);       /* supply default. */
2444                    inword = cmflgs = 0;
2445                    if (setatm(xdef,0) < 0) {
2446                        printf("?Default too long\n");
2447                        return(-9);
2448                    } else              /* Return as if whole field */
2449                      return(0);        /* typed, followed by space. */
2450                } else {
2451                    bleep(BP_WARN);
2452                }
2453                break;
2454            case 3:                     /* Question mark */
2455                if (*xhlp == NUL)
2456                    printf(" Please complete this field");
2457                else
2458                    printf(" %s",xhlp);
2459                printf("\n%s%s",cmprom,cmdbuf);
2460                fflush(stdout);
2461                break;
2462        }
2463    x = gtword();
2464/*  *xp = atmbuf; */
2465    }
2466}
2467
2468
2469/*  C M T X T  --  Get a text string, including confirmation  */
2470
2471/*
2472  Print help message 'xhlp' if ? typed, supply default 'xdef' if null
2473  string typed.  Returns
2474
2475   -1 if reparse needed or buffer overflows.
2476    1 otherwise.
2477
2478  with cmflgs set to return code, and xp pointing to result string.
2479*/
2480int
2481cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
2482
2483    int x, i;
2484    char *xx, *zq;
2485    static int xc;
2486
2487    debug(F101,"cmtxt, cmflgs","",cmflgs);
2488    inword = 0;                         /* Start atmbuf counter off at 0 */
2489    cc = 0;             
2490    if (cmflgs == -1) {                 /* If reparsing, */
2491        xc = (int)strlen(*xp);          /* get back the total text length, */
2492        bp = *xp;                       /* and back up the pointers. */
2493        np = *xp;
2494        pp = *xp;
2495    } else {                            /* otherwise, */
2496        debug(F100,"cmtxt: fresh start","",0);
2497        *xp = "";                       /* start fresh. */
2498        xc = 0;
2499    }
2500    *atmbuf = NUL;                      /* And empty the atom buffer. */
2501    if ((x = cmflgs) != 1) {
2502        x = gtword();                   /* Get first word. */
2503        *xp = pp;                       /* Save pointer to it. */
2504        debug(F111,"cmtxt:",*xp,cc);
2505    }
2506    debug(F101,"cmtxt (*f)","", f);
2507    while (1) {                         /* Loop for each word in text. */
2508        xc += cc;                       /* Char count for all words. */
2509        debug(F111,"cmtxt: gtword",atmbuf,xc);
2510        debug(F101," x","",x);
2511        switch (x) {
2512          case -9:                      /* Buffer overflow */
2513            printf("Command or field too long\n");
2514          case -4:                      /* EOF */
2515#ifdef MAC
2516          case -3:                      /* Quit/Timeout */
2517#endif /* MAC */
2518          case -2:                      /* Overflow */
2519          case -1:                      /* Deletion */
2520            return(x);
2521          case 0:                       /* Space */
2522            xc++;                       /* Just count it */
2523            break;
2524          case 1:                       /* CR or LF */
2525            if (xc == 0) *xp = xdef;
2526            if (f) {                    /* If a conversion function is given */
2527                zq = atxbuf;            /* Point to the expansion buffer */
2528                atxn = CMDBL;           /* specify its length */
2529                debug(F110,"cmtxt calling (*f)",*xp,0);
2530                if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
2531                cc = (int)strlen(atxbuf);
2532                *xp = atxbuf;           /* and return pointer to it. */
2533                debug(F111,"cmtxt (*f) returns",*xp,cc);
2534            }
2535            xx = *xp;
2536            for (i = (int)strlen(xx) - 1; i > 0; i--)
2537              if (xx[i] != SP)          /* Trim trailing blanks */
2538                break;
2539              else
2540                xx[i] = NUL;
2541            return(x);
2542          case 2:                       /* ESC */
2543            if (xc == 0) {              /* Nothing typed yet */
2544                if (*xdef) {            /* Have a default for this field? */
2545                    printf("%s ",xdef); /* Yes, supply it */
2546                    inword = cmflgs = 0;
2547#ifdef GEMDOS
2548                    fflush(stdout);
2549#endif /* GEMDOS */
2550                    cc = addbuf(xdef);
2551                } else bleep(BP_WARN);  /* No default */
2552            } else {                    /* Already in field */
2553                int x; char *p;
2554                x = strlen(atmbuf);
2555                if (xxstrcmp(atmbuf,xdef,x)) /* Matches default? */
2556                  bleep(BP_WARN);       /* No */
2557                else {                  /* Yes */
2558                    p = xdef + x;
2559                    printf("%s ", p);
2560#ifdef GEMDOS
2561                    fflush(stdout);
2562#endif /* GEMDOS */
2563                    addbuf(p);
2564                    inword = cmflgs = 0;
2565                    debug(F110,"cmtxt: addbuf",cmdbuf,0);
2566                }
2567            }
2568            break;
2569          case 3:                       /* Question Mark */
2570            if (*xhlp == NUL)
2571              printf(" Text string");
2572            else
2573              printf(" %s",xhlp);
2574            printf("\n%s%s",cmprom,cmdbuf);
2575            fflush(stdout);
2576            break;
2577          default:
2578            printf("?Unexpected return code from gtword() - %d\n",x);
2579            return(-2);
2580        }
2581        x = gtword();
2582    }
2583}
2584
2585/*  C M K E Y  --  Parse a keyword  */
2586
2587/*
2588 Call with:
2589   table    --  keyword table, in 'struct keytab' format;
2590   n        --  number of entries in table;
2591   xhlp     --  pointer to help string;
2592   xdef     --  pointer to default keyword;
2593
2594 Returns:
2595   -3       --  no input supplied and no default available
2596   -2       --  input doesn't uniquely match a keyword in the table
2597   -1       --  user deleted too much, command reparse required
2598    n >= 0  --  value associated with keyword
2599*/
2600int
2601cmkey(table,n,xhlp,xdef,f)
2602/* cmkey */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
2603    return(cmkey2(table,n,xhlp,xdef,"",f,1));
2604}
2605int
2606cmkeyx(table,n,xhlp,xdef,f)
2607/* cmkey */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
2608    return(cmkey2(table,n,xhlp,xdef,"",f,0));
2609}
2610int
2611cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
2612    struct keytab table[];
2613    int n;
2614    char *xhlp,
2615    *xdef;
2616    char *tok;
2617    xx_strp f;
2618    int pmsg;
2619{ /* cmkey2 */
2620    int i, tl, y, z, zz, xc;
2621    char *xp, *zq;
2622
2623    tl = (int)strlen(tok);
2624    inword = xc = cc = 0;               /* Clear character counters. */
2625
2626    debug(F101,"cmkey: cmflgs","",cmflgs);
2627    debug(F101,"cmkey: cmdbuf","",cmdbuf);
2628
2629    if ((zz = cmflgs) == 1) {           /* Command already entered? */
2630        if (setatm(xdef,0) < 0) {       /* Yes, copy default into atom buf */
2631            printf("?Default too long\n");
2632            return(-9);
2633        }
2634    } else
2635      zz = gtword();                    /* Otherwise get a command word */
2636 
2637    debug(F101,"cmkey: table length","",n);
2638    debug(F101," cmflgs","",cmflgs);
2639    debug(F101," zz","",zz);
2640    while (1) {
2641        xc += cc;
2642        debug(F111,"cmkey: gtword",atmbuf,xc);
2643
2644        switch(zz) {
2645          case -9:
2646            printf("Command or field too long\n");
2647          case -4:                      /* EOF */
2648          case -3:                      /* Null Command/Quit/Timeout */
2649          case -2:                      /* Buffer overflow */
2650          case -1:                      /* Or user did some deleting. */
2651            return(cmflgs = zz);
2652
2653          case 0:                       /* User terminated word with space */
2654          case 1:                       /* or newline */
2655            if (cc == 0) {              /* Supply default if we got nothing */
2656                if (setatm(xdef,0) < 0) {
2657                    printf("?Default too long\n");
2658                    return(-9);
2659                }
2660            }
2661            if (f) {                    /* If a conversion function is given */
2662                zq = atxbuf;            /* apply it */
2663                atxn = CMDBL;
2664                if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
2665                debug(F110,"cmkey atxbuf after *f",atxbuf,0);
2666                if (setatm(atxbuf,0) < 0) {
2667                    printf("Evaluated keyword too long\n");
2668                    return(-9);
2669                }
2670            }
2671            y = lookup(table,atmbuf,n,&z); /* Look up the word in the table */
2672            switch (y) {
2673              case -2:                  /* Ambiguous */
2674                if (pmsg) {
2675                    bleep(BP_FAIL);
2676                    printf("?Ambiguous - %s\n",atmbuf);
2677                }
2678                cmflgs = -2;
2679                return(-9);
2680              case -1:                  /* Not found at all */
2681                if (tl) {
2682                    for (i = 0; i < tl; i++) /* Check for token */
2683                      if (tok[i] == *atmbuf) { /* Got one */
2684                          ungword();  /* Put back the following word */
2685                          return(-5); /* Special return code for token */
2686                      }
2687                }
2688                /* Kludge alert... only print error if */
2689                /* we were called as cmkey2, but not cmkey... */
2690                /* This doesn't seem to always work. */
2691                if (tl == 0) {
2692#ifdef OS2
2693                    if (isalpha(*atmbuf) && *(atmbuf+1) == ':')
2694                      return(-7);
2695#endif /* OS2 */
2696                    if (pmsg) {
2697                        bleep(BP_FAIL);
2698                        printf("?No keywords match - %s\n",atmbuf); /* cmkey */
2699                    }
2700                    return(cmflgs = -9);
2701                } else {
2702                    if (cmflgs == 1)    /* cmkey2 */
2703                      return(cmflgs = -6);
2704                    else
2705                      return(cmflgs = -2);
2706                    /* The -6 code is to let caller try another table */
2707                }
2708              default:
2709                break;
2710            }
2711            return(y);
2712
2713          case 2:                       /* User terminated word with ESC */
2714            if (cc == 0) {
2715                if (*xdef != NUL) {     /* Nothing in atmbuf */
2716                    printf("%s ",xdef); /* Supply default if any */
2717#ifdef GEMDOS   
2718                    fflush(stdout);
2719#endif /* GEMDOS */
2720                    addbuf(xdef);
2721                    if (setatm(xdef,0) < 0) {
2722                        printf("?Default too long\n");
2723                        return(-9);
2724                    }   
2725                    inword = cmflgs = 0;
2726                    debug(F111,"cmkey: default",atmbuf,cc);
2727                } else {
2728                    if (pmsg) bleep(BP_WARN);
2729                    break;
2730                }
2731            }
2732            if (f) {                    /* If a conversion function is given */
2733                zq = atxbuf;            /* apply it */
2734                atxn = CMDBL;
2735                if ((*f)(atmbuf,&zq,&atxn) < 0)
2736                  return(-2);
2737                if (setatm(atxbuf,0) < 0) {
2738                    printf("Evaluated keyword too long\n");
2739                    return(-9);
2740                }
2741            }
2742            y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */
2743            debug(F111,"cmkey: esc",atmbuf,y);
2744            if (y == -2 || y == -3) {   /* Ambiguous */
2745                bleep(BP_WARN);
2746                break;
2747            }
2748            if (y == -1) {              /* Not found */
2749                if (pmsg) {
2750                    bleep(BP_FAIL);
2751                    printf("?No keywords match - %s\n",atmbuf);
2752                }
2753                cmflgs = -2;
2754                return(-9);
2755            }
2756/*     
2757  See if the keyword just found has the CM_ABR bit set in its flgs field, and
2758  if so, search forwards in the table for a keyword that has the same kwval
2759  but does not have CM_ABR (or CM_INV?) set, and then expand using the full
2760  keyword.  WARNING: This assumes that (a) keywords are in alphabetical order,
2761  and (b) the CM_ABR bit is set only if the the abbreviated keyword is a true
2762  abbreviation (left substring) of the full keyword.
2763*/
2764            if (test(table[z].flgs,CM_ABR)) {
2765                int zz;
2766                for (zz = z+1; zz < n; zz++)
2767                  if ((table[zz].kwval == table[z].kwval) &&
2768                      (!test(table[zz].flgs,CM_ABR))) {
2769                      z = zz;
2770                      break;
2771                  }
2772            }
2773            xp = table[z].kwd + cc;
2774            printf("%s ",xp);
2775#ifdef GEMDOS
2776            fflush(stdout);
2777#endif /* GEMDOS */
2778            addbuf(xp);
2779            inword = cmflgs = 0;
2780            debug(F110,"cmkey: addbuf",cmdbuf,0);
2781            return(y);
2782
2783          case 3:                       /* User typed "?" */
2784            if (f) {                    /* If a conversion function is given */
2785                zq = atxbuf;            /* do the conversion now. */
2786                atxn = CMDBL;
2787                if ((*f)(atmbuf,&zq,&atxn) < 0) return(-2);
2788                if (setatm(atxbuf,0) < 0) {
2789                    printf("?Evaluated keyword too long\n");
2790                    return(-9);
2791                }
2792            }
2793            y = lookup(table,atmbuf,n,&z); /* Look up what we have so far. */
2794
2795            if (y == -1) {
2796                if (pmsg) {
2797                    bleep( BP_FAIL ) ;
2798                    printf(" No keywords match\n");
2799                }
2800                cmflgs = -2;
2801                return(-9);
2802            }
2803            if (*xhlp == NUL)
2804              printf(" One of the following:\n");
2805            else
2806              printf(" %s, one of the following:\n",xhlp);
2807         
2808#ifdef OLDHELP
2809            if ((y > -1) &&
2810                !test(table[z].flgs,CM_ABR) &&
2811                ((z >= n-1) || xxstrcmp(table[z].kwd,table[z+1].kwd,cc))
2812                ) {
2813                printf(" %s\n",table[z].kwd);
2814            } else {
2815                clrhlp();
2816                for (i = 0; i < n; i++) {
2817                    if (!xxstrcmp(table[i].kwd,atmbuf,cc)
2818                        && !test(table[i].flgs,CM_INV)
2819                        )
2820                      addhlp(table[i].kwd);
2821                }       
2822                dmphlp();
2823            }
2824#else  /* New way ... */
2825            kwdhelp(table,n,atmbuf,"","",1);
2826#endif /* OLDHELP */
2827            if (*atmbuf == NUL) {
2828                if (tl == 1)
2829                  printf("or the token %c\n",*tok);
2830                else if (tl > 1)
2831                  printf("or one of the tokens: %s\n",tok);
2832            }
2833            printf("%s%s", cmprom, cmdbuf);
2834            fflush(stdout);
2835            break;
2836
2837          default:
2838            printf("\n%d - Unexpected return code from gtword\n",zz);
2839            return(cmflgs = -2);
2840        }
2841        zz = gtword();
2842    }
2843}
2844
2845int
2846chktok(tlist) char *tlist; {
2847    char *p;
2848    p = tlist;
2849    while (*p != NUL && *p != *atmbuf) p++;
2850    return((*p) ? (int) *p : 0);
2851}
2852
2853/*  C M C F M  --  Parse command confirmation (end of line)  */
2854
2855/*
2856 Returns
2857   -2: User typed anything but whitespace or newline
2858   -1: Reparse needed
2859    0: Confirmation was received
2860*/
2861int
2862cmcfm() {
2863    int x, xc;
2864
2865    debug(F101,"cmcfm: cmflgs","",cmflgs);
2866    debug(F110,"cmcfm: atmbuf",atmbuf,0);
2867    inword = xc = cc = 0;
2868    if (cmflgs == 1) return(0);
2869
2870    setatm("",0);                       /* (Probably unnecessary) */
2871
2872    while (1) {
2873        x = gtword();
2874        xc += cc;
2875        switch (x) {
2876            case -9:
2877              printf("Command or field too long\n");
2878            case -4:                    /* EOF */
2879            case -2:
2880            case -1:
2881                return(x);
2882
2883            case 1:                     /* End of line */
2884                if (xc > 0) {
2885                    printf("?Not confirmed - %s\n",atmbuf);
2886                    return(-9);
2887                } else return(0);
2888            case 2:                     /* ESC */
2889                if (xc == 0) {
2890                bleep(BP_WARN);
2891                    continue;           /* or fall thru. */
2892                }
2893            case 0:                     /* Space */
2894                if (xc == 0)            /* If no chars typed, continue, */
2895                  continue;             /* else fall thru. */
2896            case 3:                     /* Question mark */
2897                if (xc > 0) {
2898                    printf("?Not confirmed - %s\n",atmbuf);
2899                    return(-9);
2900                }
2901                printf("\n Type a carriage return to confirm the command\n");
2902                printf("%s%s",cmprom,cmdbuf);
2903                fflush(stdout);
2904                continue;
2905        }
2906    }
2907}
2908
2909#ifdef OLDHELP
2910/* Keyword help routines */
2911
2912/*  C L R H L P -- Initialize/Clear the help line buffer  */
2913
2914static VOID
2915clrhlp() {                              /* Clear the help buffer */
2916    hlpbuf[0] = NUL;
2917    hh = hx = 0;
2918}
2919
2920
2921/*  A D D H L P  --  Add a string to the help line buffer  */
2922
2923static VOID
2924addhlp(s) char *s; {                    /* Add a word to the help buffer */
2925    int j;
2926
2927    hh++;                               /* Count this column */
2928
2929    for (j = 0; (j < hc) && (*s != NUL); j++) { /* Fill the column */
2930        hlpbuf[hx++] = *s++;
2931    }
2932    if (*s != NUL)                      /* Still some chars left in string? */
2933        hlpbuf[hx-1] = '+';             /* Mark as too long for column. */
2934
2935    if (hh < (hw / hc)) {               /* Pad col with spaces if necessary */
2936        for (; j < hc; j++) {
2937            hlpbuf[hx++] = SP;
2938        }
2939    } else {                            /* If last column, */
2940        hlpbuf[hx++] = NUL;             /* no spaces. */
2941        dmphlp();                       /* Print it. */
2942        return;
2943    }
2944}
2945
2946/*  D M P H L P  --  Dump the help line buffer  */
2947
2948static VOID
2949dmphlp() {                              /* Print the help buffer */
2950    hlpbuf[hx++] = NUL;
2951    if ( hlpbuf[0] )
2952       printf(" %s\n",hlpbuf);
2953    clrhlp();
2954}
2955#endif /* OLDHELP */
2956
2957/*  G T W O R D  --  Gets a "word" from the command input stream  */
2958
2959/*
2960Usage: retcode = gtword();
2961
2962Returns:
2963 -9 if input was too long
2964 -4 if end of file (e.g. pipe broken)
2965 -3 if null command
2966 -2 if command buffer overflows
2967 -1 if user did some deleting
2968  0 if word terminates with SP or tab
2969  1 if ... CR
2970  2 if ... ESC
2971  3 if ... ? (question mark)
2972
2973With:
2974  pp pointing to beginning of word in buffer
2975  bp pointing to after current position
2976  atmbuf containing a copy of the word
2977  cc containing the number of characters in the word copied to atmbuf
2978*/
2979
2980int
2981ungword() {                             /* Unget a word */
2982    if (ungw) return(0);
2983    cmfsav = cmflgs;
2984    debug(F101,"ungword cmflgs","",cmflgs);
2985    ungw = 1;
2986    cmflgs = 0;
2987    return(0);
2988}
2989
2990static int
2991gtword() {
2992    int c;                              /* Current char */
2993    int quote = 0;                      /* Flag for quote character */
2994    int echof = 0;                      /* Flag for whether to echo */
2995    int chsrc = 0;                      /* Source of character, 1 = tty */
2996    int comment = 0;                    /* Flag for in comment */
2997    char *cp = NULL;                    /* Comment pointer */
2998    int eintr = 0;
2999    int bracelvl = 0;                   /* nested brace counter [jrs]       */
3000
3001#ifdef RTU
3002    extern int rtu_bug;
3003#endif /* RTU */
3004
3005#ifdef datageneral
3006    extern int termtype;                /* DG terminal type flag */
3007    extern int con_reads_mt;            /* Console read asynch is active */
3008    if (con_reads_mt) connoi_mt();      /* Task would interfere w/cons read */
3009#endif /* datageneral */
3010
3011    if (ungw) {                         /* Have a word saved? */
3012        debug(F110,"gtword ungetting from pp",pp,0);
3013        while (*pp++ == SP) ;
3014        if (setatm(pp,0) < 0) {
3015            printf("?Saved word too long\n");
3016            return(-9);
3017        }
3018        strncpy(atmbuf,pp,ATMBL);
3019        ungw = 0;
3020        cmflgs = cmfsav;
3021        debug(F111,"gtword returning atmbuf",atmbuf,cmflgs);
3022        return(cmflgs);
3023    }
3024    pp = np;                            /* Start of current field */
3025
3026    debug(F111,"gtword: cmdbuf",cmdbuf,cmdbuf);
3027    debug(F111," bp",bp,bp);
3028    debug(F111," pp",pp,pp);
3029
3030    while (bp < cmdbuf+CMDBL) {         /* Big get-a-character loop */
3031        echof = 0;                      /* Assume we don't echo because */
3032        chsrc = 0;                      /* character came from reparse buf. */
3033#ifdef BS_DIRSEP
3034CMDIRPARSE:
3035#endif /* BS_DIRSEP */
3036        if ((c = *bp) == NUL) {         /* If no char waiting in reparse buf */
3037           if (dpx) echof = 1;          /* must get from tty, set echo flag. */
3038           c = cmdgetc();               /* Read a character from the tty. */
3039           chsrc = 1;                   /* Remember character source is tty. */
3040#ifdef OS2
3041           if ( c < 0 ) {
3042               if ( c == -3 ) {
3043                   if (blocklvl > 0)
3044                     continue;
3045                   else
3046                     return(-3);        /* Empty command */
3047               } else {
3048                   return -4;           /* Something went wrong */
3049               }
3050           }
3051#else
3052#ifdef MAC
3053           if (c == -3)                 /* If null command... */
3054             if (blocklvl > 0)
3055               continue;
3056             else
3057               return(-3);
3058#endif /* MAC */
3059#endif /* OS2 */
3060           if (c == EOF) {              /* This can happen if stdin not tty. */
3061#ifdef EINTR
3062/*
3063  Some operating and/or C runtime systems return EINTR for no good reason,
3064  when the end of the standard input "file" is encountered.  In cases like
3065  this, we get into an infinite loop; hence the eintr counter, which is reset
3066  to 0 upon each call to this routine.
3067*/
3068                debug(F101,"gtword EOF","",errno);
3069                if (errno == EINTR && ++eintr < 4) /* When bg'd process is */
3070                  continue;             /* fg'd again. */
3071#endif /* EINTR */
3072                return(-4);
3073            }
3074            c &= cmdmsk;                /* Strip any parity bit */
3075        }                               /* if desired. */
3076
3077/* Now we have the next character */
3078
3079        if (quote && (c == CR || c == NL)) { /* Enter following quote */
3080            *bp++ = CMDQ;               /* Double it */
3081            *bp = NUL;
3082            quote = 0;
3083        }
3084        if (quote == 0) {               /* If this is not a quoted character */
3085            if (c == CMDQ) {            /* Got the quote character itself */
3086                if (!comment && quoting)
3087                  quote = 1;            /* Flag it if not in a comment */
3088            }
3089            if (c == FF) {              /* Formfeed. */
3090                c = NL;                 /* Replace with newline */
3091#ifdef OS2
3092                cmdclrscn();            /* Clear the screen */
3093#endif /* OS2 */
3094            }
3095            if (c == HT) {              /* Tab */
3096                if (comment)            /* If in comment, */
3097                  c = SP;               /* substitute space */
3098                else                    /* otherwise */
3099                  c = ESC;              /* substitute ESC (for completion) */
3100            }
3101            if (c == ';' || c == '#') { /* Trailing comment */
3102                if (inword == 0 && quoting) { /* If not in a word */
3103                    comment = 1;        /* start a comment. */
3104                    cp = bp;            /* remember where it starts. */
3105                }
3106            }
3107            if (!comment && c == SP) {  /* Space */
3108                *bp++ = (char) c;       /* deposit in buffer if not already */
3109#ifdef BEBOX
3110                if (echof) {
3111                    putchar(c);         /* echo it. */
3112                    fflush (stdout);
3113                    fflush(stderr);
3114                }
3115#else
3116                if (echof) putchar(c);  /* echo it. */
3117#endif /* BEBOX */
3118                if (inword == 0) {      /* If leading, gobble it. */
3119                    pp++;
3120                    continue;
3121                } else {                /* If terminating, return. */
3122#ifdef COMMENT
3123                    np = bp;
3124                    setatm(pp,0);
3125                    inword = cmflgs = 0;
3126                    return(0);
3127#else
3128/* This allows { ... } grouping */
3129                    if ((*pp != '{') || (bracelvl == 0)) {
3130                        np = bp;
3131                        if (setatm(pp,0) < 0) {
3132                            printf("?Field too long error 1\n");
3133                            debug(F111,"gtword too long #1",pp,strlen(pp));
3134                            return(-9);
3135                        }
3136                        inword = cmflgs = 0;
3137                        return(0);
3138                    }
3139                    continue;
3140#endif /* COMMENT */
3141                }
3142            }
3143            if (c == '{')
3144              bracelvl++;
3145            if (c == '}') {
3146                bracelvl--;
3147                if (linebegin)
3148                  blocklvl--;
3149            }
3150            if (c == NL || c == CR) {   /* CR or LF. */
3151#ifdef BEBOX
3152                if (echof) {
3153                    cmdnewl((char)c);   /* echo it. */
3154                    fflush (stdout);
3155                    fflush(stderr);
3156                }
3157#else
3158                if (echof) cmdnewl((char)c); /* echo it. */
3159#endif /* BEBOX */
3160                while (bp > pp && (*(bp-1) == SP || *(bp-1) == HT)) /* Trim */
3161                  bp--;                 /* trailing */
3162                *bp = NUL;              /* whitespace. */
3163
3164                if (linebegin && blocklvl > 0) /* Blank line in {...} block */
3165                  continue;
3166
3167                linebegin = 1;          /* At beginning of next line */
3168
3169                if ((bp > pp) &&
3170                    (*(bp-1) == '-' || *(bp-1) == '{')) { /* Line continued? */
3171                    if (chsrc) {        /* If reading from tty, */
3172                        if (*(bp-1) == '{') { /* Check for "begin block" */
3173                            *bp++ = SP; /* Insert a space for neatness */
3174                            blocklvl++; /* Count block nesting level */
3175                        } else {        /* Or hyphen */
3176                            bp--;       /* Overwrite the hyphen */
3177                        }
3178                        *bp = NUL;      /* erase the dash, */
3179                        continue;       /* and go back for next char now. */
3180                    }
3181                } else if (blocklvl > 0) { /* No continuation character */
3182                     if (chsrc) {       /* But we're in a "block" */
3183                         *bp++ = ',';   /* Add comma */
3184                         *bp = NUL;
3185                         continue;
3186                     }
3187                 } else {               /* No continuation, end of command. */
3188                     *bp = NUL;         /* Terminate the command string. */
3189                     if (comment) {     /* If we're in a comment, */
3190                         comment = 0;   /* Say we're not any more, */
3191                         *cp = NUL;     /* cut it off. */
3192                     }
3193                     np = bp;           /* Where to start next field. */
3194                     if (setatm(pp,0) < 0) { /* Copy field to atom buffer */
3195                         debug(F111,"gtword too long #2",pp,strlen(pp));
3196                        printf("?Field too long error 2\n");
3197                        return(-9);
3198                    }
3199                    inword = 0;         /* Not in a word any more. */
3200#ifdef CK_RECALL
3201                    if (chsrc &&        /* Reading commands from keyboard? */
3202                        (on_recall) &&         /* Recall is turned on? */
3203                        (cm_recall > 0) &&     /* Saving commands? */
3204                        (int)strlen(cmdbuf)) { /* Non-null command? */
3205                        if (rlast >= cm_recall - 1) { /* Yes, buffer full? */
3206                            int i;         /* Yes. */
3207                            if (recall[0]) { /* Discard oldest command */
3208                                free(recall[0]);
3209                                recall[0] = NULL;
3210                            }
3211                            for (i = 0; i < rlast; i++) { /* The rest */
3212                                recall[i] = recall[i+1]; /* move back */
3213                            }
3214                            rlast--;     /* Now we have one less */
3215                        }
3216                        rlast++;         /* Index of last command in buffer */
3217                        current = rlast; /* Also now the current command */
3218                        if (current >= cm_recall) {
3219                            printf("Oops, command recall error\n");
3220                        } else {
3221                            recall[current] = malloc((int)strlen(cmdbuf)+1);
3222                            if (recall[current])
3223                              strcpy(recall[current],cmdbuf);
3224                        }
3225                    }
3226#endif /* CK_RECALL */
3227                    return(cmflgs = 1);
3228                }
3229            }
3230
3231            /* Question mark */
3232
3233            if (!comment && quoting && echof && (c == '?')) {
3234                putchar(c);
3235                *bp = NUL;
3236                if (setatm(pp,0) < 0) {
3237                    debug(F111,"gtword too long #3",pp,strlen(pp));
3238                    printf("?Too long #3\n");
3239                    return(-9);
3240                }
3241                return(cmflgs = 3);
3242            }
3243            if (c == ESC) {             /* ESC */
3244                if (!comment) {
3245                    *bp = NUL;
3246                    if (setatm(pp,0) < 0) {
3247                        debug(F111,"gtword too long #4",pp,strlen(pp));
3248                        printf("?Too long #4\n");
3249                        return(-9);
3250                    }
3251                    return(cmflgs = 2);
3252                } else {
3253                    bleep(BP_WARN);
3254                    continue;
3255                }
3256            }
3257            if (c == BS || c == RUB) {  /* Character deletion */
3258                if (bp > cmdbuf) {      /* If still in buffer... */
3259                    cmdchardel();       /* erase it. */
3260                    bp--;               /* point behind it, */
3261#ifdef COMMENT
3262                    if (*bp == SP) inword = 0; /* Flag if current field gone */
3263#else
3264/* fixed by Ulli Schlueter */
3265                    if (*bp == '{') bracelvl--; /* Adjust brace count */
3266                    if (*bp == '}') bracelvl++;
3267                    if ((*bp == SP) &&       /* Flag if current field gone */
3268                        (*pp != '{' || bracelvl == 0))
3269                      inword = 0;
3270#endif /* COMMENT */
3271                    *bp = NUL;          /* Erase character from buffer. */
3272                } else {                /* Otherwise, */
3273                    bleep(BP_WARN);
3274                    cmres();            /* and start parsing a new command. */
3275                    *bp = *atmbuf = NUL;
3276                }
3277                if (pp < bp) continue;
3278                else return(cmflgs = -1);
3279            }
3280            if (c == LDEL) {            /* ^U, line deletion */
3281                while ((bp--) > cmdbuf) {
3282                    cmdchardel();
3283                    *bp = NUL;
3284                }
3285                cmres();                /* Restart the command. */
3286                *bp = *atmbuf = NUL;
3287                inword = 0;
3288                return(cmflgs = -1);
3289            }
3290            if (c == WDEL) {            /* ^W, word deletion */
3291                if (bp <= cmdbuf) {     /* Beep if nothing to delete */
3292                    bleep(BP_WARN);
3293                    cmres();
3294                    *bp = *atmbuf = NUL;
3295                    return(cmflgs = -1);
3296                }
3297                bp--;
3298                for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) {
3299                    cmdchardel();
3300                    *bp = NUL;
3301                }
3302                for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) {
3303                    cmdchardel();
3304                    *bp = NUL;
3305                }
3306                bp++;
3307                inword = 0;
3308                return(cmflgs = -1);
3309            }
3310            if (c == RDIS) {            /* ^R, redisplay */
3311#ifdef COMMENT
3312                *bp = NUL;
3313                printf("\n%s%s",cmprom,cmdbuf);
3314#else
3315                char *cpx; char cx;
3316                *bp = NUL;
3317                printf("\n%s",cmprom);
3318                cpx = cmdbuf;
3319                while (cx = *cpx++) {
3320#ifdef isprint
3321                    putchar(isprint(cx) ? cx : '^');
3322#else
3323                    putchar((cx >= SP && cx < DEL) ? cx : '^');
3324#endif /* isprint */
3325                }
3326#endif /* COMMENT */
3327                fflush(stdout);
3328                continue;
3329            }
3330#ifdef CK_RECALL
3331            if (chsrc &&                /* Reading commands from keyboard? */
3332                (cm_recall > 0) &&      /* Saving commands? */
3333                (c == C_UP || c == C_UP2)) { /* Go up one */
3334                if (current < 0) {      /* Nowhere to go, */
3335                    bleep(BP_WARN);
3336                    continue;
3337                }       
3338                if (recall[current]) {
3339                    if (!strcmp(recall[current],cmdbuf)) {
3340                        if (current > 0) {
3341                            current--;                   
3342                        } else {
3343                            bleep(BP_WARN);
3344                            continue;
3345                        }
3346                    }
3347                }
3348                if (recall[current]) { /* We have a previous command */
3349                    while ((bp--) > cmdbuf) { /* Erase current line */
3350                        cmdchardel();
3351                        *bp = NUL;
3352                    }
3353                    strcpy(cmdbuf,recall[current]);
3354#ifdef OSK
3355                    fflush(stdout);
3356                    write(fileno(stdout), "\r", 1);
3357                    printf("%s%s",cmprom,cmdbuf);
3358#else
3359                    printf("\r%s%s",cmprom,cmdbuf);
3360#endif /* OSK */
3361                    current--;
3362                }
3363                return(cmflgs = -1);    /* Force a reparse */
3364            }
3365            if (chsrc &&                /* Reading commands from keyboard? */
3366                (cm_recall > 0) &&      /* Saving commands? */
3367                (c == C_DN)) {          /* Down one */
3368                if (current + 1 > rlast) { /* Already at bottom, just beep */
3369                    bleep(BP_WARN);
3370                    continue;
3371                }
3372                current++;              /* OK to go down */
3373#ifdef COMMENT
3374                if (recall[current])    /* It's the same as this one? */
3375                  if (!strcmp(recall[current],cmdbuf))
3376                    current++;
3377#else
3378/* Fix by Ulli Schlueter */
3379                if (recall[current]) {
3380                    if (!strcmp(recall[current],cmdbuf)) {
3381                        if (current + 1 > rlast) { /* At bottom, beep */
3382                            bleep(BP_WARN);
3383                            continue;
3384                        } else
3385                          current++;
3386                    }
3387                }
3388#endif /* COMMENT */
3389                if (recall[current]) {
3390                    while ((bp--) > cmdbuf) { /* Erase current line */
3391                        cmdchardel();
3392                        *bp = NUL;
3393                    }
3394                    strcpy(cmdbuf,recall[current]);
3395#ifdef OSK
3396                    fflush(stdout);
3397                    write(fileno(stdout), "\r", 1);
3398                    printf("%s%s",cmprom,cmdbuf);
3399#else
3400                    printf("\r%s%s",cmprom,cmdbuf);
3401#endif /* OSK */
3402                    return(cmflgs = -1); /* Force reparse */
3403                }
3404            }
3405#endif /* CK_RECALL */
3406            if (c < SP && quote == 0) { /* Any other unquoted control char */
3407                if (!chsrc)             /* If cmd file, point past it */
3408                  bp++;
3409                else
3410                  bleep(BP_WARN);
3411                continue;               /* continue, don't put in buffer */
3412            }
3413            linebegin = 0;              /* Not at beginning of line */
3414#ifdef BEBOX
3415            if (echof) {
3416                cmdecho((char) c, 0); /* Echo what was typed. */
3417                fflush (stdout);
3418                fflush(stderr);
3419            }
3420#else
3421            if (echof) cmdecho((char) c, 0); /* Echo what was typed. */
3422#endif /* BEBOX */
3423        } else {                        /* This character was quoted. */
3424            int qf = 1;
3425            quote = 0;                  /* Unset the quote flag. */
3426
3427            /* Quote character at this level is only for SP, ?, and controls */
3428            /* If anything else was quoted, leave quote in, and let */
3429            /* the command-specific parsing routines handle it, e.g. \007 */
3430            if (c > 32 && c != '?' && c != RUB && chsrc != 0) {
3431                *bp++ = CMDQ;           /* Deposit \ if it came from tty */
3432                qf = 0;                 /* and don't erase it from screen */
3433                linebegin = 0;          /* Not at beginning of line */
3434#ifdef BS_DIRSEP
3435/*
3436  This is a hack to handle "cd \" or "cd foo\" on OS/2 and similar systems.
3437  If we were called from cmdir() and the previous character was the quote
3438  character, i.e. backslash, and this character is the command terminator,
3439  then we stuff an extra backslash into the buffer without echoing, then
3440  we stuff the carriage return back in again, and go back and process it,
3441  this time with the quote flag off.
3442*/
3443            } else if (cmdirflg && (c == CR || c == LF || c == SP)) {
3444                *bp++ = CMDQ;
3445                linebegin = 0;          /* Not at beginning of line */
3446                *bp = (c == SP ? SP : CR);
3447        goto CMDIRPARSE ;
3448#endif /* BS_DIRSEP */
3449            }
3450#ifdef BEBOX
3451            if (echof) {
3452                cmdecho((char) c, qf);  /* Echo what was typed. */
3453                fflush (stdout);
3454                fflush(stderr);
3455            }
3456#else
3457            if (echof) cmdecho((char) c, qf); /* Now echo quoted character */
3458#endif /* BEBOX */
3459            debug(F111,"gtword quote",cmdbuf,c);
3460        }
3461#ifdef COMMENT
3462        if (echof) cmdecho((char) c,quote); /* Echo what was typed. */
3463#endif /* COMMENT */
3464        if (!comment) inword = 1;       /* Flag we're in a word. */
3465        if (quote) continue;            /* Don't deposit quote character. */
3466        if (c != NL) *bp++ = (char) c;  /* Deposit command character. */
3467    }                                   /* End of big while */
3468    bleep(BP_WARN);
3469    printf("?Command too long, maximum length: %d.\n",CMDBL);
3470    cmflgs = -2;
3471    return(-9);
3472}
3473
3474/* Utility functions */
3475
3476/* A D D B U F  -- Add the string pointed to by cp to the command buffer  */
3477
3478static int
3479addbuf(cp) char *cp; {
3480    int len = 0;
3481    while ((*cp != NUL) && (bp < cmdbuf+CMDBL)) {
3482        *bp++ = *cp++;                  /* Copy and */
3483        len++;                          /* count the characters. */
3484    }
3485    *bp++ = SP;                         /* Put a space at the end */
3486    *bp = NUL;                          /* Terminate with a null */
3487    np = bp;                            /* Update the next-field pointer */
3488    return(len);                        /* Return the length */
3489}
3490
3491/*  S E T A T M  --  Deposit a token in the atom buffer.  */
3492/*
3493  Break on space, newline, carriage return, or NUL.
3494  Except flag != 0 means to allow imbedded spaces in selected fields.
3495  Null-terminate the result.
3496  If the source pointer is the atom buffer itself, do nothing.
3497  Return length of token, and also set global "cc" to this length.
3498  Return -1 if token was too long.
3499*/
3500static int
3501setatm(cp,flag) char *cp; int flag; {
3502    char *ap, *xp;
3503    int  bracelvl, n;
3504
3505    cc = 0;                             /* Character counter */
3506    ap = atmbuf;                        /* Address of atom buffer */
3507
3508    if ((int) strlen(cp) > ATMBL)
3509      return(-1);
3510
3511    if (cp == ap) {                     /* In case source is atom buffer */
3512        xp = atybuf;                    /* make a copy */
3513        strcpy(xp,ap);                  /* so we can copy it back, edited. */
3514        cp = xp;
3515    }
3516    *ap = NUL;                          /* Zero the atom buffer */
3517    if (flag) {                         /* Trim trailing blanks */
3518        n = strlen(cp);
3519        while (--n >= 0)
3520          if (cp[n] != SP) break;
3521        cp[n+1] = NUL;
3522    }
3523    while (*cp == SP) cp++;             /* Trim leading spaces */
3524#ifdef COMMENT
3525/* This one doesn't work for items like "input 20 {\13\10$ }" */
3526    bracelvl = (*cp == '{');            /* jrs */
3527    while ( /* (*cp != SP) && */ (*cp != NL) && (*cp != NUL) && (*cp != CR)) {
3528        if ((*cp == SP) && (flag == 0) && (bracelvl == 0)) break; /* jrs */
3529        *ap++ = *cp++;                  /* Copy up to SP, NL, CR, or end */
3530        if (*cp == '{') bracelvl++;     /* jrs */
3531        if (*cp == '}') bracelvl--;     /* jrs */
3532        cc++;                           /* and count */
3533    }
3534#else
3535    bracelvl = 0;
3536    while (*cp) {
3537        if (*cp == '{') bracelvl++;
3538        if (*cp == '}') bracelvl--;
3539        if (bracelvl < 0) bracelvl = 0;
3540        if (bracelvl == 0) {
3541            if ((*cp == SP || *cp == HT) && (flag == 0)) break;
3542            if (*cp == LF || *cp == CR) break;
3543        }
3544        *ap++ = *cp++;
3545        cc++;
3546    }
3547#endif /* COMMENT */
3548    *ap = NUL;                          /* Terminate the string. */
3549    return(cc);                         /* Return length. */
3550}
3551
3552/*  R D I G I T S  -- Verify that all the characters in line ARE DIGITS  */
3553
3554int
3555rdigits(s) char *s; {
3556    while (*s) {
3557        if (!isdigit(*s)) return(0);
3558        s++;
3559    }
3560    return(1);
3561}
3562
3563/* These functions attempt to hide system dependencies from the mainline */
3564/* code in gtword().  Ultimately they should be moved to ck?tio.c, where */
3565/* ? = each and every system supported by C-Kermit. */
3566
3567static int
3568cmdgetc() {                             /* Get a character from the tty. */
3569    int c;
3570
3571#ifdef datageneral
3572    {
3573        char ch;
3574        c = dgncinb(0,&ch,1);           /* -1 is EOF, -2 TO,
3575                                         * -c is AOS/VS error */
3576        if (c == -2) {                  /* timeout was enabled? */
3577            resto(channel(0));          /* reset timeouts */
3578            c = dgncinb(0,&ch,1);       /* retry this now! */
3579        }
3580        if (c < 0) return(-4);          /* EOF or some error */
3581        else c = (int) ch & 0177;       /* Get char without parity */
3582/*      echof = 1; */
3583    }
3584#else /* Not datageneral */
3585#ifdef OS2
3586    c = is_a_tty(0) ? coninc(0) : getchar();
3587    if (c < 0) return(c); /* was (-4); */
3588#else /* Not OS2 */
3589    c = getchar();                      /* or from tty. */
3590#ifdef RTU
3591    if (rtu_bug) {
3592        c = getchar();                  /* RTU doesn't discard the ^Z */
3593        rtu_bug = 0;
3594    }
3595#endif /* RTU */
3596#endif /* OS2 */
3597#endif /* datageneral */
3598    return(c);                          /* Return what we got */
3599}
3600
3601
3602/*
3603  No more screen clearing.  If you wanna clear the screen, define a macro
3604  to do it, like "define cls write screen \27[;H\27[2J".
3605*/
3606static VOID
3607cmdclrscn() {                           /* Clear the screen */
3608
3609#ifdef OS2
3610    clear();
3611#else /* OS2 */
3612#ifdef COMMENT
3613#ifdef aegis
3614    putchar(FF);
3615#else
3616#ifdef AMIGA
3617    putchar(FF);
3618#else
3619#ifdef OSK
3620    putchar(FF);
3621#else
3622#ifdef datageneral
3623    putchar(FF);
3624#endif /* datageneral */
3625#endif /* OSK */
3626#endif /* AMIGA */
3627#endif /* aegis */
3628#endif /* COMMENT */
3629#endif /* OS2 */
3630}
3631
3632static VOID                             /* What to echo at end of command */
3633#ifdef CK_ANSIC
3634cmdnewl(char c)
3635#else
3636cmdnewl(c) char c;
3637#endif /* CK_ANSIC */
3638/* cmdnewl */ {
3639    putchar(c);                         /* c is the terminating character */
3640
3641#ifdef WINTCP                           /* what is this doing here? */
3642    if (c == CR) putchar(NL);
3643#endif /* WINTCP */
3644
3645/*
3646  A.A. Chernov, who sent in changes for FreeBSD, said we also needed this
3647  for SVORPOSIX because "setup terminal by termios and curses does
3648  not convert \r to \n, so additional \n needed in newline function.  But
3649  it is also very likely to result in unwanted blank lines.
3650*/
3651
3652#ifdef OS2
3653    if (c == CR) putchar(NL);
3654#endif /* OS2 */
3655#ifdef aegis
3656    if (c == CR) putchar(NL);
3657#endif /* aegis */
3658#ifdef AMIGA
3659    if (c == CR) putchar(NL);
3660#endif /* AMIGA */
3661#ifdef datageneral
3662    if (c == CR) putchar(NL);
3663#endif /* datageneral */
3664#ifdef GEMDOS
3665    if (c == CR) putchar(NL);
3666#endif /* GEMDOS */
3667#ifdef STRATUS
3668    if (c == CR) putchar(NL);
3669#endif /* STRATUS */
3670}
3671
3672static VOID
3673cmdchardel() {                          /* Erase a character from the screen */
3674    if (!dpx) return;
3675#ifdef datageneral
3676    /* DG '\b' is EM (^y or \031) */
3677    if (termtype == 1)
3678      /* Erase a character from non-DG screen, */
3679      dgncoub(1,"\010 \010",3);
3680    else
3681#endif
3682      printf("\b \b");
3683#ifdef GEMDOS
3684    fflush(stdout);
3685#endif /* GEMDOS */
3686#ifdef BEBOX
3687    fflush(stdout);
3688#endif /* BEBOX */
3689}
3690
3691static VOID
3692#ifdef CK_ANSIC
3693cmdecho(char c, int quote)
3694#else
3695cmdecho(c,quote) char c; int quote;
3696#endif /* CK_ANSIC */
3697{ /* cmdecho */
3698    if (!dpx) return;
3699    /* Echo tty input character c */
3700    if (quote) {
3701        putchar(BS); putchar(SP); putchar(BS);
3702#ifdef isprint
3703        putchar( isprint(c) ? c : '^' );
3704#else
3705        putchar((c >= SP && c < DEL) ? c : '^');
3706#endif /* isprint */
3707    } else putchar(c);
3708#ifdef OS2
3709    if (quote==1 && c==CR) putchar(NL);
3710#endif /* OS2 */
3711}
3712
3713#endif /* NOICP */
3714
3715#ifdef NOICP
3716#include "ckcdeb.h"
3717#include "ckucmd.h"
3718#include "ckcasc.h"
3719/*** #include <ctype.h> (ckcdeb.h already includes this) ***/
3720#endif /* NOICP */
3721
3722/*  X X E S C  --  Interprets backslash codes  */
3723/*  Returns the int value of the backslash code if it is > -1 and < 256 */
3724/*  and updates the string pointer to first character after backslash code. */
3725/*  If the argument is invalid, leaves pointer unchanged and returns -1. */
3726
3727int
3728xxesc(s) char **s; {                    /* Expand backslash escapes */
3729    int x, y, brace, radix;             /* Returns the int value */
3730    char hd = '9';                      /* Highest digit in radix */
3731    char *p;
3732
3733    p = *s;                             /* pointer to beginning */
3734    if (!p) return(-1);                 /* watch out for null pointer */
3735    x = *p++;                           /* character at beginning */
3736    if (x != CMDQ) return(-1);          /* make sure it's a backslash code */
3737
3738    x = *p;                             /* it is, get the next character */
3739    if (x == '{') {                     /* bracketed quantity? */
3740        p++;                            /* begin past bracket */
3741        x = *p;
3742        brace = 1;
3743    } else brace = 0;
3744    switch (x) {                        /* Start interpreting */
3745      case 'd':                         /* Decimal radix indicator */
3746      case 'D':
3747        p++;                            /* Just point past it and fall thru */
3748      case '0':                         /* Starts with digit */
3749      case '1':
3750      case '2':  case '3':  case '4':  case '5':
3751      case '6':  case '7':  case '8':  case '9':
3752        radix = 10;                     /* Decimal */
3753        hd = '9';                       /* highest valid digit */
3754        break;
3755      case 'o':                         /* Starts with o or O */
3756      case 'O':
3757        radix = 8;                      /* Octal */
3758        hd = '7';                       /* highest valid digit */
3759        p++;                            /* point past radix indicator */
3760        break;
3761      case 'x':                         /* Starts with x or X */
3762      case 'X':
3763        radix = 16;                     /* Hexadecimal */
3764        p++;                            /* point past radix indicator */
3765        break;
3766      default:                          /* All others */
3767#ifdef COMMENT
3768        *s = p+1;                       /* Treat as quote of next char */
3769        return(*p);
3770#else
3771        return(-1);
3772#endif /* COMMENT */
3773    }
3774    /* For OS/2, there are "wide" characters required for the keyboard
3775     * binding, i.e \644 and similar codes larger than 255 (byte).
3776     * For this purpose, give up checking for < 256. If someone means
3777     * \266 should result in \26 followed by a "6" character, he should
3778     * always write \{26}6 anyway.  Now, return only the lower byte of
3779     * the result, i.e. 10, but eat up the whole \266 sequence and
3780     * put the wide result 266 into a global variable.  Yes, that's not
3781     * the most beautiful programming style but requires the least
3782     * amount of changes to other routines.
3783     */
3784    if (radix <= 10) {                  /* Number in radix 8 or 10 */
3785        for ( x = y = 0;
3786              (*p) && (*p >= '0') && (*p <= hd)
3787#ifdef OS2
3788                   && (y < 5) && (x*radix < KMSIZE);
3789              /* the maximum needed value \8196 is 4 digits long */
3790              /* while as octal it requires \1377, i.e. 5 digits */
3791#else
3792                   && (y < 3) && (x*radix < 256);
3793#endif /* OS2 */
3794              p++,y++) {
3795            x = x * radix + (int) *p - 48;
3796        }
3797#ifdef OS2
3798        wideresult = x;                 /* Remember wide result */
3799        x &= 255;
3800#endif /* OS2 */
3801        if (y == 0 || x > 255) {        /* No valid digits? */
3802            *s = p;                     /* point after it */
3803            return(-1);                 /* return failure. */
3804        }
3805    } else if (radix == 16) {           /* Special case for hex */
3806        if ((x = unhex(*p++)) < 0) { *s = p - 1; return(-1); }
3807        if ((y = unhex(*p++)) < 0) { *s = p - 2; return(-1); }
3808        x = ((x << 4) & 0xF0) | (y & 0x0F);
3809#ifdef OS2
3810        wideresult = x;
3811        if ((y = unhex(*p)) >= 0) {
3812           p++;
3813           wideresult = ((x << 4) & 0xFF0) | (y & 0x0F);
3814           x = wideresult & 255;
3815        }
3816#endif /* OS2 */
3817    } else x = -1;
3818    if (brace && *p == '}' && x > -1)   /* Point past closing brace, if any */
3819      p++;
3820    *s = p;                             /* Point to next char after sequence */
3821    return(x);                          /* Return value of sequence */
3822}
3823
3824int                                     /* Convert hex string to int */
3825#ifdef CK_ANSIC
3826unhex(char x)
3827#else
3828unhex(x) char x;
3829#endif /* CK_ANSIC */
3830/* unhex */ {
3831
3832    if (x >= '0' && x <= '9')           /* 0-9 is offset by hex 30 */
3833      return(x - 0x30);
3834    else if (x >= 'A' && x <= 'F')      /* A-F offset by hex 37 */
3835      return(x - 0x37);
3836    else if (x >= 'a' && x <= 'f')      /* a-f offset by hex 57 */
3837      return(x - 0x57);                 /* (obviously ASCII dependent) */
3838    else return(-1);
3839}
3840
3841/* See if argument string is numeric */
3842/* Returns 1 if OK, zero if not OK */
3843/* If OK, string should be acceptable to atoi() */
3844/* Allows leading space, sign */
3845
3846int
3847chknum(s) char *s; {                    /* Check Numeric String */
3848    int x = 0;                          /* Flag for past leading space */
3849    int y = 0;                          /* Flag for digit seen */
3850    char c;
3851    debug(F110,"chknum",s,0);
3852    while (c = *s++) {                  /* For each character in the string */
3853        switch (c) {
3854          case SP:                      /* Allow leading spaces */
3855          case HT:
3856            if (x == 0) continue;
3857            else return(0);
3858          case '+':                     /* Allow leading sign */
3859          case '-':
3860            if (x == 0) x = 1;
3861            else return(0);
3862            break;
3863          default:                      /* After that, only decimal digits */
3864            if (c >= '0' && c <= '9') {
3865                x = y = 1;
3866                continue;
3867            } else return(0);
3868        }
3869    }
3870    return(y);
3871}
3872
3873/*  L O W E R  --  Lowercase a string  */
3874
3875int
3876lower(s) char *s; {
3877    int n = 0;
3878    while (*s) {
3879        if (isupper(*s)) *s = (char) tolower(*s);
3880        s++, n++;
3881    }
3882    return(n);
3883}
3884
3885/*  L O O K U P  --  Lookup the string in the given array of strings  */
3886
3887/*
3888 Call this way:  v = lookup(table,word,n,&x);
3889
3890   table - a 'struct keytab' table.
3891   word  - the target string to look up in the table.
3892   n     - the number of elements in the table.
3893   x     - address of an integer for returning the table array index,
3894           or NULL if you don't need a table index.
3895
3896 The keyword table must be arranged in ascending alphabetical order.
3897 Alphabetic case doesn't matter.
3898
3899 Returns the keyword's associated value (zero or greater) if found,
3900 with the variable x set to the keyword-table index, or:
3901
3902  -3 if nothing to look up (target was null),
3903  -2 if ambiguous,
3904  -1 if not found.
3905
3906 A match is successful if the target matches a keyword exactly, or if
3907 the target is a prefix of exactly one keyword.  It is ambiguous if the
3908 target matches two or more keywords from the table.
3909*/
3910int
3911lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
3912
3913    int i, v, len, cmdlen;
3914
3915/* Get length of search object, if it's null return code -3. */
3916
3917    if (!cmd)
3918      return(-3);
3919    if (((cmdlen = (int) strlen(cmd)) == 0) || (n < 1))
3920      return(-3);
3921
3922/* Not null, look it up */
3923
3924    for (i = 0; i < n-1; i++) {
3925        len = strlen(table[i].kwd);
3926        if ((len == cmdlen && !xxstrcmp(table[i].kwd,cmd,len)) ||
3927            ((v = !xxstrcmp(table[i].kwd,cmd,cmdlen)) &&
3928             xxstrcmp(table[i+1].kwd,cmd,cmdlen))) {
3929            if (x) *x = i;
3930            return(table[i].kwval);
3931        }
3932        if (v) return(-2);
3933    }
3934
3935/* Last (or only) element */
3936
3937    if (!xxstrcmp(table[n-1].kwd,cmd,cmdlen)) {
3938        if (x) *x = n-1;
3939        return(table[n-1].kwval);
3940    } else return(-1);
3941}
3942
3943/* Like lookup, but requires a full (but case-independent) match */
3944
3945int
3946xlookup(table,cmd,n,x) struct keytab table[]; char *cmd; int n, *x; {
3947    int i, cmdlen;
3948
3949    if (!cmd)
3950      return(-3);
3951    if (((cmdlen = (int) strlen(cmd)) == 0) || (n < 1))
3952      return(-3);
3953
3954    for (i = 0; i < n; i++) {
3955        if (((int)strlen(table[i].kwd) == cmdlen) &&
3956            (!xxstrcmp(table[i].kwd,cmd,cmdlen))) {
3957            if (x) *x = i;
3958            return(table[i].kwval);
3959        }
3960    }
3961    return(-1);
3962}
3963
3964#ifndef NOICP
3965int
3966cmdsquo(x) int x; {
3967    quoting = x;
3968    return(1);
3969}
3970
3971int
3972cmdgquo() {
3973    return(quoting);
3974}
3975#endif /* NOICP */
Note: See TracBrowser for help on using the repository browser.