Commits

Anonymous committed 5a4be7d

add first pass at find_replace

  • Participants
  • Parent commits d721e79

Comments (0)

Files changed (1)

+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define check_goto(label, expr, msg) ({ if (!(expr)) { fprintf(stderr, "%s: " msg " %s: %s\n", *argv, *path, strerror(errno)); goto label; } })
+
+int read_all(int fd, char *buf, size_t count)
+{
+	ssize_t red;
+	while (count) {
+		if ((red = read(fd, buf, count)) < 0) {
+			if (errno == EINTR)
+				continue;
+			else
+				return -1;
+		}
+		buf   += red;
+		count -= red;
+	}
+	return 0;
+}
+
+int write_all(int fd, char *buf, size_t count)
+{
+	ssize_t wrote;
+	while (count) {
+		if ((wrote = write(fd, buf, count)) < 0) {
+			if (errno == EINTR)
+				continue;
+			else
+				return -1;
+		}
+		buf   += wrote;
+		count -= wrote;
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	char **path, *beg, *end, *find, *repl, *p, *file = NULL;
+	int    fd = -1;
+	size_t count, find_len, repl_len;
+	off_t  size;
+
+	if (argc < 4 || strlen(argv[1]) == 0) {
+		fprintf(stderr, "Usage: %s find replace file...\n", *argv);
+		return 1;
+	}
+
+	find = argv[1];
+	repl = argv[2];
+	find_len = strlen(find);
+	repl_len = strlen(repl);
+
+	for (path = argv + 3; *path; path++) {
+		check_goto(cleanup,    0 <= (fd   = open  (*path, O_RDWR))  , "Failed to open"      );
+		check_goto(cleanup,    0 <= (size = lseek (fd, 0, SEEK_END)), "Failed to lseek EOF" );
+		if (size == 0) goto cleanup; // empty file
+		check_goto(cleanup,    0 == lseek   (fd, 0, SEEK_SET)       , "Failed to lseek BOF" );
+		check_goto(cleanup, NULL != (file = malloc(size))           , "Failed to malloc for");
+		check_goto(cleanup,    0 == read_all(fd, file, size)        , "Failed to read"      );
+		check_goto(cleanup,    0 == lseek   (fd, 0, SEEK_SET)       , "Failed to lseek BOF" );
+
+		for (beg = file, end = beg + size, size = 0; (p = memmem(beg, end - beg, find, find_len)); size += repl_len + (p - beg), beg = p + find_len) {
+			check_goto(cleanup, 0 == write_all(fd, beg , p - beg ), "Failed to write to");
+			check_goto(cleanup, 0 == write_all(fd, repl, repl_len), "Failed to write to");
+		}
+		check_goto(cleanup, 0 == write_all(fd, beg, end - beg), "Failed to write to");
+		size += end - beg;
+		check_goto(cleanup, 0 == ftruncate(fd, size)          , "Failed to truncate");
+
+cleanup:
+		if (fd >= 0 && close(fd) < 0) fprintf(stderr, "%s: Error closing %s: %s\n", *argv, *path, strerror(errno));
+		if (file) free(file);
+		fd   = -1;
+		file = NULL;
+	}
+
+	return 0;
+}