summary refs log tree commit diff
path: root/ring.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ring.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/ring.c b/ring.c
index f99d9d4..620f490 100644
--- a/ring.c
+++ b/ring.c
@@ -30,7 +30,9 @@ static struct {
 } ring;
 
 void ringAlloc(size_t len) {
-	if (len & (len - 1)) errx(EX_CONFIG, "ring length must be power of two");
+	if (len & (len - 1)) {
+		errx(EX_CONFIG, "ring length must be power of two: %zu", len);
+	}
 	ring.lines = calloc(len, sizeof(*ring.lines));
 	if (!ring.lines) err(EX_OSERR, "calloc");
 	ring.times = calloc(len, sizeof(*ring.times));
@@ -116,7 +118,10 @@ void ringInfo(void) {
 	}
 }
 
-static const size_t FileVersion = 0x0165636E756F70;
+static const size_t FileVersion[] = {
+	0x0165636E756F70,
+	0x0265636E756F70,
+};
 
 static int writeSize(FILE *file, size_t value) {
 	return (fwrite(&value, sizeof(value), 1, file) ? 0 : -1);
@@ -129,7 +134,8 @@ static int writeString(FILE *file, const char *str) {
 }
 
 int ringSave(FILE *file) {
-	if (writeSize(file, FileVersion)) return -1;
+	if (writeSize(file, FileVersion[1])) return -1;
+	if (writeSize(file, ring.len)) return -1;
 	if (writeSize(file, producer)) return -1;
 	if (writeSize(file, consumers.len)) return -1;
 	for (size_t i = 0; i < consumers.len; ++i) {
@@ -166,8 +172,16 @@ void ringLoad(FILE *file) {
 	fread(&version, sizeof(version), 1, file);
 	if (ferror(file)) err(EX_IOERR, "fread");
 	if (feof(file)) return;
+	if (version != FileVersion[0] && version != FileVersion[1]) {
+		errx(EX_DATAERR, "unknown file version %zX", version);
+	}
+
+	size_t saveLen = 4096;
+	if (version == FileVersion[1]) readSize(file, &saveLen);
+	if (saveLen > ring.len) {
+		errx(EX_DATAERR, "cannot load save with larger ring");
+	}
 
-	if (version != FileVersion) errx(EX_DATAERR, "unknown file version");
 	readSize(file, &producer);
 
 	char *buf = NULL;
@@ -181,15 +195,23 @@ void ringLoad(FILE *file) {
 		readSize(file, &consumers.ptr[consumer].pos);
 	}
 
-	for (size_t i = 0; i < ring.len; ++i) {
+	for (size_t i = 0; i < saveLen; ++i) {
 		readTime(file, &ring.times[i]);
 	}
-	for (size_t i = 0; i < ring.len; ++i) {
+	for (size_t i = 0; i < saveLen; ++i) {
 		readString(file, &buf, &cap);
 		if (feof(file)) break;
 		ring.lines[i] = strdup(buf);
 		if (!ring.lines[i]) err(EX_OSERR, "strdup");
 	}
-
 	free(buf);
+
+	if (ring.len > saveLen) {
+		producer %= saveLen;
+		for (size_t i = 0; i < consumers.len; ++i) {
+			struct Consumer *consumer = &consumers.ptr[i];
+			consumer->pos %= saveLen;
+			if (consumer->pos > producer) consumer->pos = 0;
+		}
+	}
 }