CODESAMPLE
Pipes and Filters - C
The Pipes and Filters pattern processes a stream of data by breaking it down into a series of independent processing steps (filters) connected by channels (pipes). Each filter performs a specific transformation and passes the result to the next filter. This promotes modularity, reusability, and simplifies complex processing pipelines.
The C implementation uses a series of functions as filters, each taking a stream (represented as FILE*) as input and output. pipe() creates the communication channels between filters. dup2() redirects standard input/output to these pipes. This approach leverages C’s standard I/O and process control mechanisms, fitting its procedural style. Error handling is included for robustness.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
// Filter 1: Uppercase filter
void uppercase_filter(FILE *in, FILE *out) {
int c;
while ((c = fgetc(in)) != EOF) {
fputc(toupper(c), out);
}
}
// Filter 2: Remove spaces filter
void remove_spaces_filter(FILE *in, FILE *out) {
int c;
while ((c = fgetc(in)) != EOF) {
if (c != ' ') {
fputc(c, out);
}
}
}
int main() {
int pipe1[2];
int pipe2[2];
pid_t pid1, pid2;
if (pipe(pipe1) == -1 || pipe(pipe2) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid1 = fork();
if (pid1 == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid1 == 0) { // Child 1: Uppercase filter
dup2(pipe1[0], STDIN_FILENO);
dup2(pipe1[1], STDOUT_FILENO);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
uppercase_filter(stdin, stdout);
exit(EXIT_SUCCESS);
}
pid2 = fork();
if (pid2 == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid2 == 0) { // Child 2: Remove spaces filter
dup2(pipe1[1], STDIN_FILENO);
dup2(pipe2[1], STDOUT_FILENO);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
remove_spaces_filter(stdin, stdout);
exit(EXIT_SUCCESS);
}
// Parent: Connect to the pipeline and read the output
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[1]);
FILE *output = fdopen(pipe2[0], "r");
if (output == NULL) {
perror("fdopen");
exit(EXIT_FAILURE);
}
char buffer[100];
printf("Output: ");
while (fgets(buffer, sizeof(buffer), output) != NULL) {
printf("%s", buffer);
}
fclose(output);
wait(NULL);
wait(NULL);
return 0;
}