diff --git a/README.md b/README.md
index dc97d770..f7bcf0ca 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,8 @@
### New Functionality
#### Remote Console Facility
-A new capability has been added which allows a TELNET Connection to a user designated port so that some out of band commands can be entered to manipulate and/or adjust a running simulator. The commands which enable and control this capability are SET REMOTE TELNET=port, SET REMOTE CONNECTIONS=n and SHOW REMOTE.
+A new capability has been added which allows a TELNET Connection to a user designated port so that some out of band commands can be entered to manipulate and/or adjust a running simulator. The commands which enable and control this capability are SET REMOTE TELNET=port, SET REMOTE CONNECTIONS=n, SET REMOTE TIMEOUT=seconds, and SHOW REMOTE.
+A subset of normal simh commands are available for use in remote console sessions. These are: EXAMINE, IEXAMINE, DEPOSIT, EVALUATE, ATTACH, DETACH, ASSIGN, DEASSIGN, CONTINUE, PWD, SAVE, SET, SHOW, DIR, LS, ECHO, HELP
#### VAX/PDP11 Enhancements
RQ has new disk types: RC25, RCF25, RA80
@@ -181,6 +182,8 @@ Other related changes/extensions:
SET DEFAULT Change working directory
PWD Show working directory
SHOW DEFAULT Show working directory
+ DIR {path|file} Display file listing
+ LS {path|file} Display file listing
#### Command Processing Enhancements
diff --git a/makefile b/makefile
index a88a4b40..5212fe5b 100644
--- a/makefile
+++ b/makefile
@@ -249,6 +249,13 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
endif
endif
endif
+ ifneq (,$(call find_include,glob))
+ OS_CCDEFS += -DHAVE_GLOB
+ else
+ ifneq (,$(call find_include,fnmatch))
+ OS_CCDEFS += -DHAVE_FNMATCH
+ endif
+ endif
ifneq (,$(NETWORK_USEFUL))
ifneq (,$(call find_include,pcap))
ifneq (,$(call find_lib,$(PCAPLIB)))
diff --git a/scp.c b/scp.c
index 16561e31..7f2fb05a 100644
--- a/scp.c
+++ b/scp.c
@@ -647,6 +647,10 @@ static CTAB cmd_table[] = {
"cd set the current directory\n" },
{ "PWD", &pwd_cmd, 0,
"pwd show current directory\n" },
+ { "DIR", &dir_cmd, 0,
+ "dir {dir} list directory files\n" },
+ { "LS", &dir_cmd, 0,
+ "ls {dir} list directory files\n" },
{ "SET", &set_cmd, 0,
"set console arg{,arg...} set console options\n"
"set console WRU specify console drop to simh char\n"
@@ -3147,6 +3151,251 @@ t_stat pwd_cmd (int32 flg, char *cptr)
return show_cmd (0, "DEFAULT");
}
+#if defined (_WIN32)
+
+t_stat dir_cmd (int flg, char *cptr)
+{
+HANDLE hFind;
+WIN32_FIND_DATAA File;
+struct stat filestat;
+char WildName[PATH_MAX + 1];
+
+if (*cptr == '\0')
+ cptr = "./*";
+if ((!stat (cptr, &filestat)) && (filestat.st_mode & S_IFDIR)) {
+ sprintf (WildName, "%s%c*", cptr, strchr (cptr, '/') ? '/' : '\\');
+ cptr = WildName;
+ }
+if ((hFind = FindFirstFileA (cptr, &File)) != INVALID_HANDLE_VALUE) {
+ t_int64 FileSize, TotalSize = 0;
+ int DirCount = 0, FileCount = 0;
+ char DirName[PATH_MAX + 1], FileName[PATH_MAX + 1];
+ char *c, pathsep = '/';
+ struct tm *local;
+
+ GetFullPathNameA(cptr, sizeof(DirName), DirName, &c);
+ c = strrchr(DirName, pathsep);
+ if (NULL == c) {
+ pathsep = '\\';
+ c = strrchr(cptr, pathsep);
+ }
+ if (c) {
+ memcpy(DirName, cptr, c - cptr);
+ DirName[c - cptr] = '\0';
+ }
+ else {
+ getcwd(DirName, PATH_MAX);
+ }
+ printf (" Directory of %s\n\n", DirName);
+ if (sim_log)
+ fprintf (sim_log, " Directory of %s\n\n", DirName);
+ do {
+ FileSize = (((t_int64)(File.nFileSizeHigh)) << 32) | File.nFileSizeLow;
+ sprintf (FileName, "%s%c%s", DirName, pathsep, File.cFileName);
+ stat (FileName, &filestat);
+ local = localtime (&filestat.st_mtime);
+ printf ("%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM");
+ if (sim_log)
+ fprintf (sim_log, "%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM");
+ if (filestat.st_mode & S_IFDIR) {
+ ++DirCount;
+ printf ("
");
+ if (sim_log)
+ fprintf (sim_log, " ");
+ }
+ else {
+ if (filestat.st_mode & S_IFREG) {
+ ++FileCount;
+ fprint_val (stdout, (t_value) FileSize, 10, 17, PV_RCOMMA);
+ if (sim_log)
+ fprint_val (sim_log, (t_value) FileSize, 10, 17, PV_RCOMMA);
+ TotalSize += FileSize;
+ }
+ else {
+ printf ("%17s", "");
+ if (sim_log)
+ fprintf (sim_log, "%17s", "");
+ }
+ }
+ printf (" %s\n", File.cFileName);
+ if (sim_log)
+ fprintf (sim_log, " %s\n", File.cFileName);
+ } while (FindNextFile (hFind, &File));
+ printf ("%16d File(s)", FileCount);
+ fprint_val (stdout, (t_value) TotalSize, 10, 15, PV_RCOMMA);
+ printf (" bytes\n");
+ printf ("%16d Dir(s)\n", DirCount);
+ if (sim_log) {
+ fprintf (sim_log, "%16d File(s)", FileCount);
+ fprint_val (sim_log, (t_value) TotalSize, 10, 15, PV_RCOMMA);
+ fprintf (sim_log, " bytes\n");
+ fprintf (sim_log, "%16d Dir(s)\n", DirCount);
+ }
+ FindClose (hFind);
+ }
+else {
+ printf ("Can't list files for %s\n", cptr);
+ if (sim_log)
+ fprintf (sim_log, "Can't list files for %s\n", cptr);
+ return SCPE_ARG;
+ }
+return SCPE_OK;
+}
+
+#else /* !defined (_WIN32) */
+
+#if defined (HAVE_GLOB)
+#include
+#else /* !defined (HAVE_GLOB) */
+#include
+#if defined (HAVE_FNMATCH)
+#include
+#endif
+#endif /* defined (HAVE_GLOB) */
+
+t_stat dir_cmd (int flg, char *cptr)
+{
+#if defined (HAVE_GLOB)
+glob_t paths;
+#else
+DIR *dir;
+#endif
+struct stat filestat;
+char *c;
+char DirName[PATH_MAX + 1], WholeName[PATH_MAX + 1], WildName[PATH_MAX + 1];
+
+if (*cptr == '\0')
+ cptr = "./*";
+strcpy (WildName, cptr);
+while (strlen(WildName) && isspace(WildName[strlen(WildName)-1]))
+ WildName[strlen(WildName)-1] = '\0';
+if ((!stat (WildName, &filestat)) && (filestat.st_mode & S_IFDIR)) {
+ strcat (WildName, "/*");
+ cptr = WildName;
+ }
+if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) {
+ getcwd (WholeName, PATH_MAX);
+ strcat (WholeName, "/");
+ strcat (WholeName, cptr);
+ while (strlen(WholeName) && isspace(WholeName[strlen(WholeName)-1]))
+ WholeName[strlen(WholeName)-1] = '\0';
+ }
+while ((c = strstr (WholeName, "/./")))
+ strcpy (c + 1, c + 3);
+while ((c = strstr (WholeName, "//")))
+ strcpy (c + 1, c + 2);
+while ((c = strstr (WholeName, "/../"))) {
+ char *c1;
+ c1 = c - 1;
+ while ((c1 >= WholeName) && (*c1 != '/'))
+ c1 = c1 - 1;
+ strcpy (c1, c + 3);
+ while (0 == memcmp (WholeName, "/../", 4))
+ strcpy (WholeName, WholeName+3);
+ }
+c = strrchr (WholeName, '/');
+if (c) {
+ memcpy (DirName, WholeName, c-WholeName);
+ DirName[c-WholeName] = '\0';
+ }
+else
+ getcwd(DirName, PATH_MAX);
+cptr = WholeName;
+#if defined (HAVE_GLOB)
+memset (&paths, 0, sizeof(paths));
+if (0 == glob (cptr, 0, NULL, &paths)) {
+#else
+dir = opendir(DirName[0] ? DirName : "/.");
+if (dir) {
+ struct dirent *ent;
+#endif
+ t_int64 FileSize, TotalSize = 0;
+ int DirCount = 0, FileCount = 0;
+ char FileName[PATH_MAX + 1], *MatchName;
+ char *c;
+ struct tm *local;
+ int i;
+
+ MatchName = 1 + strrchr (cptr, '/');
+ printf (" Directory of %s\n\n", DirName[0] ? DirName : "/");
+ if (sim_log)
+ fprintf (sim_log, " Directory of %s\n\n", DirName[0] ? DirName : "/");
+#if defined (HAVE_GLOB)
+ for (i=0; id_name, 0))
+ continue;
+#endif
+ sprintf (FileName, "%s/%s", DirName, ent->d_name);
+#endif
+ stat (FileName, &filestat);
+ local = localtime (&filestat.st_mtime);
+ printf ("%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM");
+ if (sim_log)
+ fprintf (sim_log, "%02d/%02d/%04d %02d:%02d %s ", local->tm_mon+1, local->tm_mday, 1900+local->tm_year, local->tm_hour%12, local->tm_min, (local->tm_hour >= 12) ? "PM" : "AM");
+ if (filestat.st_mode & S_IFDIR) {
+ ++DirCount;
+ printf (" ");
+ if (sim_log)
+ fprintf (sim_log, " ");
+ }
+ else {
+ if (filestat.st_mode & S_IFREG) {
+ ++FileCount;
+ FileSize = filestat.st_size;
+ fprint_val (stdout, (t_value) FileSize, 10, 17, PV_RCOMMA);
+ if (sim_log)
+ fprint_val (sim_log, (t_value) FileSize, 10, 17, PV_RCOMMA);
+ TotalSize += FileSize;
+ }
+ else {
+ printf ("%17s", "");
+ if (sim_log)
+ fprintf (sim_log, "%17s", "");
+ }
+ }
+ c = strrchr (FileName, '/');
+ printf (" %s\n", c ? c + 1 : FileName);
+ if (sim_log)
+ fprintf (sim_log, " %s\n", c ? c + 1 : FileName);
+ }
+ if (FileCount) {
+ printf ("%16d File(s)", FileCount);
+ fprint_val (stdout, (t_value) TotalSize, 10, 15, PV_RCOMMA);
+ printf (" bytes\n");
+ printf ("%16d Dir(s)\n", DirCount);
+ if (sim_log) {
+ fprintf (sim_log, "%16d File(s)", FileCount);
+ fprint_val (sim_log, (t_value) TotalSize, 10, 15, PV_RCOMMA);
+ fprintf (sim_log, " bytes\n");
+ fprintf (sim_log, "%16d Dir(s)\n", DirCount);
+ }
+ }
+ else {
+ printf ("File Not Found\n");
+ if (sim_log)
+ fprintf (sim_log, "File Not Found\n");
+ }
+#if defined (HAVE_GLOB)
+ globfree (&paths);
+#else
+ closedir (dir);
+#endif
+ }
+else {
+ printf ("Can't list files for %s\n", cptr);
+ if (sim_log)
+ fprintf (sim_log, "Can't list files for %s\n", cptr);
+ return SCPE_ARG;
+ }
+return SCPE_OK;
+}
+
+#endif /* !defined(_WIN32) */
+
/* Breakpoint commands */
t_stat brk_cmd (int32 flg, char *cptr)
@@ -5804,9 +6053,9 @@ return val;
t_stat fprint_val (FILE *stream, t_value val, uint32 radix,
uint32 width, uint32 format)
{
-#define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value)))
+#define MAX_WIDTH ((int) ((CHAR_BIT * sizeof (t_value) * 4 + 3)/3))
t_value owtest, wtest;
-int32 d, digit, ndigits;
+int32 d, digit, ndigits, commas = 0;
char dbuf[MAX_WIDTH + 1];
for (d = 0; d < MAX_WIDTH; d++)
@@ -5820,16 +6069,39 @@ do {
dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10);
} while ((d > 0) && (val != 0));
-if (format != PV_LEFT) {
- wtest = owtest = radix;
- ndigits = 1;
- while ((wtest < width_mask[width]) && (wtest >= owtest)) {
- owtest = wtest;
- wtest = wtest * radix;
- ndigits = ndigits + 1;
- }
- if ((MAX_WIDTH - ndigits) < d)
- d = MAX_WIDTH - ndigits;
+switch (format) {
+ case PV_LEFT:
+ break;
+ case PV_RCOMMA:
+ for (digit = 0; digit < MAX_WIDTH; digit++)
+ if (dbuf[digit] != ' ')
+ break;
+ ndigits = MAX_WIDTH - digit;
+ commas = (ndigits - 1)/3;
+ for (digit=0; digit MAX_WIDTH) {
+ fprintf (stream, "%*s", -((int)width), dbuf);
+ return SCPE_OK;
+ }
+ else
+ d = MAX_WIDTH - width;
+ break;
+ case PV_RZRO:
+ case PV_RSPC:
+ wtest = owtest = radix;
+ ndigits = 1;
+ while ((wtest < width_mask[width]) && (wtest >= owtest)) {
+ owtest = wtest;
+ wtest = wtest * radix;
+ ndigits = ndigits + 1;
+ }
+ if ((MAX_WIDTH - (ndigits + commas)) < d)
+ d = MAX_WIDTH - (ndigits + commas);
+ break;
}
if (fputs (&dbuf[d], stream) == EOF)
return SCPE_IOERR;
diff --git a/scp.h b/scp.h
index 89c28c1e..6c119936 100644
--- a/scp.h
+++ b/scp.h
@@ -71,6 +71,7 @@ t_stat set_cmd (int32 flag, char *ptr);
t_stat show_cmd (int32 flag, char *ptr);
t_stat set_default_cmd (int32 flg, char *cptr);
t_stat pwd_cmd (int32 flg, char *cptr);
+t_stat dir_cmd (int32 flg, char *cptr);
t_stat brk_cmd (int32 flag, char *ptr);
t_stat do_cmd (int32 flag, char *ptr);
t_stat goto_cmd (int32 flag, char *ptr);
diff --git a/sim_console.c b/sim_console.c
index ce539322..368fad17 100644
--- a/sim_console.c
+++ b/sim_console.c
@@ -448,6 +448,8 @@ static CTAB allowed_remote_cmds[] = {
{ "SAVE", &save_cmd, 0 },
{ "SET", &set_cmd, 0 },
{ "SHOW", &show_cmd, 0 },
+ { "DIR", &dir_cmd, 0 },
+ { "LS", &dir_cmd, 0 },
{ "ECHO", &echo_cmd, 0 },
{ "HELP", &help_cmd, 0 },
{ NULL, NULL }
@@ -586,10 +588,11 @@ for (i=0; i < sim_rem_con_tmxr.lines; i++) {
}
}
tmxr_send_buffered_data (lp); /* flush any buffered data */
- printf ("Remote Console Command from %s> %s\n", lp->ipad, sim_rem_buf[i]);
+ printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]);
if (sim_log)
fprintf (sim_log, "Remote Console Command from %s> %s\n", lp->ipad, sim_rem_buf[i]);
if (strlen(sim_rem_buf[i]) >= sizeof(cbuf)) {
+ printf ("\r\nLine too long. Ignored. Continuing Simulator execution\r\n");
tmxr_linemsg (lp, "\r\nLine too long. Ignored. Continuing Simulator execution\r\n");
tmxr_send_buffered_data (lp); /* try to flush any buffered data */
break;
@@ -627,7 +630,7 @@ for (i=0; i < sim_rem_con_tmxr.lines; i++) {
cmdp->message (NULL, stat); /* let it deal with display */
else
if (stat >= SCPE_BASE) { /* error? */
- printf ("%s\n", sim_error_text (stat));
+ printf ("%s\r\n", sim_error_text (stat));
if (sim_log)
fprintf (sim_log, "%s\n", sim_error_text (stat));
}
diff --git a/sim_defs.h b/sim_defs.h
index 77137f5a..7accf10e 100644
--- a/sim_defs.h
+++ b/sim_defs.h
@@ -285,7 +285,8 @@ typedef uint32 t_addr;
#define PV_RZRO 0 /* right, zero fill */
#define PV_RSPC 1 /* right, space fill */
-#define PV_LEFT 2 /* left justify */
+#define PV_RCOMMA 2 /* right, space fill. Comma separte every 3 */
+#define PV_LEFT 3 /* left justify */
/* Default timing parameters */