remove patch system - not needed at the moment
[ckermit.git] / ckucmd.c
index e1bca34..3ea4807 100644 (file)
--- a/ckucmd.c
+++ b/ckucmd.c
@@ -1,14 +1,16 @@
 #include "ckcsym.h"
 
 #include "ckcsym.h"
 
-char *cmdv = "Command package 8.0.157, 11 May 2003";
+char *cmdv = "Command package 9.0.168, 12 March 2010";
 
 /*  C K U C M D  --  Interactive command package for Unix  */
 
 
 /*  C K U C M D  --  Interactive command package for Unix  */
 
+/* (In reality, it's for all platforms, not just Unix) */
+
 /*
   Author: Frank da Cruz (fdc@columbia.edu),
   Columbia University Academic Information Systems, New York City.
 
 /*
   Author: Frank da Cruz (fdc@columbia.edu),
   Columbia University Academic Information Systems, New York City.
 
-  Copyright (C) 1985, 2004,
+  Copyright (C) 1985, 2010,
     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.
     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.
@@ -83,7 +85,7 @@ struct keytab cmonths[] = {
 
 #ifndef NOSPL
 _PROTOTYP( int chkvar, (char *) );
 
 #ifndef NOSPL
 _PROTOTYP( int chkvar, (char *) );
-extern int askflag;
+extern int askflag, echostars;
 #endif /* NOSPL */
 
 #ifdef CKROOT
 #endif /* NOSPL */
 
 #ifdef CKROOT
@@ -96,6 +98,7 @@ extern int inserver;
 
 int cmfldflgs = 0;                     /* Flags for cmfld() */
 int cmkwflgs = 0;                      /* Flags from last keyword parse */
 
 int cmfldflgs = 0;                     /* Flags for cmfld() */
 int cmkwflgs = 0;                      /* Flags from last keyword parse */
+static int nomsg = 0;
 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 blocklvl = 0;               /* Block nesting level */
 static int linebegin = 0;              /* Flag for at start of a line */
 static int quoting = 1;                        /* Quoting is allowed */
@@ -203,10 +206,6 @@ modules would have to be changed...
 #include <io.h>
 #endif /* OS2 */
 
 #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 OSK
 #define cc ccount                      /* OS-9/68K compiler bug */
 #endif /* OSK */
@@ -249,6 +248,10 @@ int psetf = 0,                          /* Flag that prompt has been set */
     inword = 0;                                /* In the middle of getting a word */
 
 char *dfprom = "Command? ";             /* Default prompt */
     inword = 0;                                /* In the middle of getting a word */
 
 char *dfprom = "Command? ";             /* Default prompt */
+#ifndef NOLASTFILE
+char *lastfile = NULL;                 /* Last filespec */
+static char *tmplastfile = NULL;       /* Last filespec candidate */
+#endif /* NOLASTFILE */
 
 int cmflgs;                             /* Command flags */
 int cmfsav;                            /* A saved version of them */
 
 int cmflgs;                             /* Command flags */
 int cmfsav;                            /* A saved version of them */
@@ -264,6 +267,7 @@ 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 */
 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 */
+char *prevcmd = NULL;
 static char *atybuf = NULL;            /* For copying atom buffer */
 static char *filbuf = NULL;            /* File name buffer */
 static char *cmprom = NULL;            /* Program's prompt */
 static char *atybuf = NULL;            /* For copying atom buffer */
 static char *filbuf = NULL;            /* File name buffer */
 static char *cmprom = NULL;            /* Program's prompt */
@@ -296,6 +300,7 @@ 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 */
 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 */
+char prevcmd[CMDBL+4];                 /* For displaying the last command */
 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 atybuf[ATMBL+4];           /* For copying atom buffer */
 static char filbuf[ATMBL+4];           /* File name buffer */
 static char cmprom[PROMPTL+1];         /* Program's prompt */
@@ -304,7 +309,7 @@ static char cmprxx[PROMPTL+1];              /* Program's prompt, unevaluated */
 
 /* Command buffer pointers */
 
 
 /* Command buffer pointers */
 
-#define PPVLEN 24
+#define PPVLEN VNAML                   /* 20080305 Wolfram Sang (was 24) */
 char ppvnambuf[PPVLEN+1] = { NUL, NUL };
 
 char * cmbptr = NULL;                  /* Current position (for export) */
 char ppvnambuf[PPVLEN+1] = { NUL, NUL };
 
 char * cmbptr = NULL;                  /* Current position (for export) */
@@ -585,7 +590,7 @@ kwdhelp(s,n,pat,pre,post,off,xhlp)
     return;
 }
 
     return;
 }
 
-/*  F I L H E L P  --  Given a file list, print names in columns.  */
+/*  F I L H E L P  --  Given a file list, print names in columns.  */
 /*
   Call with:
     n     - number of entries
 /*
   Call with:
     n     - number of entries
@@ -593,6 +598,8 @@ kwdhelp(s,n,pat,pre,post,off,xhlp)
     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
     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
+    fs    - call fileselect() to decide whether to include each file.
+    The rest of the args are the same as for fileselect().
 
   Arranges filenames in columns with width based on longest filename.
   Does "more?" prompting at end of screen.
 
   Arranges filenames in columns with width based on longest filename.
   Does "more?" prompting at end of screen.
@@ -600,7 +607,22 @@ kwdhelp(s,n,pat,pre,post,off,xhlp)
 */
 
 int
 */
 
 int
-filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
+#ifdef CK_ANSIC
+xfilhelp(
+    int n, char *pre, char *post, int off, int cmdirflag,
+    int fs, char *sa, char *sb, char *sna, char *snb,
+    CK_OFF_T minsiz, CK_OFF_T maxsiz,
+    int nbu, int nxlist,
+    char ** xlist
+)
+#else
+xfilhelp(n,pre,post,off,cmdirflg,
+        fs,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
+    int n, off; char *pre, *post; int cmdirflg;
+    int fs; char *sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
+    int nbu,nxlist; char ** xlist;
+#endif /* CK_ANSIC */
+ {
     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 filbuf[CKMAXPATH + 1];                /* Temp buffer for one filename */
     int width = 0;
     int cols, height, i, j, k, lc, n2 = 0, rc = 0, itsadir = 0;
@@ -630,6 +652,11 @@ filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
            if (cmdirflg && !itsadir)   /* No, listing directories only? */
              continue;                 /* So skip this one. */
 #endif /* COMMENT */
            if (cmdirflg && !itsadir)   /* No, listing directories only? */
              continue;                 /* So skip this one. */
 #endif /* COMMENT */
+           if (fs) if (fileselect(filbuf,
+                          sa,sb,sna,snb,
+                          minsiz,maxsiz,nbu,nxlist,xlist) < 1) {
+                    continue;
+           }
 #ifdef VMS
            ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH);
 #endif /* VMS */
 #ifdef VMS
            ckstrncpy(filbuf,zrelname(filbuf,cdp),CKMAXPATH);
 #endif /* VMS */
@@ -728,6 +755,17 @@ xfilhelp:
     }
 }
 
     }
 }
 
