CS 3113: Project 2
For this project, we will implement a miniature database with a
front-end that is accessible using a web browser.
- The file will contain a set of records that describe
assignments for a course, including the name of the assignment,
its type, the maximum number points that can be earned, the
number of points actually earned, and whether the record is
valid
- Your program can be executed to insert or change data in the
database using command line arguments
- Your program can also be used in server (front-end) mode: under
certain conditions, it will produce HTML-formatted output that
shows the following:
- A list of the valid database records
- The weighted score given the valid records
- A list of the invalid records
Objectives
By the end of this project, you will be able to:
- Read/write C structures from/to a file
- Create/delete a named pipe
- Create programs that wait for the named pipe to be opened and
produce output to the named
- Create programs that can generate HTML code that is usable by a
web browser
Back-End Database
Your database will be stored in a file called grades.bin.
Every time your program begins execution, you will open this file for
both reading and writing. If the file does not exist on open, then
you should create it. Much like your project 1 implementation, your file is
composed of fixed-size blocks of data. Each block contains one
instance of the AssignmentRecord structure, as defined in record.h:
#ifndef RECORD_H
#define RECORD_H
// Maximum size of assignment name
#define NAME_SIZE 23
// Name types
typedef enum {EXAM=0, HOMEWORK, QUIZ, PROJECT} AssignmentType;
// Name Strings
char *type_names[] = {"EXAM", "HOMEWORK", "QUIZ", "PROJECT"};
// Record of a single assignment
typedef struct {
char valid;
char name[NAME_SIZE];
int type; // AssignmentType
float max_score;
float score;
}AssignmentRecord;
#endif
Notes:
- #ifndef/#define/#endif are used in many header files to ensure
that the contents of the header are only loaded once during
compilation (even if
there are multiple includes of the same file)
- NAME_SIZE defines the maximum number of characters in the name
of an assignment (including the null terminator byte)
- AssignmentType and type_names define the set of possible
assignment types and their corresponding string names
- AssignmentRecord defines all of the data that we need to
describe a single assignment
- The key idea that you will be making use of is that you can
read/write bytes of an entire record all at once. This makes
implementation of simple databases easy (but, in the general
case, one has to be very careful about architecture-dependent
differences of type representations)
Back-End Commands
Your program can be executed with a number of different sets of
command-line parameters. Here are the ones that are specific to the
back-end:
- Append a new record onto the database file:
./project2 append NAME ASSIGNMENT_TYPE MAX_SCORE ACTUAL_SCORE
- NAME is the string name for the assignment. This
argument can be longer than what will fit in a
single AssignmentRecord. You must handle this situation
by truncating the name before copying it into the record
- ASSIGNMENT_TYPE is one of the type_names defined above.
It is an error if the provided argument is not one of
these strings
- MAX_SCORE is the maximum score for this assignment (a
floating point number)
- ACTUAL_SCORE is the actual score that was earned for
this assignment (also a float)
-
If all of the arguments are valid, then the database file is
modified with this new record placed at the end.
All appended records are automatically valid
All unused characters in the name field of the AssignmentRecord
must be set to zero (this is not generally required, but will
facilitate automatic testing).
- Change the score of an existing record:
./project2 score INDEX SCORE
- INDEX is the record number to be changed
- SCORE is the new score
It is an error if the specified record does not exist, or if
the record number or score cannot be parsed.
If there is no error, then the score for the record is changed
(and nothing else)
- Change a record to be valid:
./project2 valid INDEX
- INDEX is the record number to be changed
It is an error if the specified record does not exist, or if
the record number cannot be parsed.
If there are no errors, then the record's valid flag is set to
one (1)
- Change a record to be invalid:
./project2 invalid INDEX
- INDEX is the record number to be changed
It is an error if the specified record does not exist, or if
the record number cannot be parsed.
If there are no errors, then the record's valid flag is set to
zero (0)
- Not required, but strongly suggested for debugging purposes:
./project2 text
Iterate over the records in the database and print out their details.
Front-End Interface
The front-end interface will generate a web page in the
HyperText Markup Language
(HTML). For correctness testing purposes, we are prescribing the
output very precisely. Because the output is very narrow (and does
not use HTML in complicated ways), you should write your own code to
generate the output (i.e., don't use external libraries to generate
the output).
Below are the program commands that you must support for the front
end. Both generate identical output:
- Testing:
./project2 html
Prints the full HTML output to STDOUT and terminates.
- Server mode:
./project2 server
Enters an infinite loop. Each time through the loop, your program:
- Opens in write mode a named pipe called
grades.html.
This system call will block until a process opens the
file for reading
- Reroute the pipe file descriptor to file descriptor 1. This
means that all writes to STDOUT will to be sent to the
pipe instead. Note: the previous open() system call
will allocate the first available file descriptor to
return. Sometimes, this can already be 1.
- Print the full HTML output to STDOUT
- Close both the pipe file descriptor and STDOUT (if they
are the same, you should only close it once)
- Sleep for 1 second
- Repeat
Notes:
- All HTML output must be to STDOUT
- After generating the end of HTML output, your program must
perform a "flush" to make sure that the output data are not
left in a buffer:
fflush(stdout);
Initial State
When grades.bin does not exist, starting the server will result in the
file being created with no records. The initial file and the response
from ./project2 html are as follows:
A Bit of HTML
The job of HTML is to describe the content that goes into a web page
and to provide general information about how it should be rendered.
The details of rendering, however, are left to the specific web
browser that you are using.
Markup commands in HTML are surrounded by < > pairs. The
commands often form a "container" that define both the beginning and
end of the formatting command. For example, <B> indicates that
bold formatting should start at that point and </B> indicates
that bold formatting should stop. Specifically:
this is in bold
is implemented using the HTML code:
<B>this is in bold</B>
Looking at the raw text file above, you will notice certain markup
commands
- <HTML> ... </HTML> defines the beginning and ending
of a HTML document
- <HEAD> ... </HEAD> defines the beginning and ending
of the header material
- <TITLE> ... </TITLE> defines the title (this often
appears in the tab in the web browser)
- <BODY> ... </BODY> defines the body of the web page
- <H1> ... </H1> defines a level-1 header (often
rendered as bold and large); there are corresponding commands
for levels 2, 3, ...
- <TABLE> ... </TABLE> defines a table (in this case,
the table has a border parameter value of 2, meaning thick
lines)
- <TR> defines the beginning of a row in the table (the
ending markup can be also be included, but its existence is implied).
- <TD> defines a column in the current row (again, the
ending can also be included, but it is implied).
In our web page, the first row of each table is bolded to
indicate that this is a header row.
- <UL> ... </UL> indicates the beginning and ending
of a list
- <LI> indicates the beginning of a list item (again, the
ending is implied)
- <P> indicates the beginning of a new paragraph (again, the
ending is implied)
- <A HREF="SOME URL"> HYPERLINK NAME </A> indicates a
hyperlink (the name is displayed and the link will take the
user to the indicated URL)
Examples
The following represents a sequence of commands, starting from the
initial state. For each step, we link to both the database and html
files (all are contained in the distributed tar file).
./project2 append "Project 1" PROJECT 100 89.0
adds the Project 1 record to the database. The quotes in the
command line force all of "Project", SPACE and the number one to
appear as a single string (as argv[2]). The resulting state is:
Notes:
- Index is the record number being displayed in the corresponding
row
- Scores and max scores are shown with exactly two decimal places
- Average score is computed only over the valid records. It is
the sum of scores divided by the sum of max scores, and is
displayed as a percentage with two decimal places
./project2 append "Project 2" PROJECT 100 85.0
adds the Project 2 record to the database. The resulting state is:
./project2 invalid 0
Changes record 0 to be invalid. The resulting state is:
./project2 append "Project 1 (new project assignment)" PROJECT 110 98.0
adds the Project 1 (new project assignment) record to the
database.
The resulting state is:
Notes:
- The assignment name has been truncated to fit within the record.
./project2 append "Midterm exam" EXAM 137 113.0
adds the midterm exam record to the
database.
The resulting state is:
Testing Your Code
Back-End
Front-End
Submitting Your Program
- The deadline for submission is Tuesday, October 20th at
11:45:00 pm.
- Bonus: if you have your the back-end commands working
by Wednesday, October 7th (11:45:00 pm), then you can receive up to 10%
additional points. To have this count, you must submit your
project by the early deadline to the project2-bonus
Gradescope area.
- Your submission is composed of the following files, named exactly as shown (including casing):
- project2.c: your source file
- Include your name and project number at the top of the file
- Makefile: the makefile that implements:
- fifo: creates the named pipe in the local
directory called grades.html
- all: compiles your program (this is the
default behavior) and creates the named pipe
- clean: deletes the executable file
(project2), any intermediate files (.o,
specifically), and the named pipe.
- README.txt: documentation
- Include your name and project number at the top of the file
- Document any Internet resources that you
consulted (URLs). These must be specific URLs
that we can use to see the same pages that you
are using. If there are none, then
explicitly state this.
- Document any peer class members that you
discussed your solution with. If there are none, then
explicitly state this. Note that you may
not look at or share code that solves this
specific problem.
- Documentation requirements: function-level and inline
documentation are important components of writing code. They help
you to organize your thoughts while programming and help to
communicate the method and the intent of the code to your future
self or to collaborators (of course, you will not have collaborators
in this class). While we will not be specifically grading
documentation in this class, we will not be able to comment on your
code unless it is sufficiently documented. This will be true whether
you are asking for help before the submission deadline or looking
for feedback on your solution after the deadline. In short, you
should take the time to properly document your code as you develop
it.
- Submit your files:
- Create a zip file named project2.zip containing
your source code (c and h files), Makefile and README.txt file.
- Submit your zip file to Gradescope (access via Canvas).
Shortly after your submission, you will receive
automated feedback and a grade for the
correctness component of your grade.
- You may submit multiple times until the deadline.
- To be counted as on time, your solution must be submitted to
the Gradescope server by the due date and time. Grade
penalties will be imposed for late submissions (see the
syllabus for the details).
Grading Criteria
- README.txt (10%): contains the required information
- Makefile (10%): satisfies the make file requirements
- Correctness (80%): passes all of the (hidden) unit tests
Downloads
The following file contains the record.h header file and a number of
example tests: project2_dist.tar
Automated Testing
The testing procedure that we are using is the same as in Project 0.
Hints
- Remember that characters use the ASCII encoding.
- Don't implement everything at once. Instead, get the first few
commands written and tested before moving on to the more
complicated commands.
- Any debugging code should only print to STDERR. This way, it
won't interfere with our testing procedures.
- Useful C functions:
- memset()
- memcpy()
- read()
- write()
- open()
- lseek()
- strcpy()
- dup2()
- close()
- fflush()
- You can stop a program that is executing in your shell by typing CTRL-c
Addenda
- The bonus deadline has been moved to Wednesday, October 7th (11:45:00 pm).
- 2020-10-06: The definition of the record struct has
changed: the type field has changed from AssignmentType to int
(but you can still assign AssignmentType values to it). This
will not change things for many of you, but for those of you
who have some mysterious byte values right before the floats,
this should address the problem.
andrewhfagg at gmail.com
Last modified: Tue Oct 6 16:38:30 2020