From 7c4a374f637bfb321acf18b082b79f802313081a Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 26 Jun 2019 17:32:49 +0200 Subject: [PATCH] scriptreplay: print info and signals Signed-off-by: Karel Zak --- term-utils/scriptreplay.c | 136 +++++++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 23 deletions(-) diff --git a/term-utils/scriptreplay.c b/term-utils/scriptreplay.c index 952b2c845..78e2daa4d 100644 --- a/term-utils/scriptreplay.c +++ b/term-utils/scriptreplay.c @@ -76,9 +76,11 @@ enum { }; struct replay_log { - const char *streams; /* 'I'nput, 'O'utput or both */ + const char *streams; /* 'I'nput, 'O'utput or both */ const char *filename; FILE *fp; + + unsigned int noseek; /* do not seek in this log */ }; struct replay_step { @@ -86,6 +88,9 @@ struct replay_step { double delay; size_t size; + char *name; /* signals / heders */ + char *value; + struct replay_log *data; }; @@ -139,6 +144,28 @@ static int replay_set_crmode(struct replay_setup *stp, int mode) return 0; } +static struct replay_log *replay_new_log(struct replay_setup *stp, + const char *streams, + const char *filename, + FILE *f) +{ + struct replay_log *log; + + assert(stp); + assert(streams); + assert(filename); + + stp->logs = xrealloc(stp->logs, (stp->nlogs + 1) * sizeof(*log)); + log = &stp->logs[stp->nlogs]; + stp->nlogs++; + + log->filename = filename; + log->streams = streams; + log->fp = f; + + return log; +} + static int replay_set_timing_file(struct replay_setup *stp, const char *filename) { int c, rc = 0; @@ -170,30 +197,39 @@ static int replay_set_timing_file(struct replay_setup *stp, const char *filename stp->timing_fp = NULL; } + /* create quasi-log for signals, headers, etc. */ + if (rc == 0 && stp->timing_format == REPLAY_TIMING_MULTI) { + struct replay_log *log = replay_new_log(stp, "SH", + filename, stp->timing_fp); + if (!log) + rc = -ENOMEM; + else { + log->noseek = 1; + DBG(LOG, ul_debug("accociate log file '%s' with 'SH'", filename)); + } + } + DBG(TIMING, ul_debug("timing file set to '%s' [rc=%d]", filename, rc)); return rc; } + static int replay_associate_log(struct replay_setup *stp, const char *streams, const char *filename) { - struct replay_log *log; + FILE *f; int rc; assert(stp); assert(streams); assert(filename); - stp->logs = xrealloc(stp->logs, (stp->nlogs + 1) * sizeof(*log)); - log = &stp->logs[stp->nlogs]; - stp->nlogs++; - - log->filename = filename; - log->streams = streams; - /* open the file and skip the first line */ - log->fp = fopen(filename, "r"); - rc = log->fp == NULL ? -errno : ignore_line(log->fp); + f = fopen(filename, "r"); + rc = f == NULL ? -errno : ignore_line(f); + + if (rc == 0) + replay_new_log(stp, streams, filename, f); DBG(LOG, ul_debug("accociate log file '%s' with '%s' [rc=%d]", filename, streams, rc)); return rc; @@ -208,11 +244,22 @@ static int is_wanted_stream(char type, const char *streams) return 0; } +static void replay_reset_step(struct replay_step *step) +{ + assert(step); + + step->size = 0; + step->delay = 0; + step->data = NULL; + step->type = 0; +} + static int read_multistream_step(struct replay_step *step, FILE *f, char type) { int rc = 0; char nl; + switch (type) { case 'O': /* output */ case 'I': /* input */ @@ -224,12 +271,34 @@ static int read_multistream_step(struct replay_step *step, FILE *f, char type) break; case 'S': /* signal */ - rc = ignore_line(f); /* not implemnted yet */ - break; - case 'H': /* header */ - rc = ignore_line(f); /* not implemnted yet */ + { + char buf[BUFSIZ]; + + rc = fscanf(f, "%lf ", &step->delay); /* delay */ + if (rc != 1) + break; + + rc = fscanf(f, "%s", buf); /* name */ + if (rc != 1) + break; + step->name = strrealloc(step->name, buf); + if (!step->name) + err_oom(); + + if (!fgets(buf, sizeof(buf), f)) { /* value */ + rc = -errno; + break; + } + if (*buf) { + strrem(buf, '\n'); + step->value = strrealloc(step->value, buf); + if (!step->value) + err_oom(); + } + rc = 0; break; + } default: break; } @@ -253,6 +322,9 @@ static struct replay_log *replay_get_stream_log(struct replay_setup *stp, char s static int replay_seek_log(struct replay_log *log, size_t move) { + if (log->noseek) + return 0; + DBG(LOG, ul_debug(" %s: seek ++ %zu", log->filename, move)); return fseek(log->fp, move, SEEK_CUR) == (off_t) -1 ? -errno : 0; } @@ -284,7 +356,7 @@ static int replay_get_next_step(struct replay_setup *stp, char *streams, struct DBG(TIMING, ul_debug("reading next step")); - memset(step, 0, sizeof(*step)); + replay_reset_step(step); stp->timing_line++; switch (stp->timing_format) { @@ -348,6 +420,23 @@ static int replay_emit_step_data(struct replay_setup *stp, struct replay_step *s assert(stp); assert(step); + switch (step->type) { + case 'S': + assert(step->name); + assert(step->value); + dprintf(fd, "%s %s\n", step->name, step->value); + DBG(LOG, ul_debug("log signal emited")); + return 0; + case 'H': + assert(step->name); + assert(step->value); + dprintf(fd, "%10s: %s\n", step->name, step->value); + DBG(LOG, ul_debug("log signal emited")); + return 0; + default: + break; /* continue with real data */ + } + assert(step->size); assert(step->data); assert(step->data->fp); @@ -428,7 +517,7 @@ usage(void) fputs(USAGE_SEPARATOR, out); fputs(_(" -d, --divisor speed up or slow down execution with time divisor\n"), out); fputs(_(" -m, --maxdelay wait at most this many seconds between updates\n"), out); - fputs(_(" -x, --stream stream type (out, in or signal)\n"), out); + fputs(_(" -x, --stream stream type (out, in, signal or info)\n"), out); fputs(_(" -c, --cr-mode CR char mode (auto, never, always)\n"), out); printf(USAGE_HELP_OPTIONS(25)); @@ -573,6 +662,8 @@ main(int argc, char *argv[]) appendchr(streams, sizeof(streams), 'O'); else if (strcmp("signal", optarg) == 0) appendchr(streams, sizeof(streams), 'S'); + else if (strcmp("info", optarg) == 0) + appendchr(streams, sizeof(streams), 'H'); else errx(EXIT_FAILURE, _("unsupported stream name: '%s'"), optarg); break; @@ -588,11 +679,7 @@ main(int argc, char *argv[]) argv += optind; idx = 0; - if ((argc < 1 && !(log_out || log_in || log_io)) || argc > 3) { - warnx(_("wrong number of arguments")); - errtryhelp(EXIT_FAILURE); - } - if (!log_tm) + if (!log_tm && idx < argc) log_tm = argv[idx++]; if (!log_out && !log_in && !log_io) log_out = idx < argc ? argv[idx++] : "typescript"; @@ -604,7 +691,10 @@ main(int argc, char *argv[]) if (!log_tm) errx(EXIT_FAILURE, _("timing file not specified")); - else if (replay_set_timing_file(&setup, log_tm) != 0) + if (!(log_out || log_in || log_io)) + errx(EXIT_FAILURE, _("data log file not specified")); + + if (replay_set_timing_file(&setup, log_tm) != 0) err(EXIT_FAILURE, _("cannot open %s"), log_tm); if (log_out && replay_associate_log(&setup, "O", log_out) != 0)