+/*
+  Simpler front end for xfilhelp() with shorter arg list when no
+  file selection is needed.
+*/
+int
+filhelp(n,pre,post,off,cmdirflg) int n, off; char *pre, *post; int cmdirflg; {
+    return(xfilhelp(n,pre,post,off,cmdirflg,
+                   0,NULL,NULL,NULL,NULL,
+                   (CK_OFF_T)0,(CK_OFF_T)0,0,0,(char **)NULL));
+}
+
 /*  C M S E T U P  --  Set up command buffers  */
 
 #ifdef DCMDBUF
 /*  C M S E T U P  --  Set up command buffers  */
 
 #ifdef DCMDBUF
@@ -736,6 +774,8 @@ cmsetup() {
     if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
     if (!(savbuf = malloc(CMDBL + 4))) return(-1);
     savbuf[0] = '\0';
     if (!(cmdbuf = malloc(CMDBL + 4))) return(-1);
     if (!(savbuf = malloc(CMDBL + 4))) return(-1);
     savbuf[0] = '\0';
+    if (!(prevcmd = malloc(CMDBL + 4))) return(-1);
+    prevcmd[0] = '\0';
     if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
     if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
     if (!(atybuf = malloc(ATMBL + 4))) return(-1);
     if (!(atmbuf = malloc(ATMBL + 4))) return(-1);
     if (!(atxbuf = malloc(CMDBL + 4))) return(-1);
     if (!(atybuf = malloc(ATMBL + 4))) return(-1);
@@ -810,8 +850,10 @@ prompt(f) xx_strp f; {
     sx = cmprxx;                       /* Unevaluated copy */
     if (f) {                           /* If conversion function given */
        sy = cmprom;                    /* Evaluate it */
     sx = cmprxx;                       /* Unevaluated copy */
     if (f) {                           /* If conversion function given */
        sy = cmprom;                    /* Evaluate it */
+#ifdef COMMENT
        debug(F101,"prompt sx","",sx);
        debug(F101,"prompt sy","",sy);
        debug(F101,"prompt sx","",sx);
        debug(F101,"prompt sy","",sy);
+#endif /* COMMENT */
        n = PROMPTL;
        if ((*f)(sx,&sy,&n) < 0)        /* If evaluation failed */
          sx = cmprxx;                  /* revert to unevaluated copy */
        n = PROMPTL;
        if ((*f)(sx,&sy,&n) < 0)        /* If evaluation failed */
          sx = cmprxx;                  /* revert to unevaluated copy */
@@ -1210,8 +1252,29 @@ untab(s) char *s; {
    -1 if reparse needed,
     0 otherwise, with argument n set to the number that was parsed
 */
    -1 if reparse needed,
     0 otherwise, with argument n set to the number that was parsed
 */
+/* This is the traditional cmnum() that gets an int */
 int
 cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
 int
 cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
+    CK_OFF_T z = (CK_OFF_T)0, check;
+    int x;
+    x = cmnumw(xhlp,xdef,radix,&z,f);
+    *n = z;
+    check = *n;
+    if (check != z) {
+       printf("?Magnitude of result too large for integer - %s\n",ckfstoa(z));
+       return(-9);
+    }
+    return(x);
+}
+
+/*
+  This is the new cmnum() that gets a "wide" result, whatever CK_OFF_T
+  is defined to be, normally 32 or 64 bits, depending on the platform.
+  fdc, 24 Dec 2005.
+*/
+int
+cmnumw(xhlp,xdef,radix,n,f)
+    char *xhlp, *xdef; int radix; CK_OFF_T *n; xx_strp f; {
     int x; char *s, *zp, *zq;
 #ifdef COMMENT
     char lbrace, rbrace;
     int x; char *s, *zp, *zq;
 #ifdef COMMENT
     char lbrace, rbrace;
@@ -1260,7 +1323,7 @@ cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
            if (!strcmp(zp,"-1")) return(-2);
        }
        errno = 0;                      /* Got one, we're done. */
            if (!strcmp(zp,"-1")) return(-2);
        }
        errno = 0;                      /* Got one, we're done. */
-        *n = atoi(zp);
+        *n = ckatofs(zp);
        if (errno) {
            perror(zp);
            return(-9);
        if (errno) {
            perror(zp);
            return(-9);
@@ -1294,7 +1357,7 @@ cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
            if (!strcmp(zp,"-1")) return(-2);
        }
        errno = 0;
            if (!strcmp(zp,"-1")) return(-2);
        }
        errno = 0;
-        *n = atoi(zp);
+        *n = ckatofs(zp);
        if (errno) {
            perror(zp);
            return(-9);
        if (errno) {
            perror(zp);
            return(-9);
@@ -1320,7 +1383,7 @@ cmnum(xhlp,xdef,radix,n,f) char *xhlp, *xdef; int radix, *n; xx_strp f; {
                if (!strcmp(zp,"-1")) return(-2);
            }
            errno = 0;
                if (!strcmp(zp,"-1")) return(-2);
            }
            errno = 0;
-           *n = atoi(p);
+           *n = ckatofs(p);
            if (errno) {
                perror(p);
                return(-9);
            if (errno) {
                perror(p);
                return(-9);
@@ -1565,6 +1628,7 @@ o_again:
         wild = 1 if name contains '*' or '?', 0 otherwise.
 */
 
         wild = 1 if name contains '*' or '?', 0 otherwise.
 */
 
+#ifdef COMMENT /* This horrible hack has been replaced - see further down */
 /*
    C M I O F I  --  Parse an input file OR the name of a nonexistent file.
 
 /*
    C M I O F I  --  Parse an input file OR the name of a nonexistent file.
 
@@ -1584,6 +1648,7 @@ cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
     nomsg = msgsave;
     return(x);
 }
     nomsg = msgsave;
     return(x);
 }
+#endif /* COMMENT */
 
 int
 cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
 
 int
 cmifi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
@@ -1653,6 +1718,7 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
     int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1;
     int qflag = 0;
     long y;
     int i, x, itsadir, xc, expanded = 0, nfiles = 0, children = -1;
     int qflag = 0;
     long y;
+    CK_OFF_T filesize;
     char *sp = NULL, *zq, *np = NULL;
     char *sv = NULL, *p = NULL;
 #ifdef DTILDE
     char *sp = NULL, *zq, *np = NULL;
     char *sv = NULL, *p = NULL;
 #ifdef DTILDE
@@ -1682,6 +1748,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
     if (!xhlp) xhlp = "";
     if (!xdef) xdef = "";
 
     if (!xhlp) xhlp = "";
     if (!xdef) xdef = "";
 
+#ifndef NOLASTFILE
+    makestr(&tmplastfile,NULL);
+#endif /* NOLASTFILE */
     nzxopts = 0;                       /* zxpand() options */
     debug(F101,"cmifi d","",d);
     if (d & 2) {                       /* d & 2 means don't follow symlinks */
     nzxopts = 0;                       /* zxpand() options */
     debug(F101,"cmifi d","",d);
     if (d & 2) {                       /* d & 2 means don't follow symlinks */
@@ -1758,6 +1827,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
          case 0:                       /* SP */
            if (xc == 0)                /* If no input... */
              *xp = xdef;               /* substitute the default */
          case 0:                       /* SP */
            if (xc == 0)                /* If no input... */
              *xp = xdef;               /* substitute the default */
+#ifndef NOLASTFILE
+           makestr(&tmplastfile,*xp);  /* Make a copy before bstripping */
+#endif /* #ifndef NOLASTFILE */
            *xp = brstrip(*xp);         /* Strip braces */
            if (**xp == NUL) {          /* 12 mar 2001 */
                if (np) free(np);
            *xp = brstrip(*xp);         /* Strip braces */
            if (**xp == NUL) {          /* 12 mar 2001 */
                if (np) free(np);
@@ -2052,6 +2124,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
            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);
            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);
+#ifndef NOLASTFILE
+               makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
                return(x);
            }
            if (y == 0) {               /* File was not found */
                return(x);
            }
            if (y == 0) {               /* File was not found */
@@ -2140,7 +2215,8 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
                          printf("?Off Limits: %s\n",sv);
                        else
 #endif /* CKROOT */
                          printf("?Off Limits: %s\n",sv);
                        else
 #endif /* CKROOT */
-                         printf("?No %s match - %s\n",
+                         if (!quiet)
+                           printf("?No %s match - %s\n",
                                 dirflg ? "directories" : "files", sv);
                    }
                    if (sv) free(sv);
                                 dirflg ? "directories" : "files", sv);
                    }
                    if (sv) free(sv);
@@ -2161,6 +2237,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
            } else if (*wild || y > 1) {
                if (sv) free(sv);
                if (np) free(np);
            } else if (*wild || y > 1) {
                if (sv) free(sv);
                if (np) free(np);
+#ifndef NOLASTFILE
+               makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
                return(x);
            }
 
                return(x);
            }
 
@@ -2171,7 +2250,7 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
              znext(*xp);               /* Get first (only?) matching file */
            if (dirflg)                 /* Maybe wild and expanded */
              itsadir = isdir(*xp);     /* so do this again. */
              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 */
+           filesize = dirflg ? itsadir : zchki(*xp); /* Check accessibility */
            if (expanded) {
 #ifdef ZXREWIND
                nfiles = zxrewind();    /* Rewind so next znext() gets 1st */
            if (expanded) {
 #ifdef ZXREWIND
                nfiles = zxrewind();    /* Rewind so next znext() gets 1st */
@@ -2184,15 +2263,16 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
 #endif /* ZXREWIND */
            }
            debug(F111,"cmifi nfiles",*xp,nfiles);
 #endif /* ZXREWIND */
            }
            debug(F111,"cmifi nfiles",*xp,nfiles);
+           debug(F101,"cmifi filesize","",filesize);
            free(sv);                   /* done with this */
            sv = NULL;
            free(sv);                   /* done with this */
            sv = NULL;
-           if (dirflg && y == 0) {
+           if (dirflg && !filesize) {
                printf("?Not a directory - %s\n",*xp);
 #ifdef CKCHANNELIO
                z_error = FX_ACC;
 #endif /* CKCHANNELIO */
                return(-9);
                printf("?Not a directory - %s\n",*xp);
 #ifdef CKCHANNELIO
                z_error = FX_ACC;
 #endif /* CKCHANNELIO */
                return(-9);
-           } else if (y == -3) {
+           } else if (filesize == (CK_OFF_T)-3) {
                if (!xcmfdb) {
                    if (diractive)
                      /* Don't show filename if we're not allowed to see it */
                if (!xcmfdb) {
                    if (diractive)
                      /* Don't show filename if we're not allowed to see it */
@@ -2205,10 +2285,15 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
                z_error = FX_ACC;
 #endif /* CKCHANNELIO */
                return(xcmfdb ? -6 : -9);
                z_error = FX_ACC;
 #endif /* CKCHANNELIO */
                return(xcmfdb ? -6 : -9);
-           } else if (y == -2) {
+           } else if (filesize == (CK_OFF_T)-2) {
                if (!recursive) {
                    if (np) free(np);
                if (!recursive) {
                    if (np) free(np);
-                   if (d) return(0);
+                   if (d) {
+#ifndef NOLASTFILE
+                       makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
+                       return(0);
+                   }
                    if (!xcmfdb)
                      printf("?File not readable - %s\n",*xp);
 #ifdef CKCHANNELIO
                    if (!xcmfdb)
                      printf("?File not readable - %s\n",*xp);
 #ifdef CKCHANNELIO
@@ -2216,7 +2301,7 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
 #endif /* CKCHANNELIO */
                    return(xcmfdb ? -6 : -9);
                }
 #endif /* CKCHANNELIO */
                    return(xcmfdb ? -6 : -9);
                }
-           } else if (y < 0) {
+           } else if (filesize < (CK_OFF_T)0) {
                if (np) free(np);
                if (!nomsg && !xcmfdb)
                  printf("?File not found - %s\n",*xp);
                if (np) free(np);
                if (!nomsg && !xcmfdb)
                  printf("?File not found - %s\n",*xp);
@@ -2226,6 +2311,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
                return(xcmfdb ? -6 : -9);
            }
            if (np) free(np);
                return(xcmfdb ? -6 : -9);
            }
            if (np) free(np);
+#ifndef NOLASTFILE
+           makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
            return(x);
 
 #ifndef MAC
            return(x);
 
 #ifndef MAC
@@ -2632,6 +2720,9 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
                        return(-9);
                    }
                    if (np) free(np);
                        return(-9);
                    }
                    if (np) free(np);
+#ifndef NOLASTFILE
+                   makestr(&lastfile,tmplastfile);
+#endif /* NOLASTFILE */
                    return(0);
 #ifndef VMS
 #ifdef CK_TMPDIR
                    return(0);
 #ifndef VMS
 #ifdef CK_TMPDIR
@@ -2744,7 +2835,7 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
            fflush(stdout);
            break;
 #endif /* MAC */
            fflush(stdout);
            break;
 #endif /* MAC */
-        }
+       }
 #ifdef BS_DIRSEP
         dirnamflg = 1;
         x = gtword(0);                  /* No, get a word */
 #ifdef BS_DIRSEP
         dirnamflg = 1;
         x = gtword(0);                  /* No, get a word */
@@ -2752,7 +2843,7 @@ cmifi2(xhlp,xdef,xp,wild,d,path,f,dirflg)
 #else
         x = gtword(0);                  /* No, get a word */
 #endif /* BS_DIRSEP */
 #else
         x = gtword(0);                  /* No, get a word */
 #endif /* BS_DIRSEP */
-    *xp = atmbuf;
+       *xp = atmbuf;
     }
 }
 
     }
 }
 
