Computer Science 010

Lecture Notes 9

More Emacs, Useful Unix Tools, Intro to Shell Scripts

C Mode

Wrapping long lines

A second useful feature is to allow Emacs to break long lines so that your lines all fit nicely in the window and print well. This works by specifying a column number to serve as your "fill column". If you type a space to the right of the fill column, Emacs will start a new line, indenting it as necessary. The default fill column is 70. To turn on the mode that breaks your long lines, type:

M-x auto-fill-mode

or place the following line in your C mode hook function in your .local_emacs file:

(auto-fill-mode 1)
   

Tags - finding definitions and uses of functions

Another useful feature is called tags. Tags creates a table of the functions declared in a collection of files. Within Emacs, you can ask to see a tag, and it will show you the definition of a tag. This is very convenient if you are looking at a function call and want to see the definition of the function. Before using tags, you must create a tags file. This is done with the Unix command called etags. You give etags a list of file names. It reads those files a builds a table of everything declared in those files and writes the table to a file called TAGS in your current directory.

To use tags within Emacs, you first need to tell Emacs where the tag file is:

M-x visit-tags-table 

You will be prompted for the name of the file containing the tags. It will list TAGS as a default, which you should accept by hitting the return key.

If you want to find the definition of a function, you ask Emacs to find a tag:

M-.

You will be asked for the name of the tag. It will show you the definition of that tag, reading in the file if necessary.

If you want to find everywhere that a function is used in the collection of files that has been tagged, use:

M-x tags-search

Enter the name at the prompt. To continue the search, type M-,

Suppose, you want to change the name of a function. You can use a command similar to query-replace except that it looks through all the files that have been tagged:

M-x tags-query-replace

If you want to see everything that has been declared in a single file, use:

M-x list-tags

You will be prompted for the filename.

Remember to keep your TAGS file up-to-date by re-running the Unix etags command when you change your files. (You could put a rule in your Makefile to do this.)

Additional Shell Mode commands

There are two more shell mode commands that are extremely useful. These commands allow you to repeat earlier commands, just as uparrow and downarrow do at a shell outside of Emacs. If you tried to use uparrow and downarrow in a shell in Emacs, you would notice that they move up or down a single line. If the previous command produced a lot of output, this is not very useful as it will back up through each line of output, scrolling through the buffer. Instead, use the following commands.

M-p places the previous command on the current command line. Repeated use of this command will go farther back in your shell history. If you go too far, you can come forward again with M-n.

Customize Command

A relatively new command in Emacs is the customize command. This command gives you a hypertext style interface to move between customization forms. Each form contains a list of related Emacs customization variables with some documentation. You can customize these variables by changing the value on a form. You can then choose whether you want to apply the customization for just that Emacs session or save it for all future Emacs sessions. If you choose to save it, it will write the necessary Lisp code into your .local_emacs file for you!

Here is an example. Suppose we like the keyword coloring that we have in C mode. We might wonder whether it is available in other modes as well. We'll use the customize command to see if we can find something. The customize command has no keyboard shortcut, so we invoke it with M-x customize. Emacs creates a buffer called "*Customize Group: Emacs*". This buffer lists some customization groups, including Editing, External., Convenience, etc., each with some documentation. Scanning the list, we see one named Faces and whose documentation says it deals with multiple fonts. Using the left mouse button we click on "[Go to Group]" following Faces.

Now we are on a form with customization variables and other groups. Scanning the list, we see a group called Font Lock. That sounds relevant since we got coloring earlier by entering font-lock-mode. So, let's enter that group.

We get a new buffer again with some variables and some groups. Now we see a variable called Global Font Lock Mode. It says:

Global Font Lock Mode: [Hide] [Toggle]  off (nil)
   [State]: this option is unchanged from its standard setting.
Toggle Global Font Lock mode. [More]

This sounds interesting, but we're not sure. If we click on More, we will get more documentation that suggests this is what we want to use, so let's try it. We click the Toggle button. Now it tells us the value is "on (non-nil)". The state says we have changed the value but not saved it. Let's click the state button. This brings up a menu. Since we want to see if this does what we want, we will select "Set for Current Session".

