Implement a very basic zero to one level index based file system, and provide a uniform interface for working on anything at all file like: input from keyboard, output to monitor, fake magnetic tape files, and your disc files. The "uniform interface" means that once you have opened a file-like thing, you will use exactly the same functions in exactly the same way regardless of what kind of device you are accessing. You will even use the same open function. This is made easy by adding some structure to file names. You will decide exactly what is allowed in a file name except for three things: colon : divide / and invisible characters are not allowed in file names. Then : can be used to tell the open function what device you want to access: f := open("k:", 'R') for keyboard input f := open("m:", 'W') for output to your monitor f := open("t:data.txt", 'R') input from real rabbit file f := open("t:data.txt", 'W') output to real rabbit file f := open("d:data.txt", 'R') input from one of your disc files f := open("d:data.txt", 'W') output to one of your disc files f := open("abc.b", 'R') for convenience, no : defaults to disc then readchar(f) [or whatever you want to call it] would be the way to read the next character from whatever f was connected to by the open call, but of course error if it was opened with 'W' instead of 'R' writeno(f, 123) is the way to output the number 123 readstr(f) read a whole string ... all the i/o operations you could ever want. Whenever more than one tape file is open at the same time, each needs to be attached to a different tape drive unit, but no matter how many disc files are open at once, they are all using the same disc drive. The object that f points to must contain within it everything needed to support all of those operations, but only if it is specific to the particular device. What readchar is diferent from each kind of device, so it goes in the object. readstr does not go in the object because it is a dependent function. It uses readchar over and over again, and readchar is in the f object. In general, these are the minimum independent operations: readchar writechar unreadchar close data items needed too: filename (optional, but allows much better error messages) buffer (not needed for keyboard or monitor, but consistent positioning helps, just set it to nil when not needed) unit number (only used with tapes, or if you choose to support multiple disc drives which would require an addition to the full file name, e.g. "d2:abc.txt") current position in buffer number of bytes in the buffer (for output files those two are the same thing, but for input they are not. Also not needed for keyboard or monitor) pointer to in-memory copy of the header block (only needed for disc) anything else you decide you need, but don't overdo it. You may think that the functions for refilling the buffer (for input) and writing a full buffer (on output) also belong in there, but they don't. Such functions are only used by readchar, writechar, and close (maybe unreadchar too), and they are already in there. They will be written to explicitly call the particular other functions they need. The best design for the open function is to have one single open that inspects and trims the filename it is given, and then call the specific opening function for that kind of device. The user would never know about those functions. They would of course create a vector to contain all of the necessary things, and you will need manifest constants to indicate the right position of each item in the vector without possible confusion. That vector is what open ultimately returns to become the value of f in the seven examples. It is not a good idea to just set the entries for reachar and unreadchar to nil on output files, or to use nil for writechar with an input file. Nobody expects to have to check that reachar is not nil before using it. Just make a little function that produces a suitable error message whenver it is called, and use it for those entries. For this assignment the disc system does not need to do very much. If a file is only small, it must be allowed to store the data in the header block (a level zero file) but of course you must support one level indexes too (header block has direct pointers to data blocks) Specific to the disc part, you need: a way to format (reset to empty) a disc, a way to continue using a disc without losing anything from previous use something to keep track of which disc blocks are free and in use. a way to safely shut the disc system down without losing information a root directory of your own design header blocks of your own design a way to create a file and put data in it and close it a way to open an existing file, read data from it, and close it a way for a program to detect end of file for input files (*) a way to delete a file a way to get a directory listing anything else that helps you to do the job. (*) You should be able to determine if the end of a file has been reached from the data items already described. Reading and writing files must be user friendly at least as far as it is in normal computing systems. After opening a file a program must be able to read or write data whenever it wants. Making the program provide the entire contents of a new file at once, or making it take the whole contents of an input file all at once will not do. Remember that the purpose of tape files is to give you access to data for large files without having to type it yourself. Make sure you can successfully copy files from any kind of device to any other.