|  CS 537 Spring 2008 Section 1: Programming Homework 0 Due: Tuesday, January 27th at 9 pm
 You are to do this project BY YOURSELF
 This project must be implemented in C (and not C++ or anything else)
 
  Notes:  Monday, January 26
  Hint 2: you can assume that the input is a well-formed text file, meaning that it contains no null characters.
    Thursday, January 22 Hint 1: here is sample code from this  web site  showing how to allocate a two dimensional array:
 
int **array1 = (int **)malloc(nrows * sizeof(int *));
	for(i = 0; i < nrows; i++)
		array1[i] = (int *)malloc(ncolumns * sizeof(int));
array1[1][2] = 0;
 
  Hint 2 (student generated): it may be easier to test your code for correctness by reducing the maximum length of the file and length of the line. Once that works, you can experiment on larger files. 
  Purpose The purpose of this assignment is to get familiar with the C
programming language, the  gcc  compiler, and the  gdb 
debugger.
  Part 0: a picture We want to get to know you better, and what better way than to be able
to associate a name with a face?  You need to turn in a digital
picture of yourself so I can learn who you are. Put this in your
handin directory (a jpg or a gif is fine), in the form
Firstname.Lastname.jpg (or whatever).  If you don't turn in a picture,
your project will not be graded! Part 1: Writing C code You will write a program to read in a text file and print the lines in reverse order (last line first, first line last) and also print out each line in reverse order (last non-newline character first, first character last).
 Specification: Program input: read a file specified on the command line:
 Program output: every line of the file, in reverse order.
  reverse-lines filename.txt 
 
Note that the lines of the file may be very short (blank) or very long
(up to hundreds of characters). 
This input: 
 
<!--#include file="base-head.html" -->
<title>CS 537: Operating Systems</title>
<!--#include file="base-top.html" -->
<h2>Overview</h2>
<p> Welcome to your first the Wisconsin Operating Systems course. This
course will describe a number of topicsincluding basic operating
system structure, process and thread synchronization and concurrency,
file systems and storage servers, memory management techniques,
process scheduling and resource management, system security, and a few
other "hot" topics.
 
should produce this output: 
 
.scipot "toh" rehto
wef a dna ,ytiruces metsys ,tnemeganam ecruoser dna gniludehcs ssecorp
,seuqinhcet tnemeganam yromem ,srevres egarots dna smetsys elif
,ycnerrucnoc dna noitazinorhcnys daerht dna ssecorp ,erutcurts metsys
gnitarepo cisab gnidulcniscipot fo rebmun a ebircsed lliw esruoc
sihT .esruoc smetsyS gnitarepO nisnocsiW eht tsrif ruoy ot emocleW >p<
>2h/<weivrevO>2h<
>-- "lmth.pot-esab"=elif edulcni#--!<
>eltit/<smetsyS gnitarepO :735 SC>eltit<
>-- "lmth.daeh-esab"=elif edulcni#--!<
 Assumptions
String length: You may assume no line in the input file is longer than
512 bytes. If you encounter a line that is too long, you should print error
message LINE_TOO_LONG (as detailed below) and skip the rest of this line.
 
Let's say the max size of an input line is 8
characters (and not 512). Which of these lines should be in the final
output?
 The first seemingly has 6 characters (abcdef), the second has
7, and the third 8, and thus you might naively think all should be
accepted. However, you are forgetting the newline character (\n)
which is at the end of each input line. Thus, the first two should be
accepted (as they have 7 and 8 characters including the newline). For
the third line, you should only accept 'abcdefg' and put a \n, and
skip the rest of the line, and don't forget to print the LINE_TOO_LONG
message. 
 
File length: You may assume the input file has 1024 valid lines (not too long) of input
or fewer. If you encounter more lines, print the FILE_TOO_LONG error message  once 
(as detailed below)
and reverse whatever input you currently have read in.
abcdef
abcdefg
abcdefgh
 Error MessagesAll error messages encountered while reading the input file should be of this format:
 where the specific error messages are:Error in line XXX: specific error message 
 FILE_TOO_LONG: You should print the following message: File too long LINE_TOO_LONG: You should print the following message: Line too long INVALID_FILE: If the user specifies exactly one file (as
desired) but it can't be opened (for whatever reason), you should
print the following message:
where FILE is what the user passed in.Error: Cannot open file FILE
 If you encounter a line that has both of these errors, you should print both error messages. There are some other possible errors too. For example, if the user doesn't
properly specify the input file on the command line (by say, not giving one,
or by giving too many files), you should print:
 and then exit.usage: reverse <file>
 Important: On any error code, you should print the error to the screen
using fprintf(), and send the error message tostderr(standard
error) and notstdout(standard output). This is accomplished in your C
code as follows: 
fprintf(stderr, “usage: ...
”);  Implementation tips: To do this, use the C standard I/O "f" functions:
  Documentation for these functions are available through the Linux  man
 pages: fgetc, fputc
   fgets, fgets
   fscanf, fprintf
   fopen, fclose
 
 
emperor01(1)% man fgets 
GETS(3)                 BSD Library Functions Manual
FGETS(3) 
NAME
     fgets, gets -- get a line from a stream
LIBRARY
     Standard C Library (libc, -lc)
