Assignment 1 -- 40 points

Due: Monday, September 15.

Summary: Implement the four standard I/O functions fopen(), fclose(), fgetc(), and fputc() using the Unix system calls open(), close(), read(), and write().

The implementation doesn't need to be buffered--you can consider your implementation to be "wrapper" functions to the system calls, for the most part.

Then, using the functions you have written, create a program that copies text files, similar to the Unix "cp" command.

Detail: To avoid confusion, your version of fopen() will be called my_fopen() (likewise for the other functions.) You will need a datatype similar to the FILE structure--call it MY_FILE.

Here are the details of the functions to be implemented:

MY_FILE *my_fopen(char *filename, char *type)
Opens a file "filename" with the given type (which can be "r", "w", or "a", for read, write, and append, respectively). The pointer to the MY_FILE datatype which is returned will be used in the other calls. The file should be created if it is opened for writing or appending and it doesn't exist. For the permissions that you must pass to the open() call for file creation, use 0666. This function should return NULL on error.

int my_fclose(MY_FILE *fp)
Closes the file pointer fp. Returns 0 on success and EOF (defined in <stdio.h>) on error.

int my_fgetc(MY_FILE *fp)
Reads and returns a single character from the stream fp. Returns EOF on end of file or error.

int my_fputc(int c, MY_FILE *fp)
Writes the character c to the stream fp. Returns the character written or EOF on error.

The File Copier: Write a program that copies text files, my_cp. This program will not use any of the standard I/O functions or the Unix system calls; it will use the I/O functions you have implemented, above. The usage should be: "my_cp infile outfile".

To do this properly, you should make a header file that contains the structure for MY_FILE as well as prototypes for all the functions you implemented. The file copier can then #include this header file so it will be good to go. (The source for the functions themselves can also include this header file.)

Extra Credit: For a boost of an extra 6 (six) points, implement both of the following using your my_fgetc() and my_fputc() functions:

char *my_fgets(char *s, int maxsize, MY_FILE *fp)
Reads characters from fp (up to maxsize total) until end-of-file or a newline character ('\n') is reached. (If the final character is a newline, it should be included as the last character in the string.) The characters are stored in string s. When the function completes, a pointer to s is returned, or NULL in the case of error.

int my_fputs(const char *s, MY_FILE *fp)
Writes a null-terminated string (ending in '\0', that is) to stream fp. Don't actually write the null terminator--just write the characters up to it. Return 0 on success or EOF on error.

Directory structure: So we have an easy time grading this, you should make a couple subdirectories from your home directory, like so:

    $ mkdir -p ~/298C-02/prog1

Then put all the code for this project in the prog1 subdirectory. More subdirectories will be created as the class progresses.

When the program is due, please be sure you have world-read permission on all the files in the directory, and world read and execute permission on the directory itself (and the 298C-02 directory):

    $ chmod 755 ~/298C-02
    $ chmod 755 ~/298C-02/prog1
    $ chmod o+r ~/298C-02/prog1/*

Of course, this means that anyone can go read your program files and copy them. But, to stifle any cheating, you might as well leave the directory closed until you are ready for us to go in and get it on the due date. I'll send a piece of mail to remind everyone to chmod everything (if I remember ;-).

The Makefile: Since this might be your first Makefile experience, we'll give you a sample one to help out. We've bundled all the code for the my_fxxx() functions into a single source file called "my_io.c". The functions are declared in a header file called "my_io.h", which will be included by any programs that use the I/O routines, such as my_cp. The gameplan is to create an object file with all the I/O routines in it, then link that to the my_cp program.

    # Makefile for prog1

    all: my_io.o my_cp

    my_io.o: my_io.c my_io.h
            cc -Ae -c my_io.c

    my_cp: my_cp.o my_io.o
            cc -o my_cp my_cp.o my_io.o

    my_cp.o: my_cp.c
            cc -Ae -c my_cp.c

Late Policy: 4 (four) points per day, as the clock rolls over midnight.