From 54fd54c4db9cd2e145b5540c469668abce625845 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Sat, 5 Mar 2022 15:03:16 -0500 Subject: [PATCH] SCP: Updated to current. --- makefile | 6 ++- scp.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++-- scp.h | 1 + sim_imd.c | 31 ++++++----- sim_tmxr.c | 2 +- 5 files changed, 173 insertions(+), 18 deletions(-) diff --git a/makefile b/makefile index b7f182c..db664ac 100644 --- a/makefile +++ b/makefile @@ -182,7 +182,11 @@ find_include = $(abspath $(strip $(firstword $(foreach dir,$(strip ${INCPATH}),$ ifneq (3,${SIM_MAJOR}) ifneq (0,$(TESTS)) find_test = RegisterSanityCheck $(abspath $(wildcard $(1)/tests/$(2)_test.ini)) action == &return_cmd) && (0 != *cptr)) { /* return command w return stat | SCPE_NOMESSAGE; /* suppress message since we've already done that here */ } + +/* sim_call_argv - call a routine with C style argc, argv parsed arguments + + Inputs: + + main_like_routine = the routine that is to be called with parsed arguments + cptr = the command argument string to be broken down into argc, argv + + When the main_like_routine is called, argc and argv are populated. + + argc is the number of tokens parsed from the input string plus 1 + argv is an array of parsed tokens where argv[0] is the unparsed input string + +*/ + + +t_stat sim_call_argv (int (*main_like_routine)(int argc, char *argv[]), const char *cptr) +{ +int argc = 1; +char **argv = (char **)calloc ((1 + argc), sizeof (*argv)); +size_t cptr_len = strlen (cptr); +char *argline = (char *)malloc (2 + 2 * cptr_len); +char *cp, quote; +t_stat result = SCPE_OK; + +if ((argv == NULL) || (argline == NULL)) { + free (argv); + free (argline); + return SCPE_MEM; + } +if (cptr == NULL) { + free (argv); + free (argline); + return SCPE_ARG; + } +strcpy (argline, cptr); +cp = argline + cptr_len + 1; +strcpy (cp, cptr); +argv[0] = argline; /* argv[0] points to unparsed arguments */ +argv[argc + 1] = NULL; /* make sure the argument list always ends with a NULL */ +while (*cp) { + while (sim_isspace (*cp)) /* skip blanks */ + cp++; + if (*cp == '\0') /* all done? */ + break; + if (*cp == '\'' || *cp == '"') /* quoted string? */ + quote = *cp++; + else + quote = 0; + ++argc; + argv = (char **)realloc (argv, (1 + argc) * sizeof (*argv)); + if (argv == NULL) { + result = SCPE_MEM; + break; + } + argv[argc - 1] = cp; /* save start */ + argv[argc] = NULL; /* make sure the argument list always ends with a NULL */ + while (*cp && (quote ? (*cp != quote) : !sim_isspace (*cp))) + cp++; + if (*cp) /* term at quote/spc */ + *cp++ = '\0'; + } +if (argv != NULL) + result = (t_stat)main_like_routine (argc, argv); +free (argline); +free (argv); +return result; +} + /* Substitute_args - replace %n tokens in 'instr' with the do command's arguments and other enviroment variables @@ -11903,8 +11972,12 @@ do { (bare_reason != SCPE_STOP) && (bare_reason != SCPE_STEP) && (bare_reason != SCPE_RUNTIME) && - (bare_reason != SCPE_EXIT)) - sim_messagef (reason, "\nUnexpected internal error while processing event for %s which returned %d - %s\n", sim_uname (uptr), reason, sim_error_text (reason)); + (bare_reason != SCPE_EXIT)) { + if (bare_reason == SCPE_UNATT) + sim_messagef (reason, "\nUnexpected I/O error while processing event for %s - %s\n", sim_uname (uptr), sim_error_text (reason)); + else + sim_messagef (reason, "\nUnexpected internal error while processing event for %s which returned %d - %s\n", sim_uname (uptr), reason, sim_error_text (reason)); + } } while ((reason == SCPE_OK) && ((sim_interval + sim_interval_catchup) <= 0) && (sim_clock_queue != QUEUE_LIST_END) && @@ -13873,10 +13946,13 @@ va_list arglist; t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE)); char msg_prefix[32] = ""; size_t prefix_len; +t_bool newline_prefix = (*fmt == '\n'); if ((stat == SCPE_OK) && (sim_quiet || (sim_switches & SWMASK ('Q')))) return stat; -sprintf (msg_prefix, "%%SIM-%s: ", (stat == SCPE_OK) ? "INFO" : "ERROR"); +if (newline_prefix) + ++fmt; +sprintf (msg_prefix, "%s%%SIM-%s: ", newline_prefix ? (sim_is_running ? "\r\n" : "\n") : "", (stat == SCPE_OK) ? "INFO" : "ERROR"); prefix_len = strlen (msg_prefix); while (1) { /* format passed string, args */ va_start (arglist, fmt); @@ -16250,6 +16326,73 @@ if (sim_switches & SWMASK ('T')) return result; } +struct arg_test_result { + int expected_argc; + const char *expected_argv[12]; + }; +static struct parse_arg_function_test { + const char *input; + struct arg_test_result result; + } parse_arg_function_tests[] = { + {"1 2 3 4", + {5, {"", "1", "2", "3", "4", NULL}}}, + {"'1 2 3 4'", + {2, {"", "1 2 3 4", NULL}}}, + {"1 \"2\" 3 4", + {5, {"", "1", "2", "3", "4", NULL}}}, + {NULL} + }; +static int arg_test_index; + +static int arg_check (int argc, char **argv) +{ +struct parse_arg_function_test *t = &parse_arg_function_tests[arg_test_index]; +struct arg_test_result *r = &t->result; +int i; + +sim_printf ("Arg test for input: %s\n", t->input); +if (r->expected_argc != argc) { + sim_printf ("Unexpected argc. Expected: %d, Got: %d\n", r->expected_argc, argc); + return -1; + } +if (0 != strcmp (argv[0], t->input)) { + sim_printf ("Unexpected argv[%d]. Expected: '%s', Got: '%s'\n", 0, t->input, argv[0]); + return -1; + } +for (i = 1; i >= 0;i++) { + if ((argv[i] == NULL) && (r->expected_argv[i] != NULL)) { + sim_printf ("Unexpected argv[%d]. Expected: '%s', Got: NULL\n", i, r->expected_argv[i]); + return -1; + } + if ((argv[i] != NULL) && (r->expected_argv[i] == NULL)) { + sim_printf ("Unexpected argv[%d]. Expected: NULL, Got: '%s'\n", i, argv[i]); + return -1; + } + if (argv[i] == NULL) + break; + if (strcmp (r->expected_argv[i], argv[i])) { + sim_printf ("Unexpected argv[%d]. Expected: '%s', Got: '%s'\n", i, r->expected_argv[i], argv[i]); + return -1; + } + } +sim_printf ("Good Result\n"); +return 0; +} + +static t_stat test_arg_parsing (void) +{ +t_stat result = SCPE_OK; + +if (sim_switches & SWMASK ('T')) + sim_messagef (SCPE_OK, "test_arg_parsing - starting\n"); +for (arg_test_index = 0; parse_arg_function_tests[arg_test_index].input && (result == SCPE_OK); arg_test_index++) { + result = sim_call_argv (&arg_check, parse_arg_function_tests[arg_test_index].input); + } +if (sim_switches & SWMASK ('T')) + sim_messagef (SCPE_OK, "test_arg_parsing - done\n"); +return result; +} + static t_stat sim_scp_svc (UNIT *uptr) { sim_printf ("Unit %s fired at %.0f\n", sim_uname (uptr), sim_gtime ()); @@ -16392,6 +16535,8 @@ if ((strcmp (gbuf, "ALL") == 0) || (strcmp (gbuf, "SCP") == 0)) { return sim_messagef (SCPE_IERR, "SCP register validation test failed\n"); if (test_scp_parsing () != SCPE_OK) return sim_messagef (SCPE_IERR, "SCP parsing test failed\n"); + if (test_arg_parsing () != SCPE_OK) + return sim_messagef (SCPE_IERR, "SCP argument parsing test failed\n"); if (test_scp_event_sequencing () != SCPE_OK) return sim_messagef (SCPE_IERR, "SCP event sequencing test failed\n"); } diff --git a/scp.h b/scp.h index 85a0209..a34a822 100644 --- a/scp.h +++ b/scp.h @@ -250,6 +250,7 @@ t_stat sim_cancel_step (void); const char *sim_get_tool_path (const char *tool); void sim_printf (const char *fmt, ...) GCC_FMT_ATTR(1, 2); void sim_perror (const char *msg); +t_stat sim_call_argv (int (*main_like)(int argc, char *argv[]), const char *cptr); t_stat sim_messagef (t_stat stat, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason); void sim_debug_bits_hdr (uint32 dbits, DEVICE* dptr, const char *header, diff --git a/sim_imd.c b/sim_imd.c index 9d045c3..546b77d 100644 --- a/sim_imd.c +++ b/sim_imd.c @@ -90,12 +90,12 @@ static t_stat commentParse(DISK_INFO *myDisk, uint8 comment[], uint32 buffLen) /* rewind to the beginning of the file. */ rewind(myDisk->file); - cData = fgetc(myDisk->file); + cData = (uint8)fgetc(myDisk->file); while ((!feof(myDisk->file)) && (cData != 0x1a)) { if ((comment != NULL) && (commentLen < buffLen)) { comment[commentLen++] = cData; } - cData = fgetc(myDisk->file); + cData = (uint8)fgetc(myDisk->file); } if (comment != NULL) { if (commentLen == buffLen) @@ -251,7 +251,7 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) /* sim_debug(myDisk->debugmask, myDisk->device, "Uncompressed Data\n"); */ if (sectorMap[i]-start_sect < MAX_SPT) { myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); - sim_fseek(myDisk->file, sectorSize, SEEK_CUR); + (void)sim_fseek(myDisk->file, sectorSize, SEEK_CUR); } else { sim_printf("SIM_IMD: ERROR: Illegal sector offset %d\n", sectorMap[i]-start_sect); @@ -266,7 +266,7 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); myDisk->flags |= FD_FLAG_WRITELOCK; /* Write-protect the disk if any sectors are compressed. */ if (1) { - uint8 cdata = fgetc(myDisk->file); + uint8 cdata = (uint8)fgetc(myDisk->file); sim_debug(myDisk->debugmask, myDisk->device, "Compressed Data = 0x%02x", cdata); } @@ -344,7 +344,7 @@ t_stat diskCreate(FILE *fileref, const char *ctlr_comment) if(sim_fsize(fileref) != 0) { sim_printf("SIM_IMD: Disk image already has data, do you want to overwrite it? "); - answer = getchar(); + answer = (uint8)getchar(); if((answer != 'y') && (answer != 'Y')) { return (SCPE_OPENERR); @@ -380,7 +380,8 @@ t_stat diskCreate(FILE *fileref, const char *ctlr_comment) rewind(fileref); /* Erase the contents of the IMD file in case we are overwriting an existing image. */ - if (sim_set_fsize(fileref, (t_addr)ftell (fileref)) == -1) { + if (sim_set_fsize(fileref, 0) == -1) { + free(comment); sim_printf("SIM_IMD: Error overwriting disk image.\n"); return(SCPE_OPENERR); } @@ -512,9 +513,9 @@ t_stat sectRead(DISK_INFO *myDisk, sim_debug(myDisk->debugmask, myDisk->device, "Reading C:%d/H:%d/S:%d, len=%d, offset=0x%08x\n", Cyl, Head, Sector, buflen, sectorFileOffset); - sim_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); + (void)sim_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); - sectRecordType = fgetc(myDisk->file); + sectRecordType = (uint8)fgetc(myDisk->file); switch(sectRecordType) { case SECT_RECORD_UNAVAILABLE: /* Data could not be read from the original media */ *flags |= IMD_DISK_IO_ERROR_GENERAL; @@ -522,6 +523,7 @@ t_stat sectRead(DISK_INFO *myDisk, case SECT_RECORD_NORM_ERR: /* Normal Data with read error */ case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ *flags |= IMD_DISK_IO_ERROR_CRC; + /* fall through */ case SECT_RECORD_NORM: /* Normal Data */ case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ @@ -534,6 +536,7 @@ t_stat sectRead(DISK_INFO *myDisk, case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ *flags |= IMD_DISK_IO_ERROR_CRC; + /* fall through */ case SECT_RECORD_NORM_COMP: /* Compressed Normal Data */ case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ /* sim_debug(myDisk->debugmask, myDisk->device, "Compressed Data\n"); */ @@ -611,7 +614,7 @@ t_stat sectWrite(DISK_INFO *myDisk, sectorFileOffset = myDisk->track[Cyl][Head].sectorOffsetMap[Sector-start_sect]; - sim_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); + (void)sim_fseek(myDisk->file, sectorFileOffset-1, SEEK_SET); if (*flags & IMD_DISK_IO_ERROR_GENERAL) { sectRecordType = SECT_RECORD_UNAVAILABLE; @@ -668,6 +671,7 @@ t_stat trackWrite(DISK_INFO *myDisk, FILE *fileref; IMD_HEADER track_header = { 0 }; uint8 *sectorData; + t_addr comment; unsigned long i; unsigned long dataLen; uint8 sectsize = 0; @@ -697,7 +701,8 @@ t_stat trackWrite(DISK_INFO *myDisk, commentParse(myDisk, NULL, 0); /* Truncate the IMD file after the comment field. */ - if (sim_set_fsize(fileref, (t_addr)ftell (fileref)) == -1) { + if (((comment = (t_addr)ftell (fileref)) == (t_addr)-1) || + (sim_set_fsize(fileref, comment) == -1)) { sim_printf("Disk truncation failed.\n"); *flags |= IMD_DISK_IO_ERROR_GENERAL; return(SCPE_IOERR); @@ -730,7 +735,7 @@ t_stat trackWrite(DISK_INFO *myDisk, track_header.sectsize = sectsize; /* Forward to end of the file, write track header and sector map. */ - sim_fseek(myDisk->file, 0, SEEK_END); + (void)sim_fseek(myDisk->file, 0, SEEK_END); sim_fwrite(&track_header, 1, sizeof(IMD_HEADER), fileref); sim_fwrite(sectorMap, 1, numSectors, fileref); @@ -767,7 +772,7 @@ t_stat assignDiskType(UNIT *uptr) { char header[4]; t_offset pos = sim_ftell(uptr->fileref); - sim_fseek(uptr->fileref, (t_addr)0, SEEK_SET); + rewind(uptr->fileref); if (fgets(header, 4, uptr->fileref) == NULL) uptr->u3 = IMAGE_TYPE_DSK; else if (strncmp(header, "IMD", 3) == 0) @@ -779,6 +784,6 @@ t_stat assignDiskType(UNIT *uptr) { } else uptr->u3 = IMAGE_TYPE_DSK; - sim_fseeko(uptr->fileref, pos, SEEK_SET); + (void)sim_fseeko(uptr->fileref, pos, SEEK_SET); return result; } diff --git a/sim_tmxr.c b/sim_tmxr.c index a667777..a11f9f7 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -1326,7 +1326,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se tmxr_debug_connect_line (lp, msg); free (sockname); free (peername); - ++mp->sessions; /* count the new session */ + ++lp->sessions; /* count the new session */ if (lp->acl) { /* Restrict connection with ACL rules? */ if (sim_addr_acl_check (address, lp->acl) != 0) {