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 */