Initial. Seems to work.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Fri May 18 18:59:39 2007 +0200
@@ -0,0 +1,2 @@
+CFLAGS=-g -O0
+sreplace: sreplace.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sreplace.c Fri May 18 18:59:39 2007 +0200
@@ -0,0 +1,300 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+/* Kind of string parameters */
+static int hex_strings = 0;
+
+static FILE * input, * output;
+
+struct String
+{
+ char *ptr;
+ int length;
+};
+
+struct CmpState
+{
+ struct String *str;
+ int matched;
+};
+
+struct String old_str;
+struct String new_str;
+struct CmpState cmp_state;
+
+/* Buffer:
+ [F] - read
+ [F] - read_cmp
+ [F]
+ [F] - filled
+ [ ]
+ [ ]
+
+ In the circular sense:
+ read <= read_cmp < filled
+*/
+struct Buffer
+{
+ char *base;
+ int filled;
+ int read;
+ int read_cmp;
+ int size;
+};
+
+static int get_buffer_space(struct Buffer *b, int start, int end)
+{
+ int space;
+ space = end - start + b->size;
+ if (space > b->size)
+ space -= b->size;
+
+ return space;
+}
+
+static int min(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+static int one_before(struct Buffer *b, int pos)
+{
+ if (pos == 0)
+ return b->size - 1;
+
+ return pos - 1;
+}
+
+/* This should be called without any exceeding size */
+static int file_to_buffer(struct Buffer *b, int size)
+{
+ int blocksize;
+ int res;
+
+ blocksize = min(b->size - b->filled, size);
+ if (blocksize > 0)
+ {
+ res = fread(b->base + b->filled, 1, blocksize, input);
+ /*fprintf(stderr, "fread1 %i bytes (should %i).\n", res, blocksize);*/
+ size -= res;
+ b->filled = (b->filled + res) % b->size;
+
+ /* Check EOF */
+ if (res == 0)
+ return 0;
+ }
+
+ if (size > 0 && res == blocksize)
+ {
+ blocksize = min(b->read - 1, size);
+ res = fread(b->base, 1, blocksize, input);
+ /*fprintf(stderr, "fread2 %i bytes.\n", res);*/
+ size -= res;
+ b->filled = (b->filled + res) % b->size;
+ }
+ return 1;
+}
+
+static int file_read_more(struct Buffer *b)
+{
+ int can_read;
+ int res;
+
+ can_read = get_buffer_space(b, b->filled, b->read - 1);
+
+ /*fprintf(stderr, "file_to_buffer %i\n", can_read);*/
+
+ return file_to_buffer(b, can_read);
+}
+
+/* pos will be read or read_cmp, depending on
+ what to read */
+static int can_read_from_buffer(struct Buffer *b, int pos)
+{
+ /*
+ In the circular sense:
+ read <= read_cmp < filled
+ */
+ if (pos != b->filled)
+ return 1;
+ else
+ return 0;
+}
+
+static int getc_real(struct Buffer *b)
+{
+ int a;
+
+ if (!can_read_from_buffer(b, b->read))
+ a = EOF;
+ else
+ {
+ a = *(b->base + b->read);
+ b->read += 1;
+ if (b->read == b->size)
+ b->read = 0;
+ }
+ /*fprintf(stderr, "getc_real %x\n", a);*/
+
+ return a;
+}
+
+static int getc_cmp(struct Buffer *b)
+{
+ int a;
+ if (!can_read_from_buffer(b, b->read_cmp))
+ a = EOF;
+ else
+ {
+ a = *(b->base + b->read_cmp);
+ b->read_cmp += 1;
+ if (b->read_cmp == b->size)
+ b->read_cmp = 0;
+ }
+ /*fprintf(stderr, "getc_cmp %x\n", a);*/
+
+ return a;
+}
+
+/* This will not be moved farer than read_cmp */
+static void read_advance(struct Buffer *b, int adv)
+{
+ int i;
+ for (i=0; i < adv; ++i)
+ getc_real(b);
+};
+
+static void process_buffer(struct Buffer *b)
+{
+ int c;
+
+ while (1)
+ {
+ c = getc_cmp(b);
+
+ if (c == EOF)
+ break;
+
+ if (cmp_state.str->ptr[cmp_state.matched] == (char) c)
+ {
+ cmp_state.matched++;
+ if (cmp_state.matched == cmp_state.str->length)
+ {
+ fwrite(new_str.ptr, 1, new_str.length, output);
+ read_advance(b, cmp_state.matched);
+ cmp_state.matched = 0;
+ }
+ } else
+ {
+ int c;
+ c = getc_real(b); /* Will not be EOF. read_cmp is forwarder. */
+ fputc(c, output);
+ cmp_state.matched = 0;
+ b->read_cmp = b->read;
+ }
+ }
+}
+
+static void end_buffer(struct Buffer *b)
+{
+ int c;
+ while((c = getc_real(b)) != EOF)
+ fputc(c, output);
+}
+
+static void loop()
+{
+ struct Buffer b;
+
+ b.base = (char *) malloc(2048);
+ b.read = 0;
+ b.read_cmp = 0;
+ b.filled = 0;
+ b.size = 2048;
+
+ while(file_read_more(&b) > 0)
+ {
+ int c;
+ process_buffer(&b);
+ }
+
+ end_buffer(&b);;
+}
+
+static void show_usage(const char *pname)
+{
+ printf("usage: %s OLD_STR NEW_STR\n", pname);
+}
+
+static void parse_backslashes(char *str)
+{
+ int was_backslash = 0;
+ char *write_str = str;
+
+ while (*str != 0)
+ {
+ if (*str == '\\')
+ was_backslash = 1;
+ else
+ {
+ if (was_backslash)
+ {
+ switch(*str)
+ {
+ case '\\':
+ *(write_str++) = '\\';
+ break;
+ case 'n':
+ *(write_str++) = '\n';
+ break;
+ case 't':
+ *(write_str++) = '\t';
+ break;
+ default:
+ *(write_str++) = *str;
+ }
+ }
+ else
+ {
+ *(write_str++) = *str;
+ }
+ was_backslash = 0;
+ }
+ ++str;
+ }
+ *(write_str++) = '\0';
+}
+
+static void process_parameters(int argc, char **argv)
+{
+ if (argc != 3)
+ {
+ show_usage(argv[0]);
+ exit(1);
+ }
+
+ old_str.ptr = argv[1];
+ new_str.ptr = argv[2];
+
+ parse_backslashes(old_str.ptr);
+ parse_backslashes(new_str.ptr);
+
+ old_str.length = strlen(old_str.ptr);
+ new_str.length = strlen(new_str.ptr);
+}
+
+int main(int argc, char ** argv)
+{
+ process_parameters(argc, argv);
+
+ cmp_state.str = &old_str;
+ cmp_state.matched = 0;
+
+ input = stdin;
+ output = stdout;
+
+ loop();
+}