Computer Science II Lab 1
                       What a Colorful World!

 Introduction
 ============
 Welcome back!  When last we met, for those of you whom I did meet,
 we were studying the wonderful world of computer programming.  Now
 that you have a little bit of programming under your belt, we can
 move into writing more interesting programs, explore exciting
 structures, conjure up amazing algorithms, and gain full control of
 our UNIX environment.

 This first lab is intended to be a gentle prod to help you get
 back up to speed with coding.  I expect that if you haven't done any
 programming in the last couple of months, you could be a little bit
 rusty.  How you do on this lab will show me where everyone is and
 will have a direct impact on how our lectures proceed.  (Unless of
 course you're a gopher user who is not in my class.  In which case,
 this lab will still be a good warm-up exercise).

 In this lab, we are going to explore ANSI escape sequences, which is
 what will let us do some cool things with the terminal.  It is
 structured to include many of the control structures presented in
 the previous class.  In the challenge section of the lab, you'll
 have an opportunity to show me that you can still craft loops,
 branches, and get around in a UNIX system.

 Good luck, and enjoy!


 Messing with Terminals (Guided)
 ===============================
 Several thousand years ago, mankind communicated primarily by
 hitting each other with things.  This proved to be inefficient, and
 somewhat limiting, and so we came up with grunting at each other.
 The grunts took on more and more order, and then language was born.
 The trouble is, we had to remember everything.  So then someone else
 came up with the notion of writing.  At first we wrote on caves,
 trees, bathroom walls, and so on.  Eventually someone invented
 paper, followed by the printing press.  This remained the state of
 affairs for a very long time.

 Paper was really a wonderful thing.  You could communicate with
 people, even over vast distances.  Unlike word of mouth, paper would
 convey information with high fidelity.  However, one problem
 remained.  Namely, if you are standing at point A, and your
 recipient is standing at point B, then you have to transport that
 paper to him.  If there was more than a few miles between you,
 people in between would revert to more primitive forms of
 communication and hit your courier with something large and your
 message would be lost.

 So then, a solution had to be found.  The first answer was
 telegraphy.  Wires would stretch the vast distances, and because
 wires were not human no one had any interest in hitting them.  A
 message was written down, and then an operator would push a button
 in a rhythm which would cause the operator at the other end to write
 down the message and take it to the nearby receiving party.  The
 trouble is, this was laborious, and mistakes could be made.

 Another attempt to solve the problem came in the form of the
 telephone, which allowed people to talk over vast distances using
 wires.  This reverted back to the original problem, in that it
 depended on human memory, and so there seemed to be no way to send
 an indelible message without employing someone or getting hit over
 the head, and so the problem remained.

 And then came a man who had been hit and telegraphed enough to do
 something about it.  His name was Emile Baudot.  He invented a
 digital encoding scheme, where each letter would be represented by 5
 1's and 0's.  This, when combined with the best of late 19th century
 technology, allowed a machine to send and reproduce paper
 documents.  Because the machine did the work, and the work took
 place at a distance, this was called "teleprinting".  Thus was the
 age of modern telecommunications born.  It wasn't until the rise of
 the Internet that mankind would learn how to hit each other using
 the new medium.  In honor of Baudot, we still refer to the rate
 which we can transmit symbols as a "baud rate".

 In time, the teleprinter gave rise to the teletype.  By the early
 1910's, teletypes were transmitting news stories across the world
 as quickly as operators could type them.  Stock ticker teleprinters
 churned out stock quotes as rapidly as the traders could enter
 them.  Mankind could know what was going on and how much everything
 cost at the drop of a hat, and so more and bloodier wars were fought
 during this era than any other in history.

 But there remained one problem.  It was easy to send a string of
 characters, but what about the formatting of a document?  The answer
 came in the form of special characters.  There were characters for
 line feeds, characters for carriage returns, and characters to advance
 the printer backwards and forwards.  The trouble is, with all these
 controls, it didn't fit into a 5-bit alphabet, and so 7-bit ASCII
 (American Standard Code for Information Interchange) was born, and
 became the standard for all teletype devices.

 Then came the rise of the computer.  Teletypes where used to talk to
 computers, and people were using paper at an alarming rate.  Your
 average programmer consumed somewhere in the neighborhood of 1
 deciduous forest per year, and that was just when he wasn't playing
 Star Trek!  (man trek)  So then people moved to a less permanent way
 of painting text.  Instead of paper, it was displayed on a screen,
 and thus the visual terminal was born!

 Now visual terminals offered a lot more control than paper did.  For
 instance, you could erase it.  You could color it, you could save it
 to disk, or send it to printers to be made permanent.  So naturally,
 more control codes had to be invented.  The trouble is, they didn't
 fit into 7 bits.  Rather than extend the character set, sequences of
 characters were designated for this use.

 Eventually, computers became smaller and cheaper, and so the
 physical terminal died and was replaced by a terminal emulator.  The
 terminal you are presently using is one of these, but it still
 responds to the same escape sequences as the physical devices of
 yesterday.  Thus we came the current state of the art of teleprinter
 control, the escape sequence!

 *phew*  Now are are you ready to code?

 So why ware they called escape sequences?  Well, the reason is they
 begin with a character called the "escape" character.  The escape
 character is a non-printable ASCII character which has decimal value
 27 (1B in hex, or 33 in octal).  To try your hand at this, enter,
 compile and execute the following program:


 -- begin ansiExample.cpp --
    1  #include <iostream>
    2
    3  using namespace std;
    4
    5  int main(void) {
    6    cout << "\033[36m" << "Hello World" << endl;
    7  }
 -- end ansiExample.cpp --

 That mess in line 6 is the escape sequence.  The pattern is:
   \033 (the escape character) followed by [36m.
 All ANSI escape sequences begin with \033[.  The m at the end means
 this is a mode command.  36 is the mode for cyan color.

 When you run this program, you'll probably notice that your terminal
 remains in cyan mode.  (NOTE: You can't run these things inside
 Emacs shell.  You'll have to leave Emacs or have another window open
 in order for this to work).  Terminal modes are persistent.  That
 is, they continue until something tells them otherwise.  To clear
 this mode, you have to send "\033[0m".  The number 0 is the mode
 command for "normal mode".  go ahead and try that out.  Add
 "\033[0m" to the end of line 6, so it reads:

    cout << "\033[36m" << "Hello World" << "\033[0m" << endl;

 You'll see "hello world" in cyan, but your prompt will have returned
 to the original color.  So now, there a lot of mode commands.  Some
 of these follow:

   \033[#m - the generic mode change pattern

   #    Meaning
   --   -------
   0    Normal Mode
   1    Bold
   4    Underline
   5    Blink
   7    Reverse Video
   30   Set Foreground Color to Black
   31   Set Foreground Color to Red
   32   Set Foreground Color to Green
   33   Set Foreground Color to Yellow
   34   Set Foreground Color to Blue
   35   Set Foreground Color to Magenta
   36   Set Foreground Color to Cyan
   37   Set Foreground Color to White
   40   Set Background Color to Black
   41   Set Background Color to Red
   42   Set Background Color to Green
   43   Set Background Color to Yellow
   44   Set Background Color to Blue
   45   Set Background Color to Magenta
   46   Set Background Color to Cyan
   47   Set Background Color to White

 There are also several terminal commands, which cause the terminal
 to do things.  These follow the pattern of:

   \033[*

 Some values for * are:
   *      Meaning
   ----   -------
   2J     Clear the screen
   2K     Clear the current line
   s      Save the cursor position
   u      Move the cursor to the saved position
   xA     Where x is some number.  This moves the cursor up x lines
   xB     Move the cursor down x lines
   xC     Move the cursor forward x characters
   xD     Move the cursor backward x characters
   y;xH   Move the cursor to position (x,y) (1,1 is the upper left
          corner).

 Go ahead and take a moment to play with these commands.  To get full
 credit for the guided part of the lab, your ansiExample.cpp needs to
 have a few additional commands entered.

 Now I know the one you all probably ran to.  Blink!  And you're
 probably saying, "Hey, it's not blinking!"  This is because most
 modern terminal emulators (mercifully) do not enable that by default
 because it is terribly annoying.  If you really want to see it, you
 will have to turn it on.  In putty, you can do this as follows:

   1. Hold Control and right click the window.
   2. Select "Change Settings"
   3. Click on Terminal
   4. Check the box "Enable Blinking Text"

 Also, you may see differences in the expected color output.  This is
 because what you are really doing is selecting from a 7 color
 pallet.  That pallet is decided by the terminal emulator software.

 Ok, so now you can make the cursor do anything.  You can overwrite
 text, you can highlight stuff, you can do anything you want.  The
 trouble is, it's a pain!  Wouldn't it be great if we could do
 something like:

   cout << red << "Hello world" << normal << endl;

 Well it turns out with just a little bit of work, we can do that!
 Let's write a header file.  My complete file follows.  As you type
 it in, try to think about what each part of it does.  If you
 encounter something you have never seen before, make a note of it.
 We'll have a discussion about which pieces were a mystery to you at
 the next class meeting.

 --begin ansi.h--
    1  /*
    2   * File: ansi.h
    3   * Purpose: To have fun messing with people's terminals, and making
    4   *          lots of colorful and interesting programs.
    5   *
    6   *          This provides a nice little interface to the ANSI escape
    7   *          sequence set.
    8   */
    9  #ifndef ANSI_H
   10  #define ANSI_H
   11  #include <iostream>
   12  #include <string>
   13  #include <sstream>
   14
   15  /*
   16   * Graphic Mode Modifiers
   17   */
   18  inline std::ostream& normal(std::ostream &os) {
   19    return os << "\033[0m";
   20  }
   21
   22
   23  inline std::ostream& bold(std::ostream &os) {
   24    return os << "\033[1m";
   25  }
   26
   27
   28  inline std::ostream& underline(std::ostream &os) {
   29    return os << "\033[4m";
   30  }
   31
   32
   33  inline std::ostream& blink(std::ostream &os) {
   34    return os << "\033[5m";
   35  }
   36
   37
   38  inline std::ostream& reverseVideo(std::ostream &os) {
   39    return os << "\033[7m";
   40  }
   41
   42
   43
   44  /*
   45   * Foreground Color Graphic Mode Modifiers
   46   */
   47  inline std::ostream& black(std::ostream &os) {
   48    return os << "\033[30m";
   49  }
   50
   51
   52  inline std::ostream& red(std::ostream &os) {
   53    return os << "\033[31m";
   54  }
   55
   56
   57  inline std::ostream& green(std::ostream &os) {
   58    return os << "\033[32m";
   59  }
   60
   61
   62  inline std::ostream& yellow(std::ostream &os) {
   63    return os << "\033[33m";
   64  }
   65
   66
   67  inline std::ostream& blue(std::ostream &os) {
   68    return os << "\033[34m";
   69  }
   70
   71
   72  inline std::ostream& magenta(std::ostream &os) {
   73    return os << "\033[35m";
   74  }
   75
   76
   77  inline std::ostream& cyan(std::ostream &os) {
   78    return os << "\033[36m";
   79  }
   80
   81
   82  inline std::ostream& white(std::ostream &os) {
   83    return os << "\033[37m";
   84  }
   85
   86  /*
   87   * Foreground Color Graphic Mode Modifiers
   88   */
   89  inline std::ostream& blackBackground(std::ostream &os) {
   90    return os << "\033[40m";
   91  }
   92
   93
   94  inline std::ostream& redBackground(std::ostream &os) {
   95    return os << "\033[41m";
   96  }
   97
   98
   99  inline std::ostream& greenBackground(std::ostream &os) {
  100    return os << "\033[42m";
  101  }
  102
  103
  104  inline std::ostream& yellowBackground(std::ostream &os) {
  105    return os << "\033[43m";
  106  }
  107
  108
  109  inline std::ostream& blueBackground(std::ostream &os) {
  110    return os << "\033[44m";
  111  }
  112
  113
  114  inline std::ostream& magentaBackground(std::ostream &os) {
  115    return os << "\033[45m";
  116  }
  117
  118
  119  inline std::ostream& cyanBackground(std::ostream &os) {
  120    return os << "\033[46m";
  121  }
  122
  123
  124  inline std::ostream& whiteBackground(std::ostream &os) {
  125    return os << "\033[47m";
  126  }
  127
  128
  129  /*
  130   * Simple terminal commands
  131   */
  132  inline std::ostream& clearScreen(std::ostream &os) {
  133    return os << "\033[2J";
  134  }
  135
  136
  137  inline std::ostream& clearLine(std::ostream &os) {
  138    return os << "\033[K";
  139  }
  140
  141
  142  inline std::ostream& saveCursor(std::ostream &os) {
  143    return os << "\033[s";
  144  }
  145
  146
  147  inline std::ostream& restoreCursor(std::ostream &os) {
  148    return os << "\033[u";
  149  }
  150
  151
  152  /*
  153   * This class is used by commands requiring arguments
  154   */
  155  class ArgSequence {
  156    public:
  157      ArgSequence(std::string seq) {
  158        this->seq = seq;
  159      }
  160
  161      std::ostream& operator()(std::ostream &os) const {
  162        return os << seq;
  163      }
  164
  165    private:
  166      std::string seq;
  167  };
  168
  169
  170  //overload the << operator so ostream can use the sequence!
  171  std::ostream& operator<<(std::ostream& os, const ArgSequence& aSeq) {
  172    return aSeq(os);
  173  }
  174
  175
  176  /*
  177   * Commands requiring arguments
  178   */
  179  ArgSequence cursorUp(int value) {
  180    //compute the arg sequence
  181    std::ostringstream os;
  182    os << "\033[" << value << "A";
  183
  184    //return the result
  185    return ArgSequence(os.str());
  186  }
  187
  188
  189  ArgSequence cursorDown(int value) {
  190    //compute the arg sequence
  191    std::ostringstream os;
  192    os << "\033[" << value << "B";
  193
  194    //return the result
  195    return ArgSequence(os.str());
  196  }
  197
  198
  199  ArgSequence cursorForward(int value) {
  200    //compute the arg sequence
  201    std::ostringstream os;
  202    os << "\033[" << value << "C";
  203
  204    //return the result
  205    return ArgSequence(os.str());
  206  }
  207
  208
  209  ArgSequence cursorBackward(int value) {
  210    //compute the arg sequence
  211    std::ostringstream os;
  212    os << "\033[" << value << "D";
  213
  214    //return the result
  215    return ArgSequence(os.str());
  216  }
  217
  218
  219  ArgSequence cursorPosition(int x, int y) {
  220    //compute the arg sequence
  221    std::ostringstream os;
  222    os << "\033[" << y << ";" << x << "H";
  223
  224    //return the result
  225    return ArgSequence(os.str());
  226  }
  227  #endif
 --end ansi.h--

 At 227 lines, it's quite the editor full!  However, if you look
 closely you'll note that very little changes between the functions.
 So if there was ever a time to practice copy and paste in your
 chosen editor, it's now!

 Before I explain exactly what's going on, here's a sample program to
 test out our header file.  We will use this header file in future
 labs, so it is very important that you get it correct now.

 --begin termTest.cpp--
    1  #include "ansi.h"
    2  #include <iostream>
    3  #include <iomanip>
    4
    5  using namespace std;
    6
    7  int main(int argc, char** argv) {
    8    //start on a fresh screen
    9    cout << clearScreen << cursorPosition(1,1);
   10
   11
   12    //general modes test
   13    cout << normal << "Normal" << endl;
   14    cout << underline << "Underline" << normal << endl;
   15    cout << bold << "Bold" << normal << endl;
   16    cout << blink << "Blink" << normal << endl;
   17    cout << reverseVideo << "Reverse" << normal << endl;
   18    cout << black << "Black" << endl;
   19    cout << red << "Red" << endl;
   20    cout << green << "Green" << endl;
   21    cout << yellow << "Yellow" << endl;
   22    cout << blue << "Blue" << endl;
   23    cout << magenta << "Magenta" << endl;
   24    cout << cyan << "Cyan" << endl;
   25    cout << white << "White" << endl;
   26
   27    //stack test
   28    cout << bold << yellow << magentaBackground << "Hello, blinded world!"
   29         << normal << endl;
   30
   31    //cursor movement test
   32    cout << saveCursor << cursorPosition(10, 7) << "Hello";
   33    cout << cursorDown(2) << cursorForward(1) << "World";
   34    cout << restoreCursor << cursorDown(1) << normal << endl;
   35
   36    return 0;
   37  }
 --begin termTest.cpp--

 Go ahead and type it all in, and then compile and run it with the
 commands:

   g++ termTest.cpp -o termTest
   ./termTest

 Now, let's take a look at some of the things that may seem odd
 here.  First, there is the word "inline" sprinkled all over the
 place.  You may not have seen that before.  Basically what that is
 is it tells the compiler to attempt to duplicate the function
 instead of calling it.  See, those functions are tiny one liners and
 so the overhead of invoking the code is greater than the cost of
 running the function.  Marking them inline gives the optimizer the
 hint that it may be better to simply duplicate these functions than
 it is to call them.  This makes the generated executable slightly
 larger, but it runs a little faster.

 Another thing of note is that it appears we are printing functions!
 We are not.  What is happening is that ostream has an overloaded
 insertion operator which accepts as its left argument an ostream and
 as its right argument a pointer to a function which takes an ostream
 as an argument and returns an ostream.  It's not as bad as it
 sounds, and we'll be seeing more of this in the future.

 Note that we have a small class produced here in the .h file.  This
 is a necessity for providing an ostream modifier which takes an
 argument.  We overload the () operator on our class to allow it to
 be invoked as a function, and then we provide an overloaded
 insertion operator to handle the final insertions.  Try thinking
 through what happens when we call the functions and pay close
 attention to what the functions return.  If you don't get this just
 yet, that's ok.  It's the subject of several discussions yet to
 come!


 So now, we have a nifty little header file which lets us do basic
 terminal manipulations.  You can now make much more colorful
 programs.  So let's try your hand at using our creation!



 Putting the Terminal to Work (Challenge Lab)
 ============================================
 Ok, so now let's try our hand at using the library.  This is just a
 quick little lab to get you started and for me to see what everyone
 remembers.  There are two parts.  A written part, and a program
 part.  We will do the program first.

 I had a professor back in the late 90's who always got on to me for
 putting exclamation points in my program's error messages. (He said
 it made him feel as if the computer were shouting at him!)  I
 retaliated by making a program which outlined the screen in red
 exclamation points on each error.  I want you to recreate this.
 Here's what your program should do:

   - repeatedly ask the user for a number between 1 and 10
   - if the user complies, thank them, and ask again.
   - on error, outline the terminal screen in !  and display a big
      red error message in the center.  Something like:

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !!                                                             !!
   !!                                                             !!
   !!                                                             !!
   !!                 ERROR!!!                                    !!
   !!                         Can't you follow instructions?      !!
   !!   Now enter a number between 1 and 10!:                     !!
   !!                                                             !!
   !!                                                             !!
   !!                                                             !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 Only large enough to fill the window.  For simplicity sake, you can
 assume the terminal is 80x24.  If you make your program particularly
 fancy, you will get extra credit points.



 For the written part of the assignment, I want you to review all the
 code you have typed in this lab.  Write down any features of the
 language which feel foreign to you and then try to look up how they
 work.  Write down any questions this leaves you with.  At the very
 least, you should write down the topics in this lab which puzzle
 you.

 Hang on to your code and your written document (which you can type
 if you prefer) until next week's meetings!



 Closing Remarks
 ===============
 In this lab, we looked at ANSI escape sequences.  Because of the
 vast array of terminals and terminal emulator software on the
 market, this is not a universal set of controls.  The ones I have
 elected to present here are a small subset of terminal control.
 These are the ones supported by most terminals.

 In order to alleviate the difficulties in programming serious
 terminal applications, several services were created on UNIX
 machines.  The first was TERMCAP which listed the terminal
 capabilities of the presently attached tty port (which stands for
 teletype, by the way).  Termcap was later supplanted by a library
 called curses, and a free version of curses was created called
 ncurses.  ncurses provides a good abstraction layer for doing more
 advanced terminal work.  If you are interested in what ncurses can
 do, check out the ncurses programming howto at:

   http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/index.html