Lab 6: Pipes
One of the core types of IPC on Unix system is pipes. You will be implementing pipes and redirection in your shell, and of course there’s that awesome video of the ATT folks explaining it.
In this lab, you’ll get more familiar with pipes (which will then make your life a bit easier when you implement pipes in your shell). Your mission is to produce a super-amazing ‘l33tsp34k’ generator: given a file name, you will convert its text to lowercase and then perform character substitutions to 1337-ify it. While you are already an elite haxxor and could easily write this program in C, you realize that with the power of Unix you can be even lazier and just combine existing utilities.
To explain the purpose of this program better, let’s say you have an input file (input.txt):
Mechanic: Somebody set up us the bomb.
Operator: Main screen turn on.
CATS: All your base are belong to us.
CATS: You have no chance to survive make your time.
You will run:
./leetify input.txt
And out comes:
m3ch4n!c: 50m3b0dy 53t up u5 t3h b0mb.
0p3r4t0r: m4!n 5cr33n turn 0n.
c4t5: 411 y0ur b453 4r3 b310ng t0 u5.
c4t5: y0u h4v3 n0 ch4nc3 t0 5urv!v3 m4k3 y0ur t!m3.
If you run:
./leetify input.txt output.txt
The contents printed above will be written to a file named output.txt instead.
Truly groundbreaking!
We will use three Unix utilities to achieve this:
cat
– read the original input filetolower
– convert the text to lowercasefnr
– find and replace characters
Here is the implementation of tolower
:
#include "kernel/types.h"
#include "user/user.h"
int main() {
for (int c = 0; read(0, &c, 1) > 0; ) {
if (c >= 'A' && c <= 'Z') {
c = c - 'A' + 'a';
}
write(1, &c, 1);
}
return 0;
}
Here is the implementation of fnr
:
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
char *line;
uint sz;
while (getline(&line, &sz, 0) > 0) {
for (int i = 1; i < argc; i += 2) {
char *find = argv[i];
char *repl = argv[i + 1];
uint find_len = strlen(find);
if (strlen(line) < find_len) {
continue;
}
for (int j = 0; j < strlen(line) - find_len; ++j) {
char *p = line + j;
char *q = find;
int k;
for (k = 0; *p && *p == *q && k < find_len; ++k) {
p++, q++;
}
if (k == find_len) {
memcpy(line + j, repl, find_len);
}
}
}
printf("%s", line);
}
return 0;
}
NOTE: you won’t write any code that actually does text manipulation. All text manipulation will be provided by outside utilities. You are only gluing these programs together using pipes!
One interesting thing about tolower
and fnr
is that they only read from standard input – you can’t pass in the name of a text file like you can with some Unix utilities. To solve this, we are going to use cat
to read the file… but this is actually considered a useless use of cat because most shells already support redirection of stdin
from a file like so:
tolower < ./input.txt
This makes the standard input stream of tolower
come from the file input.txt
. Nevertheless, we will use cat
to do this instead because it will help with designing our shell pipe support. The equivalent command that we will implement is:
cat ./input.txt | tolower
The output of cat
will go into a pipe that we create, which is then read by tolower
, output to a second pipe, read by fnr
, and finally printed to its output stream (either stdout or an output file):
cat -> pipe -> tolower -> pipe -> fnr -> (output file descriptor)
To get started, you should refer to our in-class pipe.c example – it shows you how to use pipe()
and dup()
. The io-redir.c and exec.c examples may help too. The command line equivalent of this program is:
cat input.txt \
| tolower \
| fnr the teh a 4 e 3 i ! \
| fnr l 1 o 0 s 5 \
> output.txt
So the programs and command line arguments you will execute with exec
are:
cat 'input.txt'
tolower
fnr the teh a 4 e 3 i !
fnr l 1 o 0 s 5
Make sure you have tolower
and fnr
working on your OS and try the pipeline above (don’t include the \
line continuations). Once that’s working, start implementing your leetify
utility. Here’s some scaffolding for leetify.c.
Grading and Submission
Once you are finished, check your changes into your OS repo. Then have a member of the course staff take a look at your lab to check it.
To receive 50% credit:
- Add all the command line tools above and run a test pipeline from the shell.
To receive 75% credit:
- Complete all previous requirements
- Implement basic functionality for the
leetify
command: given a file, it should print the leetified output.
To receive full credit for this lab:
- Complete all previous requirements
- Implement file redirection (sending output to a file instead of stdout) when a second command line argument is provided.