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

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

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

Step: 2

blur-text-image_2

Step: 3

blur-text-image_3

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