@@ -2822,7 +2913,7 @@ cmfld(xhlp,xdef,xp,f) char *xhlp, *xdef, **xp; xx_strp f; {
                }
            }
            *xp = atmbuf;               /* Point to what we got. */
                }
            }
            *xp = atmbuf;               /* Point to what we got. */
-           debug(F111,"cmfld 2",atmbuf,(f) ? 1 : 0);
+           debug(F111,"cmfld 2",atmbuf,((f) ? 1 : 0));
            if (f) {                    /* If a conversion function is given */
                zq = atxbuf;            /* employ it now. */
                atxn = CMDBL;
            if (f) {                    /* If a conversion function is given */
                zq = atxbuf;            /* employ it now. */
                atxn = CMDBL;
@@ -2977,7 +3068,7 @@ cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
                char * sx = atxbuf;
                zq = atxbuf;            /* Point to the expansion buffer */
                atxn = CMDBL;           /* specify its length */
                char * sx = atxbuf;
                zq = atxbuf;            /* Point to the expansion buffer */
                atxn = CMDBL;           /* specify its length */
-               debug(F111,"cmtxt calling (*f)",*xp,atxbuf);
+               /* debug(F111,"cmtxt calling (*f)",*xp,atxbuf); */
                if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
                sx = atxbuf;
 #ifndef COMMENT
                if ((x = (*f)(*xp,&zq,&atxn)) < 0) return(-2);
                sx = atxbuf;
 #ifndef COMMENT
@@ -3076,18 +3167,26 @@ cmtxt(xhlp,xdef,xp,f) char *xhlp; char *xdef; char **xp; xx_strp f; {
    n        --  number of entries in table;
    xhlp     --  pointer to help string;
    xdef     --  pointer to default keyword;
    n        --  number of entries in table;
    xhlp     --  pointer to help string;
    xdef     --  pointer to default keyword;
-   f        --  processing function (e.g. to evaluate variables)
+   f        --  string preprocessing function (e.g. to evaluate variables)
    pmsg     --  0 = don't print error messages
                 1 = print error messages
                 2 = include CM_HLP keywords even if invisible
                 3 = 1+2
                 4 = parse a switch (keyword possibly ending in : or =)
    pmsg     --  0 = don't print error messages
                 1 = print error messages
                 2 = include CM_HLP keywords even if invisible
                 3 = 1+2
                 4 = parse a switch (keyword possibly ending in : or =)
+                8 = don't strip comments (used, e.g., for "help #")
  Returns:
    -3       --  no input supplied and no default available
    -2       --  input doesn't uniquely match a keyword in the table
    -1       --  user deleted too much, command reparse required
     n >= 0  --  value associated with keyword
 */
  Returns:
    -3       --  no input supplied and no default available
    -2       --  input doesn't uniquely match a keyword in the table
    -1       --  user deleted too much, command reparse required
     n >= 0  --  value associated with keyword
 */
+
+/*
+  Front ends for cmkey2(): 
+  cmkey()  - The normal keyword parser
+  cmkeyx() - Like cmkey() but suppresses error messages
+  cmswi()  - Switch parser
+*/
 int
 cmkey(table,n,xhlp,xdef,f)
 /* cmkey */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
 int
 cmkey(table,n,xhlp,xdef,f)
 /* cmkey */  struct keytab table[]; int n; char *xhlp, *xdef; xx_strp f; {
@@ -3143,9 +3242,12 @@ cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
            return(-9);
        }
         rtimer();                       /* Reset timer */
            return(-9);
        }
         rtimer();                       /* Reset timer */
-    } else {
+    } else {                            /* Otherwise get a command word */
         rtimer();                       /* Reset timer */
         rtimer();                       /* Reset timer */
-        zz = gtword((pmsg == 4) ? 1 : 0);/* Otherwise get a command word */
+       if (pmsg & 8)                    /* 8 is for parsing HELP tokens */
+         zz = gtword(4);
+       else
+         zz = gtword((pmsg == 4) ? 1 : 0);
     }
 
     debug(F101,"cmkey table length","",n);
     }
 
     debug(F101,"cmkey table length","",n);
