CMSC216 Project 1: C Programming
- Due: 11:59pm Mon 16-Feb-2026
- Approximately 2.0% of total grade
- Submit to Gradescope
- Free Collaboration is allowed on projects. See the Syllabus for details.
CODE DISTRIBUTION: p1-code.zip
VIDEO OVERVIEW: https://umd.instructure.com/courses/1398391/pages/week-02-videos
CHANGELOG:
- Sun Feb 8 03:17:58 PM EST 2026
The project specification has been amended to include a missing section on Work Disclosure that all students must complete for full credit. A completed
WORK_DISCLOSURE.txtneeds to be present in the project directory with information how what collaborators and resources were used to complete the project. The template for this file is now in the project codepack and those who have already started the project can get it by updating via>> cd p1-code >> make update
Students that have already started P1 should run
make updateto get the updated files and may need to resubmit if they have done so already.- Sun Feb 8 01:42:04 PM EST 2026
Post 48 reported a problem in
glyph_init(), a provided function that is missing a line. This has been fixed in the codepack for students who have not yet downloadedp1-code.zip. Students who have already started the project can add the line markedMISSINGin manually below or just delete the entireglyph_init()function and replace it with this updated version:// PROVIDED: Initializes a glyph to mostly X's except for its // codepoint on the first line. void glyph_init(glyph_t *glyph, int codepoint){ glyph->is_set = 0; // MISSING in original posting glyph->codepoint = codepoint; glyph->width = 6; for(int i=0; i<MAX_HEIGHT; i++){ for(int j=0; j<MAX_WIDTH; j++){ if(j == glyph->width){ glyph->data[i][j] = '\0'; // null terminate } else{ glyph->data[i][j] = 'X'; } } } int len = sprintf((char *)glyph->data, "%d",codepoint); // add codepoint # to glyph glyph->data[0][len] = 'X'; // remove null termination char }
1 Introduction
Basic application programming in C is an essential step downward towards the lower levels of computing. This project explores fundamental aspects of getting work done in C:
- Dynamic memory management with
malloc()/free() - Reading data from files in text format
- Displaying information to the screen
- Building data structures with C
structsand pointers
The assignment is divided into several problems utilizing many of the above techniques.
- Problem 1 is a warm up with some basic string and printing routines to implement.
- Problem 2 builds on the previous routines to complete a banner letter printing function as well as deal with loading fonts and text files
- Problem 3 completes the application by coding a
main()function to employ the preceding functions to display banner text in a terminal.
Problems build on each other and should be done in order to complete the project.
1.1 Grading Criteria
Credit for this assignment will be given based on two categories.
- Manual Inspection Criteria (~60%): Each problem has a checklist of things that graders will look for. The checklist is in the spec and often contains hints on what to do. Make sure you have a look at these.
- Automated Testing (~40%): Each problem has tests associated with it along with instructions on how to run those tests from the command line. Tests require that code compiles and runs according to the descriptions given so make sure you verify that these work.
1.2 Getting Started
Take the following steps to get started
- Download the code associated with the project linked at the top of the spec. Unzip it and examine some of the provided code.
- Examine the overview of the files provided listed in the Download and Setup section. This gives brief descriptions of files that already exist and those that you must create.
- Pick a problem and read. There is a lot of information and many examples provided for each problem. Reading this will help you write the correct code earlier rather than later.
- Ask questions: if its not clear how to proceed, put up a Piazza post or visit an office hour.
- Get coding: don't wait to start for too long as this will greatly increase your stress level an potentially result in late submissions.
- Familiarize yourself with the late submission policy for assignments so you are not caught off guard. No submissions will be accepted more than 48 hours after the deadline.
2 Download Code and Setup
Download the code pack linked at the top of the page. Unzip this which will create a project folder. Create new files in this folder. Ultimately you will re-zip this folder to submit it.
| File | State | Notes |
|---|---|---|
Makefile |
Provided | Build file to compile all programs |
banlet_funcs.c |
EDIT | Problem 1&2 functions to write |
banlet_main.c |
EDIT | Problem 3 main function skeleton to edit |
banlet.h |
Provided | Header file |
banlet_font_standard.c |
Provided | Source file for "builtin" font |
banlet_demo.c |
Provided | Demo code to show some Banlet struct syntax / usage |
cmdline_args.c |
Provided | Demo of how to access command line arguments |
test_banlet_funcs.c |
Testing | Testing file for functions in Problem 1-2 |
data/font_banner.txt |
Data | Font files for testing |
data/font_mini.txt |
Data | |
| … | ||
data/bass.txt |
Data | Text files for testing |
data/oo.txt |
Data | |
| … | ||
| TESTING | ||
testy |
Testing | Test running script |
test-results/ |
Testing | Directory in which temporary testing files are written |
test_banlet1.org |
Testing | Problem 1 tests |
test_banlet2.org |
Testing | Problem 2 tests |
test_banlet3.org |
Testing | Problem 2 tests |
2.1 Makefile
A Makefile is provided as part of this project. Building programs in
C is a bit tedious and most folks use build systems of which make
is the oldest. The instructions and dependencies to create programs
are written in a Makefile which is then interpreted by the make
program which will run gcc and other commands to create programs.
Use this Makefile by issuing commands like make prob1
>> make help Typical usage is: > make # build all programs > make clean # remove all compiled items > make zip # create a zip file for submission > make prob1 # built targets associated with problem 1 > make test # run all tests > make test-prob2 # run test for problem 2 > make test-prob2 testnum=5 # run problem 2 test #5 only >> make prob2 # build problem 2 demo program gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_funcs.c > make clean # remove all programs/binary object files rm -f banlet_main banlet_demo test_banlet_funcs *.o >> make prob3 # build problem 3 main program gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_main.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_funcs.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_font_standard.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o banlet_main banlet_main.o banlet_funcs.o banlet_font_standard.o >> make clean # remove all programs/binary object files rm -f banlet_main banlet_demo test_banlet_funcs *.o >> make # build all programs/objects for the assignment gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_main.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_funcs.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_font_standard.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o banlet_main banlet_main.o banlet_funcs.o banlet_font_standard.o gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o banlet_demo banlet_demo.c banlet_font_standard.o gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o test_banlet_funcs test_banlet_funcs.c banlet_funcs.o banlet_font_standard.o
You are not required to understand all that is in the Makefile (yet)
but it is a very useful tool well worth your time to learn.
2.2 Automated Tests
Automated tests are included with the code distribution. These tests are known to work on grace.umd.edu only but in most cases they should run identically in Linux environments. They may work on the Windows Subsystem for Linux but no guarantees are made. They very unlikely to run on MacOS natively as Linux-specific tools are used.
The provided Makefile allows automated tests to be run via calls
like make test-prob1 to test Problem 1 and make test-prob2 to test
Problem 2. See the transcript below.
>> make test # run tests for problem 1, compiles required code first gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_funcs.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_font_standard.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o test_banlet_funcs test_banlet_funcs.c banlet_funcs.o banlet_font_standard.o ./testy test_banlet1.org ============================================================ == test_banlet1.org : Problem 1 String / Printing Functions in banlet_funcs.c == Running 15 / 15 tests 1) string_replace_char_1 : ok 2) string_replace_char_2 : ok 3) string_replace_char_3 : ok 4) string_replace_char_4 : ok 5) count_linebreaks_1 : ok 6) count_linebreaks_2 : ok 7) count_linebreaks_3 : ok 8) find_linebreaks_1 : ok 9) find_linebreaks_2 : ok 10) find_linebreaks_3 : ok 11) find_linebreaks_4 : ok 12) print_fontified_oneline_1 : ok 13) print_fontified_oneline_2 : ok 14) print_fontified_oneline_3 : ok 15) print_fontified_oneline_length : ok ============================================================ RESULTS: 15 / 15 tests passed >> make test-prob3 # run tests for problem 2 gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -c banlet_main.c gcc -Wall -Wno-comment -Werror -g -Wno-unused-variable -o banlet_main banlet_main.o banlet_funcs.o banlet_font_standard.o ./testy test_banlet3.org ============================================================ == test_banlet3.org : Problem 3 slurp_file() and banlet_main tests == Running 15 / 15 tests 1) banlet_main Hello World : ok 2) banlet_main multiline : ok ... >> make test # run tests for all problems ...
Each problem describes specifically how tests can be run and how credit will be assigned.
Note that one can run a single test with the following make
invocation which sets testnum.
>> make test-prob2 testnum=5
This is useful when debugging to limit the output and time it takes to check program results.
3 Problem 1: Banlet Support
3.1 Overview
The overarching project goal is to recreate a simplified version of
the figlet program program that is available on many Unix systems
(though no Zaratan unfortunately). This project constructs a similar
program called Banlet which prints messages as "banner letters"
which are larger and more striking than standard terminal fonts. To
set the goal, here is what banlet_main does in practice:
>> ./banlet_main 'Hi there!' # print a simple "fontified" message"
._. ._. ._. _ ._.
| | | |(`) | |_.| |__ ___ ._ __. ___ | |
| |_| ||'| | __|| '_ \ /'_`\| `__| /'_`\| |
| _ || | | |_ | | | || __/| | | __/|_|
|_| |_||_| \__||_| |_| \___||_| \___|(_)
>> ./banlet_main $'How do\nyou do?' --fontfile data/font_banner.txt # print a multiline message in a different font
# #
# # #### # # ##### ####
# # # # # # # # # #
####### # # # # # # # #
# # # # # ## # # # # #
# # # # ## ## # # # #
# # #### # # ##### ####
#####
# # #### # # ##### #### # #
# # # # # # # # # # #
# # # # # # # # # ###
# # # # # # # # # #
# # # # # # # # #
# #### #### ##### #### #
>> cat data/asimov.txt # show contents of a text file
I do not fear computers. I fear the lack of them. -Asimov
>> banlet_main --fontfile data/font_mini.txt --textfile data/asimov.txt # print file as banner text using a different font
___ _ ___ _ _
| _| ._ _|_ _|_ _ _.._ _ ._ _ ._ _|_ _ ._ _ | _|_ _ _.._ _|_|_ _ | _. _| _|_ _|_|_ _ ._ _ __ /\ _o._ _
_|_ (_|(_) | |(_) |_ | (/_(_|| (_(_)| | ||_)|_| |_(/_| _>o _|_ | (/_(_|| |_| |(/_ |(_|(_|< (_) | |_| |(/_| | |o /--\_>|| | |(_)\/
Problem 1 lays out a number of utility functions that operate on strings which gradually build towards the full functionality required.
3.2 Outline of banlet_funcs.c
The file banlet_funcs.c will contain most of the support functions
for the Banlet program. An outline of these functions are presented
below. Note that each function has the Problem # to which it belongs.
// banlet_funcs.c: support functions for the banlet_main program.
#include "banlet.h"
void glyph_init(glyph_t *glyph, int codepoint);
// PROVIDED: Initializes a glyph to mostly X's except for its
// codepoint on the first line.
void string_replace_char(char *str, char old, char new);
// PROBLEM 1: Replace instances of character 'old' with 'new' in the
// string 'str'. May use the strlen() library function to determine
// string length or directly look for a '\0' null termination
// character to end the string.
//
// EXAMPLES:
// char s1[]="A A B B A"; string_replace_char(s1, 'A', 'X'); // s1 is "X X B B X"
// char s2[]="A A B B A"; string_replace_char(s2, 'B', 'Y'); // s2 is "A A Y Y A"
// char s3[]="A A B B A"; string_replace_char(s3, ' ', '-'); // s3 is "A-A-B-B-A"
int count_linebreaks(char *msg);
// PROBLEM 1: Counts the number of newline characters '\n' in the
// string 'msg'; return this number +1 as the end of lines will always
// be a line break. May use the strlen() library function to determine
// string length or directly look for a '\0' null termination
// character to end the string.
//
// EXAMPLES:
// count_linebreaks("Hi") -> 1
// count_linebreaks("Hi There") -> 1
// count_linebreaks("Hi\nThere") -> 2
// count_linebreaks("O\nM\nG") -> 3
int *find_linebreaks(char *msg, int *nbreaks);
// PROBLEM 1: Counts the linebreaks (newline '\n' chars and end of
// string) and returns an array of integers with the position for each
// linebreak in string 'msg'. Uses the count_linebreaks()
// function. The 'nbreaks' parameter is an OUTPUT integer that should
// be set to the number of breaks in 'msg' using the C dereference
// operator (*).
//
// EXAMPLES:
// int nbreaks = -1;
// int *breaks = find_linebreaks("Hello\nWorld", &nbreaks);
// // index in string: 012345 67890
// // nbreaks is now 2
// // breask is now [5, 11]
void print_fontified_oneline(char *msg, font_t *font, int length);
// PROBLEM 1: Prints string 'msg' using 'font'. Only prints characters
// 0 to 'length-1'. Iterates over each row in font->height and then
// scans across the charactes in 'msg' printing each "row" of the
// character. On reaching index 'length', prints a newline and then
// scans across 'msg' again printing characters from the next row.
// Each msg[i] character is used to as the index into fonts->glyphs[]
// to access the "glyph" that will be printed.
//
// NOTE: This function does NOT handle embedded newline '\n'
// characters. It is intended to be called repeatedly on each line in
// multiline text with '\n' characters found using the
// 'find_linebreaks()' function.
//
// EXAMPLE:
//
// print_fontified_oneline("Hello!", &font_standard, 6);
// // Prints the following on standard output:
// ._. ._. ,-,,-, ._.
// | | | | ___ | || | ___ | |
// | |_| | /'_`\| || | / _ \ | |
// | _ || __/| || || (_) ||_|
// |_| |_| \___||_||_| \___/ (_)
void print_fontified(char *msg, font_t *font);
// PROBLEM 1: Uses print_fontified_oneline() with find_linebreaks() to
// correctly print 'msg' with 'font' even if there are linebreaks in
// 'msg'. Uses find_linebreaks() to find the end of each line in
// 'msg' and then iterates over lines printing each. Uses pointer
// arithmetic to pass the starting position of each line into calls of
// print_fontified_oneline(). Frees memory allocated (such as through
// use of count_linebreaks()) before returning.
//
// EXAMPLE:
// print_fontified("apple\nB@N@N@\nCarr0^", &font_standard);
// Shows the following on standard output:
// ,-,
// __ _ ,_ __. ,_ __. | | ___
// / _` || '_ \ | '_ \ | | /'_`\
// | (_| || |_) || |_) || || __/
// \__,_|| .__/ | .__/ |_| \___|
// |_| |_|
// ,____ ____ ._ ._. ____ ._ ._. ____
// | == ) / __ \ | \ | | / __ \ | \ | | / __ \
// | _ \ / / _` || \| | / / _` || \| | / / _` |
// | |_)|| | (_| || |\ || | (_| || |\ || | (_| |
// |____/ \ \__,.||_| \_| \ \__,.||_| \_| \ \__,.|
// \____/ \____/ \____/
// ____. ___ /\
// / ___| __ _ ._ __.._ __. / _ \ |/\|
// | | / _` || `__|| `__|| | | |
// | |___.| (_| || | | | | |_| |
// \____| \__,_||_| |_| \___/
font_t *font_load(char *filename);
// PROBLEM 2: Loads a banner font from 'filename'. The format of font
// files is documented more thoroughly in the project specification
// but is generally comprised of a first line that indicate the height
// of each glyph in the font followed by a sequence of each glyph
// starting with its codepoint (ASCII index) and a grid of characters
// in it. To make parsing easier, the ? character is used to represent
// blank spaces in glyph shapes.
//
// EXAMPLE:
// height: 4
// 42
// ???
// \|/
// /|\
// ???
// 43
// ???
// _|_
// ?|?
// ???
//
// The two characters above are the codepoint 42 '*' and codepoint 43
// '+' with the ? symbols eventually being replaced by spaces during
// loading.
//
// If 'filename' cannot be opened for reading, returns NULL.
//
// Memory allocation happens in two steps: (1) allocates memory for a
// font_t struct then (2) allocates memory for an array of glyph_t
// structs of length NUM_ASCII_GLYPHS (a constant defined in
// banlet.h). Sets the font->glyphs field to be the allocated array of
// glyphs. Reads the font->height field from teh first line of the
// file. Iterates over each element of the glyphs array and calls the
// glyph_init() function on it to populate it with default data. Then
// proceeds to read glyphs from the file. Glyphs are read by reading
// the integer codepoint first which determins which element of the
// glyph array to read into. Then a loop over the height of the font
// is used to read each row of the glyph into the
// glyph[codepoint]->data[row]; fscanf() with '%s' specifier is used
// for this. Finally, the string_replace_char() function is used to
// replace all '?' characters with ' ' (space) characters in the glyph
// data. Sets the width of each glyph using the strlen() function on
// any balid row of the glyph data. The width of each glyph is set
// based on the length of one of its 0th row and the .is_set field is
// changed to 1 to indicate the glyph is present.
//
// Glyphs are read from 'filename' until an attempt to read a glyph's
// codepoint with fscanf() returns EOF (end of file). This causes the
// routine to return the allocated font_t data for use elsewhere.
void font_free(font_t *font);
// PROBLEM 2: Frees the memory associated with 'font'. First frees
// the glyph array, then frees the font itself. Hint: this funciton
// should be 2 lines long.
char *slurp_file_two_pass(char *filename);
// PROBLEM 2: Read all characters from the file 'filename' into a
// dynamcally allocated array. Terminates the array with the '\0'
// character to form a valid C string and return that string. If the
// file cannot be opened, return NULL.
//
// Uses a "2-Pass" solution. Counts the characters in file via calls
// to fscanf() or fgetc(), then returns to beginning of the file with
// rewind(), allocates an appropriately sized block of memory, then
// reads all characters into it in a second pass.
//
// CONSTRAINT: Does not use any functions that determine the size of a
// file a priori such as fstat() or fseek() or their kin.
char *slurp_file_one_pass(char *filename);
// OPTIONAL MAKEUP CREDIT: Like surp_file_two_pass() but uses a single
// I/O pass and dynamically expands memory to handle larger
// inputs. For full makeup credit, this approach must abide by the
// following additional conditions:
// - Does not use functions that determine the size of the file
// - Does not allocate/copy memory each loop iteration, only
// "occasionally"
// - Does not use the realloc() function, only malloc()/free()
// - Has amortized linear time and linear space; the allocated array may
// not be any larger than 2x the number of characters in it
// - Uses a memory allocation scheme similar to thos used with
// dynamic arrays to meet the above requirement; see
// https://en.wikipedia.org/wiki/Dynamic_array
// - Include comments describing your makeup credit approach
// - Is used in the main() function and/or elsewhere in place of the
// other version
3.3 Editing and Testing
The project code contains a skeleton version of banlet_funcs.c which
you should fill in with definitions. With this skeleton version, you
can immediately start testing your code by typing make test-prob1.
Without changes, you will get failures for all tests as in
>> make test-prob1 ./testy test_banlet_funcs.org ============================================================ == test_banlet_funcs.org : Problem 1 First 5 Functions in banlet_funcs.c == Running 15 / 15 tests 1) string_replace_char_1 : FAIL -> results in file 'test-results/prob1-01-result.md' 2) string_replace_char_2 : FAIL -> results in file 'test-results/prob1-02-result.md' 3) string_replace_char_3 : FAIL -> results in file 'test-results/prob1-03-result.md' 4) string_replace_char_4 : FAIL -> results in file 'test-results/prob1-04-result.md' ... 15) print_fontified_oneline_4 : FAIL -> results in file 'test-results/prob1-15-result.md' ============================================================ RESULTS: 0 / 15 tests passed
However, the ability to run tests on your code an see progress is extremely important. Your first goal when starting a new project should be to see some results or running the program which is much easier if some benevolent dictator has provided a bunch of tests.
Keep in mind that as you fail tests, you can see the results files in
any text editor or in the terminal. The cat command is helpful for
this:
>> cat test-results/prob1-01-result.md
(TEST 1) string_replace_char_1 : FAIL
=====================================
COMMENTS
--------
PROGRAM: ./test_banlet_funcs string_replace_char_1
--------------------------------------------------
To run this individual test in GDB use the command:
gdb --args ./test_banlet_funcs string_replace_char_1
but any input to the program must be typed within the debugger
FAILURE MESSAGES
----------------
- Output Differenes: Expected/Actual do not match, check Diff Sections for details
SIDE-BY-SIDE DIFF of Expected vs Actual
---------------------------------------
. lines match; | lines differ; < expected line missing; > extra line in actual
```sdiff
===EXPECT=== ===ACTUAL===
IF_TEST("string_replace_char_1") { . IF_TEST("string_replace_char_1") {
// Tests replacing characters in a string . // Tests replacing characters in a string
char string[]="A A B B A"; . char string[]="A A B B A";
string_replace_char(string, 'A', 'X'); . string_replace_char(string, 'A', 'X');
printf("result: '%s'\n", string); . printf("result: '%s'\n", string);
} . }
---OUTPUT--- . ---OUTPUT---
result: 'X X B B X' | result: 'A A B B A'
```
LINE-BY-LINE DIFF of Expected vs Actual
---------------------------------------
```
EXPECT 8) result: 'X X B B X'
ACTUAL 8) result: 'A A B B A'
```
VALGRIND REPORT
---------------
The program is run on under valgrind as
stdbuf -i 0 -o 0 -e 0 valgrind --error-exitcode=13 --leak-check=full --show-leak-kinds=all --track-origins=yes ./test_banlet_funcs string_replace_char_1
which may be pasted onto a command line to run it.
```
==340236== Memcheck, a memory error detector
==340236== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==340236== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==340236== Command: ./test_banlet_funcs string_replace_char_1
==340236==
==340236==
==340236== HEAP SUMMARY:
==340236== in use at exit: 0 bytes in 0 blocks
==340236== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==340236==
==340236== All heap blocks were freed -- no leaks are possible
==340236==
==340236== For lists of detected and suppressed errors, rerun with: -s
==340236== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```
SUMMARY
-------
Test FAILED for the following reasons
- Output Differenes: Expected/Actual do not match, check Diff Sections for details
You can also use the invocation
>> make test-prob1 testnum=5
to run a single test and see its results.
3.4 String Utility Functions
The first 3 functions to implement in banlet_funcs.c are string
utility functions that will be used later. As covered in lecture, C
uses raw arrays of characters as its string type. Often these are
passed as a pointer to character data, thus the prototypes that
involve char * as in
void string_replace_char(char *str, char old, char new)
Keep the following in mind.
- You'll need to iterate over the characters in the string. Since
stris a pointer, one can use the indexing syntaxstr[i]to access individual characters in it. This can also be used to assign a new character as instr[i] = 'A';. strdoes not carry its length with it so there is nostr.lengthorlength(str)available andsizeof(str)WILL NOT WORK to determine the length of the string.- Since one definitely needs to iterate over all characters in
str, use one of the following two mechanisms to find its endstrlen(str): this handy function from the C string library gives returns the length of strings only- The
\0character: all standard strings are to be terminated with a null\0character; one can check ifstr[i] == '\0'while iterating to find the end of the string. This is the technique that is used by library functions likeprintf()to find the end of strings.
- Make sure to use an equality check when comparing elements, that is
the
x == yoperator in C, NOT the assignment operator=.
find_linebreaks()
Consider the prototype for find_linebreaks() which has some
interesting features:
int *find_linebreaks(char *msg, int *nbreaks)
Importantly, this function must return 2 things determined from
parameter msg
- An array of integers indicating the positions in
msgwhere\n(newline) characters appear along with the end of the string. This is the return value for the function which must be amalloc()'d array. Do NOTfree()the array of integers youmalloc()infind_linebreaks(): it will be freed by the calling function The length of the returned array must also be returned. C does not support multiple returns per se, but pointers more than make up for this. The parameter
nbreaksis meant to be SET byfind_linebreaks()as indicated in the function documentation. A caller will provide the address of an integer for the function to setint nbreaks = -1; int *breaks = find_linebreaks("Hello\nWorld", &nbreaks); // index in string: 012345 67890 // nbreaks is now 2 // breask is now [5, 11]
3.5 Print Fontified
Glyphs and Fonts
The function print_fontified_oneline() is used to print single line
of text in a "font" as defined by the project. Normally fonts have
interesting geometric curves and drawing instructions embedded in
them. Most standard terminals don't support printing such things but
do support printing character data. Thus "fonts" in Banlet are just a
grid of text that is to be printed in when displaying a single
character. For example, when printing a fontified version of "A", the
following glyph is used in builtin font for Banlet.
012345678 0 / \ 1 / _ \ 2 / ___ \ 3/_/ \_\ 4
Basic Algorithm for Fontified Printing
This presents some interesting challenges when printing sequences of
such glyphs as one must typically print across rows of text before
moving the to the next line. So, to print the string "CAT", one would
print the first row of each glyph, then the second, then the 3rd, and
so on. As an example, here is "CAT" built incrementally. The @
symbol is used to denote where printing finishes at each step
DEMO of printing "CAT" via print_fontified_oneline() algorithm ROW 0, PRINT 0th CHAR 'C' ____@ ROW 0, PRINT 1th CHAR 'A' ____ _ @ ROW 0, PRINT 2th CHAR 'T' ____ _ _____@ ROW 0 DONE, PRINT \n ____ _ _____ @ ROW 1, PRINT 0th CHAR 'C' ____ _ _____ / ___|@ ROW 1, PRINT 1th CHAR 'A' ____ _ _____ / ___| / \ @ ROW 1, PRINT 2th CHAR 'T' ____ _ _____ / ___| / \ |_ _|@ ROW 1 DONE, PRINT \n ____ _ _____ / ___| / \ |_ _| @ AFTER PRINTING 2th ROW ALL CHARS ____ _ _____ / ___| / \ |_ _| | | / _ \ | | @ AFTER PRINTING 3th ROW ALL CHARS ____ _ _____ / ___| / \ |_ _| | | / _ \ | | | |___ / ___ \ | | @ AFTER COMPLETING ALL ROWS / CHARS ____ _ _____ / ___| / \ |_ _| | | / _ \ | | | |___ / ___ \ | | \____|/_/ \_\ |_| @
Implementing this basic printing algorithm is the purpose of the
print_fontified_oneline() function.
Font and Glyph C Types
The font_t and glyph_t data types are defined in the banlet.h
header file and are as follows.
1: #define MAX_HEIGHT 10 // max height in chars for glyphs 2: #define MAX_WIDTH 20 // max width in chars for glyphs 3: #define NUM_ASCII_GLYPHS 128 // number of glyphs in a font 4: 5: typedef struct { // type associated with individual glyphs 6: char data[MAX_HEIGHT][MAX_WIDTH]; // 2D array of data for glyph, rows should be \0-terminated strings 7: int is_set; // 1 if set to non-default status during font_load(), 0 otherwise 8: int codepoint; // ASCII codepoint, e.g. 65 for 'A' etc. 9: int width; // width of the glyph 10: } glyph_t; 11: 12: typedef struct { // type associated with a font 13: glyph_t *glyphs; // array of glyphs with length NUM_ASCII_GLYPHS for each ASCII codepoint 14: int height; // height of all glyphs in the font 15: } font_t; 16: 17: extern font_t font_standard; // font defined in banlet_font_standard.c
In order to access the glyph data to print, one must usually go
through a font data structure such as in this sample code provided in
banlet_demo.c.
// banlet_demo.c: shows some syntax patterns to access parts of the
// font_t and glyph_t data in banlet.
#include "banlet.h"
int main(int argc, char *argv[]){
font_t *font = &font_standard; // builtin font
printf("Standard font has %d rows\n",
font->height);
int codepoint = 'A'; // ASCII code 65
printf("Width of codepoint %d in font is: %d\n",
codepoint,
font->glyphs[codepoint].width);
printf("Row 0 of glyph is: %s\n",
font->glyphs[codepoint].data[0]);
printf("Row 1 of glyph is: %s\n",
font->glyphs[codepoint].data[1]);
printf("Row 2 of glyph is: %s\n",
font->glyphs[codepoint].data[2]);
return 0;
}
- Note the combination use of the struct field dereference "arrow"
operator
x->y, array indexx[y], and the field access "dot"x.yoperators. Follow this pattern in your own code to traverse from one struct to its array fields to their fields in turn. - Note also the use of
printf()and "rows" of thedatafield. For a 2D array likechar data[MAX_HEIGHT][MAX_WIDTH];access has the following pointer semantics:datacan be treated as achar **data[i]can be treated as achar *and can be used with the%sspecifier inprintf()data[i][j]is acharand can be used with the%cspecifier inprintf().
Printing Fontified
Combine the data access pattern and the central algorithm of printing
each row of each glyph to complete print_fontified_oneline(). Keep
in mind that the function does not handle linebreaks which is the
subject of the next problem. Instead, note the prototype has a
length parameter:
void print_fontified_oneline(char *msg, int length, font_t *font)
Print from the beginning of msg up to but NOT INCLUDING the
character at index length.
4 Problem 2: Banlet Output and Input
4.1 Overview
This problem will combine several of the support functions from
Problem 1 and implement a font-loading function in order to complete
the Banlet program. It implements several more functions in
banlet_funcs.c. These are used in the provided banlet_main.c
program to produce commandline banner letters.
4.2 Printing Multiple Fontified Lines
The previous print_fontified_oneline() function did not handle
multi-line message printing. Instead, this is handled in
print_fontified().
void print_fontified(char *msg, font_t *font);
// PROBLEM 2: Uses print_fontified_oneline() with find_linebreaks() to
// correctly print 'msg' with 'font' even if there are linebreaks in
// 'msg'. Uses find_linebreaks() to find the end of each line in
// 'msg' and then iterates over lines printing each. Uses pointer
// arithmetic to pass the starting position of each line into calls of
// print_fontified(). Frees memory allocated (such as through use of
// count_linebreaks()) before returning.
//
// EXAMPLE:
// print_fontified("apple\nB@N@N@\nCarr0^", &font_standard);
// Shows the following on standard output:
// ,-,
// __ _ ,_ __. ,_ __. | | ___
// / _` || '_ \ | '_ \ | | /'_`\
// | (_| || |_) || |_) || || __/
// \__,_|| .__/ | .__/ |_| \___|
// |_| |_|
// ,____ ____ ._ ._. ____ ._ ._. ____
// | == ) / __ \ | \ | | / __ \ | \ | | / __ \
// | _ \ / / _` || \| | / / _` || \| | / / _` |
// | |_)|| | (_| || |\ || | (_| || |\ || | (_| |
// |____/ \ \__,.||_| \_| \ \__,.||_| \_| \ \__,.|
// \____/ \____/ \____/
// ____. ___ /\
// / ___| __ _ ._ __.._ __. / _ \ |/\|
// | | / _` || `__|| `__|| | | |
// | |___.| (_| || | | | | |_| |
// \____| \__,_||_| |_| \___/
This function works as follows.
- Use the
find_linebreaks()function to locate the\nin themsgstring. This gives the number of lines in the message and their starting positions inmsg. - Iterate over each "line" in the text calling
print_fontified_oneline()on just that individual line. After printing each line, move to the next line. - Use pointer arithmetic or addressing to pass different starting
positions into
print_fontified(). For example, if there is a newline at position 14 inmsg, then position 15 is the start of a new line andmsg+15will give achar *pointing at that starting position. - The length of each line can be determined using arithmetic on the
indices in the linebreaks array from
find_linebreaks() - Make sure that the array allocated by
find_linebreaks()isfree()'d before returning from this function to avoid a memory leak.
Once this function is finished, the provided banlet_main program
should be mostly functional.
>> ./banlet_main $'Nice\nWork!'
._ ._.
| \ | |(`) ___. ___
| \| ||'| / __| /'_`\
| |\ || || (__ | __/
|_| \_||_| \___| \___|
_. ._ ,_, ._.
\ \ / / ___ ._ __.| | __| |
\ \ /\ / / / _ \ | `__|| |/ /| |
\ V V / | (_) || | | < |_|
\_/\_/ \___/ |_| |_|\_\(_)
4.3 Loading Fonts
The real flexibility of any font system is being able to select
different fonts easily to see how the same text renders. There is a
built-in font in Banlet defined in a set of C structs in
banlet_font_standard.c but this is extremely cumbersome to specify
and inappropriate for creating and using new fonts. New fonts in C
files would require Banlet to be recompiled every time a new font is
added.
Instead, it is better to allow a file format that specifies new fonts
so that they can be created and loaded without modifying the source
code of Banlet. This is the intent of the font_load() function.
font_t *font_load(char *filename);
This section details the format for font files and gives some details
on the font_load() function which enables new fonts to be created in
text files and loaded on the fly of use in Banlet.
Font Files
A number of demonstration font files are in the data/ directory for
the project. This includes the font_standard.txt file which is a
file version of the builtin font. It makes a good example and the
first portion is here using the head command which prints the first
few lines in files, 30 lines in this case:
>> head -30 data/font_alternate.txt height: 6 32 ?? ?? ?? ?? ?? ?? 33 ?_? |?| |?| |_| (_) ??? 34 ?_?_? (?|?) ?V?V? ????? ????? ????? 35 ???_??_??? ?_|?||?|_? |_??..??_| |_??????_| ??|_||_|?? ?????????? 36
The first and most obvious strangeness is the presence of the many ?
characters. Each ? character will be replaced with a space
character instead but reading data from the file is much easier
without whitespace in it. For example, the glyphs for 'ABC'
appear in
data/font_standard.txt adjacent to one another as follows:
65 ????_???? ???/?\??? ??/?_?\?? ?/?___?\? /_/???\_\ ????????? 66 ?____?? |?__?)? |??_?\? |?|_)?| |____/? ??????? 67 ??____? ?/?___| |?|???? |?|___? ?\____| ???????
Using the string_replace_char() will eventually make these appear in
a familiar fashion as:
65
_
/ \
/ _ \
/ ___ \
/_/ \_\
66
____
| __ )
| _ \
| |_) |
|____/
67
____
/ ___|
| |
| |___
\____|
Aside from the ? characters, font files follow a simple pattern.
- Line 1 is
height: Nwhere N is the height of all glyphs in the font. This will always be less thanMAX_HEIGHT. - The next line will be a codepoint for some glyph like 32 (space) or 65 ('A')
- After the codepoint will be N lines which comprise the
datafor the glyph; correct fonts will all be within the bounds set byMAX_WIDTH. - The pattern then repeats with another codepoint and N lines of the glyph.
Study the example font files in the data directory to make sure you
have a good sense of the structure of those files.
Allocating and Initializing Fonts/Glyph Arrays
You'll need to allocate a font_t using malloc() which will
eventually be returned from font_load().
Glyph arrays should also be allocated using malloc(). Allocate
NUM_ASCII_GLYPHS entries in the array but multiply this by the size
of the glyph_t struct.
Remember to "connect" font struct to the glyph array by assigning the
font->glyph field to the malloc()'d array.
On each glyph in the array, call the provided function glyph_init()
function which will fill it with some default data. This will make it
much easier to identify any mistakes made in printing glyphs that
weren't initialized. Uninitialized glyphs will print like below with
their codepoint on the first line of display.
78XXXX XXXXXX XXXXXX XXXXXX XXXXXX XXXXXX
Reading Font Files
Make use of standard C I/O functions such as fopen() to open the
glyph files and fscanf() to read from them. Note the following
tricks associated with fscanf() are useful while parsing the font file.
int x; fscanf(fin, "some text %d", &x);: this invocation will read exactly the characterssome textthen parse an integer and fillxin with it. Use this approach for the first line of the font files.int x; fscanf("%d", &x);: this invocation will skip whitespace until an integer is found. This whitespace skipping includes moving to subsequent lines so no special inclusion of newline\nis needed.char str2d[ROWS][COLS]; fscanf("%s", str2d[2]);: this invocation will read a string into the 2th row ofstr2dwhich itself is an array ofCOLScharacters. Useful for reading each row of a glyph. It is best to read directly into thefont->glyphs[codepoint].data[row]area.int ret = fscanf("...",...); if(ret == EOF){ ... }: reading data from a file can fail if there is no data left and the End of File (EOF) has been reached. The special valueEOFis returned byfscanf()in this case. On attempting to read the next glyph's codepoint, check the return value offscanf()as you'll need to break out of your reading loop on reaching the file end.
A few other tips:
- Set the width of each glyph according to the length of one of its
rows. All rows should be of equal length and there is no requirement
to check this but the
.widthfield must be set during a load. - Also change the
.is_setfield to 1 to indicate that the font has changed the glyph away from the default picture set inglyph_init(). - Don't forget to
fclose()the font file once you are finished with it. Often times Valgrind will report memory leaks for code that neglects to close files.
4.4 Loading Text Files (slurp)
It will be convenient later for Banlet to be able to load text from a text file for printing. To that end the following function will be implemented.
char *slurp_file_two_pass(char *filename); // PROBLEM 2: Read all characters from the file 'filename' into a // dynamcally allocated array. Terminates the array with the '\0' // character to form a valid C string and return that string. If the // file cannot be opened, return NULL. // // Uses a "2-Pass" solution. Counts the characters in file via calls // to fscanf() or fgetc(), then returns to beginning of the file with // rewind(), allocates an appropriately sized block of memory, then // reads all characters into it in a second pass. // // CONSTRAINT: Does not use any functions that determine the size of a // file a priori such as fstat() or fseek() or their kin.
An essential difficulty here is that the number of characters in a file is not known by the program ahead of time. There a variety of ways to do surmount this difficulty but required algorithm is discussed below with an optional implementation for Makeup Credit described later.
As described in the slurp_file_two_pass() comments, this approach
does the input in 2 passes.
- Read the text file counting its characters. After reaching the end of the file, its size is no known so an array large enough to hold all characters can be allocated in the heap.
- Return to the beginning of the file then read each character again and store it in the allocated space.
Some useful functions to keep in mind here are as follows.
fscanf(fin,"%c",&mychar)reads a single character at a time advancing forwards in the FILE by 1charon each readrewind(fin)returns a FILEfinto its start allowing one to re-read the same input
Don't forget to null terminate the string: there will not be any
\0 characters in the file if it is normal text. Instead, allocate
enough space for this extra character and manually place it.
AFTER you complete the two-pass version and the remainder of the project, consider implementing the MAKEUP CREDIT version which is a more complex algorithm for input.
5 Problem 3: Banlet Main
5.1 Overview
As with all C programs, Banlet needs a main() function. This entry
point is where the service functions like font_load() and
print_fontified() get called.
A skeleton main() is provided in the file banlet_main.c and
students should fill in the REQUIRED portions of this file. These
may be long (a few dozen lines) or short (a single line with a
function call). Details of what to fill in are describe below
5.2 Command Line Arguments in C Programs
To determine what text to print, what font to use, and any text data
files to read, the main() function will need to access command line
arguments. C programs provide this through the standard parameters
passed to main()
int main(int argc, char *argv[]) // ^^^ ^^^^ // how many array of strings
The provided demo cmdline_args.c shows how to iterate through the
argv[] array according to the bounds set by argc. Study this
program as you will need to adapt its techniques to handle the command
line arguments in Banlet.
5.3 Handling Banlet Command Line Arguments
Banlet will allow arbitrary variation in the order of its command line
arguments. This means all of the following are valid ways to run
banlet_main.
>> banlet_main 'Hello!' >> banlet_main 'Hello!' --fontfile font.txt >> banlet_main --fontfile font.txt 'Hello!' >> banlet_main --textfile text.txt >> banlet_main --textfile text.txt --fontfile font.txt >> banlet_main --fontfile font.txt --textfile text.txt
NOTE: variations that do NOT appear above will not be tested. You may detect those cases and print an error or let your program crash at no penalty. This refereed to as "undefined behavior".
A naive solution to handling the allowed variations is to hard code an
if() case for each and take appropriate action. This is an
undesirable approach because
- There will be quite a bit of repeated code as several cases need to
load a font all cases need to call
print_fontified(). - Hard coding all cases does not scale: if later another
option were added like
--interactive, the number of conditional cases might double again from 6 to 12.
A better approach is to loop through the command line arguments (as is alluded to in the preceding section) and set program variables according to the option at stake. There are 3 kinds of arguments:
--fontfile font.txt: this option will be a know fixed string"--fontfile"and it is always followed by the filename on whichfont_load()should be called.--textfile text.txt: again, the fixed string"--textfile"appears and is followed by a file which contains the text to print. The text can be read usingslurp_file().'Some Text': there is no"--option", just the text that comprises the message to print.
This suggests the following rough algorithm to handle the specified command line arguments and make it possible to expand them later. The algorithm is specified in a Python-like pseudocode.
fun main(argc, argv[]):
text = NULL
font = default_font
text_from_file = false
for i=1 to argc-1:
if argv[i] is "--fontfile":
load argv[i+1] as a font
error and exit if the font can't be loaded
set font to the loaded font
i = i+1
else if argv[i] is "--textfile":
load argv[i+1] as a string
error and exit if the string can't be loaded
set text to be the loaded string
i = i+1
else:
set text to be argv[i]
done
check that the text is not NULL, error out if so
display the text using font
free any memory that was allocated
done
Should any additional command line arguments be added, they become new conditional cases in the loop over command line arguemtns.
Study this approach and implement a C version of it in
banlet_main.c.
TIP: Simple uses are like banlet_main 'Hello world!'. Initially
you can just handle these by assuming that argv[1] is the text to
print. If pinched for time, this will allow you to pass a few more
test cases if you're struggling with the command line
processing. However, you'll eventually need to handle other command
line arguments to pass all test cases and complete the program.
5.4 Testing banlet_main Interactively
Once you have completed the main() function can test Banlet
interactively using banlet_main as shown below.
>> ./banlet_main ':-)'
__
_ \ \
(_)._____. | |
_ |_____| | |
(_) | |
/_/
>> ./banlet_main --fontfile data/font_banner.txt $'Great\nSuccess'
#####
# # ##### ###### ## #####
# # # # # # #
# #### # # ##### # # #
# # ##### # ###### #
# # # # # # # #
##### # # ###### # # #
#####
# # # # #### #### ###### #### ####
# # # # # # # # # #
##### # # # # ##### #### ####
# # # # # # # #
# # # # # # # # # # # # #
##### #### #### #### ###### #### ####
>> ./banlet_main --textfile data/testing.txt --fontfile data/font_mini.txt
___
| _ __|_o._ _ _ _.._ ._ | ._ ._ _ _|_|_ _ ._ ._ _ _ _ ._ _ _
| (/__> |_|| |(_| (_(_|| | (_)| ||\/ |_)| (_)\/(/_ |_| |(/_ |_)| (/__>(/_| |(_(/_
_| / | |
_
_|_ |_ _ _ ._ _|_ _|_|_ _ o._ _.|_ _ _ ._ _ _
(_) | |_)|_|(_|_>o | |(_) |_ |_| |(/_|| (_||_)_>(/_| |(_(/_o
_| /
_ _
__ |_ _| _ _ _ ._ | \o o| __|_._ _.
|_(_|_>(_|(/_| |_/| ||<_> |_| (_|
_| _|
>> ./banlet_main --textfile data/testing.txt --fontfile data/font_alternate.txt
_____ _ _ _ _ _
|_ _| ___ ___ | |_ (_) _ __ __ _ ___ __ _ _ __ ___ _ __ | | _ _ _ __ _ __ ___ __ __ ___ | |_ | |__ ___ _ __ _ __ ___ ___ ___ _ __ ___ ___
| | / _ \/ __|| __|| || '_ \ / _` | / __| / _` || '_ \ / _ \ | '_ \ | || | | | | '_ \ | '__| / _ \ \ \ / / / _ \ | __|| '_ \ / _ \ | '_ \ | '__| / _ \/ __| / _ \| '_ \ / __| / _ \
| | | __/\__ \| |_ | || | | || (_| | | (__ | (_| || | | | | (_) || | | || || |_| | | |_) || | | (_) | \ V / | __/ | |_ | | | || __/ | |_) || | | __/\__ \| __/| | | || (__ | __/
|_| \___||___/ \__||_||_| |_| \__, | \___| \__,_||_| |_| \___/ |_| |_||_| \__, | | .__/ |_| \___/ \_/ \___| \__||_| |_| \___| | .__/ |_| \___||___/ \___||_| |_| \___| \___|
|___/ |___/ |_| |_|
__ _ _ _ _ _ _
___ / _| | |__ _ _ __ _ ___ _ __ ___ | |_ | |_ | |__ ___ (_) _ __ __ _ | |__ ___ ___ _ __ ___ ___
/ _ \ | |_ | '_ \ | | | | / _` |/ __| | '_ \ / _ \ | __| | __|| '_ \ / _ \| || '__| / _` || '_ \ / __| / _ \| '_ \ / __| / _ \
| (_) || _| | |_) || |_| || (_| |\__ \ _ | | | || (_) || |_ | |_ | | | || __/| || | | (_| || |_) |\__ \| __/| | | || (__ | __/ _
\___/ |_| |_.__/ \__,_| \__, ||___/( ) |_| |_| \___/ \__| \__||_| |_| \___||_||_| \__,_||_.__/ |___/ \___||_| |_| \___| \___|(_)
|___/ |/
._____. _ .____ _ _ _ _
| ____| __| | ___ __ _ ___ _ __ | _ \ (_) (_)| | __ ___ | |_ _ __ __ _
_____ | +== / _` |/ __| / _` | / _ \| '__| | | | || | | || |/ // __|| __|| '__| / _` |
|_____| | |___ | (_| |\__ \| (_| || __/| | | |_| || | | || < \__ \| |_ | | | (_| |
|_____| \__,_||___/ \__, | \___||_| |____/ |_| _/ ||_|\_\|___/ \__||_| \__,_|
|___/ |__/
Optional Enrichment for the Creatively Inclined
Font design is an interesting art form and the Banlet framework gives you a little bit of space in which to play. If you are so inclined, consider copying and modifying some of the provided fonts or design your own. The Figlet Homepage has several more examples of fonts. Figlet inspired Banlet and most of the fonts here are adaptations of the fonts that are part of the Figlet distribution.
There is no additional credit for font creation, just the satisfaction of an artist gets from their work.
6 Grading Criteria
6.1 Points by Section
The following criteria will be checked. Some are Automated and
available during development via command like make test while others
are done Manually by graders after submission.
| Weight | Criteria |
|---|---|
AUTOMATED TESTS via make test-prob1 make test-prob1 |
|
| 15 | make test-prob1 Runs tests in test_banlet1.org on the first 4 functions in banlet_funcs.c |
| 10 | make test-prob2 Runs tests in test_banlet2.org on the remaining functions in banlet_funcs.c |
| 15 | make test-prob3 Runs tests in test_banlet3.org on banlet_main |
| 40 | SUBTOTAL |
| MANUAL INSPECTION | |
| 15 | Code Style: Functions adhere to CMSC 216 C Coding Style Guide which dictates |
| reasonable indentation, appropriate commenting, consistency of curly usage, etc. | |
| 15 | Appropriate code shape and flow: no over-complicated sections that with unneeded nested conditionals, |
| loops, etc. when simpler solutions would suffice. | |
| Pay careful attention to simple, clean shapes in these functions: | |
print_fontified_one_line() / print_fontified() |
|
font_load() slurp_file_two_pass() / slurp_file_one_pass() |
|
main() with respect to command line argument handling |
|
| 10 | Use of simple and appropriate C standard library functions. Use of exotic functions beyond what has |
| been discussed in lecture and lab will likely lose credit. While less desirable to use in industrial | |
settings, favor simple functions like strcmp() vs their more complex counterparts like strncmp(). |
|
| Favor simple input mechanism even if this might be vulnerable to memory problems on arbitrary input. | |
| 10 | Avoids pedantic error checking such as whether malloc() returns NULL or whether function parameters |
| are valid. While appropriate for industrial programs, such checks are not needed in learning projects | |
| like this and distract from the goals. | |
| 10 | WORK_DISCLOSURE.txt is present, describes collaborators and resources in reasonable detail |
| 60 | SUBTOTAL |
MAKEUP CREDIT Implementation of slurp_file_one_pass() |
|
| 5 | make test-makeup runs tests in test_banlet_makeup.org on slurp_file_one_pass() |
| 5 | Review of function body to meet indicated requirements with reasonable style / algorithm |
6.2 Work Disclosure
In conjunction with the Free Collaboration policy for projects, all
submissions must include a WORK_DISCLOSURE.txt file. This document
outlines the resources that were utilized to complete the
project. Each significant resource, be it course staff member, fellow
student, website, textbook, AI, or other item should be named with at
least a sentence describing how that item influenced the submission.
The rough format of these disclosures is provided in the template
WORK_DISCLOSURE.txt file that is part of the project. This document
will be checked for reasonable completeness by staff during Manual
Inspection. The provided template document is below and should be
edited and included in the project submission.
_________________
WORK DISCLOSURE
_________________
(A) HUMAN COLLABORATORS
=======================
Aside from the person submitting this assignment, the following people
contributed ideas and discussion to the completion of this work
INCLUDING course staff members. Write NONE if no collaborators were
involved.
- Person 1 <person1@email.com> helped understand Problem X and the
meaning of...
- Person 2 <person2@email.com> helped debug Code for Problem Y...
- etc.
(B) RESOURCE UTILIZATION
========================
The following resources such as websites, course notes, artificial
intelligence tools (LLMs/ChatBots/etc.) were utilized in the
completion of this work. Include course materials such as textbooks
and lecture slides as well. (Write NONE if no resources were used
[which would be hard to believe]).
- Resource 1 is here <https://some.resource.org/useful_stuff.html> and
provided help for Problem Z to understand...
- Resource 2 is the book "C Code for Dummies" by Boo Kauthor with
chapter 8 helping a lot with the malloc()/free() usage on Problem W
- Resource 3 is here <https://airegurgitator.com> and provided AI
refinements for the algorithm used on problem Q and also helped
debug code for Problem N.
- etc.
(C) ADHERENCE TO THE PRIME DIRECTIVE
====================================
PRIME DIRECTIVE: Be able to explain your own work including assignment
answers, program code, and exam solutions. The work you submit should
be the product of your own effort and reflect your personal
understanding. (See the course syllabus for more information.)
I submit this work in accordance with the PRIME DIRECTIVE. I affirm
that I can explain the code and answers within as I created them and
they reflect my personal understanding.
Signed,
<REPLACE WITH SUBMITTER NAME>
7 Makeup Credit
MAKEUP CREDIT are additional points that allow students to exceed the total of points possible for the project. These points go into the overall pool of points earned on projects and will make up for lost credit on this or other projects.
MAKEUP CREDIT is NOT EXTRA CREDIT: student scores on the project portion of the course will not exceed 100%. However, MAKEUP CREDIT allows for students to ensure they get full project credit even with some mistakes.
Makeup Credit is available on this Project in the form of an alternate implementation of the Slurp File Input functionality.
- The required
slurp_file_two_pass()function must be present as part of the base project requirements - Optionally students can complete
slurp_file_one_pass()for up to 10 additional Makeup Credit points. It's description is included in the code outline and is copied below for reference.
char *slurp_file_one_pass(char *filename); // OPTIONAL MAKEUP CREDIT: Like surp_file_two_pass() but uses a single // I/O pass and dynamically expands memory to handle larger // inputs. For full makeup credit, this approach must abide by the // following additional conditions: // - Does not use functions that determine the size of the file // - Does not allocate/copy memory each loop iteration, only // "occasionally" // - Does not use the realloc() function, only malloc()/free() // - Has amortized linear time and linear space; the allocated array may // not be any larger than 2x the number of characters in it // - Uses a memory allocation scheme similar to thos used with // dynamic arrays to meet the above requirement; see // https://en.wikipedia.org/wiki/Dynamic_array // - Include comments describing your makeup credit approach // - Is used in the main() function and/or elsewhere in place of the // other version
8 Project Submission
8.1 Submit to Gradescope
Submission is identical to lab work. There are two options to submit to Gradescope.
In a terminal, run the command
>> make submit
and punch in your email/password on Gradescope to use the provided
gradescope-submitscript to upload your work. This is more convenient so is recommended.- Run the command
make zipto createp1-complete.zip, download this file and upload it to Gradescope through a web browser. This is a good fallback if you are having trouble with command line submission.
Refer to Lab01 Submission Instructions if you need a refresher on submitting.
8.2 Late Policies
You may wish to review the policy on late project submission which will cost 1 Engagement Point per day late. No projects will be accepted more than 48 hours after the deadline.
https://www.cs.umd.edu/~profk/216/syllabus.html#late-submission