diff --git a/hw2/src/par.c b/hw2/src/par.c index 7a33854..b759f5c 100644 --- a/hw2/src/par.c +++ b/hw2/src/par.c @@ -7,47 +7,43 @@ /* This is ANSI C code. */ - #include "errmsg.h" -#include "buffer.h" /* Also includes . */ +#include "buffer.h" /* Also includes . */ #include "reformat.h" #include #include #include #include +#include #undef NULL -#define NULL ((void *) 0) - - -const char * const progname = "par"; -const char * const version = "3.20"; +#define NULL ((void *)0) +const char *const progname = "par"; +const char *const version = "3.20"; static int digtoint(char c) /* Returns the value represented by the digit c, */ /* or -1 if c is not a digit. Does not use errmsg. */ { - return c == '0' ? 0 : - c == '1' ? 1 : - c == '2' ? 2 : - c == '3' ? 3 : - c == '4' ? 4 : - c == '5' ? 5 : - c == '6' ? 6 : - c == '7' ? 7 : - c == '8' ? 8 : - c == '9' ? 9 : - -1; + return c == '0' ? 0 : c == '1' ? 1 + : c == '2' ? 2 + : c == '3' ? 3 + : c == '4' ? 4 + : c == '5' ? 5 + : c == '6' ? 6 + : c == '7' ? 7 + : c == '8' ? 8 + : c == '9' ? 9 + : -1; /* We can't simply return c - '0' because this is ANSI */ /* C code, so it has to work for any character set, not */ /* just ones which put the digits together in order. */ } - static int strtoudec(const char *s, int *pn) /* Puts the decimal value of the string s into *pn, returning */ @@ -57,10 +53,13 @@ static int strtoudec(const char *s, int *pn) { int n = 0; - if (!*s) return 0; + if (!*s) + return 0; - do { - if (n >= 1000 || !isdigit(*s)) return 0; + do + { + if (n >= 1000 || !isdigit(*s)) + return 0; n = 10 * n + digtoint(*s); } while (*++s); @@ -69,11 +68,9 @@ static int strtoudec(const char *s, int *pn) return 1; } - static void parseopt( - const char *opt, int *pwidth, int *pprefix, - int *psuffix, int *phang, int *plast, int *pmin -) + const char *opt, int *pwidth, int *pprefix, + int *psuffix, int *phang, int *plast, int *pmin) /* Parses the single option in opt, setting *pwidth, *pprefix, */ /* *psuffix, *phang, *plast, or *pmin as appropriate. Uses errmsg. */ { @@ -84,43 +81,62 @@ static void parseopt( char *buf; size_t len; - if (*opt == '-') ++opt; + if (*opt == '-') + ++opt; - if (!strcmp(opt, "version")) { + if (!strcmp(opt, "version")) + { stream = open_memstream(&buf, &len); fprintf(stream, "%s %s\n", progname, version); - fflush (stream); + fflush(stream); set_error(buf); - fclose (stream); - free (buf); + fclose(stream); + free(buf); return; } oc = *opt; - if (isdigit(oc)) { - if (!strtoudec(opt, &n)) goto badopt; - if (n <= 8) *pprefix = n; - else *pwidth = n; + if (isdigit(oc)) + { + if (!strtoudec(opt, &n)) + goto badopt; + if (n <= 8) + *pprefix = n; + else + *pwidth = n; } - else { - if (!oc) goto badopt; + else + { + if (!oc) + goto badopt; n = 1; r = strtoudec(opt + 1, &n); - if (opt[1] && !r) goto badopt; + if (opt[1] && !r) + goto badopt; - if (oc == 'w' || oc == 'p' || oc == 's') { - if (!r) goto badopt; - if (oc == 'w') *pwidth = n; - else if (oc == 'p') *pprefix = n; - else *psuffix = n; + if (oc == 'w' || oc == 'p' || oc == 's') + { + if (!r) + goto badopt; + if (oc == 'w') + *pwidth = n; + else if (oc == 'p') + *pprefix = n; + else + *psuffix = n; } - else if (oc == 'h') *phang = n; - else if (n <= 1) { - if (oc == 'l') *plast = n; - else if (oc == 'm') *pmin = n; + else if (oc == 'h') + *phang = n; + else if (n <= 1) + { + if (oc == 'l') + *plast = n; + else if (oc == 'm') + *pmin = n; } - else goto badopt; + else + goto badopt; } clear_error(); @@ -128,14 +144,13 @@ static void parseopt( badopt: stream = open_memstream(&buf, &len); - fprintf(stream,"Bad option: %.149s\n", saveopt); - fflush (stream); + fprintf(stream, "Bad option: %.149s\n", saveopt); + fflush(stream); set_error(buf); - fclose (stream); - free (buf); + fclose(stream); + free(buf); } - static char **readlines(void) /* Reads lines from stdin until EOF, or until a blank line is encountered, */ @@ -147,57 +162,79 @@ static char **readlines(void) int c, blank; char ch, *ln, *nullline = NULL, nullchar = '\0', **lines = NULL; - cbuf = newbuffer(sizeof (char)); - if (is_error()) goto rlcleanup; - pbuf = newbuffer(sizeof (char *)); - if (is_error()) goto rlcleanup; + cbuf = newbuffer(sizeof(char)); + if (is_error()) + goto rlcleanup; + pbuf = newbuffer(sizeof(char *)); + if (is_error()) + goto rlcleanup; - for (blank = 1; ; ) { + for (blank = 1;;) + { c = getchar(); - if (c == EOF) break; - if (c == '\n') { - if (blank) { - ungetc(c,stdin); + if (c == EOF) + break; + if (c == '\n') + { + if (blank) + { + ungetc(c, stdin); break; } additem(cbuf, &nullchar); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; ln = copyitems(cbuf); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; additem(pbuf, &ln); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; clearbuffer(cbuf); blank = 1; } - else { - if (!isspace(c)) blank = 0; + else + { + if (!isspace(c)) + blank = 0; ch = c; additem(cbuf, &ch); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; } } - if (!blank) { + if (!blank) + { additem(cbuf, &nullchar); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; ln = copyitems(cbuf); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; additem(pbuf, &ln); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; } additem(pbuf, &nullline); - if (is_error()) goto rlcleanup; + if (is_error()) + goto rlcleanup; lines = copyitems(pbuf); rlcleanup: - if (cbuf) freebuffer(cbuf); - if (pbuf) { - if (!lines) { - for (;;) { + if (cbuf) + freebuffer(cbuf); + if (pbuf) + { + if (!lines) + { + for (;;) + { lines = nextitem(pbuf); - if (!lines) break; + if (!lines) + break; free(*lines); } } @@ -207,35 +244,42 @@ rlcleanup: return lines; } - static void setdefaults( - const char * const *inlines, int *pwidth, int *pprefix, - int *psuffix, int *phang, int *plast, int *pmin -) + const char *const *inlines, int *pwidth, int *pprefix, + int *psuffix, int *phang, int *plast, int *pmin) /* If any of *pwidth, *pprefix, *psuffix, *phang, *plast, *pmin are */ /* less than 0, sets them to default values based on inlines, according */ /* to "par.doc". Does not use errmsg because it always succeeds. */ { int numlines; - const char *start, *end, * const *line, *p1, *p2; + const char *start, *end, *const *line, *p1, *p2; - if (*pwidth < 0) *pwidth = 72; - if (*phang < 0) *phang = 0; - if (*plast < 0) *plast = 0; - if (*pmin < 0) *pmin = *plast; + if (*pwidth < 0) + *pwidth = 72; + if (*phang < 0) + *phang = 0; + if (*plast < 0) + *plast = 0; + if (*pmin < 0) + *pmin = *plast; - for (line = inlines; *line; ++line); + for (line = inlines; *line; ++line) + ; numlines = line - inlines; if (*pprefix < 0) { if (numlines <= *phang + 1) *pprefix = 0; - else { + else + { start = inlines[*phang]; - for (end = start; *end; ++end); - for (line = inlines + *phang + 1; *line; ++line) { - for (p1 = start, p2 = *line; p1 < end && *p1 == *p2; ++p1, ++p2); + for (end = start; *end; ++end) + ; + for (line = inlines + *phang + 1; *line; ++line) + { + for (p1 = start, p2 = *line; p1 < end && *p1 == *p2; ++p1, ++p2) + ; end = p1; } *pprefix = end - start; @@ -246,99 +290,300 @@ static void setdefaults( { if (numlines <= 1) *psuffix = 0; - else { + else + { start = *inlines; - for (end = start; *end; ++end); - for (line = inlines + 1; *line; ++line) { - for (p2 = *line; *p2; ++p2); + for (end = start; *end; ++end) + ; + for (line = inlines + 1; *line; ++line) + { + for (p2 = *line; *p2; ++p2) + ; for (p1 = end; p1 > start && p2 > *line && p1[-1] == p2[-1]; - --p1, --p2); + --p1, --p2) + ; start = p1; } - while (end - start >= 2 && isspace(*start) && isspace(start[1])) ++start; + while (end - start >= 2 && isspace(*start) && isspace(start[1])) + ++start; *psuffix = end - start; } } } - static void freelines(char **lines) /* Frees the strings pointed to in the NULL-terminated array lines, then */ /* frees the array. Does not use errmsg because it always succeeds. */ { char **line; - for (line = lines; *line; ++line) + for (line = lines; *line; ++line) free(*line); free(lines); } +static int setValue(int *val, char *arg, char *name) +{ + FILE *stream; + char *buf; + size_t len; + if (!arg) + { + stream = open_memstream(&buf, &len); + fprintf(stream, "Require value for argument %s", name); + fflush(stream); + set_error(buf); + fclose(stream); + free(buf); + } -int original_main(int argc, const char * const *argv) + // if (*val != -1) + // { + // stream = open_memstream(&buf, &len); + // fprintf(stream, "Multiple input for argument %s", name); + // fflush(stream); + // set_error(buf); + // fclose(stream); + // free(buf); + // return 0; + // } + if (!strtoudec(arg, val)) + { + stream = open_memstream(&buf, &len); + fprintf(stream, "Invalid Input %s\n", arg); + fflush(stream); + set_error(buf); + fclose(stream); + free(buf); + return 0; + } + return 1; +} + +static int setOptions(int argc, char **argv, int *widthbak, int *prefixbak, int *suffixbak, int * hangbak, int *lastbak, int *minbak) +{ + FILE *stream; + char *buf; + size_t len; + int option_index = 0; + static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, + {"width", required_argument, 0, 'w'}, + {"prefix", required_argument, 0, 'p'}, + {"suffix", required_argument, 0, 's'}, + {"hang", optional_argument, 0, 'h'}, + {"last", no_argument, 0, 'L'}, + {"no-last", no_argument, 0, 'n'}, + {"min", no_argument, 0, 'M'}, + {"no-min", no_argument, 0, 'N'}, + {0, 0, 0, 0}}; + + for (char ch = getopt_long(argc, argv, "w:p:s:h::l:m:", long_options, &option_index); ch != -1; ch = getopt_long(argc, argv, "w:p:s:h::l:m:", long_options, &option_index)) + { + + switch (ch) + { + case 'v': + stream = open_memstream(&buf, &len); + fprintf(stream, "%s %s\n", progname, version); + fflush(stream); + set_error(buf); + fclose(stream); + free(buf); + return 0; + break; + case 'W': + if (!setValue(widthbak, optarg, "width")) + return 0; + break; + case 'w': + if (!setValue(widthbak, optarg, "width")) + return 0; + break; + case 'p': + if (!setValue(prefixbak, optarg, "prefix")) + return 0; + break; + case 's': + if (!setValue(suffixbak, optarg, "suffix")) + return 0; + break; + case 'h': + if (!optarg) + { + optarg = "1"; + } + if (!setValue(hangbak, optarg, "hang")) + return 0; + break; + case 'l': + if (!setValue(lastbak, optarg, "last")) + return 0; + if (*lastbak != 0 && *lastbak != 1) + { + stream = open_memstream(&buf, &len); + fprintf(stream, "Value for -l must be 0 or 1"); + fflush(stream); + set_error(buf); + fclose(stream); + free(buf); + return 0; + } + break; + case 'm': + if (!setValue(minbak, optarg, "last")) + return 0; + if (*minbak != 0 && *minbak != 1) + { + stream = open_memstream(&buf, &len); + fprintf(stream, "Value for -m must be 0 or 1"); + fflush(stream); + set_error(buf); + fclose(stream); + free(buf); + return 0; + } + break; + case 'L': + if (!setValue(lastbak, "1", "last")) + return 0; + break; + case 'n': + if (!setValue(lastbak, "0", "last")) + return 0; + break; + case 'M': + if (!setValue(minbak, "1", "min")) + return 0; + break; + case 'N': + if (!setValue(minbak, "0", "last")) + return 0; + break; + default: + break; + } + } + return 1; +} + +int original_main(int argc, const char *const *argv) { int width, widthbak = -1, prefix, prefixbak = -1, suffix, suffixbak = -1, - hang, hangbak = -1, last, lastbak = -1, min, minbak = -1, c; + hang, hangbak = -1, last, lastbak = -1, min, minbak = -1, c, argc_env; char *parinit, *picopy = NULL, *opt, **inlines = NULL, **outlines = NULL, - **line; - const char * const whitechars = " \f\n\r\t\v"; + **line, **argv_env, *tmp; + const char *const whitechars = " \f\n\r\t\v"; + + // parinit = getenv("PARINIT"); + // if (parinit) { + // picopy = malloc((strlen(parinit) + 1) * sizeof (char)); + // if (!picopy) { + // set_error(outofmem); + // goto parcleanup; + // } + // strcpy(picopy,parinit); + // opt = strtok(picopy,whitechars); + // while (opt) { + // parseopt(opt, &widthbak, &prefixbak, + // &suffixbak, &hangbak, &lastbak, &minbak); + // if (is_error()) goto parcleanup; + // opt = strtok(NULL,whitechars); + // } + // free(picopy); + // picopy = NULL; + // } + + // while (*++argv) { + // parseopt(*argv, &widthbak, &prefixbak, + // &suffixbak, &hangbak, &lastbak, &minbak); + // if (is_error()) goto parcleanup; + // } parinit = getenv("PARINIT"); - if (parinit) { + if (parinit) + { picopy = malloc((strlen(parinit) + 1) * sizeof (char)); if (!picopy) { set_error(outofmem); goto parcleanup; } + argc_env = 1; + argv_env = malloc((argc_env) * sizeof (char*)); + argv_env[0] = malloc((strlen(argv[0])+1) * sizeof(char)); + tmp = argv_env[0]; + strcpy(tmp, argv[0]); strcpy(picopy,parinit); opt = strtok(picopy,whitechars); while (opt) { - parseopt(opt, &widthbak, &prefixbak, - &suffixbak, &hangbak, &lastbak, &minbak); - if (is_error()) goto parcleanup; + argc_env ++; + argv_env = realloc(argv_env, (argc_env + 1)*sizeof(char*)); + argv_env[argc_env-1] = malloc((strlen(opt)+1)*sizeof(char)); + tmp = argv_env[argc_env-1]; + strcpy(tmp, opt); opt = strtok(NULL,whitechars); } - free(picopy); - picopy = NULL; - } + argv_env = realloc(argv_env, (argc_env + 1)*sizeof(char*)); + argv_env[argc_env] = NULL; - while (*++argv) { - parseopt(*argv, &widthbak, &prefixbak, - &suffixbak, &hangbak, &lastbak, &minbak); - if (is_error()) goto parcleanup; - } + for (size_t i = 0; i < argc_env; i++) + { + printf("%s\n", argv_env[i]); + } + - for (;;) { - for (;;) { + if (!setOptions(argc_env, (char **)argv_env, &widthbak, &prefixbak, &suffixbak, &hangbak, &lastbak, &minbak)) + goto parcleanup; + freelines(argv_env); + } + if (!setOptions(argc, (char **)argv, &widthbak, &prefixbak, &suffixbak, &hangbak, &lastbak, &minbak)) + goto parcleanup; + + printf("width: %d, prefix: %d, suffix: %d, hang: %d, last: %d, min: %d", widthbak, prefixbak, suffixbak, hangbak, lastbak, minbak); + + for (;;) + { + for (;;) + { c = getchar(); - if (c == EOF) goto parcleanup; - if (c != '\n') break; + if (c == EOF) + goto parcleanup; + if (c != '\n') + break; putchar(c); } - ungetc(c,stdin); + ungetc(c, stdin); inlines = readlines(); - if (is_error()) goto parcleanup; - if (!*inlines) { + if (is_error()) + goto parcleanup; + if (!*inlines) + { free(inlines); inlines = NULL; continue; } - width = widthbak; prefix = prefixbak; suffix = suffixbak; - hang = hangbak; last = lastbak; min = minbak; - setdefaults((const char * const *) inlines, + width = widthbak; + prefix = prefixbak; + suffix = suffixbak; + hang = hangbak; + last = lastbak; + min = minbak; + setdefaults((const char *const *)inlines, &width, &prefix, &suffix, &hang, &last, &min); - outlines = reformat((const char * const *) inlines, + outlines = reformat((const char *const *)inlines, width, prefix, suffix, hang, last, min); - if (is_error()) goto parcleanup; + if (is_error()) + goto parcleanup; freelines(inlines); inlines = NULL; - for (line = outlines; *line; ++line) + for (line = outlines; *line; ++line) puts(*line); freelines(outlines); @@ -347,15 +592,19 @@ int original_main(int argc, const char * const *argv) parcleanup: - if (picopy) free(picopy); - if (inlines) freelines(inlines); - if (outlines) freelines(outlines); + if (picopy) + free(picopy); + if (inlines) + freelines(inlines); + if (outlines) + freelines(outlines); - if (is_error()) { + if (is_error()) + { report_error(stderr); clear_error(); - return(EXIT_FAILURE); + return (EXIT_FAILURE); } - return(EXIT_SUCCESS); + return (EXIT_SUCCESS); } diff --git a/hw2/tests/basecode_tests.c b/hw2/tests/basecode_tests.c index 70cd753..d5091fe 100644 --- a/hw2/tests/basecode_tests.c +++ b/hw2/tests/basecode_tests.c @@ -37,7 +37,7 @@ Test(base_suite, basic_test) { */ Test(base_suite, prefix_suffix_test) { char *name = "prefix_suffix"; - sprintf(program_options, "%s", "w80"); + sprintf(program_options, "%s", "-w 80"); int err = run_using_system(name, "", "", STANDARD_LIMITS); assert_expected_status(EXIT_SUCCESS, err); assert_outfile_matches(name, NULL); @@ -62,7 +62,7 @@ Test(base_suite, valgrind_leak_test) { */ Test(base_suite, valgrind_uninitialized_test) { char *name = "valgrind_uninitialized"; - sprintf(program_options, "%s", "p10 s10"); + sprintf(program_options, "%s", "-p 10 -s 10"); int err = run_using_system(name, "", "valgrind --leak-check=no --undef-value-errors=yes --error-exitcode=37", STANDARD_LIMITS); assert_no_valgrind_errors(err); assert_expected_status(0x1, err);