@@ -3160,7 +3262,10 @@ cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
        switch (zz) {
          case -10:                     /* Timeout */
            if (gtimer() < timelimit) {
        switch (zz) {
          case -10:                     /* Timeout */
            if (gtimer() < timelimit) {
-               zz = gtword((pmsg == 4) ? 1 : 0);
+               if (pmsg & 8)           /* 8 is for parsing HELP tokens */
+                 zz = gtword(4);
+               else
+                 zz = gtword((pmsg == 4) ? 1 : 0);
                continue;
            } else {
 #ifdef IKSD
                continue;
            } else {
 #ifdef IKSD
@@ -3227,6 +3332,7 @@ cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
                }
 #endif /* M_UNGW */
            }
                }
 #endif /* M_UNGW */
            }
+#ifdef COMMENT                         /* ^^^ */
            if (cmswitch && *atmbuf != '/') {
                if (pmsg & 1) {
                    bleep(BP_FAIL);
            if (cmswitch && *atmbuf != '/') {
                if (pmsg & 1) {
                    bleep(BP_FAIL);
@@ -3235,6 +3341,7 @@ cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
                cmflgs = -2;
                return(-6);
            }
                cmflgs = -2;
                return(-6);
            }
+#endif /* COMMENT */
            if (cmswitch) {
                int i;
                for (i = 0; i < wordlen; i++) {
            if (cmswitch) {
                int i;
                for (i = 0; i < wordlen; i++) {
@@ -3556,7 +3663,7 @@ cmkey2(table,n,xhlp,xdef,tok,f,pmsg)
            printf("\n%d - Unexpected return code from gtword\n",zz);
            return(cmflgs = -2);
        }
            printf("\n%d - Unexpected return code from gtword\n",zz);
            return(cmflgs = -2);
        }
-       zz = gtword((pmsg == 4) ? 1 : 0);
+       zz = (pmsg & 8) ? gtword(4) : gtword((pmsg == 4) ? 1 : 0);
        debug(F111,"cmkey gtword zz",atmbuf,zz);
     }
 }
        debug(F111,"cmkey gtword zz",atmbuf,zz);
     }
 }
