For this lab you will build a simple command-line application that maintains a linked list based on inputs from a file or stdin. You will further begin to discover the joys of parsing by reading numbers a single character at a time.
Your directory contains a lot of folders, but the ones you are most interested in are src and bin.
To compile your project, use make in the top-level directory (i.e. not in src).
To run your program, execute the builder executable in the bin directory with ./bin/builder
You are going to build a linked list that holds Lines, supporting number of operations. For these linked lists, an empty list will be represented by a cell with a NULL head value. All functions should ensure that all pointers are valid before use: use assertCondition(). You can look at line.c for an example of allocating memory on the heap. To free memory on the heap, use free(ptr) on a pointer ptr.
You MUST implement the following functions:
List* emptyList() - MUST create an empty list. You MUST represented by a valid list cell with a NULL head and next value.
int size(List* lst) - MUST return the size of the list.
bool isEmpty(List* lst) - MUST return true only if the list is empty. You SHOULD throw an error if the pointer is null, but you MAY return True instead.
void printList(List* lst) - MUST call printLine on each Line in order, and then print a newline ("\n"). You MUST NOT add any additional separators between the lines.
void tPrintList(List* lst) - MUST print the header "| x | y |\n" and then call tPrintLine on each Line in order. You MUST NOT add any additional separators between the lines.
void append(List* lst, Line* line) - MUST add line to the end of the list. If the list is empty, you MUST NOT allocate a new cell. Otherwise the tail of the list MUST point to a newly allocated cell which holds line as it's value.
void insert_after(List* lst, Line* line) - MUST add line after the cell pointed to by lst. If the list is non-empty, you MUST allocate a new cell and place it immediately after the first elements of lst. If the list is empty you MAY throw an error or MAY treat this as append.
void insert_at(List*lst, Line* line, int idx) - MUST add line at index idx in the list. Lists are indexed from 0. You MUST NOT invalidate pointers to the first cell of the list, even if idx is 0.
void remove_next(List* lst) - MUST remove the cell after the one pointed to by lst. If the list is non-empty, you MUST remove the element pointed to by lst's tail from the list. You SHOULD free both the Line and List cell that are removed.
void remove_at(List* lst, int idx) - MUST remove the cell at index idx in the list. Lists are indexed from 0. You MUST NOT invalidate pointers to the first cell of the list, even if idx is 0. You SHOULD free both the Line and List cell that are removed.
For the full project you will need a number of utility functions.
You SHOULD write functions to skip any number white spaces and blank spaces in a file.
You SHOULD use getc() and ungetc() to define these functions.
White spaces are spaces, tabs, newlines, feeds, carriage returns, and vertical tabs. You SHOULD use isspace() to check for those.
Blank spaces are only spaces and tabs.
You MAY define functions char passWhitespace/passBlankspace(FILE* input) that return the next non-whitespace (resp non-blankspace) character, and functions void skipWhitespace/skipBlankspace(FILE* input) that skip past all whitespace (resp blankspace) characters.
You SHOULD put these functions in utils.h.
You MUST write a readNumber function that reads in a number one character at a time.
You MUST use getc() and ungetc() to define this.
You SHOULD put this function in utils.h.
You SHOULD have the function return a Boolean success condition. This will require you pass in an integer pointer to store the actual number.
You MAY write variants of error and assertcondition that take an integer line number and include it in the error output.
You SHOULD use debug, debug_l, and debugLevel for debugging output.
You will read instructions from a file or standard input. The argument handler in args.c will return either a file name or the string "-" if input should come from standard in. Each line in the file MUST specify a different instruction. Elements of an instruction MUST be separated by a single space character.
You SHOULD define a new file to hold the function(s) for processing instructions. You MAY use builder.h/builder.c.
The first character in each line MUST be a single letter, which will determine the rest of the instruction.
The letter p describes a print command, which pretty-prints the entire linked list.
The letter t describes a table print command, which prints the entire linked list in tabular format.
The letter a describes an append command, which appends a new line to the list. This is followed by two numbers, which represent the two values in the line.
The letter i describes an insert command, which inserts a line into the list at a specified index. This will be followed by three numbers: the first two representing the two values in the line, and the final number representing the index.
The letter d describes a delete command, which deletes a line from the list at a specified index. This will be followed by one number, the index of the element to re there will be just an index.
After the file is over (EOF), you SHOULD free the remaining elements of the list. This SHOULD be done with a function in list.h.
You SHOULD use valgrind to ensure the memory is correctly freed.
Finally, you SHOULD support the following additional flags:
A verbose flag that prints after every command.