ein Kapitel zurück                                           ein Kapitel weiter

Im ersten Kapitel zu Pipe haben wir ein Programm geschrieben das aus einer Datei im Kindprozess gelesen hat. Dies gelesene haben wir dann in die Pipe geschrieben und der Elternprozess hat dies dann ausgelesen und wir haben es dann an die Standardausgabe auf dem Bildschirm weitergeleitet. Bei etwas längeren Texten zum Ausgeben war dies etwas unpassend, da der ganze Text auf einmal Ausgegeben wurde so das wir nicht sehen konnten was am Anfang des Textes stand. Nun könnte man natürlich hergehen und eine Funktion schreiben bei der wir alle 23 Zeilen aufgefordert werde ein Taste zu drücken damit wir die nächsten 23 Zeilen lesen können. Sicherlich es wäre ein gute Übung aber wozu das Rad wieder neu erfinden. Unix stellt uns dafür doch Funktionen wie z.B. less, pg, nl, tail, oder more zur Verfügung womit wir Zeilen - bzw. Seitenweise durch den Text blättern können. Wir wollen den Kindprozess mit dem Programm less überlagern.........

/*Download:pip4.c*/
#include <unistd.h> #include <sys/wait.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <signal.h> #define EXIT(s) {fprintf(stderr, "%s",s); exit(0);} #define USAGE(s) {fprintf(stderr, "%s Datei zum lesen\n",s); exit(0);} #define MAX 8192 enum {ERROR=-1,SUCCESS}; int main(int argc, char **argv) { int fd[2]; pid_t pid; FILE *pipe_writer, *file; char puffer[MAX]; if(argc!=2) USAGE(argv[0]); if((file=fopen(argv[1], "r")) == NULL) EXIT("Fehler bei fopen.........\n"); if(pipe(fd) == ERROR) EXIT("Fehler bei pipe.......\n"); if((pid=fork()) == ERROR) EXIT("Fehler bei fork......\n"); if(pid > 0) /*Elternprozess*/ { close(fd[0]); /*Wir schließen die Leseseite*/ if((pipe_writer = fdopen(fd[1], "w")) == NULL) EXIT("Fehler bei fdopen............\n"); fread(&puffer, MAX, 1, file); fputs(puffer, pipe_writer); /*Wir schreiben in die Pipe*/ fclose(pipe_writer); /*Mit dem schließen der Schreibseite */ /*teilen wir dem Kindprozess das Ende*/ /*des Schreiben in die Pipe mit*/ if(waitpid(pid,NULL,0) == ERROR) EXIT("Fehler bei waitpid.........\n"); exit(0); } else /*Kindprozess ließt aus der pipe mit less*/ { sleep(1); close(fd[1]); /*Schließen der Schreibseite*/ if(fd[0] != STDIN_FILENO) /*muss überprüft werden*/ { /*duplizieren Standardeingabe*/ if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) EXIT("Fehler bei dup2......\n"); close(fd[0]); /*Wird nicht mehr benötigt*/ } if(execl("/usr/bin/less", "less", NULL) == ERROR) ; EXIT("Fehler bei execl.......\n"); } }

Sehen sie sich dieses Beispiel doch anhand einer Grafik an......




Sieh sehen auf einmal bekommen all die Funktionen die sie bereits kennen langsam Ihren Sinn. Wichtig ist auch das sie bei der Standarteingabe dem Kindprozess die Leseseite der Pipe einrichten und mit einer exec - Funktion den Kindprozess überlagern.

Wenn sie sich die Grafik oben nochmals ansehen werden sie sich Fragen, ob man da nicht noch andere Programme dazwischenhängen kann?
Ja, den Pipes eignen sich Ideal für Filterprogramme. Zum Beispiel einen Druckerfilter um einen Text bestimmt formatiert auszugeben oder alle Buchstaben GROSS ausgeben. Wir wollen einen Filter schreiben der bestimmte Wörter ausfiltert und sie im Text dann als xxx angibt. Hier nun das Filterprogramm.........