@@ -3685,7 +3792,7 @@ cmdelta(yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss)
        debug(F101,"cmdelta hh","",hh);
        debug(F101,"cmdelta mm","",mm);
        debug(F101,"cmdelta ss","",ss);
        debug(F101,"cmdelta hh","",hh);
        debug(F101,"cmdelta mm","",mm);
        debug(F101,"cmdelta ss","",ss);
-       debug(F101,"cmdelta sin","",sign);
+       debug(F101,"cmdelta sign","",sign);
        debug(F101,"cmdelta dyy","",dyy);
        debug(F101,"cmdelta dmo","",dmo);
        debug(F101,"cmdelta ddd","",ddd);
        debug(F101,"cmdelta dyy","",dyy);
        debug(F101,"cmdelta dmo","",dmo);
        debug(F101,"cmdelta ddd","",ddd);
@@ -3727,11 +3834,24 @@ cmdelta(yy, mo, dd, hh, mm, ss, sign, dyy, dmo, ddd, dhh, dmm, dss)
     }
     sign = (sign < 0) ? -1 : 1;
     if (dmo != 0) {
     }
     sign = (sign < 0) ? -1 : 1;
     if (dmo != 0) {
-       mo += (sign * dmo);
-       if (mo > 12 || mo < 0) {
-           yy += mo / 12;
-           mo = mo % 12;
-       }
+        if (sign > 0) {
+            mo += (sign * dmo);
+            if (mo > 12) {
+                yy += mo / 12;
+                mo = mo % 12;
+            }
+        } else if (sign < 0) {
+            while (dmo > 12) {
+                yy--;
+                dmo -= 12;
+            }
+            if (dmo < mo) {
+                mo -= dmo;
+            } else {
+                yy--;
+                mo = 12 - (dmo - mo);
+            }
+        }
     }
     if (dyy != 0) {
        yy += (sign * dyy);
     }
     if (dyy != 0) {
        yy += (sign * dyy);
@@ -4163,6 +4283,13 @@ cmcvtdate(s,t) char * s; int t; {
        p = s;
        goto delta;
     }
        p = s;
        goto delta;
     }
+#ifdef COMMENT
+/*
+  What is the purpose of this?  It breaks parsing of email dates like
+  "Wed, 13 Feb 2002 17:43:02 -0800 (PST)".  Removing this code fixes the
+  problem and Kermit still passes the 'dates' script.
+  - fdc, Sat Nov 26 10:52:45 2005.
+*/
     if (dow > -1) {
        /* Day of week given followed by something that is not a time */
        /* or a delta so it can't be valid */
     if (dow > -1) {
        /* Day of week given followed by something that is not a time */
        /* or a delta so it can't be valid */
@@ -4170,6 +4297,7 @@ cmcvtdate(s,t) char * s; int t; {
        debug(F111,"cmcvtdate fail",cmdatemsg,-1);
        return(NULL);
     }
        debug(F111,"cmcvtdate fail",cmdatemsg,-1);
        return(NULL);
     }
+#endif /* COMMENT */
 
     /* Handle "today", "yesterday", "tomorrow", and +/- n units */
 
 
     /* Handle "today", "yesterday", "tomorrow", and +/- n units */
 
@@ -4706,12 +4834,28 @@ cmcvtdate(s,t) char * s; int t; {
        isgmt++;                        /* All dates are GMT from here down */
        if (zone != 0) {                /* But not this one so make it GMT */
            hh += zone;                 /* RFC 822 timezone: EST etc */
        isgmt++;                        /* All dates are GMT from here down */
        if (zone != 0) {                /* But not this one so make it GMT */
            hh += zone;                 /* RFC 822 timezone: EST etc */
+           debug(F101,"cmcvtdate hh + zone","",hh);
            if (hh > 23) {              /* Offset crosses date boundary */
            if (hh > 23) {              /* Offset crosses date boundary */
+               int i;
                long jd;
                jd = mjd(yyyymmdd);     /* Get MJD */
                jd += hh / 24;          /* Add new day(s) */
                hh = hh % 24;           /* and convert back to yyyymmdd */
                ckstrncpy(yyyymmdd,mjd2date(jd),YYYYMMDD);
                long jd;
                jd = mjd(yyyymmdd);     /* Get MJD */
                jd += hh / 24;          /* Add new day(s) */
                hh = hh % 24;           /* and convert back to yyyymmdd */
                ckstrncpy(yyyymmdd,mjd2date(jd),YYYYMMDD);
+               debug(F111,"cmcvtdate zone-adjusted date",yyyymmdd,hh);
+               for (i = 0; i < 4; i++)
+                 yearbuf[i] = yyyymmdd[i];
+               yearbuf[4] = NUL;
+               monbuf[0] = yyyymmdd[4];
+               monbuf[1] = yyyymmdd[5];
+               monbuf[2] = NUL;
+               daybuf[0] = yyyymmdd[6];
+               daybuf[1] = yyyymmdd[7];
+               daybuf[2] = NUL;
+               day = daybuf;
+               nday = atoi(daybuf);
+               month = monbuf;
+               year = yearbuf;
            }
        }
        p = p3;                         /* Put back whatever we poked above */
            }
        }
        p = p3;                         /* Put back whatever we poked above */
@@ -4768,7 +4912,7 @@ cmcvtdate(s,t) char * s; int t; {
            p++;
        }
     }
            p++;
        }
     }
