about summary refs log tree commit diff
path: root/holes.c
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-08-21 20:17:03 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-08-21 20:17:03 +0200
commite8269dc42cceedd2e82ebf860b1f3fa8a8b69ded (patch)
treea9c06a7756f4e22b2bee0f568f6d050c5cdbee6a /holes.c
parentde5d95e0fb849c74e05a865fa2c2e1abf7800cf9 (diff)
downloadholes-e8269dc42cceedd2e82ebf860b1f3fa8a8b69ded.tar.gz
holes-e8269dc42cceedd2e82ebf860b1f3fa8a8b69ded.tar.xz
holes-e8269dc42cceedd2e82ebf860b1f3fa8a8b69ded.zip
holes: don't use bytewise i/o
Use fread to reduce overhead of calling stdio.
Then use memchr to find the initial thing we search for (to dismiss
nonmatching blocks quickly), then loop manually while it matches.
Diffstat (limited to 'holes.c')
-rw-r--r--holes.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/holes.c b/holes.c
index 41fc50c..6bff701 100644
--- a/holes.c
+++ b/holes.c
@@ -16,20 +16,37 @@ holes(FILE *input, char *filename)
 {
 	off_t offset = 0;
 	off_t run = 0;	
-	int ch;
+	static char buf[16384];
 
-	while ((ch = getc_unlocked(input)) != EOF) {
-		if (ch == byte) {
-			run++;
+	int len;
+	int i;
+	char *d;
+
+	while ((len = fread(buf, 1, sizeof buf, input)) >= 1) {
+		if (run == 0) {
+			d = memchr(buf, byte, len);
+			if (!d) {
+				offset += len;
+				continue;
+			}
+			i = d - buf;
+			offset += i;
 		} else {
-			if (run >= minlen) {
-				if (filename)
-					printf("%s: ", filename);
-				printf("%08lx %ld\n", offset - run, run);
+			i = 0;
+		}
+		for (; i < len; i++) {
+			if (buf[i] == byte) {
+				run++;
+			} else {
+				if (run >= minlen) {
+					if (filename)
+						printf("%s: ", filename);
+					printf("%08lx %ld\n", offset - run, run);
+				}
+				run = 0;
 			}
-			run = 0;
+			offset++;
 		}
-		offset++;
 	}
 	if (ferror(input)) {
 		fprintf(stderr, "%s: can't read '%s': %s\n",