SYNOPSIS
     #include <stdio.h>
     char *
     fgets(char *restrict s, int n, FILE *restrict stream);
     char *
     gets(char *s);
 
To invoke the compiler, run the command line: 
 This will compile the file "filename.c" and produce the output program
"filename" that you can then run with the command "./filename" (the
"./" is to tell Linux in which directory to find the program. The "-g"
flag indicates that the compiler should produce extra data to enable
source-level debugging, and the "-o" options specifies to put the
program in a specific file as compared to the standard name "a.out".
emperor01(1) gcc -g -o programname filename.c
 
 Other TipsStart small, and get things working incrementally. For example, first
get a program that simply reads in the input file, one line at a time, and
prints out what it reads in. Then, slowly add features and test them as you
go. Testing is critical. One great programmer I once knew said you have to
write 5-10 lines of test code for every line of code you produce; testing your
code to make sure it works is crucial. Write tests to see if your code handles
all the cases you think it should. Be as comprehensive as you can be. Of
course, when grading your projects, we will be. Thus, it is better if you find
your bugs first, before we do. Keep old versions around. Keep copies of older versions of your program
around, as you may introduce bugs and not be able to easily undo them. A
simple way to do this is to keep copies around, by explicitly making copies of
the file at various points during development. For example, let's say you get
a simple version of myreverse.cworking (say, that just reads in the
file); typecp myreverse.c myreverse.v1.cto make a copy into the file
myreverse.v1.c. More sophisticated developers use version control systems like
CVS , but we'll not get into that here (yet). Keep your source code in a private directory. An easy way to do this is
to log into your account and first change directories into private/and
then make a directory therein (sayp1, by typingmkdir p1after
you've typedcd private/to change into the private
directory). However, you can always check who can read the contents of your
AFS directory by using thefscommand. For example, by typing in
fs listacl .you will see who can access files in your current directory. If
you see thatsystem:anyusercan read (r) files, your directory contents
are readable by anybody. To fix this, you would typefs setacl
. system:anyuser “”in the directory you wish to make private. The
dot “.” referred to in both of these examples is just shorthand for
the current working directory.  Part 2: Debugging C code The  gdb  debugger allows you to stop your program at any point
and investigate program variables. Specification: Start your program under the debugger. Put a breakpoint on your main
loop reading a line from the file. Single step through input of a
single line. Print out the values of at least two different
variables. Submit a transcript of your debugging session. Implementation tips:You start gdb by invoking it with the program name:
 Start running your program with the "run" command any input or output
redirection:
emperor01(5)% gdb programname
GNU gdb Red Hat Linux (6.5-37.el5_2.2rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host
libthread_db library "/lib/libthread_db.so.1".
(gdb) 
 
 You can set breakpoints on a function with the "break" command and
pass it either a function name or a file and line number:
(gdb) run < filename.c 
 
 You can print variables with the "print" command:
(gdb) break main
Breakpoint 1 at 0x8048419: file filename.c, line 8.
(gdb) break filename.c:11
Breakpoint 3 at 0x804841e: file filename.c, line 11.
(gdb) 
 
 You can list code with the "list" command, which takes a function name
or a filename:linenumber (like break):
gdb) print stdin 
$3 = (struct _IO_FILE *) 0x2ae420 
(gdb)  
 
 
(gdb) list main
1	#include <stdio.h> 
2	#include <string.h> 
3	
4	int main(int argc, char * argv[]) 
5	{
6	  char buffer[200]; 
7	  char * tmp; 
8	  while (!feof(stdin)) { 
9	    int len; 
10	    int i; 
(gdb)
 
After execution stops at a breakpoint, you can continue exection with
the "cont" command:
 One execution stops, you can step forward one source code line at a
time with the "next" command (abbreviated "n"), which jumps over function calls, or the
"step" command (abbreviated "s"), which goes into the function and stops:
(gdb) run < filename.c
Starting program: /afs/cs.wisc.edu/u/s/w/swift/tmp/programname <
filename.c 
Breakpoint 1, main () at filename.c:8 
8	  while (!feof(stdin)) {
(gdb) cont
Continuing.
 
 
Breakpoint 1, main () at filename.c:12 
12	  while (!feof(stdin)) { 
(gdb) next 
15	    tmp = fgets(buffer, 200, stdin);
(gdb) next 
16	    if (tmp == 0){ 
(gdb) next 
19	    len = strlen(tmp);
(gdb) next
20	    for (i = len-2; i >= 0; i--) {
(gdb) next
21	      printf("%c",myfunction(tmp[i]));
(gdb) step
myfunction (c=62 '>') at filename.c:5
5	  return((int)c);
(gdb)
 You can quit gdb with the "quit" command.
 
  What to turn in: 
  Please put all  files in the directory: ~cs537-1/handin/<your-login>/p0 A digital picture of yourself 
   Please turn in your source code as a single file named
  "assignment0.c" (there is no need for multiple files or a makefile for this assignment)
   Please turn in a transcript from your debugging session as a text file
  name "debug-trace.txt"
   
  What we will look for: 
   Does the code work on simple files?
   Does the code work on more complex files (zero-length lines,
  very long lines)
   Did you get the debugger to work?
   Did you turn in a picture?
 
 |