summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bounce.c12
-rw-r--r--pounce.111
-rw-r--r--ring.c36
3 files changed, 48 insertions, 11 deletions
diff --git a/bounce.c b/bounce.c
index 34a56a8..b26a1cb 100644
--- a/bounce.c
+++ b/bounce.c
@@ -102,6 +102,7 @@ int main(int argc, char *argv[]) {
 	char certPath[PATH_MAX] = "";
 	char privPath[PATH_MAX] = "";
 	const char *save = NULL;
+	size_t ring = 4096;
 
 	bool insecure = false;
 	const char *host = NULL;
@@ -115,7 +116,7 @@ int main(int argc, char *argv[]) {
 	const char *away = "pounced :3";
 	const char *quit = "connection reset by purr";
 
-	const char *Opts = "!A:C:H:K:NP:Q:W:a:f:h:j:n:p:r:u:vw:";
+	const char *Opts = "!A:C:H:K:NP:Q:W:a:f:h:j:n:p:r:s:u:vw:";
 	const struct option LongOpts[] = {
 		{ "insecure", no_argument, NULL, '!' },
 		{ "away", required_argument, NULL, 'A' },
@@ -133,6 +134,7 @@ int main(int argc, char *argv[]) {
 		{ "nick", required_argument, NULL, 'n' },
 		{ "port", required_argument, NULL, 'p' },
 		{ "real", required_argument, NULL, 'r' },
+		{ "size", required_argument, NULL, 's' },
 		{ "user", required_argument, NULL, 'u' },
 		{ "verbose", no_argument, NULL, 'v' },
 		{ "pass", required_argument, NULL, 'w' },
@@ -158,6 +160,11 @@ int main(int argc, char *argv[]) {
 			break; case 'n': nick = optarg;
 			break; case 'p': port = optarg;
 			break; case 'r': real = optarg;
+			break; case 's': {
+				char *rest;
+				ring = strtoull(optarg, &rest, 0);
+				if (*rest) errx(EX_USAGE, "invalid size: %s", optarg);
+			}
 			break; case 'u': user = optarg;
 			break; case 'v': verbose = true;
 			break; case 'w': pass = optarg;
@@ -171,7 +178,6 @@ int main(int argc, char *argv[]) {
 	if (!privPath[0]) {
 		snprintf(privPath, sizeof(privPath), DEFAULT_PRIV_PATH, bindHost);
 	}
-
 	if (!host) errx(EX_USAGE, "no host");
 	if (!nick) {
 		nick = getenv("USER");
@@ -180,7 +186,7 @@ int main(int argc, char *argv[]) {
 	if (!user) user = nick;
 	if (!real) real = nick;
 
-	ringAlloc(4096);
+	ringAlloc(ring);
 	if (save) saveLoad(save);
 
 	int bind[8];
diff --git a/pounce.1 b/pounce.1
index f83882a..a3bfdd8 100644
--- a/pounce.1
+++ b/pounce.1
@@ -1,4 +1,4 @@
-.Dd October 29, 2019
+.Dd October 30, 2019
 .Dt POUNCE 1
 .Os
 .
@@ -23,6 +23,7 @@
 .Op Fl n Ar nick
 .Op Fl p Ar port
 .Op Fl r Ar real
+.Op Fl s Ar size
 .Op Fl u Ar user
 .Op Fl w Ar pass
 .Op Ar config ...
@@ -144,6 +145,14 @@ Set realname to
 .Ar real .
 The default realname is the same as the nickname.
 .
+.It Fl s Ar size , Cm size = Ar size
+Set the buffer
+.Ar size .
+This determines the maximum number of messages
+stored in memory.
+The size must be a power of two.
+The default size is 4096.
+.
 .It Fl u Ar user , Cm user = Ar user
 Set username to
 .Ar user .
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;
+		}
+	}
 }