ckucmd.c
资源名称:cku197.tar.Z [点击查看]
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:151k
源码类别:
通讯/手机编程
开发平台:
Windows_Unix
- #include "ckcsym.h"
- #define DOCHKVAR
- char *cmdv = "Command package 7.0.121, 24 Dec 1999";
- /* C K U C M D -- Interactive command package for Unix */
- /*
- Author: Frank da Cruz (fdc@columbia.edu),
- Columbia University Academic Information Systems, New York City.
- Copyright (C) 1985, 2000,
- Trustees of Columbia University in the City of New York.
- All rights reserved. See the C-Kermit COPYING.TXT file or the
- copyright text in the ckcmai.c module for disclaimer and permissions.
- */
- #ifdef OS2 /* Command-terminal-to-C-Kermit character mask */
- int cmdmsk = 255;
- #else
- int cmdmsk = 127;
- #endif /* OS2 */
- #ifdef BS_DIRSEP /* Directory separator is backslash */
- #undef BS_DIRSEP
- #endif /* BS_DIRSEP */
- #ifdef OS2
- #define BS_DIRSEP
- #endif /* BS_DIRSEP */
- #define CKUCMD_C
- #include "ckcdeb.h" /* Formats for debug(), etc. */
- #include "ckcker.h" /* Needed for BIGBUFOK definition */
- #include "ckcnet.h" /* Needed for server-side Telnet */
- #include "ckucmd.h" /* Needed for xx_strp prototype */
- #include "ckuusr.h" /* Needed for prompt length */
- #undef CKUCMD_C
- _PROTOTYP( int unhex, (char) );
- _PROTOTYP( static VOID cmdclrscn, (void) );
- struct keytab cmonths[] = {
- { "april", 4, 0 },
- { "august", 8, 0 },
- { "december", 12, 0 },
- { "february", 2, 0 },
- { "january", 1, 0 },
- { "july", 7, 0 },
- { "june", 6, 0 },
- { "march", 3, 0 },
- { "may", 5, 0 },
- { "november", 11, 0 },
- { "october", 10, 0 },
- { "september", 9, 0 }
- };
- #ifndef NOICP /* The rest only if interactive command parsing selected */
- #ifndef NOSPL
- _PROTOTYP( int chkvar, (char *) );
- extern int askflag;
- #endif /* NOSPL */
- int cmfldflgs = 0; /* Flags for cmfld() */
- static int cmkwflgs = 0; /* Flags from last keyword parse */
- static int blocklvl = 0; /* Block nesting level */
- static int linebegin = 0; /* Flag for at start of a line */
- static int quoting = 1; /* Quoting is allowed */
- static int swarg = 0; /* Parsing a switch argument */
- static int xcmfdb = 0; /* Flag for parsing chained fdbs... */
- static int chsrc = 0; /* Source of character, 1 = tty */
- #ifdef BS_DIRSEP
- static int dirnamflg = 0;
- #endif /* BS_DIRSEP */
- /*
- Modeled after the DECSYSTEM-20 command parser (the COMND JSYS), RIP. Features:
- . parses and verifies keywords, filenames, text strings, numbers, other data
- . displays appropriate menu or help message when user types "?"
- . does keyword and filename completion when user types ESC or TAB
- . does partial filename completion
- . accepts any unique abbreviation for a keyword
- . allows keywords to have attributes, like "invisible" and "abbreviation"
- . can supply defaults for fields omitted by user
- . provides command retry and recall
- . provides command line editing (character, word, and line deletion)
- . accepts input from keyboard, command files, macros, or redirected stdin
- . allows for full or half duplex operation, character or line input
- . allows -escapes for hard-to-type characters
- . allows specification of a user exit to expand variables, etc.
- . settable prompt, protected from deletion, dynamically re-evaluated each time.
- . allows chained parse functions.
- Functions:
- cmsetp - Set prompt (cmprom is prompt string)
- cmsavp - Save current prompt
- prompt - Issue prompt
- cmini - Clear the command buffer (before parsing a new command)
- cmres - Reset command buffer pointers (before reparsing)
- cmkey - Parse a keyword or token (also cmkey2)
- cmswi - Parse a switch
- cmnum - Parse a number
- cmifi - Parse an input file name
- cmofi - Parse an output file name (also cmifip, cmifi2, ...)
- cmdir - Parse a directory name (also cmdirp)
- cmfld - Parse an arbitrary field
- cmtxt - Parse a text string
- cmdate - Parse a date-time string
- cmcfm - Parse command confirmation (end of line)
- cmfdb - Parse any of a list of the foregoing (chained parse functions)
- Return codes:
- -9: like -2 except this module already printed the error message
- -3: no input provided when required
- -2: input was invalid (e.g. not a number when a number was required)
- -1: reparse required (user deleted into a preceding field)
- 0 or greater: success
- See individual functions for greater detail.
- Before using these routines, the caller should #include ckucmd.h, and set the
- program's prompt by calling cmsetp(). If the file parsing functions cmifi,
- cmofi, or cmdir are to be used, this module must be linked with a ck?fio file
- system support module for the appropriate system, e.g. ckufio for Unix. If
- the caller puts the terminal in character wakeup ("cbreak") mode with no echo,
- then these functions will provide line editing -- character, word, and line
- deletion, as well as keyword and filename completion upon ESC and help
- strings, keyword, or file menus upon '?'. If the caller puts the terminal
- into character wakeup/noecho mode, care should be taken to restore it before
- exit from or interruption of the program. If the character wakeup mode is not
- set, the system's own line editor may be used.
- NOTE: Contrary to expectations, many #ifdef's have been added to this module.
- Any operation requiring an #ifdef (like clear screen, get character from
- keyboard, erase character from screen, etc) should eventually be turned into a
- call to a function that is defined in ck?tio.c, but then all the ck?tio.c
- modules would have to be changed...
- */
- /* Includes */
- #include "ckcker.h"
- #include "ckcasc.h" /* ASCII character symbols */
- #include "ckucmd.h" /* Command parsing definitions */
- #ifdef OSF13
- #ifdef CK_ANSIC
- #ifdef _NO_PROTO
- #undef _NO_PROTO
- #endif /* _NO_PROTO */
- #endif /* CK_ANSIC */
- #endif /* OSF13 */
- #include <errno.h> /* Error number symbols */
- #ifdef OS2
- #ifndef NT
- #define INCL_NOPM
- #define INCL_VIO /* Needed for ckocon.h */
- #include <os2.h>
- #undef COMMENT
- #else
- #define APIRET ULONG
- #include <windows.h>
- #endif /* NT */
- #include "ckocon.h"
- #include <io.h>
- #endif /* OS2 */
- #ifdef NT
- #define stricmp _stricmp
- #endif /* NT */
- #ifdef OSK
- #define cc ccount /* OS-9/68K compiler bug */
- #endif /* OSK */
- #ifdef GEMDOS /* Atari ST */
- #ifdef putchar
- #undef putchar
- #endif /* putchar */
- #define putchar(x) conoc(x)
- #endif /* GEMDOS */
- #ifdef CK_AUTODL
- extern int cmdadl, justone;
- #endif /* CK_AUTODL */
- extern int timelimit, nzxopts;
- #ifdef CKSYSLOG
- #ifdef UNIX
- #ifdef CKXPRINTF /* Our printf macro conflicts with */
- #undef printf /* use of "printf" in syslog.h */
- #endif /* CKXPRINTF */
- #include <syslog.h>
- #ifdef CKXPRINTF
- #define printf ckxprintf
- #endif /* CKXPRINTF */
- #endif /* UNIX */
- #endif /* CKSYSLOG */
- /* Local variables */
- static
- int psetf = 0, /* Flag that prompt has been set */
- cc = 0, /* Character count */
- dpx = 0, /* Duplex (0 = full) */
- inword = 0; /* In the middle of getting a word */
- #ifdef OLDHELP
- static
- int hw = HLPLW, /* Help line width */
- hc = HLPCW, /* Help line column width */
- hh, /* Current help column number */
- hx; /* Current help line position */
- #endif /* OLDHELP */
- char *dfprom = "Command? "; /* Default prompt */
- int cmflgs; /* Command flags */
- int cmfsav; /* A saved version of them */
- static char pushc = NUL;
- static char brkchar = NUL;
- #define CMDEFAULT 1023
- static char cmdefault[CMDEFAULT+1];
- #ifdef DCMDBUF
- char *cmdbuf = NULL; /* Command buffer */
- char *savbuf = NULL; /* Buffer to save copy of command */
- char *atmbuf = NULL; /* Atom buffer - for current field */
- char *atxbuf = NULL; /* For expanding the atom buffer */
- #ifdef OLDHELP
- static char *hlpbuf; /* Help string buffer */
- #endif /* OLDHELP */
- static char *atybuf = NULL; /* For copying atom buffer */
- static char *filbuf = NULL; /* File name buffer */
- static char *cmprom = NULL; /* Program's prompt */
- static char *cmprxx = NULL; /* Program's prompt, unevaluated */
- #ifdef CK_RECALL
- /*
- Command recall is available only if we can make profligate use of malloc().
- */
- #define R_MAX 10 /* How many commands to save */
- int cm_recall = R_MAX; /* Size of command recall buffer */
- int on_recall = 1; /* Recall feature is ON */
- static int no_recall = 0; /* Recall OFF for this cmd only */
- static int force_add = 0; /* Force cmd into recall buffer */
- int in_recall = 0; /* Recall buffers are init'd */
- static int
- current = -1, /* Pointer to current command */
- rlast = -1; /* Index of last command in buffer */
- static char **recall = NULL; /* Array of recall buffer pointers */
- #endif /* CK_RECALL */
- #else
- char cmdbuf[CMDBL+4]; /* Command buffer */
- char savbuf[CMDBL+4]; /* Buffer to save copy of command */
- char atmbuf[ATMBL+4]; /* Atom buffer */
- char atxbuf[CMDBL+4]; /* For expanding the atom buffer */
- #ifdef OLDHELP
- static char hlpbuf[HLPBL+4]; /* Help string buffer */
- #endif /* OLDHELP */
- static char atybuf[ATMBL+4]; /* For copying atom buffer */
- static char filbuf[ATMBL+4]; /* File name buffer */
- static char cmprom[PROMPTL+1]; /* Program's prompt */
- static char cmprxx[PROMPTL+1]; /* Program's prompt, unevaluated */
- #endif /* DCMDBUF */
- /* Command buffer pointers */
- #define PPVLEN 24
- char ppvnambuf[PPVLEN+1] = { NUL, NUL };
- char * cmbptr = NULL; /* Current position (for export) */
- static char *bp, /* Current command buffer position */
- *pp, /* Start of current field */
- *np; /* Start of next field */
- static int ungw, /* For ungetting words */
- atxn; /* Expansion buffer (atxbuf) length */
- #ifdef OS2
- extern int wideresult;
- #endif /* OS2 */
- extern int cmd_cols, cmd_rows, local, quiet;
- #ifdef TNCODE
- #ifdef IAC
- #undef IAC
- #endif /* IAC */
- #define IAC 255
- #endif /* TNCODE */
- #ifdef OLDHELP
- _PROTOTYP( static VOID addhlp, (char *) );
- _PROTOTYP( static VOID clrhlp, (void) );
- _PROTOTYP( static VOID dmphlp, (void) );
- #endif /* OLDHELP */
- _PROTOTYP( static int gtword, (int) );
- _PROTOTYP( static int addbuf, (char *) );
- _PROTOTYP( static int setatm, (char *, int) );
- _PROTOTYP( static VOID cmdnewl, (char) );
- _PROTOTYP( static VOID cmdchardel, (void) );
- _PROTOTYP( static VOID cmdecho, (char, int) );
- _PROTOTYP( static int test, (int, int) );
- #ifdef GEMDOS
- _PROTOTYP( extern char *strchr, (char *, int) );
- #endif /* GEMDOS */
- extern char * dftty;
- /* The following are for use with chained FDB's */
- static int crflag = 0; /* Carriage return was typed */
- static int qmflag = 0; /* Question mark was typed */
- static int esflag = 0; /* Escape was typed */
- /* Directory separator */
- #ifdef GEMDOS
- static char dirsep = '\';
- #else
- #ifdef datageneral
- static char dirsep = ':';
- #else
- #ifdef MAC
- static char dirsep = ':';
- #else
- #ifdef VMS
- static char dirsep = '.';
- #else
- #ifdef STRATUS
- static char dirsep = '>';
- #else
- static char dirsep = '/'; /* UNIX, OS/2, OS-9, Amiga, etc. */
- #endif /* STRATUS */
- #endif /* VMS */
- #endif /* MAC */
- #endif /* datageneral */
- #endif /* GEMDOS */
- /* C K S P R E A D -- Print string double-spaced */
- static char * sprptr = NULL;
- static char *
- ckspread(s) char * s; {
- int n = 0;
- char * p;
- n = strlen(s);
- if (sprptr)
- free(sprptr);
- sprptr = malloc(n + n + 3);
- if (sprptr) {
- p = sprptr;
- while (*s) {
- *p++ = *s++;
- *p++ = SP;
- }
- *p = NUL;
- }
- return(sprptr ? sprptr : "");
- }
- /* T E S T -- Bit test */
- static int
- test(x,m) int x, m; { /* Returns 1 if any bits from m are on in x, else 0 */
- return((x & m) ? 1 : 0);
- }
- /* K W D H E L P -- Given a keyword table, print keywords in columns. */
- /*
- Call with:
- s - keyword table
- n - number of entries
- pat - pattern (left substring) that must match for each keyword
- pre - prefix to add to each keyword
- post - suffix to add to each keyword
- off - offset on first screenful, allowing room for introductory text
- xhlp - 1 to print any CM_INV keywords that are not also abbreviations.
- 2 to print CM_INV keywords if CM_HLP also set
- 4 if it's a switch table (to show ':' if CM_ARG)
- Arranges keywords in columns with width based on longest keyword.
- Does "more?" prompting at end of screen.
- Uses global cmd_rows and cmd_cols for screen size.
- */
- VOID
- kwdhelp(s,n,pat,pre,post,off,xhlp)
- struct keytab s[]; int n, off, xhlp; char *pat, *pre, *post;
- /* kwdhelp */ {
- int width = 0;
- int cc;
- int cols, height, i, j, k, lc, n2 = 0;
- char *b = NULL, *p, *q;
- char *pa, *px;
- char **s2 = NULL;
- char *tmpbuf = NULL;
- cc = strlen(pat);
- if (!s) return; /* Nothing to do */
- if (n < 1) return; /* Ditto */
- if (off < 0) off = 0; /* Offset for first page */
- if (!pre) pre = ""; /* Handle null string pointers */
- if (!post) post = "";
- lc = off; /* Screen-line counter */
- if (xhlp & 4) /* For switches */
- tmpbuf = (char *)malloc(TMPBUFSIZ+1);
- if (s2 = (char **) malloc(n * sizeof(char *))) {
- for (i = 0; i < n; i++) { /* Find longest keyword */
- s2[i] = NULL;
- if (ckstrcmp(s[i].kwd,pat,cc,0))
- continue;
- if (s[i].flgs & CM_INV) {
- #ifdef COMMENT
- /* This code does not show invisible keywords at all except for "help ?" */
- /* and then only help topics (CM_HLP) in the top-level keyword list. */
- if ((xhlp & 2) == 0)
- continue;
- else if ((s[i].flgs & CM_HLP) == 0)
- continue;
- #else
- /* This code shows invisible keywords that are not also abbreviations when */
- /* ? was typed AFTER the beginning of the field so the user can find out */
- /* what they are and (for example) why completion doesn't work at this point */
- if (s[i].flgs & CM_ABR)
- continue;
- else if ((xhlp & 3) == 0)
- continue;
- else if ((xhlp & 2) && ((s[i].flgs & CM_HLP) == 0))
- continue;
- #endif /* COMMENT */
- }
- j = strlen(s[i].kwd);
- if (!(xhlp & 4) || !tmpbuf) { /* Regular keyword table */
- s2[n2++] = s[i].kwd; /* Copy pointers to visible ones */
- } else { /* Switches */
- sprintf(tmpbuf, /* Make a copy that shows ":" if */
- "%s%s", /* the switch takes an argument. */
- s[i].kwd,
- (s[i].flgs & CM_ARG) ? ":" : ""
- );
- makestr(&(s2[n2]),tmpbuf);
- if (s[i].flgs & CM_ARG) j++;
- n2++;
- }
- if (j > width)
- width = j;
- }
- /* Column width */
- n = n2;
- }
- if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
- char * bx;
- bx = b + cmd_cols;
- width += (int)strlen(pre) + (int)strlen(post) + 2;
- cols = cmd_cols / width; /* How many columns? */
- if (cols < 1) cols = 1;
- height = n / cols; /* How long is each column? */
- if (n % cols) height++; /* Add one for remainder, if any */
- for (i = 0; i < height; i++) { /* Loop for each row */
- for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
- b[j] = SP;
- for (j = 0; j < cols; j++) { /* Loop for each column in row */
- k = i + (j * height); /* Index of next keyword */
- if (k < n) { /* In range? */
- pa = pre;
- px = post;
- p = s2[k]; /* Point to verb name */
- q = b + (j * width) + 1; /* Where to copy it to */
- while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
- q--; /* Back up over NUL */
- while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
- q--; /* Back up over NUL */
- while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
- if (j < cols - 1) {
- q--;
- *q = SP; /* Replace the space */
- }
- }
- }
- p = b + cmd_cols - 1; /* Last char in line */
- while (*p-- == SP) ; /* Trim */
- *(p+2) = NUL;
- printf("%sn",b); /* Print the line */
- if (++lc > (cmd_rows - 2)) { /* Screen full? */
- if (!askmore()) /* Do more-prompting... */
- goto xkwdhelp;
- else
- lc = 0;
- }
- }
- /* printf("n"); */ /* Blank line at end of report */
- } else { /* Malloc failure, no columns */
- for (i = 0; i < n; i++) {
- if (s[i].flgs & CM_INV) /* Use original keyword table */
- continue; /* skipping invisible entries */
- printf("%s%s%sn",pre,s[i].kwd,post);
- if (++lc > (cmd_rows - 2)) { /* Screen full? */
- if (!askmore()) /* Do more-prompting... */
- goto xkwdhelp;
- else
- lc = 0;
- }
- }
- }
- xkwdhelp:
- if (xhlp & 4) {
- if (tmpbuf) free(tmpbuf);
- for (i = 0; i < n; i++)
- if (s2[i]) free(s2[i]);
- }
- if (s2) free(s2); /* Free array copy */
- if (b) free(b); /* Free line buffer */
- return;
- }
- /* F I L H E L P -- Given a file list, print names in columns. */
- /*
- Call with:
- n - number of entries
- pre - prefix to add to each filename
- post - suffix to add to each filename
- off - offset on first screenful, allowing room for introductory text
- cmdirflg - 1 if only directory names should be listed, 0 to list all files
- Arranges filenames in columns with width based on longest filename.
- Does "more?" prompting at end of screen.
- Uses global cmd_rows and cmd_cols for screen size.
- */
- int
- filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
- char filbuf[CKMAXPATH + 1]; /* Temp buffer for one filename */
- int width = 0;
- int cols, height, i, j, k, lc, n2 = 0, rc = 0, itsadir = 0;
- char *b = NULL, *p, *q;
- char *pa, *px;
- char **s2 = NULL;
- #ifdef VMS
- char * cdp = zgtdir();
- #endif /* VMS */
- if (n < 1) return(0);
- if (off < 0) off = 0; /* Offset for first page */
- if (!pre) pre = ""; /* Handle null string pointers */
- if (!post) post = "";
- lc = off; /* Screen-line counter */
- if (s2 = (char **) malloc(n * sizeof(char *))) {
- for (i = 0; i < n; i++) { /* Loop through filenames */
- itsadir = 0;
- s2[i] = NULL; /* Initialize each pointer to NULL */
- znext(filbuf); /* Get next filename */
- if (!filbuf[0]) /* Shouldn't happen */
- break;
- #ifdef COMMENT
- itsadir = isdir(filbuf); /* Is it a directory? */
- if (cmdirflg && !itsadir) /* No, listing directories only? */
- continue; /* So skip this one. */
- #endif /* COMMENT */
- #ifdef VMS
- ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH);
- #endif /* VMS */
- j = strlen(filbuf);
- #ifndef VMS
- if (itsadir && j < CKMAXPATH - 1 && j > 0) {
- if (filbuf[j-1] != dirsep) {
- filbuf[j++] = dirsep;
- filbuf[j] = NUL;
- }
- }
- #endif /* VMS */
- if (!(s2[n2] = malloc(j+1))) {
- printf("?Memory allocation failuren");
- rc = -9;
- goto xfilhelp;
- }
- if (j <= CKMAXPATH) {
- strcpy(s2[n2],filbuf);
- n2++;
- } else {
- printf("?Name too long - %sn", filbuf);
- rc = -9;
- goto xfilhelp;
- }
- if (j > width) /* Get width of widest one */
- width = j;
- }
- n = n2; /* How many we actually got */
- }
- sh_sort(s2,NULL,n,0,0,filecase); /* Alphabetize the list */
- rc = 1;
- if (s2 && (b = (char *) malloc(cmd_cols + 1))) { /* Make a line buffer */
- char * bx;
- bx = b + cmd_cols;
- width += (int)strlen(pre) + (int)strlen(post) + 2;
- cols = cmd_cols / width; /* How many columns? */
- if (cols < 1) cols = 1;
- height = n / cols; /* How long is each column? */
- if (n % cols) height++; /* Add one for remainder, if any */
- for (i = 0; i < height; i++) { /* Loop for each row */
- for (j = 0; j < cmd_cols; j++) /* First fill row with blanks */
- b[j] = SP;
- for (j = 0; j < cols; j++) { /* Loop for each column in row */
- k = i + (j * height); /* Index of next filename */
- if (k < n) { /* In range? */
- pa = pre;
- px = post;
- p = s2[k]; /* Point to filename */
- q = b + (j * width) + 1; /* and destination */
- while ((q < bx) && (*q++ = *pa++)) ; /* Copy prefix */
- q--; /* Back up over NUL */
- while ((q < bx) && (*q++ = *p++)) ; /* Copy filename */
- q--; /* Back up over NUL */
- while ((q < bx) && (*q++ = *px++)) ; /* Copy suffix */
- if (j < cols - 1) {
- q--;
- *q = SP; /* Replace the space */
- }
- }
- }
- p = b + cmd_cols - 1; /* Last char in line */
- while (*p-- == SP) ; /* Trim */
- *(p+2) = NUL;
- printf("%sn",b); /* Print the line */
- if (++lc > (cmd_rows - 2)) { /* Screen full? */
- if (!askmore()) { /* Do more-prompting... */
- rc = 0;
- goto xfilhelp;
- } else
- lc = 0;
- }
- }
- printf("n"); /* Blank line at end of report */
- goto xfilhelp;
- } else { /* Malloc failure, no columns */
- for (i = 0; i < n; i++) {
- znext(filbuf);
- if (!filbuf[0]) break;
- printf("%s%s%sn",pre,filbuf,post);
- if (++lc > (cmd_rows - 2)) { /* Screen full? */
- if (!askmore()) { /* Do more-prompting... */
- rc = 0;
- goto xfilhelp;
- } else lc = 0;
- }
- }
- xfilhelp:
- if (b) free(b);
- for (i = 0; i < n2; i++)
- if (s2[i]) free(s2[i]);
- if (s2) free(s2);
- return(rc);
- }
- }
- /* C M S E T U P -- Set up command buffers */
- #ifdef DCMDBUF
- int
- cmsetup() {
- if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
- if (!(savbuf = malloc(CMDBL + 4))) return(-1);
- savbuf[0] = ' ';
- #ifdef OLDHELP
- if (!(hlpbuf = malloc(HLPBL + 4))) return(-1);
- #endif /* OLDHELP */
- if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
- if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
- if (!(atybuf = malloc(ATMBL + 4))) return(-1);
- if (!(filbuf = malloc(ATMBL + 4))) return(-1);
- if (!(cmprom = malloc(PROMPTL + 4))) return(-1);
- if (!(cmprxx = malloc(PROMPTL + 4))) return(-1);
- #ifdef CK_RECALL
- cmrini(cm_recall);
- #endif /* CK_RECALL */
- return(0);
- }
- #endif /* DCMDBUF */
- /* C M S E T P -- Set the program prompt. */
- VOID
- cmsetp(s) char *s; {
- if (!s) s = "";
- ckstrncpy(cmprxx,s,PROMPTL);
- psetf = 1; /* Flag that prompt has been set. */
- }
- /* C M S A V P -- Save a copy of the current prompt. */
- VOID
- #ifdef CK_ANSIC
- cmsavp(char s[], int n)
- #else
- cmsavp(s,n) char s[]; int n;
- #endif /* CK_ANSIC */
- /* cmsavp */ {
- if (psetf) /* But not if no prompt is set. */
- ckstrncpy(s,cmprxx,n);
- }
- int
- cmgbrk() {
- return(brkchar);
- }
- int
- cmgkwflgs() {
- return(cmkwflgs);
- }
- /* P R O M P T -- Issue the program prompt. */
- VOID
- prompt(f) xx_strp f; {
- char *sx, *sy; int n;
- #ifdef CK_SSL
- extern int ssl_active_flag, tls_active_flag;
- #endif /* CK_SSL */
- #ifdef OS2
- extern int display_demo;
- /* If there is a demo screen to be displayed, display it */
- if (display_demo && cmdsrc() == 0) {
- demoscrn();
- display_demo = 0;
- }
- #endif /* OS2 */
- if (psetf == 0) /* If no prompt set, set default. */
- cmsetp(dfprom);
- sx = cmprxx; /* Unevaluated copy */
- if (f) { /* If conversion function given */
- sy = cmprom; /* Evaluate it */
- debug(F101,"prompt sx","",sx);
- debug(F101,"prompt sy","",sy);
- n = PROMPTL;
- if ((*f)(sx,&sy,&n) < 0) /* If evaluation failed */
- sx = cmprxx; /* revert to unevaluated copy */
- else if (!*cmprom) /* ditto if it came up empty */
- sx = cmprxx;
- else
- sx = cmprom;
- } else
- ckstrncpy(cmprom,sx,PROMPTL);
- cmprom[PROMPTL-1] = NUL;
- if (!*sx) /* Don't print if empty */
- return;
- #ifdef OSK
- fputs(sx, stdout);
- #else
- #ifdef MAC
- printf("%s", sx);
- #else
- printf("r%s",sx); /* Print the prompt. */
- #ifdef CK_SSL
- if (!(ssl_active_flag || tls_active_flag))
- #endif /* CK_SSL */
- fflush(stdout); /* Now! */
- #endif /* MAC */
- #endif /* OSK */
- }
- #ifndef NOSPL
- VOID
- pushcmd(s) char * s; { /* For use with IF command. */
- if (!s) s = np;
- ckstrncpy(savbuf,s,CMDBL); /* Save the dependent clause, */
- cmres(); /* and clear the command buffer. */
- debug(F110, "pushcmd savbuf", savbuf, 0);
- }
- VOID
- pushqcmd(s) char * s; { /* For use with ELSE command. */
- char c, * p = savbuf; /* Dest */
- if (!s) s = np; /* Source */
- while (*s) { /* Get first nonwhitespace char */
- if (*s != SP)
- break;
- else
- s++;
- }
- if (*s != '{') { /* If it's not "{" */
- pushcmd(s); /* do regular pushcmd */
- return;
- }
- while (c = *s++) { /* Otherwise insert quotes */
- if (c == CMDQ)
- *p++ = CMDQ;
- *p++ = c;
- }
- cmres(); /* and clear the command buffer. */
- debug(F110, "pushqcmd savbuf", savbuf, 0);
- }
- #endif /* NOSPL */
- #ifdef COMMENT
- /* no longer used... */
- VOID
- popcmd() {
- ckstrncpy(cmdbuf,savbuf,CMDBL); /* Put back the saved material */
- *savbuf = ' '; /* and clear the save buffer */
- cmres();
- }
- #endif /* COMMENT */
- /* C M R E S -- Reset pointers to beginning of command buffer. */
- VOID
- cmres() {
- inword = 0; /* We're not in a word */
- cc = 0; /* Character count is zero */
- /* Initialize pointers */
- pp = cmdbuf; /* Beginning of current field */
- bp = cmdbuf; /* Current position within buffer */
- np = cmdbuf; /* Where to start next field */
- cmfldflgs = 0;
- cmflgs = -5; /* Parse not yet started. */
- ungw = 0; /* Don't need to unget a word. */
- }
- /* C M I N I -- Clear the command and atom buffers, reset pointers. */
- /*
- The argument specifies who is to echo the user's typein --
- 1 means the cmd package echoes
- 0 somebody else (system, front end, terminal) echoes
- */
- VOID
- cmini(d) int d; {
- #ifdef DCMDBUF
- if (!atmbuf)
- if (cmsetup()<0)
- fatal("fatal error: unable to allocate command buffers");
- #endif /* DCMDBUF */
- #ifdef USE_MEMCPY
- memset(cmdbuf,0,CMDBL);
- memset(atmbuf,0,ATMBL);
- #else
- for (bp = cmdbuf; bp < cmdbuf+CMDBL; bp++) *bp = NUL;
- for (bp = atmbuf; bp < atmbuf+ATMBL; bp++) *bp = NUL;
- #endif /* USE_MEMCPY */
- *atmbuf = *savbuf = *atxbuf = *atybuf = *filbuf = NUL;
- #ifdef OLDHELP
- *hlpbuf = NUL;
- #endif /* OLDHELP */
- blocklvl = 0; /* Block level is 0 */
- linebegin = 1; /* And we're at the beginning of a line */
- dpx = d; /* Make a global copy of the echo flag */
- debug(F101,"cmini dpx","",dpx);
- crflag = 0;
- qmflag = 0;
- esflag = 0;
- #ifdef CK_RECALL
- no_recall = 0;
- #endif /* CK_RECALL */
- cmres();
- }
- #ifndef NOSPL
- /* The following bits are to allow the command package to call itself */
- /* in the middle of a parse. To do this, begin by calling cmpush, and */
- /* end by calling cmpop. */
- #ifdef DCMDBUF
- struct cmp {
- int i[5]; /* stack for integers */
- char *c[3]; /* stack for pointers */
- char *b[8]; /* stack for buffer contents */
- };
- struct cmp *cmp = 0;
- #else
- int cmp_i[CMDDEP+1][5]; /* Stack for integers */
- char *cmp_c[CMDDEP+1][5]; /* for misc pointers */
- char *cmp_b[CMDDEP+1][7]; /* for buffer contents pointers */
- #endif /* DCMDBUF */
- int cmddep = -1; /* Current stack depth */
- int
- cmpush() { /* Save the command environment */
- char *cp; /* Character pointer */
- if (cmddep >= CMDDEP) /* Enter a new command depth */
- return(-1);
- cmddep++;
- debug(F101,"&cmpush","",cmddep);
- #ifdef DCMDBUF
- /* allocate memory for cmp if not already done */
- if (!cmp && !(cmp = (struct cmp *) malloc(sizeof(struct cmp)*(CMDDEP+1))))
- fatal("cmpush: no memory for cmp");
- cmp[cmddep].i[0] = cmflgs; /* First do the global ints */
- cmp[cmddep].i[1] = cmfsav;
- cmp[cmddep].i[2] = atxn;
- cmp[cmddep].i[3] = ungw;
- cmp[cmddep].c[0] = bp; /* Then the global pointers */
- cmp[cmddep].c[1] = pp;
- cmp[cmddep].c[2] = np;
- #else
- cmp_i[cmddep][0] = cmflgs; /* First do the global ints */
- cmp_i[cmddep][1] = cmfsav;
- cmp_i[cmddep][2] = atxn;
- cmp_i[cmddep][3] = ungw;
- cmp_c[cmddep][0] = bp; /* Then the global pointers */
- cmp_c[cmddep][1] = pp;
- cmp_c[cmddep][2] = np;
- #endif /* DCMDBUF */
- /* Now the buffers themselves. A lot of repititious code... */
- #ifdef DCMDBUF
- cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
- if (cp) strcpy(cp,cmdbuf);
- cmp[cmddep].b[0] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
- if (cp) strcpy(cp,savbuf);
- cmp[cmddep].b[1] = cp;
- if (cp == NULL) return(-1);
- #ifdef OLDHELP
- cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */
- if (cp) strcpy(cp,hlpbuf);
- cmp[cmddep].b[2] = cp;
- if (cp == NULL) return(-1);
- #else
- cmp[cmddep].b[2] = NULL;
- #endif /* OLDHELP */
- cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
- if (cp) strcpy(cp,atmbuf);
- cmp[cmddep].b[3] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
- if (cp) strcpy(cp,atxbuf);
- cmp[cmddep].b[4] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
- if (cp) strcpy(cp,atybuf);
- cmp[cmddep].b[5] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
- if (cp) strcpy(cp,filbuf);
- cmp[cmddep].b[6] = cp;
- if (cp == NULL) return(-1);
- #else
- cp = malloc((int)strlen(cmdbuf)+1); /* 0: Command buffer */
- if (cp) strcpy(cp,cmdbuf);
- cmp_b[cmddep][0] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(savbuf)+1); /* 1: Save buffer */
- if (cp) strcpy(cp,savbuf);
- cmp_b[cmddep][1] = cp;
- if (cp == NULL) return(-1);
- #ifdef OLDHELP
- cp = malloc((int)strlen(hlpbuf)+1); /* 2: Help string buffer */
- if (cp) strcpy(cp,hlpbuf);
- cmp_b[cmddep][2] = cp;
- if (cp == NULL) return(-1);
- #else
- cmp_b[cmddep][2] = NULL;
- #endif /* OLDHELP */
- cp = malloc((int)strlen(atmbuf)+1); /* 3: Atom buffer */
- if (cp) strcpy(cp,atmbuf);
- cmp_b[cmddep][3] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(atxbuf)+1); /* 4: Expansion buffer */
- if (cp) strcpy(cp,atxbuf);
- cmp_b[cmddep][4] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(atybuf)+1); /* 5: Atom buffer copy */
- if (cp) strcpy(cp,atybuf);
- cmp_b[cmddep][5] = cp;
- if (cp == NULL) return(-1);
- cp = malloc((int)strlen(filbuf)+1); /* 6: File name buffer */
- if (cp) strcpy(cp,filbuf);
- cmp_b[cmddep][6] = cp;
- if (cp == NULL) return(-1);
- #endif /* DCMDBUF */
- cmini(dpx); /* Initize the command parser */
- return(0);
- }
- int
- cmpop() { /* Restore the command environment */
- debug(F101,"&cmpop","",cmddep);
- if (cmddep < 0) return(-1); /* Don't pop too much! */
- #ifdef DCMDBUF
- cmflgs = cmp[cmddep].i[0]; /* First do the global ints */
- cmfsav = cmp[cmddep].i[1];
- atxn = cmp[cmddep].i[2];
- ungw = cmp[cmddep].i[3];
- bp = cmp[cmddep].c[0]; /* Then the global pointers */
- pp = cmp[cmddep].c[1];
- np = cmp[cmddep].c[2];
- #else
- cmflgs = cmp_i[cmddep][0]; /* First do the global ints */
- cmfsav = cmp_i[cmddep][1];
- atxn = cmp_i[cmddep][2];
- ungw = cmp_i[cmddep][3];
- bp = cmp_c[cmddep][0]; /* Then the global pointers */
- pp = cmp_c[cmddep][1];
- np = cmp_c[cmddep][2];
- #endif /* DCMDBUF */
- /* Now the buffers themselves. */
- /* Note: strncpy(), not ckstrncpy() -- Here we WANT the NUL padding... */
- #ifdef DCMDBUF
- if (cmp[cmddep].b[0]) {
- strncpy(cmdbuf,cmp[cmddep].b[0],CMDBL); /* 0: Command buffer */
- free(cmp[cmddep].b[0]);
- cmp[cmddep].b[0] = NULL;
- }
- if (cmp[cmddep].b[1]) {
- strncpy(savbuf,cmp[cmddep].b[1],CMDBL); /* 1: Save buffer */
- free(cmp[cmddep].b[1]);
- cmp[cmddep].b[1] = NULL;
- }
- #ifdef OLDHELP
- if (cmp[cmddep].b[2]) {
- strncpy(hlpbuf,cmp[cmddep].b[2],HLPBL); /* 2: Help buffer */
- free(cmp[cmddep].b[2]);
- cmp[cmddep].b[2] = NULL;
- }
- #endif /* OLDHELP */
- if (cmp[cmddep].b[3]) {
- strncpy(atmbuf,cmp[cmddep].b[3],ATMBL); /* 3: Atomic buffer! */
- free(cmp[cmddep].b[3]);
- cmp[cmddep].b[3] = NULL;
- }
- if (cmp[cmddep].b[4]) {
- strncpy(atxbuf,cmp[cmddep].b[4],ATMBL); /* 4: eXpansion buffer */
- free(cmp[cmddep].b[4]);
- cmp[cmddep].b[4] = NULL;
- }
- if (cmp[cmddep].b[5]) {
- strncpy(atybuf,cmp[cmddep].b[5],ATMBL); /* 5: Atom buffer copY */
- free(cmp[cmddep].b[5]);
- cmp[cmddep].b[5] = NULL;
- }
- if (cmp[cmddep].b[6]) {
- strncpy(filbuf,cmp[cmddep].b[6],ATMBL); /* 6: Filename buffer */
- free(cmp[cmddep].b[6]);
- cmp[cmddep].b[6] = NULL;
- }
- #else
- if (cmp_b[cmddep][0]) {
- strncpy(cmdbuf,cmp_b[cmddep][0],CMDBL); /* 0: Command buffer */
- free(cmp_b[cmddep][0]);
- cmp_b[cmddep][0] = NULL;
- }
- if (cmp_b[cmddep][1]) {
- strncpy(savbuf,cmp_b[cmddep][1],CMDBL); /* 1: Save buffer */
- free(cmp_b[cmddep][1]);
- cmp_b[cmddep][1] = NULL;
- }
- #ifdef OLDHELP
- if (cmp_b[cmddep][2]) {
- strncpy(hlpbuf,cmp_b[cmddep][2],HLPBL); /* 2: Help buffer */
- free(cmp_b[cmddep][2]);
- cmp_b[cmddep][2] = NULL;
- }
- #endif /* OLDHELP */
- if (cmp_b[cmddep][3]) {
- strncpy(atmbuf,cmp_b[cmddep][3],ATMBL); /* 3: Atomic buffer! */
- free(cmp_b[cmddep][3]);
- cmp_b[cmddep][3] = NULL;
- }
- if (cmp_b[cmddep][4]) {
- strncpy(atxbuf,cmp_b[cmddep][4],ATMBL); /* 4: eXpansion buffer */
- free(cmp_b[cmddep][4]);
- cmp_b[cmddep][4] = NULL;
- }
- if (cmp_b[cmddep][5]) {
- strncpy(atybuf,cmp_b[cmddep][5],ATMBL); /* 5: Atom buffer copY */
- free(cmp_b[cmddep][5]);
- cmp_b[cmddep][5] = NULL;
- }
- if (cmp_b[cmddep][6]) {
- strncpy(filbuf,cmp_b[cmddep][6],ATMBL); /* 6: Filename buffer */
- free(cmp_b[cmddep][6]);
- cmp_b[cmddep][6] = NULL;
- }
- #endif /* DCMDBUF */
- cmddep--; /* Rise, rise */
- debug(F101,"&cmpop","",cmddep);
- return(cmddep);
- }
- #endif /* NOSPL */
- #ifdef COMMENT
- VOID
- stripq(s) char *s; { /* Function to strip '' quotes */
- char *t;
- while (*s) {
- if (*s == CMDQ) {
- for (t = s; *t != ' '; t++) *t = *(t+1);
- }
- s++;
- }
- }
- #endif /* COMMENT */
- /* Convert tabs to spaces, one for one */
- VOID
- untab(s) char *s; {
- while (*s) {
- if (*s == HT) *s = SP;
- s++;
- }
- }
- /* C M N U M -- Parse a number in the indicated radix */
- /*
- The only radix allowed in unquoted numbers is 10.
- Parses unquoted numeric strings in base 10.
- Parses backslash-quoted numbers in the radix indicated by the quote:
- nnn = dnnn = decimal, onnn = octal, xnn = Hexadecimal.
- If these fail, then if a preprocessing function is supplied, that is applied
- and then a second attempt is made to parse an unquoted decimal string.
- And if that fails, the preprocessed string is passed to an arithmetic
- expression evaluator.
- Returns:
- -3 if no input present when required,
- -2 if user typed an illegal number,
- -1 if reparse needed,
- 0 otherwise, with argument n set to the number that was parsed
- */
- int
- cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
- int x; char *s, *zp, *zq;
- char lbrace, rbrace;
- if (!xhlp) xhlp = "";
- if (!xdef) xdef = "";
- if (cmfldflgs & 1) {
- lbrace = '(';
- rbrace = ')';
- } else {
- lbrace = '{';
- rbrace = '}';
- }
- if (radix != 10) { /* Just do base 10 */
- printf("cmnum: illegal radix - %dn",radix);
- return(-1);
- } /* Easy to add others but there has never been a need for it. */
- x = cmfld(xhlp,xdef,&s,(xx_strp)0);
- debug(F101,"cmnum: cmfld","",x);
- if (x < 0) return(x); /* Parse a field */
- zp = atmbuf;
- /*
- Edit 192 - Allow any number field to be braced. This lets us include
- spaces in expressions, but perhaps more important lets us have user-defined
- functions in numeric fields.
- */
- if (*zp == lbrace) { /* Braced field, strip braces */
- x = (int) strlen(atmbuf);
- if (x > 0) { /* The "if" is to shut up optimizers */
- if (*(atmbuf+x-1) == rbrace) {
- *(atmbuf+x-1) = NUL; /* that complain about a possible */
- zp++; /* reference to atbmbuf[-1] even */
- }
- } /* though we know that x > 0. */
- }
- if (chknum(zp)) { /* Check for decimal number */
- *n = atoi(zp); /* Got one, we're done. */
- debug(F101,"cmnum 1st chknum ok","",*n);
- return(0);
- } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
- #ifndef OS2
- *n = x;
- #else
- *n = wideresult;
- #endif /* OS2 */
- debug(F101,"cmnum xxesc ok","",*n);
- return(*zp ? -2 : 0);
- } else if (f) { /* If conversion function given */
- zq = atxbuf; /* Try that */
- atxn = CMDBL;
- if ((*f)(zp,&zq,&atxn) < 0) /* Convert */
- return(-2);
- zp = atxbuf;
- }
- debug(F110,"cmnum zp 1",zp,0);
- if (!*zp) zp = xdef; /* Result empty, substitute default */
- debug(F110,"cmnum zp 2",zp,0);
- if (chknum(zp)) { /* Check again for decimal number */
- *n = atoi(zp); /* Got one, we're done. */
- debug(F101,"cmnum 2nd chknum ok","",*n);
- return(0);
- #ifndef NOSPL
- } else if ((x = xxesc(&zp)) > -1) { /* Check for backslash escape */
- #ifndef OS2
- *n = x;
- #else
- *n = wideresult;
- #endif /* OS2 */
- debug(F101,"cmnum xxesc 2 ok","",*n);
- return(*zp ? -2 : 0);
- } else if (f) { /* Not numeric, maybe an expression */
- char * p;
- p = evala(zp);
- if (chknum(p)) {
- *n = atoi(p);
- debug(F101,"cmnum exp eval ok","",*n);
- return(0);
- } else return(-2);
- #endif /* NOSPL */
- } else { /* Not numeric */
- return(-2);
- }
- }
- #ifdef CKCHANNELIO
- extern int z_error;
- #endif /* CKCHANNELIO */
- /* C M O F I -- Parse the name of an output file */
- /*
- Depends on the external function zchko(); if zchko() not available, use
- cmfld() to parse output file names.
- Returns:
- -9 like -2, except message already printed,
- -3 if no input present when required,
- -2 if permission would be denied to create the file,
- -1 if reparse needed,
- 0 or 1 if file can be created, with xp pointing to name.
- 2 if given the name of an existing directory.
- */
- int
- cmofi(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
- int x; char *s, *zq;
- #ifdef DOCHKVAR
- int tries;
- #endif /* DOCHKVAR */
- #ifdef DTILDE
- char *dirp;
- #endif /* DTILDE */
- cmfldflgs = 0;
- if (!xhlp) xhlp = "";
- if (!xdef) xdef = "";
- if (*xhlp == NUL) xhlp = "Output file";
- *xp = "";
- x = cmfld(xhlp,xdef,&s,(xx_strp)0);
- debug(F111,"cmofi cmfld returns",s,x);
- if (x < 0)
- return(x);
- if (*s == '{') { /* Strip enclosing braces */
- int n;
- n = strlen(s);
- if (s[n-1] == '}') {
- s[n-1] = NUL;
- s++;
- }
- }
- debug(F110,"cmofi 1.5",s,0);
- #ifdef DOCHKVAR
- tries = 0;
- {
- char *p = s;
- /*
- This is really ugly. If we skip conversion the first time through,
- then variable names like %a will be used as filenames (e.g. creating
- a file called %A in the root directory). If we DON'T skip conversion
- the first time through, then single backslashes used as directory
- separators in filenames will be misinterpreted as variable lead-ins.
- So we prescan to see if it has any variable references. But this
- module is not supposed to know anything about variables, functions,
- etc, so this code does not really belong here, but rather it should
- be at the same level as zzstring().
- */
- /*
- Hmmm, this looks a lot like chkvar() except it that includes nnn number
- escapes. But why? This makes commands like "mkdir c:123" impossible.
- And in fact, "mkdir c:123" creates a directory called "c:{". What's worse,
- rmdir(), which *does* call chkvar(), won't let us remove it. So let's at
- least try making cmofi() symmetrical with cmifi()...
- */
- #ifdef COMMENT
- char * q;
- while ( (tries == 0) && (p = strchr(p,CMDQ)) ) {
- q = *(p+1); /* Char after backslash */
- if (!q) /* None, quit */
- break;
- if (isupper(q)) /* If letter, convert to lowercase */
- q = tolower(q);
- if (isdigit(q)) { /* If it's a digit, */
- tries = 1; /* assume it's a backslash code */
- break;
- }
- switch (q) {
- case CMDQ: /* Double backslash */
- tries = 1; /* so call the conversion function */
- break;
- case '%': /* Variable or array reference */
- case '&': /* must be followed by letter */
- if (isalpha(*(p+2)) || (*(p+2) >= '0' && *(p+2) <= '9'))
- tries = 1;
- break;
- case 'm': case 'v': case '$': /* m(), v(), $() */
- if (*(p+2) == '(')
- if (strchr(p+2,')'))
- tries = 1;
- break;
- case 'f': /* Fname() */
- if (strchr(p+2,'('))
- if (strchr(p+2,')'))
- tries = 1;
- break;
- case '{': /* {...} */
- if (strchr(p+2,'}'))
- tries = 1;
- break;
- case 'd': case 'o': /* Decimal or Octal number */
- if (isdigit(*(p+2)))
- tries = 1;
- break;
- case 'x': /* Hex number */
- if (isdigit(*(p+2)) ||
- ((*(p+2) >= 'a' && *(p+2) <= 'f') ||
- ((*(p+2) >= 'A' && *(p+2) <= 'F'))))
- tries = 1;
- default:
- break;
- }
- p++;
- }
- #else
- #ifndef NOSPL
- if (f) { /* If a conversion function is given */
- char *s = p; /* See if there are any variables in */
- while (*s) { /* the string and if so, expand them */
- if (chkvar(s)) {
- tries = 1;
- break;
- }
- s++;
- }
- }
- #endif /* NOSPL */
- #endif /* COMMENT */
- }
- #ifdef OS2
- o_again:
- #endif /* OS2 */
- if (tries == 1)
- #endif /* DOCHKVAR */
- if (f) { /* If a conversion function is given */
- zq = atxbuf; /* do the conversion. */
- atxn = CMDBL;
- if ((x = (*f)(s,&zq,&atxn)) < 0)
- return(-2);
- s = atxbuf;
- if (!*s) /* Result empty, substitute default */
- s = xdef;
- }
- debug(F111,"cmofi 2",s,x);
- #ifdef DTILDE
- dirp = tilde_expand(s); /* Expand tilde, if any, */
- if (*dirp != ' ') { /* right in the atom buffer. */
- if (setatm(dirp,1) < 0) {
- printf("?Name too longn");
- return(-9);
- }
- }
- s = atmbuf;
- debug(F110,"cmofi 3",s,0);
- #endif /* DTILDE */
- if (iswild(s)) {
- printf("?Wildcards not allowed - %sn",s);
- return(-2);
- }
- debug(F110,"cmofi 4",s,0);
- #ifdef CK_TMPDIR
- /* isdir() function required for this! */
- if (isdir(s)) {
- debug(F110,"cmofi 5: is directory",s,0);
- *xp = s;
- return(2);
- }
- #endif /* CK_TMPDIR */
- if (strcmp(s,CTTNAM) && (zchko(s) < 0)) { /* OK to write to console */
- #ifdef COMMENT
- #ifdef OS2
- /*
- We don't try again because we already prescanned the string to see if
- if it contained anything that could be used by zzstring().
- */
- if (tries++ < 1)
- goto o_again;
- #endif /* OS2 */
- #endif /* COMMENT */
- /*
- Note: there are certain circumstances where zchko() can give a false
- positive, so don't rely on it to catch every conceivable situation in
- which the given output file can't be created. In other words, we print
- a message and fail here if we KNOW the file can't be created. If we
- succeed but the file can't be opened, the code that tries to open the file
- has to print a message.
- */
- debug(F110,"cmofi 6: failure",s,0);
- printf("?Write permission denied - %sn",s);
- #ifdef CKCHANNELIO
- z_error = FX_ACC;
- #endif /* CKCHANNELIO */
- return(-9);
- } else {
- debug(F110,"cmofi 7: ok",s,0);
- *xp = s;
- return(x);
- }
- }
- /* C M I F I -- Parse the name of an existing file */
- /*
- This function depends on the external functions:
- zchki() - Check if input file exists and is readable.
- zxpand() - Expand a wild file specification into a list.
- znext() - Return next file name from list.
- If these functions aren't available, then use cmfld() to parse filenames.
- */
- /*
- Returns
- -4 EOF
- -3 if no input present when required,
- -2 if file does not exist or is not readable,
- -1 if reparse needed,
- 0 or 1 otherwise, with:
- xp pointing to name,
- wild = 1 if name contains '*' or '?', 0 otherwise.
- */
- /*
- C M I O F I -- Parse an input file OR the name of a nonexistent file.
- Use this when an existing file is wanted (so we get help, completion, etc),
- but if a file of the given name does not exist, the name of a new file is
- accepted. For example, with the EDIT command (edit an existing file, or
- create a new file). Returns -9 if file does not exist. It is up to the
- caller to check creatability.
- */
- static int nomsg = 0;
- int
- cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
- int msgsave, x;
- msgsave = nomsg;
- nomsg = 1;
- x = cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0);
- nomsg = msgsave;
- return(x);
- }
- int
- cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
- return(cmifi2(xhlp,xdef,xp,wild,0,NULL,f,0));
- }
- /*
- cmifip() is called when we want to supply a path or path list to search
- in case the filename that the user gives is (a) not absolute, and (b) can't
- be found as given. The path string can be the name of a single directory,
- or a list of directories separated by the PATHSEP character, defined in
- ckucmd.h. Look in ckuusr.c and ckuus3.c for examples of usage.
- */
- int
- cmifip(xhlp,xdef,xp,wild,d,path,f)
- char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; {
- return(cmifi2(xhlp,xdef,xp,wild,0,path,f,0));
- }
- /* C M D I R -- Parse a directory name */
- /*
- This function depends on the external functions:
- isdir(s) - Check if string s is the name of a directory
- zchki(s) - Check if input file s exists and what type it is.
- If these functions aren't available, then use cmfld() to parse dir names.
- Returns
- -9 For all sorts of reasons, after printing appropriate error message.
- -4 EOF
- -3 if no input present when required,
- -2 if out of space or other internal error,
- -1 if reparse needed,
- 0 or 1, with xp pointing to name, if directory specified,
- */
- int
- cmdir(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
- int wild;
- return(cmifi2(xhlp,xdef,xp,&wild,0,NULL,f,1));
- }
- /* Like CMDIR but includes PATH search */
- int
- cmdirp(xhlp,xdef,xp,path,f) char *xhlp, *xdef, **xp; char * path; xx_strp f; {
- int wild;
- return(cmifi2(xhlp,xdef,xp,&wild,0,path,f,1));
- }
- /*
- cmifi2() is the base filename parser called by cmifi, cmifip, cmdir, etc.
- Use it directly when you also want to parse a directory or device
- name as an input file, as in the DIRECTORY command. Call with:
- xhlp -- help message on ?
- xdef -- default response
- xp -- pointer to result (in our space, must be copied from here)
- wild -- flag set upon return to indicate if filespec was wild
- d -- 0 to parse files, 1 to parse files or directories
- path -- search path for files
- f -- pointer to string processing function (e.g. to evaluate variables)
- dirflg -- 1 to parse *only* directories, 0 otherwise
- */
- int
- cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
- char *xhlp,*xdef,**xp; int *wild, d; char * path; xx_strp f; int dirflg; {
- extern int recursive, diractive;
- int i, x, itsadir, xc, expanded = 0, nfiles = 0;
- long y;
- char *sp = NULL, *zq, *np = NULL;
- char *sv = NULL, *p = NULL;
- #ifdef DTILDE
- char *dirp;
- #endif /* DTILDE */
- #ifndef NOPARTIAL
- #ifndef OS2
- #ifdef OSK
- /* This large array is dynamic for OS-9 -- should do for others too... */
- extern char **mtchs;
- #else
- #ifdef UNIX
- /* OK, for UNIX too */
- extern char **mtchs;
- #else
- #ifdef VMS
- extern char **mtchs;
- #else
- extern char *mtchs[];
- #endif /* VMS */
- #endif /* UNIX */
- #endif /* OSK */
- #endif /* OS2 */
- #endif /* NOPARTIAL */
- if (!xhlp) xhlp = "";
- if (!xdef) xdef = "";
- cmfldflgs = 0;
- if (path)
- if (!*path)
- path = NULL;
- if (path) { /* Make a copy we can poke */
- x = strlen(path);
- np = (char *) malloc(x + 1);
- if (np) {
- strcpy(np, path);
- path = sp = np;
- }
- }
- debug(F110,"cmifi2 path",path,0);
- ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
- xdef = cmdefault;
- inword = 0; /* Initialize counts & pointers */
- cc = 0;
- xc = 0;
- *xp = ""; /* Pointer to result string */
- if ((x = cmflgs) != 1) { /* Already confirmed? */
- #ifdef BS_DIRSEP
- dirnamflg = 1;
- x = gtword(0); /* No, get a word */
- dirnamflg = 0;
- #else
- x = gtword(0); /* No, get a word */
- #endif /* BS_DIRSEP */
- } else { /* If so, use default, if any. */
- if (setatm(xdef,1) < 0) {
- printf("?Default name too longn");
- if (np) free(np);
- return(-9);
- }
- }
- i_path:
- *xp = atmbuf; /* Point to result. */
- while (1) {
- xc += cc; /* Count this character. */
- debug(F111,"cmifi gtword",atmbuf,xc);
- debug(F101,"cmifi switch x","",x);
- switch (x) { /* x = gtword() return code */
- case -10:
- if (gtimer() > timelimit) {
- #ifdef IKSD
- extern int inserver;
- if (inserver) {
- printf("rnIKSD IDLE TIMEOUT: %d secrn", timelimit);
- doexit(GOOD_EXIT,0);
- }
- #endif /* IKSD */
- if (!quiet) printf("?Timed outn");
- return(-10);
- } else {
- x = gtword(0);
- continue;
- }
- case -9:
- printf("Command or field too longn");
- case -4: /* EOF */
- case -2: /* Out of space. */
- case -1: /* Reparse needed */
- if (np) free(np);
- return(x);
- case 0: /* SP or NL */
- case 1:
- if (xc == 0) /* If no input... */
- *xp = xdef; /* substitute the default */
- if (**xp == NUL) { /* If field still empty return -3. */
- if (np) free(np);
- return(-3);
- }
- *xp = brstrip(*xp); /* Strip braces */
- debug(F110,"cmifi brstrip",*xp,0);
- #ifndef NOSPL
- if (f) { /* If a conversion function is given */
- #ifdef DOCHKVAR
- char *s = *xp; /* See if there are any variables in */
- int x;
- while (*s) { /* the string and if so, expand them */
- if (chkvar(s)) {
- #endif /* DOCHKVAR */
- zq = atxbuf;
- atxn = CMDBL;
- if ((*f)(*xp,&zq,&atxn) < 0) {
- if (np) free(np);
- return(-2);
- }
- *xp = atxbuf;
- if (!atxbuf[0])
- *xp = xdef;
- #ifdef DOCHKVAR
- break;
- }
- s++;
- }
- #endif /* DOCHKVAR */
- }
- #endif /* NOSPL */
- #ifdef DTILDE
- dirp = tilde_expand(*xp); /* Expand tilde, if any, */
- if (*dirp != ' ') { /* in the atom buffer. */
- if (setatm(dirp,1) < 0) {
- printf("Expanded name too longn");
- if (np) free(np);
- return(-9);
- }
- }
- *xp = atmbuf;
- #endif /* DTILDE */
- debug(F110,"cmifi tilde_expand",*xp,0);
- if (!sv) { /* Only do this once */
- sv = malloc((int)strlen(*xp)+1); /* Make a safe copy */
- if (!sv) {
- printf("?cmifi: malloc errorn");
- if (np) free(np);
- return(-9);
- }
- strcpy(sv,*xp);
- debug(F110,"cmifi sv",sv,0);
- }
- /* This is to get around "cd /" failing because "too many directories match" */
- expanded = 0; /* Didn't call zxpand */
- #ifdef datageneral
- debug(F110,"cmifi isdir 1",*xp,0);
- {
- int y; char *s;
- s = *xp;
- y = strlen(s);
- if (y > 1 &&
- (s[y-1] == ':' ||
- s[y-1] == '^' ||
- s[y-1] == '=')
- )
- s[y-1] = NUL;
- }
- debug(F110,"cmifi isdir 2",*xp,0);
- #endif /* datageneral */
- #ifdef VMS
- if (dirflg) {
- if (!strcmp(*xp,"..")) { /* For UNIXers... */
- setatm("-",0);
- *xp = atmbuf;
- } else if (!strcmp(*xp,".")) {
- setatm("[]",0);
- *xp = atmbuf;
- }
- }
- #endif /* VMS */
- itsadir = isdir(*xp); /* Is it a directory? */
- debug(F111,"cmifi itsadir",*xp,itsadir);
- #ifdef VMS
- /* If they said "blah" where "blah.dir" is a directory... */
- /* change it to [.blah]. */
- if (!itsadir) {
- char tmpbuf[600];
- int flag = 0; char c, * p;
- p = *xp;
- while ((c = *p++) && !flag)
- if (ckstrchr(".[]:*?<>",c))
- flag = 1;
- debug(F111,"cmifi VMS dirname flag",*xp,flag);
- if (!flag) {
- sprintf(tmpbuf,"[.%s]",*xp);
- itsadir = isdir(tmpbuf);
- if (itsadir) {
- setatm(tmpbuf,0);
- *xp = atmbuf;
- }
- debug(F111,"cmifi VMS dirname flag itsadir",*xp,itsadir);
- }
- } else if (itsadir == 1 && *(xp[0]) == '.' && *(xp[1])) {
- char *p;
- if (p = malloc(cc + 4)) {
- sprintf(p,"[%s]",*xp);
- setatm(p,0);
- *xp = atmbuf;
- debug(F110,"cmdir .foo",*xp,0);
- free(p);
- }
- } else if (itsadir == 2 && !diractive) {
- int x; /* [FOO]BAR.DIR instead of [FOO.BAR] */
- char *p;
- p = malloc(cc + 4);
- if (p) {
- x = cvtdir(*xp,p); /* Convert to [FOO.BAR] */
- if (x > 0) {
- setatm(p,0);
- *xp = atmbuf;
- debug(F110,"cmdir cvtdir",*xp,0);
- }
- free(p);
- }
- }
- #endif /* VMS */
- if (dirflg) { /* Parsing a directory name? */
- /* Yes, does it contain wildcards? */
- if (iswild(*xp) ||
- diractive && (!strcmp(*xp,".") || !strcmp(*xp,".."))
- ) {
- nzxopts = ZX_DIRONLY; /* Match only directory names */
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- nfiles = y;
- expanded = 1;
- } else {
- #ifdef VMS
- /*
- This is to allow (e.g.) "cd foo", where FOO.DIR;1 is in the
- current directory.
- */
- debug(F111,"cmdir itsadir",*xp,itsadir);
- if (!itsadir) {
- char *s;
- int n;
- s = *xp;
- n = strlen(s);
- if (n > 0 &&
- #ifdef COMMENT
- *s != '[' && s[n-1] != ']' &&
- *s != '<' && s[n-1] != '>' &&
- #else
- ckindex("[",s,0,0,1) == 0 &&
- ckindex("<",s,0,0,1) == 0 &&
- #endif /* COMMENT */
- s[n-1] != ':') {
- char * dirbuf = NULL;
- dirbuf = (char *)malloc(n+4);
- if (dirbuf) {
- if (*s == '.')
- sprintf(dirbuf,"[%s]",s);
- else
- sprintf(dirbuf,"[.%s]",s);
- itsadir = isdir(dirbuf);
- debug(F111,"cmdir dirbuf",dirbuf,itsadir);
- if (itsadir) {
- setatm(dirbuf,0);
- *xp = atmbuf;
- debug(F110,"cmdir new *xp",*xp,0);
- }
- free(dirbuf);
- }
- /* This is to allow CDPATH to work in VMS... */
- } else if (n > 0) {
- char * p; int i, j, k, d;
- char rb[2] = "]";
- if (p = malloc(x + 8)) {
- strcpy(p,*xp);
- i = ckindex(".",p,-1,1,1);
- d = ckindex(".dir",p,0,0,0);
- j = ckindex("]",p,-1,1,1);
- if (j == 0) {
- j = ckindex(">",p,-1,1,1);
- rb[0] = '>';
- }
- k = ckindex(":",p,-1,1,1);
- if (i < j || i < k) i = 0;
- if (d < j || d < k) d = 0;
- /* Change [FOO]BAR or [FOO]BAR.DIR */
- /* to [FOO.BAR] */
- if (j > 0 && j < n) {
- p[j-1] = '.';
- if (d > 0) p[d-1] = NUL;
- strcat(p,rb);
- debug(F110,"cmdir xxx",p,0);
- }
- itsadir = isdir(p);
- debug(F111,"cmdir p",p,itsadir);
- if (itsadir) {
- setatm(p,0);
- *xp = atmbuf;
- debug(F110,"cmdir new *xp",*xp,0);
- }
- free(p);
- }
- }
- }
- #endif /* VMS */
- y = (!itsadir) ? 0 : 1;
- debug(F111,"cmifi y itsadir",*xp,y);
- }
- } else { /* Parsing a filename. */
- debug(F110,"cmifi *xp pre-zxpand",*xp,0);
- #ifndef COMMENT
- nzxopts = (d == 0) ? ZX_FILONLY : 0; /* So always expand. */
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- #else
- /* Here we're trying to fix a problem in which a directory name is accepted */
- /* as a filename, but this breaks too many other things. */
- nzxopts = 0;
- if (!d) {
- if (itsadir & !iswild(*xp)) {
- debug(F100,"cmifi dir when filonly","",0);
- printf("?Not a regular file: "%s"n",*xp);
- if (sv) free(sv);
- if (np) free(np);
- return(-9);
- } else {
- nzxopts = ZX_FILONLY;
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- }
- }
- #endif /* COMMENT */
- nfiles = y;
- debug(F111,"cmifi y nzxpand",*xp,y);
- debug(F111,"cmifi y atmbuf",atmbuf,itsadir);
- expanded = 1;
- }
- /* domydir() calls zxrewind() so we MUST call nzxpand() here */
- if (!expanded && diractive) {
- debug(F110,"cmifi diractive catch-all zxpand",*xp,0);
- nzxopts = (d == 0) ? ZX_FILONLY : (dirflg ? ZX_DIRONLY : 0);
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- nfiles = y;
- expanded = 1;
- }
- *wild = (iswild(sv) || (y > 1)) && (itsadir == 0);
- #ifdef RECURSIVE
- if (!*wild) *wild = recursive;
- #endif /* RECURSIVE */
- debug(F111,"cmifi sv wild",sv,*wild);
- if (dirflg && *wild && !diractive) {
- printf("?Wildcard matches more than one directoryn");
- if (sv) free(sv);
- if (np) free(np);
- return(-9);
- }
- if (itsadir && d && !dirflg) { /* It's a directory and not wild */
- if (sv) free(sv); /* and it's ok to parse directories */
- if (np) free(np);
- return(x);
- }
- if (y == 0) {
- if (path && !isabsolute(sv)) {
- char * ptr = path;
- char c;
- while (1) {
- c = *ptr;
- if (c == PATHSEP || c == NUL) {
- if (!*path) {
- path = NULL;
- break;
- }
- *ptr = NUL;
- #ifdef UNIX
- /* By definition of CDPATH, an empty member denotes the current directory */
- if (!*path)
- strcpy(atmbuf,".");
- else
- #endif /* UNIX */
- strncpy(atmbuf,path,ATMBL);
- #ifdef VMS
- atmbuf[ATMBL] = NUL;
- /* If we have a logical name, evaluate it recursively */
- if (*(ptr-1) == ':') { /* Logical name ends in : */
- char *p; int n;
- while (((n = strlen(atmbuf)) > 0) &&
- atmbuf[n-1] == ':') {
- atmbuf[n-1] = NUL;
- for (p = atmbuf; *p; p++)
- if (islower(*p)) *p = toupper(*p);
- debug(F111,"cmdir CDPATH LN 1",atmbuf,n);
- p = getenv(atmbuf);
- debug(F110,"cmdir CDPATH LN 2",p,0);
- if (!p)
- break;
- strncpy(atmbuf,p,ATMBL);
- atmbuf[ATMBL] = NUL;
- }
- }
- #else
- #ifdef OS2
- if (*(ptr-1) != '\' && *(ptr-1) != '/')
- strcat(atmbuf,"\");
- #else
- #ifdef UNIX
- if (*(ptr-1) != '/')
- strcat(atmbuf,"/");
- #else
- #ifdef datageneral
- if (*(ptr-1) != ':')
- strcat(atmbuf,":");
- #endif /* datageneral */
- #endif /* UNIX */
- #endif /* OS2 */
- #endif /* VMS */
- strcat(atmbuf,sv);
- debug(F110,"cmifip add path",atmbuf,0);
- if (c == PATHSEP) ptr++;
- path = ptr;
- break;
- }
- ptr++;
- }
- x = 1;
- inword = 0;
- cc = 0;
- xc = (int) strlen(atmbuf);
- *xp = "";
- goto i_path;
- }
- if (d) {
- if (sv) free(sv);
- if (np) free(np);
- return(-2);
- } else {
- if (!nomsg)
- printf("?No %s match - %sn",
- dirflg ? "directories" : "files", sv);
- if (sv) free(sv);
- if (np) free(np);
- return(-9);
- }
- } else if (y < 0) {
- printf("?Too many %s match - %sn",
- dirflg ? "directories" : "files", sv);
- if (sv) free(sv);
- if (np) free(np);
- return(-9);
- } else if (*wild || y > 1) {
- if (sv) free(sv);
- if (np) free(np);
- return(x);
- }
- /* If not wild, see if it exists and is readable. */
- debug(F111,"cmifi sv not wild",sv,*wild);
- if (expanded)
- znext(*xp); /* Get first (only?) matching file */
- if (dirflg) /* Maybe wild and expanded */
- itsadir = isdir(*xp); /* so do this again. */
- y = dirflg ? itsadir : zchki(*xp); /* Now check accessibility */
- if (expanded) {
- #ifdef ZXREWIND
- nfiles = zxrewind(); /* Rewind so next znext() gets 1st */
- #else
- nzxopts = dirflg ? ZX_DIRONLY : 0;
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- nfiles = nzxpand(*xp,nzxopts);
- #endif /* ZXREWIND */
- }
- debug(F111,"cmifi nfiles",*xp,nfiles);
- free(sv); /* done with this */
- sv = NULL;
- if (dirflg && y == 0) {
- printf("?Not a directory - %sn",*xp);
- #ifdef CKCHANNELIO
- z_error = FX_ACC;
- #endif /* CKCHANNELIO */
- return(-9);
- } else if (y == -3) {
- if (!xcmfdb) {
- if (diractive)
- /* Don't show filename if we're not allowed to see it */
- printf("?Read permission deniedn");
- else
- printf("?Read permission denied - %sn",*xp);
- }
- if (np) free(np);
- #ifdef CKCHANNELIO
- z_error = FX_ACC;
- #endif /* CKCHANNELIO */
- return(xcmfdb ? -6 : -9);
- } else if (y == -2) {
- if (!recursive) {
- if (np) free(np);
- if (d) return(0);
- if (!xcmfdb)
- printf("?File not readable - %sn",*xp);
- #ifdef CKCHANNELIO
- z_error = FX_ACC;
- #endif /* CKCHANNELIO */
- return(xcmfdb ? -6 : -9);
- }
- } else if (y < 0) {
- if (np) free(np);
- if (!nomsg && !xcmfdb)
- printf("?File not found - %sn",*xp);
- #ifdef CKCHANNELIO
- z_error = FX_FNF;
- #endif /* CKCHANNELIO */
- return(xcmfdb ? -6 : -9);
- }
- if (np) free(np);
- return(x);
- #ifndef MAC
- case 2: /* ESC */
- debug(F101,"cmifi esc, xc","",xc);
- if (xc == 0) {
- if (*xdef) {
- printf("%s ",xdef); /* If at beginning of field */
- #ifdef GEMDOS
- fflush(stdout);
- #endif /* GEMDOS */
- inword = cmflgs = 0;
- addbuf(xdef); /* Supply default. */
- if (setatm(xdef,0) < 0) {
- printf("Default name too longn");
- if (np) free(np);
- return(-9);
- }
- } else { /* No default */
- bleep(BP_WARN);
- }
- break;
- }
- #ifndef NOSPL
- if (f) { /* If a conversion function is given */
- #ifdef DOCHKVAR
- char *s = *xp; /* See if there are any variables in */
- while (*s) { /* the string and if so, expand it. */
- if (chkvar(s)) {
- #endif /* DOCHKVAR */
- zq = atxbuf;
- atxn = CMDBL;
- if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
- if (np) free(np);
- return(-2);
- }
- #ifdef DOCHKVAR
- /* reduce cc by number of \ consumed by conversion */
- /* function (needed for OS/2, where is path separator) */
- cc -= (strlen(*xp) - strlen(atxbuf));
- #endif /* DOCHKVAR */
- *xp = atxbuf;
- if (!atxbuf[0]) { /* Result empty, use default */
- *xp = xdef;
- cc = strlen(xdef);
- }
- #ifdef DOCHKVAR
- break;
- }
- s++;
- }
- #endif /* DOCHKVAR */
- }
- #endif /* NOSPL */
- #ifdef DTILDE
- dirp = tilde_expand(*xp); /* Expand tilde, if any, */
- if (*dirp != ' ') { /* in the atom buffer. */
- if (setatm(dirp,0) < 0) {
- printf("Expanded name too longn");
- if (np) free(np);
- return(-9);
- }
- }
- *xp = atmbuf;
- #endif /* DTILDE */
- sp = *xp + cc;
- #ifdef UNIXOROSK
- if (!strcmp(atmbuf,"..")) {
- printf(" ");
- strcat(cmdbuf," ");
- cc++;
- bp++;
- *wild = 0;
- *xp = atmbuf;
- break;
- } else if (!strcmp(atmbuf,".")) {
- bleep(BP_WARN);
- if (np) free(np);
- return(-1);
- } else {
- /* This patches a glitch when user types "./foo<ESC>" */
- /* in which the next two chars are omitted from the */
- /* expansion. There should be a better fix, however, */
- /* since there is no problem with "../foo<ESC>". */
- char *p = *xp;
- if (*p == '.' && *(p+1) == '/')
- cc -= 2;
- }
- #endif /* UNIXOROSK */
- #ifdef datageneral
- *sp++ = '+'; /* Data General AOS wildcard */
- #else
- *sp++ = '*'; /* Others */
- #endif /* datageneral */
- *sp-- = ' ';
- #ifdef GEMDOS
- if (!strchr(*xp, '.')) /* abde.e -> abcde.e* */
- strcat(*xp, ".*"); /* abc -> abc*.* */
- #endif /* GEMDOS */
- /* Add wildcard and expand list. */
- #ifdef COMMENT
- /* This kills partial completion when ESC given in path segment */
- nzxopts = dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
- #else
- nzxopts = 0;
- #endif /* COMMENT */
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- nfiles = y;
- debug(F111,"cmifi nzxpand",*xp,y);
- if (y > 0) {
- #ifdef OS2
- znext(filbuf); /* Get first */
- #ifdef ZXREWIND
- zxrewind(); /* Must "rewind" */
- #else
- nzxpand(*xp,nxzopts);
- #endif /* ZXREWIND */
- #else /* Not OS2 */
- ckstrncpy(filbuf,mtchs[0],CKMAXPATH);
- #endif /* OS2 */
- } else
- *filbuf = ' ';
- filbuf[CKMAXPATH] = NUL;
- debug(F111,"cmifi filbuf",filbuf,y);
- *sp = ' '; /* Remove wildcard. */
- *wild = (y > 1);
- if (y == 0) {
- if (!nomsg) {
- printf("?No %s match - %sn",
- dirflg ? "directories" : "files", atmbuf);
- if (np) free(np);
- return(-9);
- } else {
- bleep(BP_WARN);
- if (np) free(np);
- return(-1);
- }
- } else if (y < 0) {
- printf("?Too many %s match - %sn",
- dirflg ? "directories" : "files", atmbuf);
- if (np) free(np);
- return(-9);
- } else if (y > 1) { /* Not unique. */
- #ifndef NOPARTIAL
- /* Partial filename completion */
- int j, k; char c;
- k = 0;
- debug(F111,"cmifi partial",filbuf,cc);
- #ifdef OS2
- {
- int cur = 0,
- len = 0,
- len2 = 0,
- min = strlen(filbuf);
- char localfn[CKMAXPATH+1];
- len = min;
- for (j = 1; j <= y; j++) {
- znext(localfn);
- if (dirflg && !isdir(localfn))
- continue;
- len2 = strlen(localfn);
- for (cur = cc;
- cur < len && cur < len2 && cur <= min;
- cur++
- ) {
- /* OS/2 or Windows, case doesn't matter */
- if (tolower(filbuf[cur]) != tolower(localfn[cur]))
- break;
- }
- if (cur < min)
- min = cur;
- }
- filbuf[min] = NUL;
- if (min > cc)
- k++;
- }
- #else /* OS2 */
- for (i = cc; (c = filbuf[i]); i++) {
- for (j = 1; j < y; j++)
- if (mtchs[j][i] != c) break;
- if (j == y) k++;
- else filbuf[i] = filbuf[i+1] = NUL;
- }
- #endif /* OS2 */
- debug(F111,"cmifi partial k",filbuf,k);
- if (k > 0) { /* Got more characters */
- sp = filbuf + cc; /* Point to new ones */
- #ifdef VMS
- for (i = 0; i < cc; i++) {
- cmdchardel(); /* Back up over old partial spec */
- bp--;
- }
- sp = filbuf; /* Point to new word start */
- debug(F100,"cmifi vms erase ok","",0);
- #endif /* VMS */
- cc = k; /* How many new ones we just got */
- printf("%s",sp); /* Print them */
- while (*bp++ = *sp++) ; /* Copy to command buffer */
- bp--; /* Back up over NUL */
- debug(F110,"cmifi partial cmdbuf",cmdbuf,0);
- if (setatm(filbuf,0) < 0) {
- printf("?Partial name too longn");
- if (np) free(np);
- return(-9);
- }
- debug(F111,"cmifi partial atmbuf",atmbuf,cc);
- *xp = atmbuf;
- }
- #endif /* NOPARTIAL */
- bleep(BP_WARN);
- } else { /* Unique, complete it. */
- #ifndef VMS
- #ifdef CK_TMPDIR
- /* isdir() function required for this! */
- debug(F111,"cmifi unique",filbuf,cc);
- if (isdir(filbuf) && !dirflg) {
- int len;
- len = strlen(filbuf);
- if (len > 0 && len < ATMBL - 1) {
- if (filbuf[len-1] != dirsep) {
- filbuf[len] = dirsep;
- filbuf[len+1] = NUL;
- }
- }
- sp = filbuf + cc;
- bleep(BP_WARN);
- printf("%s",sp);
- cc++;
- while (*bp++ = *sp++) ;
- bp--;
- if (setatm(filbuf,0) < 0) {
- printf("?Directory name too longn");
- if (np) free(np);
- return(-9);
- }
- debug(F111,"cmifi directory atmbuf",atmbuf,cc);
- *xp = atmbuf;
- } else { /* Not a directory or dirflg */
- #endif /* CK_TMPDIR */
- #endif /* VMS */
- #ifndef VMS /* VMS dir names are special */
- #ifndef datageneral /* VS dirnames must not end in ":" */
- if (dirflg) {
- int len;
- len = strlen(filbuf);
- if (len > 0 && len < ATMBL - 1) {
- if (filbuf[len-1] != dirsep) {
- filbuf[len] = dirsep;
- filbuf[len+1] = NUL;
- }
- }
- }
- #endif /* datageneral */
- #endif /* VMS */
- sp = filbuf + cc; /* Point past what user typed. */
- #ifdef VMS
- debug(F111,"cmifi VMS erasing",filbuf,cc);
- for (i = 0; i < cc; i++) {
- cmdchardel(); /* Back up over old partial spec */
- bp--;
- }
- sp = filbuf; /* Point to new word start */
- debug(F111,"cmifi after VMS erase sp=",sp,cc);
- #endif /* VMS */
- /* Complete the name. */
- #ifdef COMMENT
- printf("%s%s",dirflg ? "" : " ",sp);
- #else
- printf("%s ",sp); /* Complete the name. */
- #endif /* COMMENT */
- #ifdef GEMDOS
- fflush(stdout);
- #endif /* GEMDOS */
- addbuf(sp); /* Add the characters to cmdbuf. */
- if (setatm(filbuf,0) < 0) { /* And to atmbuf. */
- printf("?Completed name too longn");
- if (np) free(np);
- return(-9);
- }
- if (dirflg && !isdir(filbuf)) {
- printf("?Not a directory - %sn", filbuf);
- if (np) free(np);
- return(-9);
- }
- inword = cmflgs = 0;
- *xp = atmbuf; /* Return pointer to atmbuf. */
- if (np) free(np);
- return(0);
- #ifndef VMS
- #ifdef CK_TMPDIR
- }
- #endif /* CK_TMPDIR */
- #endif /* VMS */
- }
- break;
- case 3: /* Question mark - file menu wanted */
- if (*xhlp == NUL)
- printf(dirflg ? " Directory name" : " Input file specification");
- else
- printf(" %s",xhlp);
- #ifdef GEMDOS
- fflush(stdout);
- #endif /* GEMDOS */
- #ifdef OLDHELP
- if (xc > 0) {
- #endif /* OLDHELP */
- #ifndef NOSPL
- if (f) { /* If a conversion function is given */
- #ifdef DOCHKVAR
- char *s = *xp; /* See if there are any variables in */
- while (*s) { /* the string and if so, expand them */
- if (chkvar(s)) {
- #endif /* DOCHKVAR */
- zq = atxbuf;
- atxn = CMDBL;
- if ((x = (*f)(*xp,&zq,&atxn)) < 0) {
- if (np) free(np);
- return(-2);
- }
- #ifdef DOCHKVAR
- /* reduce cc by number of \ consumed by conversion */
- /* function (needed for OS/2, where is path separator) */
- cc -= (strlen(*xp) - strlen(atxbuf));
- #endif /* DOCHKVAR */
- *xp = atxbuf;
- #ifdef DOCHKVAR
- break;
- }
- s++;
- }
- #endif /* DOCHKVAR */
- }
- #endif /* NOSPL */
- #ifdef DTILDE
- dirp = tilde_expand(*xp); /* Expand tilde, if any */
- if (*dirp != ' ') {
- if (setatm(dirp,0) < 0) {
- printf("?Expanded name too longn");
- if (np) free(np);
- return(-9);
- }
- }
- *xp = atmbuf;
- #endif /* DTILDE */
- debug(F111,"cmifi ? *xp, cc",*xp,cc);
- sp = *xp + cc; /* Insert "*" at end */
- #ifdef datageneral
- *sp++ = '+'; /* Insert +, the DG wild card */
- #else
- *sp++ = '*';
- #endif /* datageneral */
- *sp-- = ' ';
- #ifdef GEMDOS
- if (! strchr(*xp, '.')) /* abde.e -> abcde.e* */
- strcat(*xp, ".*"); /* abc -> abc*.* */
- #endif /* GEMDOS */
- debug(F110,"cmifi ? wild",*xp,0);
- #ifdef COMMENT
- /* This kills file lists when we're still the path part */
- nzxopts = dirflg ? ZX_DIRONLY : (d ? 0 : ZX_FILONLY);
- #else
- #ifdef COMMENT
- /* But this makes "cd ?" list regular files */
- nzxopts = 0;
- #else
- nzxopts = dirflg ? ZX_DIRONLY : 0;
- #endif /* COMMENT */
- #endif /* COMMENT */
- debug(F101,"cmifi matchdot","",matchdot);
- if (matchdot) nzxopts |= ZX_MATCHDOT;
- if (recursive) nzxopts |= ZX_RECURSE;
- y = nzxpand(*xp,nzxopts);
- nfiles = y;
- *sp = ' ';
- if (y == 0) {
- if (nomsg) {
- printf(": %sn",atmbuf);
- printf("%s%s",cmprom,cmdbuf);
- fflush(stdout);
- if (np) free(np);
- return(-1);
- } else {
- printf("?No %s match - %sn",
- dirflg ? "directories" : "files", atmbuf);
- if (np) free(np);
- return(-9);
- }
- } else if (y < 0) {
- printf("?Too many %s match - %sn",
- dirflg ? "directories" : "files", atmbuf);
- if (np) free(np);
- return(-9);
- } else {
- printf(", one of the following:n");
- #ifdef OLDHELP
- clrhlp();
- for (i = 0; i < y; i++) {
- znext(filbuf);
- if (!dirflg || isdir(filbuf)) {
- #ifdef VMS
- printf(" %sn",filbuf); /* VMS names can be long */
- #else
- addhlp(filbuf);
- #endif /* VMS */
- }
- }
- dmphlp();
- #else /* New way... */
- if (filhelp(y,"","",1,dirflg) < 0) {
- if (np) free(np);
- return(-9);
- }
- #endif /* OLDHELP */
- }
- #ifdef OLDHELP
- } else
- printf("n");
- #endif /* OLDHELP */
- printf("%s%s",cmprom,cmdbuf);
- fflush(stdout);
- break;
- #endif /* MAC */
- }
- #ifdef BS_DIRSEP
- dirnamflg = 1;
- x = gtword(0); /* No, get a word */
- dirnamflg = 0;
- #else
- x = gtword(0); /* No, get a word */
- #endif /* BS_DIRSEP */
- *xp = atmbuf;
- }
- }
- /* C M F L D -- Parse an arbitrary field */
- /*
- Returns
- -3 if no input present when required,
- -2 if field too big for buffer,
- -1 if reparse needed,
- 0 otherwise, xp pointing to string result.
- */
- int
- cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
- int x, xc;
- char *zq;
- inword = 0; /* Initialize counts & pointers */
- cc = 0;
- xc = 0;
- *xp = "";
- debug(F110,"cmfld xdef 1",xdef,0);
- if (!xhlp) xhlp = "";
- if (!xdef) xdef = "";
- ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
- xdef = cmdefault;
- debug(F111,"cmfld xdef 2",xdef,cmflgs);
- if ((x = cmflgs) != 1) { /* Already confirmed? */
- x = gtword(0); /* No, get a word */
- } else {
- if (setatm(xdef,0) < 0) { /* If so, use default, if any. */
- printf("?Default too longn");
- return(-9);
- }
- }
- *xp = atmbuf; /* Point to result. */
- debug(F111,"cmfld atmbuf 1",atmbuf,cmflgs);
- while (1) {
- xc += cc; /* Count the characters. */
- debug(F111,"cmfld: gtword",atmbuf,xc);
- debug(F101,"cmfld x","",x);
- switch (x) {
- case -9:
- printf("Command or field too longn");
- case -4: /* EOF */
- case -3: /* Empty. */
- case -2: /* Out of space. */
- case -1: /* Reparse needed */
- return(x);
- case 0: /* SP or NL */
- case 1:
- debug(F111,"cmfld 1",atmbuf,xc);
- if (xc == 0) { /* If no input, return default. */
- if (setatm(xdef,0) < 0) {
- printf("?Default too longn");
- return(-9);
- }
- }
- *xp = atmbuf; /* Point to what we got. */
- debug(F111,"cmfld 2",atmbuf,(f) ? 1 : 0);
- if (f) { /* If a conversion function is given */
- zq = atxbuf; /* employ it now. */
- atxn = CMDBL;
- debug(F111,"cmfld zzstring",atxbuf,x);
- if ((*f)(*xp,&zq,&atxn) < 0)
- return(-2);
- if (setatm(atxbuf,1) < 0) { /* Replace by new value */
- printf("Value too longn");
- return(-9);
- }
- *xp = atmbuf;
- }
- debug(F111,"cmfld 3",atmbuf,xc);
- if (**xp == NUL) { /* If variable evaluates to null */
- if (setatm(xdef,0) < 0) {
- printf("?Default too longn");
- return(-9);
- }
- if (**xp == NUL) x = -3; /* If still empty, return -3. */
- }
- debug(F111,"cmfld returns",*xp,x);
- return(x);
- case 2: /* ESC */
- if (xc == 0 && *xdef) {
- printf("%s ",xdef); /* If at beginning of field, */
- #ifdef GEMDOS
- fflush(stdout);
- #endif /* GEMDOS */
- addbuf(xdef); /* Supply default. */
- inword = cmflgs = 0;
- if (setatm(xdef,0) < 0) {
- printf("?Default too longn");
- return(-9);
- } else /* Return as if whole field */
- return(0); /* typed, followed by space. */
- } else {
- bleep(BP_WARN);
- }
- break;
- case 3: /* Question mark */
- if (*xhlp == NUL)
- printf(" Please complete this field");
- else
- printf(" %s",xhlp);
- printf("n%s%s",cmprom,cmdbuf);
- fflush(stdout);
- break;
- }
- x = gtword(0);
- /* *xp = atmbuf; */
- }
- }
- /* C M T X T -- Get a text string, including confirmation */
- /*
- Print help message 'xhlp' if ? typed, supply default 'xdef' if null
- string typed. Returns:
- -1 if reparse needed or buffer overflows.
- 1 otherwise.
- with cmflgs set to return code, and xp pointing to result string.
- */
- int
- cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
- int x, i;
- char *xx, *zq;
- static int xc;
- if (!xhlp) xhlp = "";
- if (!xdef) xdef = "";
- cmfldflgs = 0;
- ckstrncpy(cmdefault,xdef,CMDEFAULT); /* Copy default */
- xdef = cmdefault;
- debug(F101,"cmtxt, cmflgs","",cmflgs);
- inword = 0; /* Start atmbuf counter off at 0 */
- cc = 0;
- if (cmflgs == -1) { /* If reparsing, */
- *xp = pp;
- xc = (int)strlen(*xp); /* get back the total text length, */
- bp = *xp; /* and back up the pointers. */
- np = *xp;
- pp = *xp;
- } else { /* otherwise, */
- debug(F100,"cmtxt: fresh start","",0);
- *xp = ""; /* start fresh. */
- xc = 0;
- }
- *atmbuf = NUL; /* And empty the atom buffer. */
- rtimer(); /* Reset timer */
- if ((x = cmflgs) != 1) {
- int done = 0;
- while (!done) {
- x = gtword(0); /* Get first word. */
- *xp = pp; /* Save pointer to it. */
- debug(F111,"cmtxt:",*xp,cc);
- if (x == -10) {
- if (gtimer() > timelimit) {
- if (!quiet) printf("?Timed outn");
- return(x);
- }
- } else
- done = 1;
- }
- }
- while (1) { /* Loop for each word in text. */
- xc += cc; /* Char count for all words. */
- debug(F111,"cmtxt gtword",atmbuf,xc);
- debug(F101,"cmtxt x","",x);
- switch (x) {
- case -10:
- if (gtimer() > timelimit) {
- #ifdef IKSD
- extern int inserver;
- if (inserver) {
- printf("rnIKSD IDLE TIMEOUT: %d secrn", timelimit);
- doexit(GOOD_EXIT,0);
- }
- #endif /* IKSD */
- if (!quiet) printf("?Timed outn");
- return(-10);
- } else {
- x = gtword(0);
- continue;
- }
- case -9: /* Buffer overflow */
- printf("Command or field too longn");
- case -4: /* EOF */
- #ifdef MAC
- case -3: /* Quit/Timeout */
- #endif /* MAC */
- case -2: /* Overflow */
- case -1: /* Deletion */
- return(x);
- case 0: /* Space */
- xc++; /* Just count it */
- break;
- case 1: /* CR or LF */
- if (xc == 0) *xp = xdef;
- if (f) { /* If a conversion function is given */
- zq = atxbuf; /* Point to the expansion buffer */
- atxn = CMDBL; /* specify its length */
- debug(F110,"cmtxt calling (*f)",*xp,0);
- if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
- cc = (int)strlen(atxbuf);
- if (cc < 1) {
- *xp = xdef;
- cc = strlen(xdef);
- } else {
- *xp = atxbuf; /* and return pointer to it. */
- }
- debug(F111,"cmtxt (*f) returns",*xp,cc);
- }
- xx = *xp;
- for (i = (int)strlen(xx) - 1; i > 0; i--)
- if (xx[i] != SP) /* Trim trailing blanks */
- break;
- else
- xx[i] = NUL;
- #ifdef CK_RECALL
- addcmd(cmdbuf);
- #endif /* CK_RECALL */
- return(x);
- case 2: /* ESC */
- if (xc == 0) { /* Nothing typed yet */
- if (*xdef) { /* Have a default for this field? */
- printf("%s ",xdef); /* Yes, supply it */
- inword = cmflgs = 0;
- #ifdef GEMDOS
- fflush(stdout);
- #endif /* GEMDOS */
- cc = addbuf(xdef);
- } else bleep(BP_WARN); /* No default */
- } else { /* Already in field */
- int x; char *p;