-    debug(F110,"cmcvtdate after timezone",p,0);
+    debug(F110,"cmcvtdate source string after timezone",p,0);
 
     if (*p) {                          /* Anything left? */
        p2 = p;
 
     if (*p) {                          /* Anything left? */
        p2 = p;
@@ -5250,6 +5394,7 @@ cmdiffdate(d1,d2) char * d1, * d2; {
     return((char *)result);
 }
 
     return((char *)result);
 }
 
+#ifndef NOSPL
 /* s h u f f l e d a t e  --  Rearrange date string */
 
 /*
 /* s h u f f l e d a t e  --  Rearrange date string */
 
 /*
@@ -5259,11 +5404,13 @@ cmdiffdate(d1,d2) char * d1, * d2; {
       1: Reformat date to yyyy-mmm-dd (mmm = English month abbreviation).
       2: Reformat date to dd-mmm-yyyy (mmm = English month abbreviation).
       3: Reformat as numeric yyyymmddhhmmss.
       1: Reformat date to yyyy-mmm-dd (mmm = English month abbreviation).
       2: Reformat date to dd-mmm-yyyy (mmm = English month abbreviation).
       3: Reformat as numeric yyyymmddhhmmss.
+      4: Reformat in asctime() format Sat Nov 26 11:10:34 2005
     Returns:
       Pointer to result if args valid, otherwise original arg pointer.
 */
 char *
 shuffledate(p,opt) char * p; int opt; {
     Returns:
       Pointer to result if args valid, otherwise original arg pointer.
 */
 char *
 shuffledate(p,opt) char * p; int opt; {
+    extern char * wkdays[];
     int len;
     char ibuf[32];
     static char obuf[48];
     int len;
     char ibuf[32];
     static char obuf[48];
@@ -5272,10 +5419,58 @@ shuffledate(p,opt) char * p; int opt; {
 
     if (!p) p = "";
     if (!*p) p = ckdate();
 
     if (!p) p = "";
     if (!*p) p = ckdate();
-    if (opt < 1 || opt > 3)
+    if (opt < 1 || opt > 4)
       return(p);
     len = strlen(p);
     if (len < 8 || len > 31) return(p);
       return(p);
     len = strlen(p);
     if (len < 8 || len > 31) return(p);
+    if (opt == 4) {                    /* Asctime format (26 Nov 2005) */
+       char c, * s;
+       long z; int k;
+       ckstrncpy(ibuf,p,31);
+       k = len;
+       while (k >= 0 && ibuf[k] == CR || ibuf[k] == LF)
+         ibuf[k--] = NUL;
+       while (k >= 0 && ibuf[k] == SP || ibuf[k] == HT)
+         ibuf[k--] = NUL;
+       if (k < 9) ckstrncpy(&ibuf[8]," 00:00:00",9);
+       p = ibuf;
+        z = mjd(p);                     /* Convert to modified Julian date */
+        z = z % 7L;
+        if (z < 0) {
+            z = 0 - z;
+            k = 6 - ((int)z + 3) % 7;
+        } else {
+            k = ((int)z + 3) % 7;      /* Day of week */
+        }
+       s = wkdays[k];
+        obuf[0] = s[0];                        /* Day of week */
+        obuf[1] = s[1];
+        obuf[2] = s[2];
+        obuf[3] = SP;                  /* Space */
+       c = p[6];
+        p[6] = NUL;
+       mm = atoi(&ibuf[4]);            /* Month */
+       s = moname[mm-1];               /* Name of month */
+       p[6] = c;
+
+        obuf[4] = s[0];                        /* Month */
+        obuf[5] = s[1];
+        obuf[6] = s[2];
+        obuf[7] = SP;                  /* Space */
+       if (p[6] == '0')                /* Date of month */
+         obuf[8] = SP;
+       else
+         obuf[8] = p[6];
+        obuf[9] = p[7];
+       ckstrncpy(&obuf[10],&p[8],10);  /* Time */
+        obuf[19] = SP;                 /* Space */
+       obuf[20] = p[0];                /* Year */
+       obuf[21] = p[1];
+       obuf[22] = p[2];
+       obuf[23] = p[3];
+       obuf[24] = NUL;
+       return((char *)obuf);
+    }
     if (opt == 3) {
        ckstrncpy(obuf,p,48);
        /* yyyymmdd hh:mm:ss */
     if (opt == 3) {
        ckstrncpy(obuf,p,48);
        /* yyyymmdd hh:mm:ss */
@@ -5325,6 +5520,7 @@ shuffledate(p,opt) char * p; int opt; {
     }
     return((char *)obuf);
 }
     }
     return((char *)obuf);
 }
+#endif /* NOSPL */
 
 /*  C K C V T D A T E  --  Like cmcvtdate(), but returns string.  */
 /*  For use by date-related functions */
 
 /*  C K C V T D A T E  --  Like cmcvtdate(), but returns string.  */
 /*  For use by date-related functions */
@@ -5662,10 +5858,11 @@ cmcfm() {
 /* See ckucmd.h for FDB and OFDB definitions. */
 
 struct OFDB cmresult = {               /* Universal cmfdb result holder */
 /* See ckucmd.h for FDB and OFDB definitions. */
 
 struct OFDB cmresult = {               /* Universal cmfdb result holder */
-    NULL,
-    0,
-    NULL,
-    0
+    NULL,                              /* Address of succeeding FDB struct */
+    0,                                 /* Function code */
+    NULL,                              /* String result */
+    0,                                 /* Integer result */
+    (CK_OFF_T)0                                /* Wide result */
 };
 
 VOID
 };
 
 VOID
@@ -5699,6 +5896,7 @@ cmfdb(fdbin) struct FDB * fdbin; {
     struct FDB * in = fdbin;
     struct OFDB * out = &cmresult;
     int x = 0, n, r;
     struct FDB * in = fdbin;
     struct OFDB * out = &cmresult;
     int x = 0, n, r;
+    CK_OFF_T w = (CK_OFF_T)0;
     char *s, *xp, *m = NULL;
     int errbits = 0;
 
     char *s, *xp, *m = NULL;
     int errbits = 0;
 
@@ -5738,6 +5936,19 @@ cmfdb(fdbin) struct FDB * fdbin; {
            debug(F101,"cmfdb cmnum","",x);
            if (x < 0) errbits |= 1;
            break;
            debug(F101,"cmfdb cmnum","",x);
            if (x < 0) errbits |= 1;
            break;
+         case _CMNUW:                  /* Wide cmnum - 24 Dec 2005 */
+           r = in->ndata1;
+           if (r != 10 && r != 8) r = 10;
+#ifndef NOSPL
+            x_ifnum = 1;                /* Disables warning messages */
+#endif /* NOSPL */
+           x = cmnumw(in->hlpmsg,in->dflt,r,&w,in->spf);
+#ifndef NOSPL
+            x_ifnum = 0;
+#endif /* NOSPL */
+           debug(F101,"cmfdb cmnumw","",w);
+           if (x < 0) errbits |= 1;
+           break;
          case _CMOFI:
            x = cmofi(in->hlpmsg,in->dflt,&s,in->spf);
            debug(F101,"cmfdb cmofi","",x);
          case _CMOFI:
            x = cmofi(in->hlpmsg,in->dflt,&s,in->spf);
            debug(F101,"cmfdb cmofi","",x);
@@ -5795,8 +6006,10 @@ cmfdb(fdbin) struct FDB * fdbin; {
            out->fdbaddr = in;
            out->sresult = s;
            out->nresult = (in->fcode == _CMKEY) ? x : n;
            out->fdbaddr = in;
            out->sresult = s;
            out->nresult = (in->fcode == _CMKEY) ? x : n;
+           out->wresult = w;
            out->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0;
            debug(F111,"cmfdb out->nresult",out->sresult,out->nresult);
            out->kflags = (in->fcode == _CMKEY) ? cmkwflgs : 0;
            debug(F111,"cmfdb out->nresult",out->sresult,out->nresult);
+           debug(F111,"cmfdb out->wresult",out->sresult,out->wresult);
            nomsg = 0;
            xcmfdb = 0;
            /* debug(F111,"cmfdb cmdbuf & crflag",cmdbuf,crflag); */
            nomsg = 0;
            xcmfdb = 0;
            /* debug(F111,"cmfdb cmdbuf & crflag",cmdbuf,crflag); */
@@ -5836,7 +6049,6 @@ cmfdb(fdbin) struct FDB * fdbin; {
        pp = np = bp = xp;              /* Back up pointers */
        cmflgs = -1;                    /* Force a reparse */
 
        pp = np = bp = xp;              /* Back up pointers */
        cmflgs = -1;                    /* Force a reparse */
 
-
 #ifndef NOSPL
        if (!askflag) {                 /* If not executing ASK-class cmd... */
 #endif /* NOSPL */
 #ifndef NOSPL
        if (!askflag) {                 /* If not executing ASK-class cmd... */
 #endif /* NOSPL */
@@ -5853,6 +6065,29 @@ cmfdb(fdbin) struct FDB * fdbin; {
     }
 }
 
     }
 }
 
+/*
+   C M I O F I  --  Parse an input file OR the name of a nonexistent file.
+
+   Replaces the commented-out version above.  This one actually works and
+   has the expected straightforward interface.
+*/
+int
+cmiofi(xhlp,xdef,xp,wild,f) char *xhlp, *xdef, **xp; int *wild; xx_strp f; {
+    int x;
+    struct FDB f1, f2;
+    cmfdbi(&f1,_CMIFI,xhlp,xdef,"",0,0,f,NULL,&f2);
+    cmfdbi(&f2,_CMOFI,"","","",0,0,f,NULL,NULL);
+    x = cmfdb(&f1);
+    if (x < 0) {
+       if (x == -3) {
+           x = -9;
+           printf("?Filename required\n");
+       }
+    }
+    *wild = cmresult.nresult;
+    *xp = cmresult.sresult;
+    return(x);
+}
 
 /*  G T W O R D  --  Gets a "word" from the command input stream  */
 
 
 /*  G T W O R D  --  Gets a "word" from the command input stream  */
 
@@ -5862,6 +6097,7 @@ Usage: retcode = gtword(brk);
   brk = 1 to add ':' and '=' (for parsing switches).  These characters
         act as break characters only if the first character of the field
         is slash ('/'), i.e. switch introducer.
   brk = 1 to add ':' and '=' (for parsing switches).  These characters
         act as break characters only if the first character of the field
         is slash ('/'), i.e. switch introducer.
+  brk = 4 to not strip comments (used only for "help #" and "help ;").
 
 Returns:
 -10 Timelimit set and timed out
 
 Returns:
 -10 Timelimit set and timed out
@@ -5939,7 +6175,6 @@ gtword(brk) int brk; {
     if (con_reads_mt) connoi_mt();      /* Task would interfere w/cons read */
 #endif /* datageneral */
 
     if (con_reads_mt) connoi_mt();      /* Task would interfere w/cons read */
 #endif /* datageneral */
 
-
 #ifdef COMMENT
 #ifdef DEBUG
     if (deblog) {
 #ifdef COMMENT
 #ifdef DEBUG
     if (deblog) {
@@ -6062,7 +6297,11 @@ CMDIRPARSE:
 
        c = *bp;
         if (!c) {                      /* If no char waiting in reparse buf */
 
        c = *bp;
         if (!c) {                      /* If no char waiting in reparse buf */
-           if (dpx && (!pushc
+           if ((dpx
+#ifndef NOSPL
+                || echostars
+#endif /* NOSPL */
+                ) && (!pushc
 #ifndef NOSPL
                        || askflag
 #endif /* NOSPL */
 #ifndef NOSPL
                        || askflag
 #endif /* NOSPL */
@@ -6206,9 +6445,11 @@ CMDIRPARSE:
                break;
              case ';':                 /* Trailing comment */
              case '#':
                break;
              case ';':                 /* Trailing comment */
              case '#':
-               if (inword == 0 && quoting) { /* If not in a word */
-                   comment = 1;        /* start a comment. */
-                   cp = bp;            /* remember where it starts. */
+               if (! (brk & 4) ) {     /* If not keeping comments */
+                   if (inword == 0 && quoting) { /* If not in a word */
+                       comment = 1;    /* start a comment. */
+                       cp = bp;        /* remember where it starts. */
+                   }
                }
                break;
            }
                }
                break;
            }
@@ -6218,13 +6459,13 @@ CMDIRPARSE:
                /* debug(F101,"gtword echof 2","",echof); */
 #ifdef BEBOX
                 if (echof) {
                /* debug(F101,"gtword echof 2","",echof); */
 #ifdef BEBOX
                 if (echof) {
-                    putchar(c);                /* echo it. */
+                   cmdecho((char) c, 0); /* Echo what was typed. */
                     fflush(stdout);
                     fflush(stderr);
                 }
 #else
                     fflush(stdout);
                     fflush(stderr);
                 }
 #else
-                if (echof) {           /* echo it. */
-                   putchar((CHAR)c);
+                if (echof) {
+                   cmdecho((char) c, 0); /* Echo what was typed. */
                    if (timelimit)
                      fflush(stdout);
                }
                    if (timelimit)
                      fflush(stdout);
                }
@@ -6260,19 +6501,20 @@ CMDIRPARSE:
                  blocklvl--;
             }
            if ((c == '=' || c == ':') &&
                  blocklvl--;
             }
            if ((c == '=' || c == ':') &&
-               !kstartactive && !comment && brk && (firstnb == '/')
+               /* ^^^ */
+               !kstartactive && !comment && brk /* && (firstnb == '/') */
                ) {
                 *bp++ = (char) c;      /* Switch argument separator */
                /* debug(F111,"gtword switch argsep",cmdbuf,brk); */
 #ifdef BEBOX
                 if (echof) {
                ) {
                 *bp++ = (char) c;      /* Switch argument separator */
                /* debug(F111,"gtword switch argsep",cmdbuf,brk); */
 #ifdef BEBOX
                 if (echof) {
-                    putchar(c);                /* Echo it. */
+                   cmdecho((char) c, 0); /* Echo what was typed. */
                     fflush(stdout);
                     fflush(stderr);
                 }
 #else
                if (echof) {
                     fflush(stdout);
                     fflush(stderr);
                 }
 #else
                if (echof) {
-                   putchar((CHAR)c);
+                   cmdecho((char) c, 0); /* Echo what was typed. */
                    if (timelimit)
                      fflush(stdout);
                }
                    if (timelimit)
                      fflush(stdout);
                }
@@ -6280,7 +6522,7 @@ CMDIRPARSE:
                if ((*pp != lbrace) || (bracelvl == 0)) {
                    np = bp;
                    cmbptr = np;
                if ((*pp != lbrace) || (bracelvl == 0)) {
                    np = bp;
                    cmbptr = np;
-                   if (setatm(pp,0) < 0) {
+                   if (setatm(pp,2) < 0) { /* ^^^ */
                        printf("?Field too long error 1\n");
                        debug(F111,"gtword too long #1",pp,strlen(pp));
                        return(-9);
                        printf("?Field too long error 1\n");
                        debug(F111,"gtword too long #1",pp,strlen(pp));
                        return(-9);
@@ -6447,7 +6689,7 @@ CMDIRPARSE:
                        && !kstartactive
                        && !comment
                        ) {
                        && !kstartactive
                        && !comment
                        ) {
-                       putchar((CHAR)c);
+                       cmdecho((char) c, 0);
                        *bp = NUL;
                        if (setatm(pp,0) < 0) {
                            debug(F111,"gtword too long ?",pp,strlen(pp));
                        *bp = NUL;
                        if (setatm(pp,0) < 0) {
                            debug(F111,"gtword too long ?",pp,strlen(pp));
@@ -6546,18 +6788,32 @@ CMDIRPARSE:
                      printf("\n%s",cmprom);
                      cpx = cmdbuf;
                      while ((cx = *cpx++)) {
                      printf("\n%s",cmprom);
                      cpx = cmdbuf;
                      while ((cx = *cpx++)) {
-#ifdef isprint
-                         putchar((CHAR) (isprint(cx) ? cx : '^'));
-#else
-                         putchar((CHAR) ((cx >= SP && cx < DEL) ? cx : '^'));
-#endif /* isprint */
+                         cmdecho(cx,0);
                      }
                      fflush(stdout);
                      continue;
                  }
                      }
                      fflush(stdout);
                      continue;
                  }
+#ifndef NOLASTFILE
+                 case VT:
+                   if (lastfile) {
+                       printf("%s ",lastfile);
+#ifdef GEMDOS
+                       fflush(stdout);
+#endif /* GEMDOS */
+                       inword = cmflgs = 0;
+                       addbuf(lastfile);       /* Supply default. */
+                       if (setatm(lastfile,0) < 0) {
+                           printf("Last name too long\n");
+                           if (np) free(np);
+                           return(-9);
+                       }
+                   } else {            /* No default */
+                       bleep(BP_WARN);
+                   }
+                   return(0);
+#endif /* NOLASTFILE */
                }
 
                }
 
-
 #ifdef CK_RECALL
                if (on_recall &&        /* Reading commands from keyboard? */
                    (cm_recall > 0) &&  /* Saving commands? */
 #ifdef CK_RECALL
                if (on_recall &&        /* Reading commands from keyboard? */
                    (cm_recall > 0) &&  /* Saving commands? */
@@ -6633,7 +6889,12 @@ CMDIRPARSE:
                 fflush(stderr);
             }
 #else
                 fflush(stderr);
             }
 #else
-            if (echof) cmdecho((char) c, 0); /* Echo what was typed. */
+#ifdef NOSPL
+            if (echof || chsrc)
+#else
+            if (echof || (echostars && chsrc))
+#endif /* NOSPL */
+             cmdecho((char) c, 0);     /* Echo what was typed. */
 #endif /* BEBOX */
         } else {                       /* This character was quoted. */
            int qf = 1;
 #endif /* BEBOX */
         } else {                       /* This character was quoted. */
            int qf = 1;
@@ -7209,7 +7470,10 @@ cmdnewl(c) char c;
 
 static VOID
 cmdchardel() {                         /* Erase a character from the screen */
 
 static VOID
 cmdchardel() {                         /* Erase a character from the screen */
-    if (!dpx) return;
+#ifndef NOSPL
+    if (!echostars)
+#endif /* NOSPL */
+      if (!dpx) return;
 #ifdef datageneral
     /* DG '\b' is EM (^y or \031) */
     if (termtype == 1)
 #ifdef datageneral
     /* DG '\b' is EM (^y or \031) */
     if (termtype == 1)
@@ -7234,7 +7498,15 @@ cmdecho(char c, int quote)
 cmdecho(c,quote) char c; int quote;
 #endif /* CK_ANSIC */
 { /* cmdecho */
 cmdecho(c,quote) char c; int quote;
 #endif /* CK_ANSIC */
 { /* cmdecho */
+#ifdef NOSPL
     if (!dpx) return;
     if (!dpx) return;
+#else
+    if (!echostars) {
+       if (!dpx) return;
+    } else {
+       c = (char)echostars;
+    }
+#endif /* NOSPL */
     /* Echo tty input character c */
     if (quote) {
        putchar(BS);
     /* Echo tty input character c */
     if (quote) {
        putchar(BS);
@@ -7245,7 +7517,9 @@ cmdecho(c,quote) char c; int quote;
 #else
        putchar((CHAR) ((c >= SP && c < DEL) ? c : '^'));
 #endif /* isprint */
 #else
        putchar((CHAR) ((c >= SP && c < DEL) ? c : '^'));
 #endif /* isprint */
-    } else putchar(c);
+    } else {
+       putchar(c);
+    }
 #ifdef OS2
     if (quote==1 && c==CR) putchar((CHAR) NL);
 #endif /* OS2 */
 #ifdef OS2
     if (quote==1 && c==CR) putchar((CHAR) NL);
 #endif /* OS2 */
@@ -7550,7 +7824,7 @@ lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
 
     if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) {
         if (x) *x = n-1;
 
     if (!ckstrcmp(table[n-1].kwd,cmd,cmdlen,0)) {
         if (x) *x = n-1;
-       debug(F111,"lookup",table[i].kwd,table);
+       /* debug(F111,"lookup",table[i].kwd,table); */
         return(table[n-1].kwval);
     } else return(-1);
 }
         return(table[n-1].kwval);
     } else return(-1);
 }