filter.c
changeset 0 7f37716d4f1e
child 1 5af08d964c9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/filter.c	Sun Aug 05 23:06:42 2007 +0200
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "dictre.h"
+
+extern struct Def defs[];
+extern int ndefs;
+extern int dont_touch[];
+extern int ndont_touch;
+
+static void more_memory(void **ptr, int size)
+{
+    void *new;
+
+    new = realloc(*ptr, size);
+    *ptr = new;
+}
+
+static
+char * manage_filter(const char *def, int deflen, int writeto, int readfrom,
+        int *outlen)
+{
+    int maxfd;
+    int defptr;
+    int outptr;
+    char *out;
+    int outsize;
+    int outrest;
+
+    out = 0;
+    outsize = 1000;
+    outptr = 0;
+    more_memory((void **) &out, outsize);
+    outrest = 1000;
+
+    maxfd = writeto;
+    if (readfrom > maxfd)
+        maxfd = readfrom;
+
+    defptr = 0;
+    do
+    {
+        fd_set writeset, readset;
+        FD_ZERO(&writeset);
+        FD_ZERO(&readset);
+        if (defptr < deflen)
+            FD_SET(writeto, &writeset);
+        FD_SET(readfrom, &readset);
+
+        select(maxfd+1, &readset, &writeset, 0, 0);
+
+        if (FD_ISSET(readfrom, &readset))
+        {
+            int res;
+            res = read(readfrom, out + outptr, outrest);
+            if (res == 0)
+            {
+                close(readfrom);
+                break;
+            }
+            outrest -= res;
+            outptr += res;
+            if (outrest == 0)
+            {
+                outrest = 1000;
+                outsize += 1000;
+                more_memory((void **) &out, outsize);
+            }
+        }
+
+        if (FD_ISSET(writeto, &writeset))
+        {
+            int res;
+            res = write(writeto, def+defptr, 1);
+            defptr++;
+            if (defptr >= deflen)
+                close(writeto);
+        }
+    } while(1);
+
+    if (defptr < deflen)
+    {
+        fprintf(stderr, "Error in filter! not all written.\n");
+        exit(-1);
+    }
+
+    *outlen = outptr;
+    return out;
+}
+
+static char * filter(char *def, int deflen, const char *filter_par, int *outlen)
+{
+    int write_pipe[2];
+    int read_pipe[2];
+    int pid;
+    int res;
+    int status;
+    char *out;
+
+    pipe(write_pipe);
+    pipe(read_pipe);
+
+
+    pid = fork();
+    switch(pid)
+    {
+        case 0:  /* child */
+            close(0);
+            dup(write_pipe[0]);
+            close(write_pipe[0]);
+            close(write_pipe[1]);
+            close(1);
+            dup(read_pipe[1]);
+            close(read_pipe[1]);
+            close(read_pipe[0]);
+            execlp("bash", "bash", "-c", filter_par, 0);
+            perror("execlp");
+            exit(-1);
+            break;
+        case -1:
+            perror("fork");
+            exit(-1);
+            break;
+        default:  /* parent */
+            close(write_pipe[0]);
+            close(read_pipe[1]);
+            break;
+    }
+
+    /* parent */
+    out = manage_filter(def, deflen, write_pipe[1], read_pipe[0], outlen);
+
+    res = wait(&status);
+    if (res != pid || WEXITSTATUS(status) != 0)
+    {
+        fprintf(stderr, "Error filtering: pid=%i status=%i",
+                pid, WEXITSTATUS(status));
+        exit(-1);
+    }
+
+    return out;
+}
+
+static int in_dont_touch(int n)
+{
+    int i;
+    for(i =0; i < ndont_touch; ++i)
+    {
+        if (n == dont_touch[i])
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void filter_all(const char *filter_par)
+{
+    int i;
+
+    for(i=0; i < ndefs; ++i)
+    {
+        char *newdef;
+        int newdeflen;
+        if (!in_dont_touch(i))
+        {
+            newdef = filter(defs[i].d, defs[i].length,
+                    filter_par, &newdeflen);
+            defs[i].length = newdeflen;
+            defs[i].d = newdef;
+        }
+    }
+}