Reputation: 22203
In order not to forget C (at work I mostly have to deal with XSLT and other languages that are much less fun), from time to time I like to write a small utility program.
An application that replaces strings in any kind of file without producing a second file (is there a nicer phrase that describes this?) is what came to my mind today.
What I have come up with is as follows:
#include <stdio.h>
#include <string.h>
#define CHUNKLEN 256
void replcnks(char *str, char *cnk1, char *cnk2);
int main(int argc, char **argv)
{
FILE *file;
char *old, *new, *fname, buf[CHUNKLEN];
long len;
if(argc != 4)
{
puts("Invalid arguments\n");
return 0;
}
old = argv[1];
new = argv[2];
fname = argv[3];
file = fopen(fname, "rb+");
do
{
len = fread(buf, 1, CHUNKLEN, file);
replcnks(buf, old, new);
fseek(file, -len, SEEK_CUR);
fwrite(buf, 1, len, file);
fseek(file, len, SEEK_CUR);
}
while(len == CHUNKLEN);
fclose(file);
return 0;
}
void replcnks(char *str, char *cnk1, char *cnk2)
{
char *pos;
int clen1 = strlen(cnk1), clen2 = strlen(cnk2);
while((pos = strstr(str, cnk1)))
{
memmove(pos + clen2, pos + clen1, strlen(pos) - clen1 + 1);
memcpy(pos, cnk2, clen2);
}
}
The program works, but it produces minor errors when the replacement string has a different size than the original one. When it is longer, the ending of the file is cut; when it is shorter, the output has a few garbage values in some places. I guess the problem lies in one of the fseek
s.
How to fix this program?
The solution is probably straightforward, but I guess I'm out of brainpower today - but I would like to sleep peacefully :).
Upvotes: 0
Views: 285
Reputation: 16582
You can't really do what you're trying to do, as there's no good way to replace a chunk of a file with a differently sized chunk.
It also fails if the string being replaced falls across a chunk boundary.
And it'll probably do very bad things if replacing a short string with a longer one, as you don't have room in the buffer for that.
If you really really wanted to do this, you'd have to have some kind of buffering scheme where you track reading and writing separately, such that you don't write bytes you haven't read yet. And then you'll still have to cope with growing or truncating the file...
Upvotes: 4
Reputation: 2993
What JasonD said - you're trying to over-write a bit of a file with a differently-sized bit of a file, the filesystem has no way of magically shrinking/expanding the middle of the file to suit. I'd load the source into RAM and then either create a new file, or delete/rename/backup the source and then write the result with the original name.
Upvotes: 1