summary refs log blame commit diff stats
path: root/specials/file-replace.c
blob: 2e01367d148261d2cfd7f9f3f21d643e8a94239b (plain) (tree)






















































































































                                                                                                           
#include <stdio.h>
#include <stdlib.h>

/* for ftruncate */
#include <unistd.h>
#include <sys/types.h>

size_t str_length(char *s)
{
	size_t n = 0;
	while (*s++ != '\0') {
		n++;
	}
	return n;
}

int str_equal(char *a, char *b)
{
	do {
		if (*a++ != *b++) {
			return 0;
		}
	} while (*b != '\0');
	return 1;
}

long find_in_file(FILE *f, char *needle)
{
	size_t nlen = str_length(needle);
	long pos = 0;
	char *str = malloc(nlen + 1);
	while (!feof(f) || !ferror(f)) {
		if (fread(str, 1, nlen, f) != nlen) {
			break;
		}
		str[nlen] = '\0';
		//printf("%ld: %s\n", ftell(f), str);
		if (str_equal(str, needle)) {
			return pos;
		}
		fseek(f, ++pos, SEEK_SET);
	}
	free(str);
	return -1;
}

void move_char(FILE *f, long src, long dst)
{
	int c;
	fseek(f, src, SEEK_SET);
	c = fgetc(f);
	fseek(f, dst, SEEK_SET);
	fputc(c, f);
}

void file_move_contents(FILE *f, long from, long to, long end)
{
	int c;
	long p, q;
	if (from < to) {
		// in case of moving to the right side, 
		// we start from right end and move backwards to the start
		for (p = end, q = end + to - from; p >= from; p--, q--) {
			move_char(f, p, q);
		}
	} else {
		// otherwise, we start from the left and move towards
		// the right
		for (p = from, q = to; p <= end; p++, q++) {
			move_char(f, p, q);
		}
	}
}

int main(int argc, char **argv)
{
	FILE *f;
	int fd;
	long pos;
	long olen, nlen, end;
	if (argc < 4) {
		printf("Usage: %s [file] [needle] [replacement]\n", argv[0]);
		printf("Replaces needle in the contents of file with replacement.\n\n");
		return 2;
	}
	if (argv[2][0] == '\0') {
		printf("%s: Invalid needle: needle can not be empty.\n", argv[0]);
		return 3;
	}
	f = fopen(argv[1], "r+");
	if (f == NULL) {
		printf("%s: Error: Can not open file `%s` for reading.\n",
			argv[0], argv[1]);
		return 1;
	}
	pos = find_in_file(f, argv[2]);
	if (pos == -1) {
		printf("The string \"%s\" is not found in file `%s`\n",
			argv[2], argv[1]);
	} else {
		printf("The string \"%s\" is found in file `%s` at position %ld\n", argv[2], argv[1], pos);
		fseek(f, 0L, SEEK_END);
		end = ftell(f);
		olen = str_length(argv[2]);
		nlen = str_length(argv[3]);
		file_move_contents(f, pos + olen, pos + nlen, end - 1);
		// write down the replacement in the right place
		fseek(f, pos, SEEK_SET);
		fwrite(argv[3], 1, nlen, f);
		fseek(f, 0L, SEEK_END);
		end = ftell(f);
		// truncate the file to the right size
		fd = fileno(f);
		ftruncate(fd, end + nlen - olen);
	}
	fclose(f);
	return 0;
}