/*Download:pip5.c*/
#include <stdio.h> #include <unistd.h> #include <string.h> #define MAX 255 char *filterwords[] = { "und" , "oder", "aber", "ein", NULL}; char token[] = " "; void output(char *puffer) { int i=0,len; static int merker=0; char *p,tmp[20]; p=strtok(puffer, token); /*Trennen die einzelnen Wörter*/ while(p != NULL) { i=0; merker=0; while(filterwords[i]!=NULL) { /*Wir vergleichen alle Wörter die wir ausfiltern wollen mit dem aktuellen Wort auf das p zeigt*/ if(strstr(p, filterwords[i]) != NULL) { len=strlen(filterwords[i]); /*Wir zählen die Länge des zu ersetzenden Wortes*/ memset(tmp, 'x', len); /*Jetzt schreiben wir len x in das Array tmp*/ fputs(tmp,stdout); /*Nun geben wir len x auf den Bildschirm aus*/ fputs(" ",stdout); /*Leerzeichen*/ merker=1; /*Merker ob schon etwas ausgegeben wurde*/ } i++; } if(merker==0) { /*Normale Ausgabe da nichts gefiltert wurde*/ fputs(p,stdout); fputs(" ",stdout); /*Leerzeichen*/ } p=strtok(NULL, token); } } int main() { char pufferin[MAX]; while(fgets(pufferin, MAX, stdin)) output(pufferin); return 0; }

Ich habe folgende Filterwörter verwendet........

char *filterwords[] = { "und" , "oder", "aber", "ein", NULL};  

Diese Worte werden alle mit xxx ausgegeben. Dies Programm können sie beliebig anpassen. Z.B. zur Vermeidung von vulgären Ausdrücken wenn man Schimpfmails erhält. Wenn sie eine ganze Datenbank von Ausfilterungswörtern erstellen wollen rate ich Ihnen zu einer dynamischen Struktur in Form von Verketteter Listen. Sie könnten so in etwa natürlich auch ein Fremdsprachenübersetzungsprogramm schreiben. Wir wollen jetzt unser Programm vom Kapitel zuvor mit unserem Filterprogramm anpassen.........

/*Download:pip6.c*/
#include <unistd.h> #include <sys/wait.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <signal.h> #define EXIT(s) {fprintf(stderr, "%s",s); exit(0);} #define USAGE(s) {fprintf(stderr, "%s Datei zum lesen\n",s); exit(0);} #define MAX 8192 enum {ERROR=-1,SUCCESS}; int main(int argc, char **argv) { int fd[2]; pid_t pid; FILE *pipe_writer, *file; char puffer[MAX]; if(argc!=2) USAGE(argv[0]); if((file=fopen(argv[1], "r")) == NULL) EXIT("Fehler bei fopen.........\n"); if(pipe(fd) == ERROR) EXIT("Fehler bei pipe.......\n"); if((pid=fork()) == ERROR) EXIT("Fehler bei fork......\n"); if(pid > 0) /*Elternprozess*/ { close(fd[0]); /*Wir schließen die Leseseite*/ if((pipe_writer = fdopen(fd[1], "w")) == NULL) EXIT("Fehler bei fdopen............\n"); fread(&puffer, MAX, 1, file); fputs(puffer, pipe_writer); /*Wir schreiben in die Pipe*/ /*Mit dem schließen der Schreibseite*/ /*teilen wir dem Kindprozess das Ende*/ /*des Schreiben in die Pipe mit*/ fclose(pipe_writer); if(waitpid(pid,NULL,0) == ERROR) EXIT("Fehler bei waitpid.........\n"); exit(0); } else /*Kindprozess ließt aus der pipe mit less*/ { sleep(1); close(fd[1]); /*Schließen der Schreibseite*/ if(fd[0] != STDIN_FILENO) /*muss überprüft werden*/ { /*duplizieren Standardeingabe*/ if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) EXIT("Fehler bei dup2......\n"); close(fd[0]); } if(execl("./filter", "filter", NULL) == ERROR) ; EXIT("Fehler bei execl.......\n"); } }

Wir mussten eigentlich nur eine Zeile anpassen. Nämlich die, zur Überlagerung unseres neuem Programms im Kindprozess, die execl-Funktion. Nun führen das Programm an ein Längeren Textdatei aus und schon funktioniert unser Filter.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf