CS140 -- Lab 3

This lab comes in four parts and is designed to give you practice using the fields library, lists and command line arguments. Files that you may care about:

Part 1: reverse

Implement reverse using the fields library so that it works exactly as described in the following blurb:
NAME
     reverse - concatenate and display files in reverse order

SYNOPSIS
     reverse [ -n ] [ filename...  ]

DESCRIPTION
     reverse reads each filename in sequence and displays it in reverse order
     on the standard output.  Thus:

          UNIX> reverse file1

     displays the contents of file1 in reverse order on the standard output, and

          UNIX> reverse file1 file2 

     prints each of the two files in reverse order and places the result 
     on standard output. Hence file1 would be printed in reverse order
     followed by file2 in reverse order.

OPTIONS
     -n   Precede each line of output with its line number and a colon (:). 
	  Allocate 6 spaces for the number and right justify the number.
          Reset the line number to one with each file if there are multiple 
          files.

ERROR CHECKING
 
     reverse prints an error message if:
	1. there are no arguments,
	2. the -n flag is present but there are no filenames given,
	3. a filename does not exist. reverse should print an error message
		and proceed to the next file.
You should use a linked list rather than an array to store the lines in the file. Think about how to add items to the linked list to make it easy to print out the file in reverse order.

Part 2: listfile

Implement listfile using the fields library so that it works exactly as described in the following blurb:
NAME
     listfile - display a fractional portion of the specified file

SYNOPSIS
     listfile start_fraction end_fraction filename

DESCRIPTION
     listfile copies the lines of filename between start_line and
     end_line to the standard output where start_line and end_line are 
     computed as follows:
	start_line = start_fraction * (number of lines in file)  
	end_line = end_fraction * (number of lines in file)  
     start_line should be rounded down to the next lower integer and
     end_line should be rounded up to the next higher integer. For example, 5.03
     will become 5 for start_line and 6 for end_line.  Similarly, 5.67 will
     before 5 for start_line and 6 for end_line.

     Precede each line of output with its line number and a colon (:). 
     Allocate 6 spaces for the number and right justify the number.

ERROR CHECKING
     listfile prints an error message if:
        1. either start_fraction or end_fraction is not a valid number,
	2. either start_fraction or end_fraction is not between 0 and 1,
	3. end_fraction is less than start_fraction, or 
	4. the file named filename does not exist.

Here are some helpful hints:

  1. You will need to make two passes through the lines in the file. The first pass will count the number of lines and the second pass will print the lines.

  2. Use a linked list to store the lines in the file so that you do not have to read the file twice.

  3. Use the math library's ceil function to round a number up to the next highest integer. The declaration for the ceil function is:
    	double ceil(double number)
    	
    You will need to cast the return result of ceil to an integer. You will also have to include the <math.h> file in order to use the ceil function.

  4. You can round a number down to the next lowest integer by simply casting it to an integer. For example:
    	double number;
    	int rounded_number:
    
    	rounded_number = (int)number;  // rounds a number down
    	

Part 3: Mywc

Here is a man page for mywc. Your job is to implement mywc, using the fields library so that it works exactly as described in the following blurb:
NAME
     mywc - display a count of lines, words and characters

SYNOPSIS
     mywc filename ... 

DESCRIPTION
     mywc counts the number of lines, words, and characters in each filename.
     It also keeps a total count for all named files.  A word is a string of
     characters delimited by SPACE or NEWLINE characters (i.e.
     a word is as defined in fields.o). When counting characters, only
     count the characters in the words. Do not count spaces between words
     or newline characters. The filenames should be printed along
     with their counts. If there is more than one filename, then a total
     line should be printed as the last line of the program which includes
     a cumulative count of the number of lines, words, and characters. A
     total line should not occur if only one filename is specified.

         UNIX> cd /home/cs140/www-home/spring-2005/www-home/notes/Types
         UNIX> mywc makefile
	      52     124     563 makefile
         UNIX> mywc *
	     165     933    3897 hexi.html
	     520    2394   11968 index.html
	      52     124     563 makefile
	      12      20      81 p1.c
	      11      18      78 p2.c
	      32     105     448 p3.c
	      32     105     448 p4.c
	      10      12      59 pa.c
	      22      43     280 paycheck.c
	       9      12      42 pb.c
	      22      36     135 pc.c
	      28      59     252 pd.c
	     915    3861   18251 total

         Note -- when you say mywc *, the shell substitutes
         all the filenames in the current directory for the *.
         Thus, your command line has argc = 13 and 
         argv = { "mywc", "hexi.html", "index.html", .... }

ERRORS
     If any file given on the command line cannot be opened by 
     new_inputstruct(), then call perror(fn), where fn is the file name,
     and then continue with the other files.  If you are in doubt, try
     the executable in /home/cs140/www-home/spring-2005/labs/answers/lab3.

     I don't expect mywc to work on non-ascii files, or files that have
     extremely long lines (1000 characters or more).

Part 4: Ignoring Comments

Re-write mywc so that it ignores any words that are enclosed in C-style comments. That is, do not count any words or characters that are enclosed by a pair of "/*" and "*/" strings. Your program should also exclude the "/*" and "*/" strings from its counts. All lines should still be counted, regardless of whether or not they are completely commented out. Name your program nocomment.

You may make the following simplifying assumptions:

  1. the "/*" and "*/" strings will occur as stand-alone strings.
  2. comments will not be nested. In other words, do not worry about comments such as:
    	/* this is /* a nested */ comment */
    	
You should make sure your program works properly if the file terminates while a comment is open (i.e., the matching "*/" has not been found).