We know font-lock will already be on in C mode, so let's look at a different type of buffer. Let's start a shell. Wow! The prompts are in red. We can look at some other modes, like Compile mode. We can look at .local_emacs. All of these are now using colors for the font. If we like what we see, we can go back to the customization buffer and select "Save for Future Sessions". Now, if we look at our .local_emacs file we can see the Lisp code that the customize command added.

Unfortunately, there are limits to what can be customized this way. First, it can only be used to change the values of variables. Second, those variables have to be declared as customizable variables in the Lisp code that created them. Since this is a new feature, older code does not do this. Nevertheless, this appears to be a very useful new feature allowing a lot of customizations without requiring Lisp programming.

Emacs Lisp Packages

The customizations that we have seen are written in Emacs Lisp, as is the .local_emacs file that we have been working with. Emacs is probably the first widely used open source project, predating Linux by 10 or more years. As a result, there are many, many customizations available. The good news, then, is that is rarely necessary to write your own. It may be useful to install and customize something that somebody else did, though.

Finding them

Emacs has been around a long time. Customizations that have proved to be popular and stable have become part of the standard release of Emacs. Thus, before searching the Web for some kind of package, you should first see if something is already available in your current installation. There are a few ways you can do that. First, you could use the apropos command to see if there is anything that meets your need. For example, suppose you want to do some Java programming and would like to use a Java mode similar to the C mode we have been using. You can type:

C-h a java

You will see that there is indeed a Java mode already available.

Another thing you can do is look at the files in the directory where Emacs stores the customizations it comes with. The directory is /usr/cs-local/emacs/20.3/lisp. If you scan the list, some names will be more suggestive of what they do than others are. For example, we might guess that ediff is a version of diff (the file comparison utility) that runs inside of Emacs. Note that the files in this directory end in either .el or .elc. You should only look at the .el files; .elc are compiled files.

Installing them

Perhaps you will want to do something that does not come with the default Emacs installation. In that case, you can visit the Emacs lisp ftp site to see if somebody has implemented something you want. If you find what you want, you can download it and install it yourself. For example, here is what you would do to install a package that allows you to play pong inside of Emacs.

First, create a directory to put all your Emacs lisp files into. A good choice is a directory called lisp in your home directory. Now, go to the ftp site and find the appropriate package. In this case it is inside the Games folder on the ftp site. It will display in your Web browser. Save it to a file in your lisp directory, in this case lisp/pong.el. Now, you need to modify .local_emacs so that it knows about this new package. Add the following lines to your .local_emacs file:

