summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Smith <jules@op59.net>2020-02-24 17:30:54 +0000
committerChris Liddell <chris.liddell@artifex.com>2020-02-26 08:18:49 +0000
commit6c1002cc251907e702fd5db9dc81365a964816c6 (patch)
treec988c07cccafb5822498ed164a645dddc90bf12e
parent39557bd53eee75a8b8f762457ce57a5437e79d6c (diff)
downloadghostpdl-6c1002cc251907e702fd5db9dc81365a964816c6.tar.gz
Add support for multiple squeezes in one run.
E.g. MEMENTO_SQUEEZES=115867-1..+3,119928-1..+3 ... This is equivalent running multiple times with MEMENTO_FAILAT set to 115866, 115867, 11588, 119927, 119928, 119929.
-rw-r--r--base/memento.c245
1 files changed, 244 insertions, 1 deletions
diff --git a/base/memento.c b/base/memento.c
index 4069c85e9..50eed104f 100644
--- a/base/memento.c
+++ b/base/memento.c
@@ -48,6 +48,7 @@ int atexit(void (*)(void));
#include <unistd.h>
#endif
+#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
@@ -402,6 +403,11 @@ static void Memento_initMutex(Memento_mutex *m)
#endif
#endif
+typedef struct {
+ int begin;
+ int end;
+} Memento_range;
+
/* And our global structure */
static struct {
int inited;
@@ -432,6 +438,9 @@ static struct {
size_t numFrees;
size_t numReallocs;
Memento_mutex mutex;
+ Memento_range *squeezes;
+ int squeezes_num;
+ int squeezes_pos;
} memento;
#define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize)
@@ -1623,6 +1632,184 @@ void Memento_fin(void)
}
}
+/* Reads number from <text> using strtol().
+
+Params:
+ text:
+ text to read.
+ out:
+ pointer to output value.
+ relative:
+ *relative set to 1 if <text> starts with '+' or '-', else set to 0.
+ end:
+ *end is set to point to next unread character after number.
+
+Returns 0 on success, else -1.
+*/
+static int read_number(const char *text, int *out, int *relative, char **end)
+{
+ if (text[0] == '+' || text[0] == '-') {
+ *relative = 1;
+ }
+ else {
+ *relative = 0;
+ }
+ errno = 0;
+ *out = strtol(text, end, 0 /*base*/);
+ if (errno || *end == text) {
+ fprintf(stderr, "Failed to parse number at start of '%s'.\n", text);
+ return -1;
+ }
+ if (0) fprintf(stderr, "text='%s': *out=%i *relative=%i\n",
+ text, *out, *relative);
+ return 0;
+}
+
+/* Reads number plus optional delta value from <text>.
+
+Evaluates <number> or <number>[+|-<delta>]. E.g. text='1234+2' sets *out=1236,
+text='1234-1' sets *out=1233.
+
+Params:
+ text:
+ text to read.
+ out:
+ pointer to output value.
+ end:
+ *end is set to point to next unread character after number.
+
+Returns 0 on success, else -1.
+*/
+static int read_number_delta(const char *text, int *out, char **end)
+{
+ int e;
+ int relative;
+ e = read_number(text, out, &relative, end);
+ if (e) {
+ return e;
+ }
+ if (relative) {
+ fprintf(stderr, "Base number should not start with '+' or '-' at start of '%s'.\n",
+ text);
+ return -1;
+ }
+ if (*end) {
+ if (**end == '-' || **end == '+') {
+ int delta;
+ e = read_number(*end, &delta, &relative, end);
+ if (e) {
+ return e;
+ }
+ *out += delta;
+ }
+ }
+ if (0) fprintf(stderr, "text='%s': *out=%i\n", text, *out);
+ return 0;
+}
+
+/* Reads range.
+
+E.g.:
+ text='115867-2' sets *begin=115865 *end=115866.
+ text='115867-1..+3' sets *begin=115866 *end=115869.
+
+Supported patterns for text:
+ <range>
+ <value> - returns *begin=value *end=*begin+1.
+ <value1>..<value2> - returns *begin=value1 *end=value2.
+ <value>..+<number> - returns *begin=value *end=*begin+number.
+ <value>
+ <number>
+ <number>+<number>
+ <number>-<number>
+
+ <number>: [0-9]+
+
+If not specified, *end defaults to *begin+1.
+
+Returns 0 on success, else -1, with *string_end pointing to first unused
+character.
+*/
+static int read_number_range(const char *text, int *begin, int *end, char **string_end)
+{
+ int e;
+ e = read_number_delta(text, begin, string_end);
+ if (e) {
+ return e;
+ }
+ if (string_end && (*string_end)[0] == '.' && (*string_end)[1] == '.') {
+ int relative;
+ e = read_number((*string_end) + 2, end, &relative, string_end);
+ if (e) {
+ return e;
+ }
+ if (relative) {
+ *end += *begin;
+ }
+ }
+ else {
+ *end = *begin + 1;
+ }
+ if (*end < *begin) {
+ fprintf(stderr, "Range %i..%i has negative extent, at start of '%s'.\n",
+ *begin, *end, text);
+ return -1;
+ }
+ if (0) fprintf(stderr, "text='%s': *begin=%i *end=%i\n", text, *begin, *end);
+ return 0;
+}
+
+/*
+Format: <range>[,<range>]+
+
+For description of <range>, see read_number_range() above.
+
+E.g.:
+ MEMENTO_SQUEEZES=1234-2..+4,2345,2350..+2
+*/
+static int Memento_add_squeezes(const char *text)
+{
+ int e = 0;
+ for(;;) {
+ int begin;
+ int end;
+ char *string_end;
+ if (!*text) {
+ break;
+ }
+ e = read_number_range(text, &begin, &end, &string_end);
+ if (e) {
+ break;
+ }
+ if (*string_end && *string_end != ',') {
+ fprintf(stderr, "Expecting comma at start of '%s'.\n", string_end);
+ e = -1;
+ break;
+ }
+ fprintf(stderr, "Adding squeeze range %i..%i.\n",
+ begin, end, string_end-text);
+ memento.squeezes_num += 1;
+ memento.squeezes = MEMENTO_UNDERLYING_REALLOC(
+ memento.squeezes,
+ memento.squeezes_num * sizeof(*memento.squeezes)
+ );
+ if (!memento.squeezes) {
+ fprintf(stderr, "Failed to allocate memory for memento.squeezes_num=%i\n",
+ memento.squeezes_num);
+ e = -1;
+ break;
+ }
+ memento.squeezes[memento.squeezes_num-1].begin = begin;
+ memento.squeezes[memento.squeezes_num-1].end = end;
+
+ if (*string_end == 0) {
+ break;
+ }
+ text = string_end + 1;
+ }
+ return e;
+}
+
static void Memento_init(void)
{
char *env;
@@ -1634,6 +1821,9 @@ static void Memento_init(void)
memento.free.tail = NULL;
memento.sequence = 0;
memento.countdown = 1024;
+ memento.squeezes = NULL;
+ memento.squeezes_num = 0;
+ memento.squeezes_pos = 0;
env = getenv("MEMENTO_FAILAT");
memento.failAt = (env ? atoi(env) : 0);
@@ -1652,6 +1842,17 @@ static void Memento_init(void)
env = getenv("MEMENTO_SQUEEZEAT");
memento.squeezeAt = (env ? atoi(env) : 0);
+ env = getenv("MEMENTO_SQUEEZES");
+ if (env) {
+ int e;
+ fprintf(stderr, "Parsing squeeze ranges in MEMENTO_SQUEEZES=%s\n", env);
+ e = Memento_add_squeezes(env);
+ if (e) {
+ fprintf(stderr, "Failed to parse MEMENTO_SQUEEZES=%s\n", env);
+ exit(1);
+ }
+ }
+
env = getenv("MEMENTO_PATTERN");
memento.pattern = (env ? atoi(env) : 0);
@@ -1791,6 +1992,11 @@ static int squeeze(void)
} else
memento.patternBit <<= 1;
memento.squeezing = 1;
+
+ /* This is necessary to allow Memento_failThisEventLocked() near the
+ end to do 'return squeeze();'. */
+ memento.squeezes_num = 0;
+
return 1;
}
@@ -1979,9 +2185,46 @@ static int Memento_failThisEventLocked(void)
if (Memento_event()) Memento_breakpointLocked();
+ if (!memento.squeezing && memento.squeezes_num) {
+ /* Move to next relevant squeeze region if appropriate. */
+ for(;;) {
+ if (memento.squeezes_pos == memento.squeezes_num) {
+ break;
+ }
+ if (memento.sequence >= memento.squeezes[memento.squeezes_pos].end) {
+ memento.squeezes_pos += 1;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* See whether memento.sequence is within this squeeze region. */
+ if (memento.squeezes_pos < memento.squeezes_num) {
+ int begin = memento.squeezes[memento.squeezes_pos].begin;
+ int end = memento.squeezes[memento.squeezes_pos].end;
+ if (memento.sequence >= begin && memento.sequence < end) {
+ if (1) {
+ fprintf(stderr,
+ "squeezes match memento.sequence=%i: memento.squeezes_pos=%i/%i %i..%i\n",
+ memento.sequence,
+ memento.squeezes_pos,
+ memento.squeezes_num,
+ memento.squeezes[memento.squeezes_pos].begin,
+ memento.squeezes[memento.squeezes_pos].end
+ );
+ }
+ return squeeze();
+ }
+ }
+ }
+
if ((memento.sequence >= memento.failAt) && (memento.failAt != 0))
Memento_startFailing();
- if ((memento.sequence >= memento.squeezeAt) && (memento.squeezeAt != 0)) {
+ if (memento.squeezes_num==0
+ && (memento.sequence >= memento.squeezeAt)
+ && (memento.squeezeAt != 0)
+ ) {
return squeeze();
}