diff --git a/console.c b/console.c index ce72627d4..cfec9f58d 100644 --- a/console.c +++ b/console.c @@ -45,11 +45,11 @@ struct RIO_ELE { rio_ptr prev; /* Next element in stack */ }; -rio_ptr buf_stack; -char linebuf[RIO_BUFSIZE]; +static rio_ptr buf_stack; +static char linebuf[RIO_BUFSIZE]; /* Maximum file descriptor */ -int fd_max = 0; +static int fd_max = 0; /* Parameters */ static int err_limit = 5; @@ -66,13 +66,13 @@ static char *prompt = "cmd>"; static cmd_function quit_helpers[MAXQUIT]; static int quit_helper_cnt = 0; -bool do_quit_cmd(int argc, char *argv[]); -bool do_help_cmd(int argc, char *argv[]); -bool do_option_cmd(int argc, char *argv[]); -bool do_source_cmd(int argc, char *argv[]); -bool do_log_cmd(int argc, char *argv[]); -bool do_time_cmd(int argc, char *argv[]); -bool do_comment_cmd(int argc, char *argv[]); +static bool do_quit_cmd(int argc, char *argv[]); +static bool do_help_cmd(int argc, char *argv[]); +static bool do_option_cmd(int argc, char *argv[]); +static bool do_source_cmd(int argc, char *argv[]); +static bool do_log_cmd(int argc, char *argv[]); +static bool do_time_cmd(int argc, char *argv[]); +static bool do_comment_cmd(int argc, char *argv[]); static void init_in(); @@ -88,6 +88,7 @@ void init_cmd() param_list = NULL; err_cnt = 0; quit_flag = false; + add_cmd("help", do_help_cmd, " | Show documentation"); add_cmd("option", do_option_cmd, " [name val] | Display or set options"); @@ -100,6 +101,7 @@ void init_cmd() add_param("verbose", &verblevel, "Verbosity level", NULL); add_param("error", &err_limit, "Number of errors until exit", NULL); add_param("echo", &echo, "Do/don't echo commands", NULL); + init_in(); init_time(&last_time); first_time = last_time; @@ -114,6 +116,7 @@ void add_cmd(char *name, cmd_function operation, char *documentation) last_loc = &next_cmd->next; next_cmd = next_cmd->next; } + cmd_ptr ele = (cmd_ptr) malloc_or_fail(sizeof(cmd_ele), "add_cmd"); ele->name = name; ele->operation = operation; @@ -134,6 +137,7 @@ void add_param(char *name, last_loc = &next_param->next; next_param = next_param->next; } + param_ptr ele = (param_ptr) malloc_or_fail(sizeof(param_ele), "add_param"); ele->name = name; ele->valp = valp; @@ -147,15 +151,16 @@ void add_param(char *name, static char **parse_args(char *line, int *argcp) { /* - Must first determine how many arguments there are. - Replace all white space with null characters - */ + * Must first determine how many arguments there are. + * Replace all white space with null characters + */ size_t len = strlen(line); /* First copy into buffer with each substring null-terminated */ char *buf = malloc_or_fail(len + 1, "parse_args"); char *src = line; char *dst = buf; bool skipping = true; + int c; int argc = 0; while ((c = *src++) != '\0') { @@ -174,14 +179,15 @@ static char **parse_args(char *line, int *argcp) *dst++ = c; } } + /* Now assemble into array of strings */ char **argv = calloc_or_fail(argc, sizeof(char *), "parse_args"); - size_t i; src = buf; - for (i = 0; i < argc; i++) { + for (int i = 0; i < argc; i++) { argv[i] = strsave_or_fail(src, "parse_args"); src += strlen(argv[i]) + 1; } + free_block(buf, len + 1); *argcp = argc; return argv; @@ -201,6 +207,7 @@ static bool interpret_cmda(int argc, char *argv[]) { if (argc == 0) return true; + /* Try to find matching command */ cmd_ptr next_cmd = cmd_list; bool ok = true; @@ -215,33 +222,35 @@ static bool interpret_cmda(int argc, char *argv[]) record_error(); ok = false; } + return ok; } /* Execute a command from a command line */ static bool interpret_cmd(char *cmdline) { - int argc; if (quit_flag) return false; + #if RPT >= 6 report(6, "Interpreting command '%s'\n", cmdline); #endif + int argc; char **argv = parse_args(cmdline, &argc); bool ok = interpret_cmda(argc, argv); - int i; - for (i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) free_string(argv[i]); free_array(argv, argc, sizeof(char *)); + return ok; } /* Set function to be executed as part of program exit */ void add_quit_helper(cmd_function qf) { - if (quit_helper_cnt < MAXQUIT) { + if (quit_helper_cnt < MAXQUIT) quit_helpers[quit_helper_cnt++] = qf; - } else + else report_event(MSG_FATAL, "Exceeded limit on quit helpers"); } @@ -252,7 +261,7 @@ void set_echo(bool on) } /* Built-in commands */ -bool do_quit_cmd(int argc, char *argv[]) +static bool do_quit_cmd(int argc, char *argv[]) { cmd_ptr c = cmd_list; bool ok = true; @@ -268,16 +277,19 @@ bool do_quit_cmd(int argc, char *argv[]) p = p->next; free_block(ele, sizeof(param_ele)); } + while (buf_stack) pop_file(); + for (int i = 0; i < quit_helper_cnt; i++) { ok = ok && quit_helpers[i](argc, argv); } + quit_flag = true; return ok; } -bool do_help_cmd(int argc, char *argv[]) +static bool do_help_cmd(int argc, char *argv[]) { cmd_ptr clist = cmd_list; report(1, "Commands:", argv[0]); @@ -295,17 +307,17 @@ bool do_help_cmd(int argc, char *argv[]) return true; } -bool do_comment_cmd(int argc, char *argv[]) +static bool do_comment_cmd(int argc, char *argv[]) { - int i; if (echo) return true; - for (i = 0; i < argc - 1; i++) { + + int i; + for (i = 0; i < argc - 1; i++) report_noreturn(1, "%s ", argv[i]); - } - if (i < argc) { + if (i < argc) report(1, "%s", argv[i]); - } + return true; } @@ -316,13 +328,13 @@ bool get_int(char *vname, int *loc) long int v = strtol(vname, &end, 0); if (v == LONG_MIN || *end != '\0') return false; + *loc = (int) v; return true; } -bool do_option_cmd(int argc, char *argv[]) +static bool do_option_cmd(int argc, char *argv[]) { - size_t i; if (argc == 1) { param_ptr plist = param_list; report(1, "Options:"); @@ -333,7 +345,8 @@ bool do_option_cmd(int argc, char *argv[]) } return true; } - for (i = 1; i < argc; i++) { + + for (int i = 1; i < argc; i++) { char *name = argv[i]; int value = 0; bool found = false; @@ -363,36 +376,40 @@ bool do_option_cmd(int argc, char *argv[]) return false; } } + return true; } -bool do_source_cmd(int argc, char *argv[]) +static bool do_source_cmd(int argc, char *argv[]) { if (argc < 2) { report(1, "No source file given"); return false; } + if (!push_file(argv[1])) { report(1, "Could not open source file '%s'", argv[1]); return false; } + return true; } -bool do_log_cmd(int argc, char *argv[]) +static bool do_log_cmd(int argc, char *argv[]) { if (argc < 2) { report(1, "No log file given"); return false; } + bool result = set_logfile(argv[1]); - if (!result) { + if (!result) report(1, "Couldn't open log file '%s'", argv[1]); - } + return result; } -bool do_time_cmd(int argc, char *argv[]) +static bool do_time_cmd(int argc, char *argv[]) { double delta = delta_time(&last_time); bool ok = true; @@ -408,31 +425,35 @@ bool do_time_cmd(int argc, char *argv[]) report(1, "Delta time = %.3f", delta); } } + return ok; } /* Create new buffer for named file. - * Name == NULL for stdin. - * Return true if successful. + * Name == NULL for stdin. + * Return true if successful. */ static bool push_file(char *fname) { int fd = fname ? open(fname, O_RDONLY) : STDIN_FILENO; if (fd < 0) return false; + if (fd > fd_max) fd_max = fd; + rio_ptr rnew = malloc_or_fail(sizeof(rio_t), "push_file"); rnew->fd = fd; rnew->cnt = 0; rnew->bufptr = rnew->buf; rnew->prev = buf_stack; buf_stack = rnew; + return true; } /* Pop a file buffer from stack. - * Return true if stack is now empty + * Return true if stack is now empty */ static void pop_file() { @@ -451,7 +472,7 @@ static void init_in() } /* Read command from input file. - * When hit EOF, close that file and return NULL + * When hit EOF, close that file and return NULL */ static char *readline() { @@ -480,10 +501,11 @@ static char *readline() report_noreturn(1, linebuf); } return linebuf; - } else - return NULL; + } + return NULL; } } + /* Have text in buffer */ c = *buf_stack->bufptr++; *lptr++ = c; @@ -491,15 +513,18 @@ static char *readline() if (c == '\n') break; } + if (c != '\n') { /* Hit buffer limit. Artificially terminate line */ *lptr++ = '\n'; } *lptr++ = '\0'; + if (echo) { report_noreturn(1, prompt); report_noreturn(1, linebuf); } + return linebuf; } @@ -510,9 +535,15 @@ static bool read_ready() if (buf_stack->bufptr[i] == '\n') return true; } + return false; } +static bool cmd_done() +{ + return !buf_stack || quit_flag; +} + /* * Handle command processing in program that uses select as main control loop. * Like select, but checks whether command input either present in internal @@ -537,12 +568,15 @@ int cmd_select(int nfds, interpret_cmd(cmdline); prompt_flag = true; } + if (cmd_done()) return 0; + if (!block_flag) { /* Process any commands in input buffer */ if (!readfds) readfds = &local_readset; + /* Add input fd to readset for select */ infd = buf_stack->fd; FD_SET(infd, readfds); @@ -551,15 +585,17 @@ int cmd_select(int nfds, fflush(stdout); prompt_flag = true; } - if (infd >= nfds) { + + if (infd >= nfds) nfds = infd + 1; - } } if (nfds == 0) return 0; + int result = select(nfds, readfds, writefds, exceptfds, timeout); if (result <= 0) return result; + infd = buf_stack->fd; if (readfds && FD_ISSET(infd, readfds)) { /* Commandline input available */ @@ -572,17 +608,11 @@ int cmd_select(int nfds, return result; } -bool cmd_done() -{ - return !buf_stack || quit_flag; -} - bool finish_cmd() { bool ok = true; - if (!quit_flag) { + if (!quit_flag) ok = ok && do_quit_cmd(0, NULL); - } return ok && err_cnt == 0; } @@ -593,8 +623,7 @@ bool run_console(char *infile_name) return false; } - while (!cmd_done()) { + while (!cmd_done()) cmd_select(0, NULL, NULL, NULL, NULL); - } return err_cnt == 0; } diff --git a/console.h b/console.h index a8d16c455..b88b187f5 100644 --- a/console.h +++ b/console.h @@ -7,6 +7,7 @@ typedef bool (*cmd_function)(int argc, char *argv[]); /* Information about each command */ + /* Organized as linked list in alphabetical order */ typedef struct CELE cmd_ele, *cmd_ptr; struct CELE { @@ -42,9 +43,6 @@ void add_param(char *name, char *doccumentation, setter_function setter); -/* Execute a sequence of commands read from a file */ -bool interpret_file(FILE *fp); - /* Extract integer from text and store at loc */ bool get_int(char *vname, int *loc); @@ -54,10 +52,8 @@ void add_quit_helper(cmd_function qf); /* Turn echoing on/off */ void set_echo(bool on); -/* Is it time to quit the command loop? */ -bool cmd_done(); - /* Complete command interpretation */ + /* Return true if no errors occurred */ bool finish_cmd(); diff --git a/harness.c b/harness.c index bfeea6e0a..64250ae12 100644 --- a/harness.c +++ b/harness.c @@ -17,14 +17,17 @@ /* Value at start of every allocated block */ #define MAGICHEADER 0xdeadbeef + /* Value when deallocate block */ #define MAGICFREE 0xffffffff + /* Value at end of every block */ #define MAGICFOOTER 0xbeefdead + /* Byte to fill newly malloced space with */ #define FILLCHAR 0x55 -/** Data structures used by our code **/ +/* Data structures used by our code */ /* * Represent allocated blocks as doubly-linked list, with @@ -40,8 +43,10 @@ typedef struct BELE { static block_ele_t *allocated = NULL; static size_t allocated_count = 0; + /* Percent probability of malloc failure */ int fail_probability = 0; + static bool cautious_mode = true; static bool noallocate_mode = false; static bool error_occurred = false; @@ -77,6 +82,7 @@ static block_ele_t *find_header(void *p) report_event(MSG_ERROR, "Attempting to free null block"); error_occurred = true; } + block_ele_t *b = (block_ele_t *) ((size_t) p - sizeof(block_ele_t)); if (cautious_mode) { /* Make sure this is really an allocated block */ @@ -93,6 +99,7 @@ static block_ele_t *find_header(void *p) error_occurred = true; } } + if (b->magic_header != MAGICHEADER) { report_event( MSG_ERROR, @@ -100,6 +107,7 @@ static block_ele_t *find_header(void *p) p); error_occurred = true; } + return b; } @@ -112,7 +120,7 @@ static size_t *find_footer(block_ele_t *b) } /* - Implementation of application functions + * Implementation of application functions */ void *test_malloc(size_t size) { @@ -120,16 +128,19 @@ void *test_malloc(size_t size) report_event(MSG_FATAL, "Calls to malloc disallowed"); return NULL; } + if (fail_allocation()) { report_event(MSG_WARN, "Malloc returning NULL"); return NULL; } + block_ele_t *new_block = malloc(size + sizeof(block_ele_t) + sizeof(size_t)); if (!new_block) { report_event(MSG_FATAL, "Couldn't allocate any more memory"); error_occurred = true; } + // cppcheck-suppress nullPointerRedundantCheck new_block->magic_header = MAGICHEADER; // cppcheck-suppress nullPointerRedundantCheck @@ -141,10 +152,12 @@ void *test_malloc(size_t size) new_block->next = allocated; // cppcheck-suppress nullPointerRedundantCheck new_block->prev = NULL; + if (allocated) allocated->prev = new_block; allocated = new_block; allocated_count++; + return p; } @@ -154,6 +167,7 @@ void test_free(void *p) report_event(MSG_FATAL, "Calls to free disallowed"); return; } + if (!p) return; @@ -189,9 +203,9 @@ char *test_strdup(const char *s) { size_t len = strlen(s) + 1; void *new = test_malloc(len); - if (!new) return NULL; + return (char *) memcpy(new, s, len); } @@ -245,9 +259,9 @@ bool exception_setup(bool limit_time) alarm(0); time_limited = false; } - if (error_message) { + + if (error_message) report_event(MSG_ERROR, error_message); - } error_message = ""; return false; } @@ -270,6 +284,7 @@ void exception_cancel() alarm(0); time_limited = false; } + jmp_ready = false; error_message = ""; } diff --git a/harness.h b/harness.h index e97fef0bf..d0ec15384 100644 --- a/harness.h +++ b/harness.h @@ -16,11 +16,12 @@ void test_free(void *p); char *test_strdup(const char *s); #ifdef INTERNAL + /* Report number of allocated blocks */ size_t allocation_check(); /* Probability of malloc failing, expressed as percent */ -int fail_probability; +extern int fail_probability; /* * Set/unset cautious mode. @@ -56,10 +57,12 @@ void exception_cancel(); void trigger_exception(char *msg); #else /* !INTERNAL */ + /* Tested program use our versions of malloc and free */ #define malloc test_malloc #define free test_free #define strdup test_strdup + #endif #endif /* LAB0_HARNESS_H */ diff --git a/qtest.c b/qtest.c index bd3fb2f19..aac1b6fbe 100644 --- a/qtest.c +++ b/qtest.c @@ -43,7 +43,7 @@ static int big_queue_size = BIG_QUEUE; static queue_t *q = NULL; /* Number of elements in queue */ -size_t qcnt = 0; +static size_t qcnt = 0; /* How many times can queue operations fail */ static int fail_limit = BIG_QUEUE; @@ -108,11 +108,13 @@ static bool do_new(int argc, char *argv[]) ok = do_free(argc, argv); } error_check(); + if (exception_setup(true)) q = q_new(); exception_cancel(); qcnt = 0; show_queue(3); + return ok && !error_check(); } @@ -127,27 +129,30 @@ static bool do_free(int argc, char *argv[]) if (!q) report(3, "Warning: Calling free on null queue"); error_check(); + if (qcnt > big_queue_size) set_cautious_mode(false); if (exception_setup(true)) q_free(q); exception_cancel(); set_cautious_mode(true); + q = NULL; qcnt = 0; show_queue(3); + size_t bcnt = allocation_check(); if (bcnt > 0) { report(1, "ERROR: Freed queue, but %lu blocks are still allocated", bcnt); ok = false; } + return ok && !error_check(); } static bool do_insert_head(int argc, char *argv[]) { - char *inserts; char *lasts = NULL; int reps = 1; bool ok = true; @@ -155,16 +160,19 @@ static bool do_insert_head(int argc, char *argv[]) report(1, "%s needs 1-2 arguments", argv[0]); return false; } - inserts = argv[1]; + + char *inserts = argv[1]; if (argc == 3) { if (!get_int(argv[2], &reps)) { report(1, "Invalid number of insertions '%s'", argv[2]); return false; } } + if (!q) report(3, "Warning: Calling insert head on null queue"); error_check(); + if (exception_setup(true)) { for (int r = 0; ok && r < reps; r++) { bool rval = q_insert_head(q, inserts); @@ -202,20 +210,21 @@ static bool do_insert_head(int argc, char *argv[]) } } exception_cancel(); + show_queue(3); return ok; } static bool do_insert_tail(int argc, char *argv[]) { - char *inserts; int reps = 1; bool ok = true; if (argc != 2 && argc != 3) { report(1, "%s needs 1-2 arguments", argv[0]); return false; } - inserts = argv[1]; + + char *inserts = argv[1]; if (argc == 3) { if (!get_int(argv[2], &reps)) { report(1, "Invalid number of insertions '%s'", argv[2]); @@ -225,6 +234,7 @@ static bool do_insert_tail(int argc, char *argv[]) if (!q) report(3, "Warning: Calling insert tail on null queue"); error_check(); + if (exception_setup(true)) { for (int r = 0; ok && r < reps; r++) { bool rval = q_insert_tail(q, inserts); @@ -259,12 +269,14 @@ static bool do_remove_head(int argc, char *argv[]) report(1, "%s needs 0-1 arguments", argv[0]); return false; } + char *removes = malloc(string_length + STRINGPAD + 1); if (!removes) { report(1, "INTERNAL ERROR. Could not allocate space for removed strings"); return false; } + char *checks = malloc(string_length + 1); if (!checks) { report(1, @@ -272,6 +284,7 @@ static bool do_remove_head(int argc, char *argv[]) free(removes); return false; } + bool check = argc > 1; bool ok = true; if (check) { @@ -288,10 +301,12 @@ static bool do_remove_head(int argc, char *argv[]) else if (!q->head) report(3, "Warning: Calling remove head on empty queue"); error_check(); + bool rval = false; if (exception_setup(true)) rval = q_remove_head(q, removes, string_length + 1); exception_cancel(); + if (rval) { removes[string_length + STRINGPAD] = '\0'; if (removes[0] == '\0') { @@ -304,9 +319,8 @@ static bool do_remove_head(int argc, char *argv[]) * If there's other character in padding, it's overflowed. */ int i = string_length + 1; - while ((i < string_length + STRINGPAD) && (removes[i] == 'X')) { + while ((i < string_length + STRINGPAD) && (removes[i] == 'X')) i++; - } if (i != string_length + STRINGPAD) { report(1, "ERROR: copying of string in remove_head overflowed " @@ -326,12 +340,15 @@ static bool do_remove_head(int argc, char *argv[]) ok = false; } } + if (ok && check && strcmp(removes, checks) != 0) { report(1, "ERROR: Removed value %s != expected value %s", removes, checks); ok = false; } + show_queue(3); + free(removes); free(checks); return ok && !error_check(); @@ -343,16 +360,19 @@ static bool do_remove_head_quiet(int argc, char *argv[]) report(1, "%s takes no arguments", argv[0]); return false; } + bool ok = true; if (!q) report(3, "Warning: Calling remove head on null queue"); else if (!q->head) report(3, "Warning: Calling remove head on empty queue"); error_check(); + bool rval = false; if (exception_setup(true)) rval = q_remove_head(q, NULL, 0); exception_cancel(); + if (rval) { report(2, "Removed element from queue"); qcnt--; @@ -365,6 +385,7 @@ static bool do_remove_head_quiet(int argc, char *argv[]) ok = false; } } + show_queue(3); return ok && !error_check(); } @@ -375,13 +396,16 @@ static bool do_reverse(int argc, char *argv[]) report(1, "%s takes no arguments", argv[0]); return false; } + if (!q) report(3, "Warning: Calling reverse on null queue"); error_check(); + set_noallocate_mode(true); if (exception_setup(true)) q_reverse(q); exception_cancel(); + set_noallocate_mode(false); show_queue(3); return !error_check(); @@ -393,21 +417,25 @@ static bool do_size(int argc, char *argv[]) report(1, "%s takes 0-1 arguments", argv[0]); return false; } + int reps = 1; bool ok = true; if (argc != 1 && argc != 2) { report(1, "%s needs 0-1 arguments", argv[0]); return false; } + if (argc == 2) { if (!get_int(argv[1], &reps)) { report(1, "Invalid number of calls to size '%s'", argv[2]); } } + int cnt = 0; if (!q) report(3, "Warning: Calling size on null queue"); error_check(); + if (exception_setup(true)) { for (int r = 0; ok && r < reps; r++) { cnt = q_size(q); @@ -415,6 +443,7 @@ static bool do_size(int argc, char *argv[]) } } exception_cancel(); + if (ok) { if (qcnt == cnt) { report(2, "Queue size = %d", cnt); @@ -425,6 +454,7 @@ static bool do_size(int argc, char *argv[]) ok = false; } } + show_queue(3); return ok && !error_check(); @@ -436,12 +466,15 @@ bool do_sort(int argc, char *argv[]) report(1, "%s takes no arguments", argv[0]); return false; } + if (q == NULL) report(3, "Warning: Calling sort on null queue"); + int cnt = q_size(q); if (cnt < 2) report(3, "Warning: Calling sort on single node"); error_check(); + set_noallocate_mode(true); if (exception_setup(true)) q_sort(q); @@ -469,11 +502,13 @@ static bool show_queue(int vlevel) bool ok = true; if (verblevel < vlevel) return true; + int cnt = 0; if (!q) { report(vlevel, "q = NULL"); return true; } + report_noreturn(vlevel, "q = ["); list_ele_t *e = q->head; if (exception_setup(true)) { @@ -486,10 +521,12 @@ static bool show_queue(int vlevel) } } exception_cancel(); + if (!ok) { report(vlevel, " ... ]"); return false; } + if (!e) { if (cnt <= big_queue_size) report(vlevel, "]"); @@ -503,6 +540,7 @@ static bool show_queue(int vlevel) qcnt); ok = false; } + return ok; } @@ -543,16 +581,19 @@ static bool queue_quit(int argc, char *argv[]) report(3, "Freeing queue"); if (qcnt > big_queue_size) set_cautious_mode(false); + if (exception_setup(true)) q_free(q); exception_cancel(); set_cautious_mode(true); + size_t bcnt = allocation_check(); if (bcnt > 0) { report(1, "ERROR: Freed queue, but %lu blocks are still allocated", bcnt); return false; } + return true; } @@ -602,18 +643,23 @@ int main(int argc, char *argv[]) break; } } + queue_init(); init_cmd(); console_init(); + set_verblevel(level); if (level > 1) { set_echo(true); } if (logfile_name) set_logfile(logfile_name); + add_quit_helper(queue_quit); + bool ok = true; ok = ok && run_console(infile_name); ok = ok && finish_cmd(); + return ok ? 0 : 1; } diff --git a/queue.h b/queue.h index da01970b4..b5ae35439 100644 --- a/queue.h +++ b/queue.h @@ -24,10 +24,10 @@ typedef struct ELE { /* Queue structure */ typedef struct { list_ele_t *head; /* Linked list of elements */ - /* - * You will need to add more fields to this structure - * to efficiently implement q_size and q_insert_tail - */ + /* TODO: You will need to add more fields to this structure + * to efficiently implement q_size and q_insert_tail. + */ + /* TODO: Remove the above comment when you are about to implement. */ } queue_t; /* Operations on queue */ diff --git a/report.c b/report.c index 8b60e7a0b..6fc3113d1 100644 --- a/report.c +++ b/report.c @@ -13,12 +13,12 @@ #define MAX(a, b) ((a) < (b) ? (b) : (a)) -FILE *errfile = NULL; -FILE *verbfile = NULL; -FILE *logfile = NULL; +static FILE *errfile = NULL; +static FILE *verbfile = NULL; +static FILE *logfile = NULL; int verblevel = 0; -void init_files(FILE *efile, FILE *vfile) +static void init_files(FILE *efile, FILE *vfile) { errfile = efile; verbfile = vfile; @@ -29,7 +29,7 @@ static char fail_buf[1024] = "FATAL Error. Exiting\n"; static volatile int ret = 0; /* Default fatal function */ -void default_fatal_fun() +static void default_fatal_fun() { ret = write(STDOUT_FILENO, fail_buf, strlen(fail_buf) + 1); if (logfile) @@ -37,7 +37,7 @@ void default_fatal_fun() } /* Optional function to call when fatal error encountered */ -void (*fatal_fun)() = default_fatal_fun; +static void (*fatal_fun)() = default_fatal_fun; void set_verblevel(int level) { @@ -60,14 +60,17 @@ void report_event(message_t msg, char *fmt, ...) int level = msg == MSG_WARN ? 2 : msg == MSG_ERROR ? 1 : 0; if (verblevel < level) return; + if (!errfile) init_files(stdout, stdout); + va_start(ap, fmt); fprintf(errfile, "%s: ", msg_name); vfprintf(errfile, fmt, ap); fprintf(errfile, "\n"); fflush(errfile); va_end(ap); + if (logfile) { va_start(ap, fmt); fprintf(logfile, "Error: "); @@ -77,6 +80,7 @@ void report_event(message_t msg, char *fmt, ...) va_end(ap); fclose(logfile); } + if (fatal) { if (fatal_fun) fatal_fun(); @@ -88,6 +92,7 @@ void report(int level, char *fmt, ...) { if (!verbfile) init_files(stdout, stdout); + if (level <= verblevel) { va_list ap; va_start(ap, fmt); @@ -95,6 +100,7 @@ void report(int level, char *fmt, ...) fprintf(verbfile, "\n"); fflush(verbfile); va_end(ap); + if (logfile) { va_start(ap, fmt); vfprintf(logfile, fmt, ap); @@ -109,12 +115,14 @@ void report_noreturn(int level, char *fmt, ...) { if (!verbfile) init_files(stdout, stdout); + if (level <= verblevel) { va_list ap; va_start(ap, fmt); vfprintf(verbfile, fmt, ap); fflush(verbfile); va_end(ap); + if (logfile) { va_start(ap, fmt); vfprintf(logfile, fmt, ap); @@ -126,24 +134,26 @@ void report_noreturn(int level, char *fmt, ...) /* Functions denoting failures */ -/* General failure */ - /* Need to be able to print without using malloc */ -void fail_fun(char *format, char *msg) +static void fail_fun(char *format, char *msg) { snprintf(fail_buf, sizeof(fail_buf), format, msg); /* Tack on return */ fail_buf[strlen(fail_buf)] = '\n'; /* Use write to avoid any buffering issues */ ret = write(STDOUT_FILENO, fail_buf, strlen(fail_buf) + 1); + if (logfile) { /* Don't know file descriptor for logfile */ fputs(fail_buf, logfile); } + if (fatal_fun) fatal_fun(); + if (logfile) fclose(logfile); + exit(1); } @@ -155,10 +165,11 @@ static size_t allocate_cnt = 0; static size_t allocate_bytes = 0; static size_t free_cnt = 0; static size_t free_bytes = 0; -/* These are externally visible */ -size_t peak_bytes = 0; -size_t last_peak_bytes = 0; -size_t current_bytes = 0; + +/* Counters giving peak memory usage */ +static size_t peak_bytes = 0; +static size_t last_peak_bytes = 0; +static size_t current_bytes = 0; static void check_exceed(size_t new_bytes) { @@ -180,11 +191,13 @@ void *malloc_or_fail(size_t bytes, char *fun_name) fail_fun("Malloc returned NULL in %s", fun_name); return NULL; } + allocate_cnt++; allocate_bytes += bytes; current_bytes += bytes; peak_bytes = MAX(peak_bytes, current_bytes); last_peak_bytes = MAX(last_peak_bytes, current_bytes); + return p; } @@ -197,6 +210,7 @@ void *calloc_or_fail(size_t cnt, size_t bytes, char *fun_name) fail_fun("Calloc returned NULL in %s", fun_name); return NULL; } + allocate_cnt++; allocate_bytes += cnt * bytes; current_bytes += cnt * bytes; @@ -210,12 +224,13 @@ char *strsave_or_fail(char *s, char *fun_name) { if (!s) return NULL; + size_t len = strlen(s); check_exceed(len + 1); char *ss = malloc(len + 1); - if (!ss) { + if (!ss) fail_fun("strsave failed in %s", fun_name); - } + allocate_cnt++; allocate_bytes += len + 1; current_bytes += len + 1; @@ -231,6 +246,7 @@ void free_block(void *b, size_t bytes) if (!b) report_event(MSG_ERROR, "Attempting to free null block"); free(b); + free_cnt++; free_bytes += bytes; current_bytes -= bytes; @@ -242,6 +258,7 @@ void free_array(void *b, size_t cnt, size_t bytes) if (!b) report_event(MSG_ERROR, "Attempting to free null block"); free(b); + free_cnt++; free_bytes += cnt * bytes; current_bytes -= cnt * bytes; diff --git a/report.h b/report.h index 26dbebf62..9e2b770d0 100644 --- a/report.h +++ b/report.h @@ -17,16 +17,11 @@ typedef enum { MSG_WARN, MSG_ERROR, MSG_FATAL } message_t; /* Buffer sizes */ #define MAX_CHAR 512 -void init_files(FILE *errfile, FILE *verbfile); - bool set_logfile(char *file_name); extern int verblevel; void set_verblevel(int level); -/* Optional function to call when fatal error encountered */ -extern void (*fatal_fun)(); - /* Error messages */ void report_event(message_t msg, char *fmt, ...); @@ -36,9 +31,6 @@ void report(int verblevel, char *fmt, ...); /* Like report, but without return character */ void report_noreturn(int verblevel, char *fmt, ...); -/* Simple failure report. Works even when malloc returns NULL */ -void fail_fun(char *format, char *msg); - /* Attempt to call malloc. Fail when returns NULL */ void *malloc_or_fail(size_t bytes, char *fun_name); @@ -66,21 +58,4 @@ void init_time(double *timep); and reset timer */ double delta_time(double *timep); -/** Counters giving peak memory usage **/ - -/* Never resets */ -size_t peak_bytes; - -/* Resettable */ -size_t last_peak_bytes; - -/* Instantaneous */ -size_t current_bytes; - -/* Reset last_peak_bytes */ -void reset_peak_bytes(); - -/* Handler for SIGTERM signals */ -void sigterm_handler(int sig); - #endif /* LAB0_REPORT_H */