(setq load-path (cons ("~lisp/" load-path))
   
(defun play-pong ()
   (interactive)
   (load "pong")
   (pong)
)

load-path is a list of directories that Emacs looks in for lisp packages. The first line changes the value of the load-path variable to be the same as before but with your lisp directory prepended to it. Next, we define a function called play-pong. We say that play-pong is interactive. This means that the user can execute it by saying "M-x play-pong". When the user executes this new command, Emacs will load the pong.el file from your lisp directory. It will then call the function pong which happens to be defined in that file to start a game.

Try it!

Advanced Unix

Redirecting I/O

Some programs produce a lot of output, and it is often useful to save the output to a file so that you can look at it in Emacs or use it as input to other programs. This allows you to scroll backward and forward through the output, search for specific parts of the output, etc.

In other cases, it may be useful to have a program that normally gets its input from the keyboard actually read its input from a file instead. For example, when testing code, you can put the input into a file and send this file to your program instead of needing to type it in repeatedly.

This is called input/output redirection. Input redirection causes input to be read from a file instead of a keyboard. The syntax to do this is as follows:

-> prog < infile

This will run prog with input redirected from infile. When prog uses an input function like scanf, gets, or getchar, it will read from the file named infile rather than the keyboard.

Output redirection writes output to a file instead of displaying it on the screen. The syntax to do this is:

-> prog > outfile

This will run prog with output redirected to outfile. When prog uses an output function like printf, it will write to the file named outfile rather than the screen.

Both input and output redirection can be used on the same command, such as:

-> prog < infile > outfile

Pipes

Pipes are an interesting combination of input and output redirection. A pipe allows you to redirect the output of one program to the input of another program. For example,

-> ls -la | wc

will help you figure out how many files you have in your directory. "ls -l" lists your files, one per line. The output of the ls command does not appear on your screen. Instead it is redirected to be the input to wc. wc (short for word count) is a Unix utilitiy that reports the number of charcters, words, and lines in its input. (The number of files in your directory is one less than the number of words that wc reports because it has an extra line indicating the amount of disk space used by the files combined.)

The pipe above is functionally equivalent to the following sequence of commands:

-> ls -la > tmp
-> wc < tmp
-> rm tmp

The piped command is faster than using the 3 command sequence for several reasons. First, you type less. Your typing speed is certainly the slowest part in either method of implementing this. Second, Unix does not need to modify the file system. Third, ls and wc can operate concurrently when using a pipe. Without a pipe, wc cannot begin execution until ls completes.

Grep

Grep is another extremely useful Unix utility. It searches a list of files for all lines that contain a given string. For example,

-> grep mode .local_emacs
;;; These are my customizations for C mode
(defun my-c-mode-hook ()
  (font-lock-mode 1)
  (auto-fill-mode 1)
  ;; Turn on auto-newline-insert mode
  ;; Turn on hungry-delete mode
;; Install my-c-mode-hook so these commands are run whenever I enter C mode.
(add-hook 'c-mode-hook 'my-c-mode-hook)

The output from grep is exactly those lines in .local_emacs that contain the string "mode". Note tha the string may be part of a larger word.

Often you use grep to find all files that contain something, such as a particular function call. Instead of passing in a file name, you would normally use a wildcard to specify a collection of files. For example,

-> grep strcmp *.c
small_large.c:   if (smallest[0] != '\0' || strcmp (smallest, next) > 0 {
small_large.c:   if (largest[0] != '\0' || strcmp (next, largest) > 0 {
small_large_ptr.c:   if (smallest == NULL || strcmp (smallest, next) > 0 {
small_large_ptr.c:   if (largest == NULL || strcmp (next, largest) > 0 {
spell.c:   if (strcmp (list[i], word) == 0) {
spell_UI.c:   if (strcmp (word, "q") == 0) {
string_funcs.c:   if (strcmp (retvalue, l[i]) > 0 {
string_funcs.c:   if (strcmp (retvalue, l[i]) < 0 {
   

This reports all occurrences of strcmp in all files whose names end in .c. Note that when grep searches multiple files, it identifies which file each line comes from.

Sometimes you want to search for more than one word. To do that you need to include a blank in the string to search. You must enclose the string in quotes, otherwise the second word would be assumed to be a filename. For example, suppose I want to know all functions declared in header files that take strings for an argument. I could say:

-> grep "char *" *.h
spell.h: bool spellCheck (char **list, int length, char *word, char **corrections);
string_funcs.h: char *smallest (char **l, int num);
string_funcs.h: char *largest (char **l, int num);
string_funcs.h: bool isPalindrome (char *s);
string_funcs.h: char *reverse (char *s);

By default, grep does a case sensitive matching of strings. That is "list" does not match "List". This is inappropriate, particularly if we are searching text. It could be that the word we are looking for sometimes starts a sentence and sometimes does not. To do a case-insensitive search, add the -i flag:

-> grep -i menu *.c
book.c  int menu ( void ) ;    /* function menu prototype */
book.c: int choice;       /* Value returned from the menu */
book.c:   choice = menu ();   /* show the main menu */
book.c: menu   This function shows the main menu, reads the user selection,
book.c: int menu ()
book.c:   printf: ( "\n<<Super Duper Menu >>\n");
string_list.c:   printf ("\n<<String List Menu >>\n");

The fact that all lowercase versions of menu were found before all uppercase versions of menu is purely coincidental. -i would also find occurrences of MENU, mEnU, etc., if they existed.

Other Unix utilities

Much of the power of Unix comes from the extensive set of utility programs that it usually includes. We will examine a few of those here.

Let's look at the man pages to learn about these commands: