Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Help me answer these questions! Code listed under image. The first part is the Main.C. Each bolded part is the file/test runs. /* About this

Help me answer these questions! Code listed under image. The first part is the Main.C. Each bolded part is the file/test runs. image text in transcribed

/*

About this program:

- This program counts words.

- The specific words that will be counted are passed in as command-line

arguments.

- The program reads words (one word per line) from standard input until EOF or

an input line starting with a dot '.'

- The program prints out a summary of the number of times each word has

appeared.

- Various command-line options alter the behavior of the program.

E.g., count the number of times 'cat', 'nap' or 'dog' appears.

> ./main cat nap dog

Given input:

cat

.

Expected output:

Looking for 3 words

Result:

cat:1

nap:0

dog:0

*/

#include

#include

#include

#include

#define LENGTH(s) (sizeof(s) / sizeof(*s))

/* Structures */

typedef struct {

char *word;

int counter;

} WordCountEntry;

int process_stream(WordCountEntry entries[], int entry_count)

{

short line_count = 0;

char buffer[30];

while (get(buffer)) {

if (*buffer == '.')

break;

/* Compare against each entry */

int i = 0;

while (i

if (!strcmp(entries[i].word, buffer))

entries[i].counter++;

i++;

}

line_count++;

}

return line_count;

}

void print_result(WordCountEntry entries[], int entry_count)

{

printf("Result: ");

while (entry_count-- > 0) {

printf("%s:%d ", entries->word, entries->counter);

}

}

void printHelp(const char *name)

{

printf("usage: %s [-h] ... ", name);

}

int main(int argc, char **argv)

{

const char *prog_name = *argv;

WordCountEntry entries[5];

int entryCount = 0;

/* Entry point for the testrunner program */

if (argc > 1 && !strcmp(argv[1], "-test")) {

run_smp0_tests(argc - 1, argv + 1);

return EXIT_SUCCESS;

}

while (*argv != NULL) {

if (**argv == '-') {

switch ((*argv)[1]) {

case 'h':

printHelp(prog_name);

default:

printf("%s: Invalid option %s. Use -h for help. ",

prog_name, *argv);

}

}

else {

if (entryCount

entries[entryCount].word = *argv;

entries[entryCount++].counter = 0;

}

}

argv++;

}

if (entryCount == 0) {

printf("%s: Please supply at least one word. Use -h for help. ",

prog_name);

return EXIT_FAILURE;

}

if (entryCount == 1) {

printf("Looking for a single word ");

}

else {

printf("Looking for %d words ", entryCount);

}

process_stream(entries, entryCount);

print_result(entries, entryCount);

return EXIT_SUCCESS;

}

_____________________

( smp0.tests.c )

/*************** YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE ***************/

#define _GNU_SOURCE

#include

#undef _GNU_SOURCE

#include

#include

#include

#include "testrunner.h"

#include "smp0_tests.h"

#define quit_if(cond) do {if (cond) exit(EXIT_FAILURE);} while(0)

/* test of -h switch behavior (B3) */

int test_help_switch(int argc, char **argv)

{

char *args[] = {"./main", "-h", NULL};

FILE *out, *err, *tmp;

char buffer[100];

freopen("/devull", "r", stdin);

freopen("smp0.out", "w", stdout);

freopen("smp0.err", "w", stderr);

quit_if(main(2, args) != EXIT_FAILURE);

fclose(stdout);

fclose(stderr);

out = fopen("smp0.out", "r");

err = fopen("smp0.err", "r");

if (fgets(buffer, 100, out) != NULL && !strncmp(buffer, "usage:", 6)) {

tmp = out;

}

else {

quit_if(fgets(buffer, 100, err) == NULL);

quit_if(strncmp(buffer, "usage:", 6));

tmp = err;

}

if (fgets(buffer, 100, tmp) != NULL) {

quit_if(!strcmp(buffer, "./main: Invalid option -h. Use -h for help. "));

}

fclose(out);

fclose(err);

return EXIT_SUCCESS;

}

/* test of basic functionality (B4, B5) */

int test_basic_functionality(int argc, char **argv)

{

char *args[] = {"./main", "cat", "dog", "nap", NULL};

char *result[] = {"Looking for 3 words ",

"Result: ",

"cat:1 ",

"dog:0 ",

"nap:0 "};

FILE *out;

int i;

char buffer[100];

out = fopen("smp0.in", "w");

fprintf(out, "cat ");

fprintf(out, ". ");

fclose(out);

freopen("smp0.in", "r", stdin);

freopen("smp0.out", "w", stdout);

quit_if(main(4, args) != EXIT_SUCCESS);

fclose(stdin);

fclose(stdout);

out = fopen("smp0.out", "r");

for (i = 0; i

quit_if(fgets(buffer, 100, out) == NULL);

quit_if(strcmp(buffer, result[i]));

}

fclose(out);

return EXIT_SUCCESS;

}

/* test of stderr output support (C1) */

int test_stderr_output(int argc, char **argv)

{

char *args[] = {"./main", "-wrong", NULL};

char *result[] = {"./main: Invalid option -wrong. Use -h for help. ",

"./main: Please supply at least one word. Use -h for help. "};

FILE *err;

int i;

char buffer[100];

freopen("/devull", "r", stdin);

freopen("/devull", "w", stdout);

freopen("smp0.err", "w", stderr);

quit_if(main(2, args) != EXIT_FAILURE);

fclose(stderr);

err = fopen("smp0.err", "r");

for (i = 0; i

quit_if(fgets(buffer, 100, err) == NULL);

quit_if(strcmp(buffer, result[i]));

}

fclose(err);

return EXIT_SUCCESS;

}

/* test of -fFILENAME switch behavior (C2) */

int test_file_output(int argc, char **argv)

{

char *args[] = {"./main", "-fsmp0.out", "cat", "dog", "nap", NULL};

char *result[] = {"Looking for 3 words ",

"Result: ",

"cat:1 ",

"dog:0 ",

"nap:0 "};

FILE *out;

int i;

char buffer[100];

out = fopen("smp0.in", "w");

fprintf(out, "cat ");

fprintf(out, ". ");

fclose(out);

freopen("/devull", "w", stdout);

freopen("smp0.in", "r", stdin);

quit_if(main(5, args) != EXIT_SUCCESS);

fflush(0);

quit_if((out = fopen("smp0.out", "r")) == NULL);

for (i = 0; i

quit_if(fgets(buffer, 100, out) == NULL);

quit_if(strcmp(buffer, result[i]));

}

fclose(out);

return EXIT_SUCCESS;

}

/* test of supporting an arbitrary number of words (C3) */

int test_malloc(int argc, char **argv)

{

char *args[] = {"./main", "cat", "dog", "nap", "c", "a", "t", NULL};

char *result[] = {"Looking for 6 words ",

"Result: ",

"cat:1 ",

"dog:0 ",

"nap:0 ",

"c:0 ", "a:0 ", "t:0 "};

FILE *out;

int i;

char buffer[100];

quit_if(system("grep malloc main.c > /devull"));

out = fopen("smp0.in", "w");

fprintf(out, "cat ");

fprintf(out, ". ");

fclose(out);

freopen("smp0.in", "r", stdin);

freopen("smp0.out", "w", stdout);

quit_if(main(7, args) != EXIT_SUCCESS);

fclose(stdin);

fclose(stdout);

out = fopen("smp0.out", "r");

for (i = 0; i

quit_if(fgets(buffer, 100, out) == NULL);

quit_if(strcmp(buffer, result[i]));

}

fclose(out);

return EXIT_SUCCESS;

}

/* test of fgets usage (C4) */

int test_fgets(int argc, char **argv)

{

quit_if(system("grep fgets main.c > /devull"));

return EXIT_SUCCESS;

}

/* test of multiple words per line support (C5) */

int test_strtok(int argc, char **argv)

{

char *args[] = {"./main", "cat", "dog", "nap", NULL};

char *result[] = {"Looking for 3 words ",

"Result: ",

"cat:1 ",

"dog:2 ",

"nap:1 "};

FILE *out;

int i;

char buffer[100];

out = fopen("smp0.in", "w");

fprintf(out, "cat ");

fprintf(out, "dog dog nap ");

fprintf(out, ". ");

fclose(out);

freopen("smp0.in", "r", stdin);

freopen("smp0.out", "w", stdout);

quit_if(main(4, args) != EXIT_SUCCESS);

fclose(stdin);

fclose(stdout);

out = fopen("smp0.out", "r");

for (i = 0; i

quit_if(fgets(buffer, 100, out) == NULL);

quit_if(strcmp(buffer, result[i]));

}

fclose(out);

return EXIT_SUCCESS;

}

void delete_temp_files()

{

unlink("smp0.in");

unlink("smp0.out");

unlink("smp0.err");

}

/*

* Main entry point for SMP0 test harness

*/

int run_smp0_tests(int argc, char **argv)

{

/* Tests can be invoked by matching their name or their suite name

or 'all'*/

testentry_t tests[] = {

{"help_switch", "suite1", test_help_switch},

{"basic_functionality", "suite1",

test_basic_functionality},

{"stderr_output", "suite1", test_stderr_output},

{"file_output", "suite1", test_file_output},

{"malloc", "suite1", test_malloc},

{"fgets", "suite1", test_fgets},

{"strtok", "suite1", test_strtok}};

atexit(delete_temp_files);

return run_testrunner(argc, argv, tests, sizeof(tests) / sizeof (testentry_t));

}

____________________________

smp0.tests.h

/*************** YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE ***************/ int run_smp0_tests(int argc, char **argv); int main(int argc, char **argv);

____________________________________________________________________________

testrunner. c

/*************** YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE ***************/

/*

A simple testrunner framework

Original Author: L. Angrave

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "testrunner.h"

/* Constants */

#define false (0)

#define true (1)

#define test_killed (2)

/* defaults */

static int default_timeout_seconds=5;

static int timeout_seconds;

void set_testrunner_default_timeout(int s) {

assert(s>0);

default_timeout_seconds=s;

}

void set_testrunner_timeout(int s) {

assert(s>0);

timeout_seconds=s;

}

/* --- Helper macros and functions --- */

#define DIE(mesg) {fprintf(stderr," %s(%d):%s ",__fname__,__LINE__,mesg); exit(1);}

static int eql( char*s1, char*s2) {return s1&&s2&&!strcmp(s1,s2);}

/* Callback function for qsort on strings */

static int mystrcmp( const void *p1, const void *p2) {

return eql( ( char*)p1, ( char*)p2);

}

/* Stats of all tests run so far */

typedef struct

{

int ran, passed, failed;

} stats_t;

/* -- Signal handlers -- */

static pid_t child_pid;

static int sent_child_timeout_kill_signal;

static void kill_child_signal_handler(intsigno) {

if(!child_pid) return;

char m[]="-Timeout(Killing test process)-";

write(0,m,sizeof(m)-1);

kill(child_pid,SIGKILL);

sent_child_timeout_kill_signal=1;

}

/* Internal function to run a test as a forked child. The child process is terminated if it runs for more than a few seconds */

static int invoke_test_with_timelimit(testentry_t* test, int redirect_stdouterr,int argc, char **argv)

{

char fname[255];

int wait_status;

pid_t wait_val;

struct sigaction action;

assert(!child_pid);

assert(test && test->test_function && test->name);

set_testrunner_timeout(default_timeout_seconds);

errno=0;

child_pid = fork ();

if (child_pid == -1) {

fprintf(stderr,"-fork failed so running test inline-");

return test->test_function (argc, argv);

}

if (child_pid == 0)

{

if(redirect_stdouterr) {

snprintf(fname,(int)sizeof(fname),"stdout-%s.txt",test->name);

fname[sizeof(fname)-1]=0;

freopen(fname, "w", stdout);

memcpy(fname+3,"err",3);

freopen(fname, "w", stderr);

}

exit(test->test_function(argc,argv));

}else {

wait_status=-1;

sigemptyset(&action.sa_mask);

action.sa_handler=kill_child_signal_handler;

sigaction(SIGALRM,&action,NULL);

sent_child_timeout_kill_signal=0;

alarm(timeout_seconds);

wait_val = waitpid (child_pid, &wait_status, 0);

int child_exited_normally= WIFEXITED (wait_status);

int child_exit_value=WEXITSTATUS (wait_status);

int child_term_by_signal=WIFSIGNALED(wait_status);

int child_term_signal=WTERMSIG(wait_status);

if(child_term_by_signal) {

fprintf(stderr,"testrunner:Test terminated by signal %d ",child_term_signal);

fprintf(stderr,"testrunner:waitpid returned %d (child_pid=%d,wait_status=%d)",wait_val,child_pid,wait_status);

}

if(child_pid != wait_val)

fprintf(stderr,"testrunner: strange... wait_val != child_pid ");

int passed= (child_pid == wait_val) && (child_exit_value==0) && (child_exited_normally!=0);

alarm(0);

kill(child_pid,SIGKILL);

child_pid=0;

return sent_child_timeout_kill_signal ? test_killed : passed ? 0 : 1;

}

}

/*

* run a test and update the stats. The main guts of this functionality is provided by invoke_test_with_timelimit

* This outer wrapper updates thes output and statistics before and after running the test.

*/

static int

run_one_test (stats_t * stats, testentry_t * test, int redirect_stdouterr,int argc, char **argv)

{

int test_result;

assert (stats && test->name && argc > 0 && argv && *argv);

stats->ran++;

stats->failed++;

printf ("%2d.%-20s:", stats->ran, test->name);

fflush(stdout);

test_result=invoke_test_with_timelimit(test,redirect_stdouterr,argc,argv);

if (test_result == 0)

{

stats->failed--;

stats->passed++;

}

printf(":%s ", (test_result == 0 ? "pass" : test_result ==

2 ? "TIMEOUT * " : "FAIL *"));

return test_result!=0;

}

/* Help functionality to print out sorted list of test names and suite names */

static void print_targets(testentry_t tests[], int count) {

char**array;

char *previous;

int i;

array=(char**)calloc(sizeof(char*),count);

/* Sort the test names and print unique entries*/

for(i=0;i

qsort(array,count,sizeof(array[0]),mystrcmp);

printf(" Valid tests : all");

for(i=0,previous="";i

/* Sort the suite names and print unique entries*/

for(i=0;i

qsort(array, count,sizeof(array[0]),mystrcmp);

printf(" Valid suites:");

for(i=0,previous="";i

printf(" ");

}

/*

* Main entry point for test harness

*/

int

run_testrunner(int argc, char **argv,testentry_t tests[],int test_count)

{

char *test_name, *target;

int i;

stats_t stats;

int target_matched,max_errors_before_quit,redirect_stdouterr;

memset (&stats, 0, sizeof (stats));

max_errors_before_quit=1;

redirect_stdouterr=0;

assert (tests != NULL);

assert(test_count>0);

assert (argc > 0 && argv && *argv);

while(true) {

target = argc > 1 ? argv[1] : "";

assert (target);

if(*target!='-') break;

argc--;argv++;

if(target[1]=='f' && target[2])

max_errors_before_quit=atoi(target+1);

else if(target[1]=='r')

redirect_stdouterr=1;

}

target_matched = false;

for (i=0;i

test_name = tests[i].name;

assert(test_name);

assert(tests[i].suite);

assert(tests[i].test_function);

if (eql(target,test_name)||eql(target,"all") || eql (target,tests[i].suite) ) {

if(!target_matched) printf("Running tests... ");

target_matched = true;

run_one_test (&stats, &tests[i],redirect_stdouterr, argc - 1,argv + 1);

}

}

if (!target_matched)

{

fprintf (stderr, "Test '%s' not found", (strlen(target)>0?target : "(empty)"));

print_targets(tests,test_count);

}

else {

printf (" Test Results:%d tests,%d passed,%d failed. ", stats.ran,

stats.passed, stats.failed);

}

return stats.passed == stats.ran && target_matched ? 0 : 1;

}

________________________________________________________

testrunner.h

/*************** YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE ***************/ typedef int (*test_fp) (int, char **);

typedef struct { char *name; char *suite; test_fp test_function;

} testentry_t;

int run_testrunner(int argc, char **argv, testentry_t *entries,int entry_count); void set_testrunner_default_timeout(int s); void set_testrunner_timeout(int s);

1) Explain why this program uses the exclamation operator with the strcmp() function 2) Explain why the 'LENGTH' macro returns the length of an array. Would it work with a pointer to a dynamically allocated array? (Hint: understand sizeof). Bug hunting 3) Explain and fix the logical flow bug within the switch statement. (What happens when the -h option is used?) 4) Explain and fix the argument parsing error. (Why is entrycount never zero?) 5) Fix print_result() to print results correctly and in the same order as the words were specified on the command line. Explain your solution 1) Explain why this program uses the exclamation operator with the strcmp() function 2) Explain why the 'LENGTH' macro returns the length of an array. Would it work with a pointer to a dynamically allocated array? (Hint: understand sizeof). Bug hunting 3) Explain and fix the logical flow bug within the switch statement. (What happens when the -h option is used?) 4) Explain and fix the argument parsing error. (Why is entrycount never zero?) 5) Fix print_result() to print results correctly and in the same order as the words were specified on the command line. Explain your solution

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access with AI-Powered Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Students also viewed these Databases questions