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:

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:

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:

To receive 75% credit:

To receive full credit for this lab: