diff --git a/Makefile b/Makefile index cb83107..56af208 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PROGRAM = crc32 .PHONY: all clean install -FILES = main.c +FILES = main.c args.c CFLAGS += -Wall -Werror -ansi -pedantic LDFLAGS += diff --git a/args.c b/args.c new file mode 100644 index 0000000..2a43f37 --- /dev/null +++ b/args.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2012 Connor Olding + * + * This program is licensed under the terms of the MIT License, and + * is distributed without any warranty. You should have received a + * copy of the license along with this program; see the file LICENSE. + */ + +#include "args.h" +#include + +static int argc, argi; +static char** argv, * flag; + +static char* nextarg() +{ + char* temp = flag; + flag = NULL; + if (temp[1]) + return temp + 1; + if (++argi == argc) + return NULL; + return argv[argi]; +} + +void args_parse(int argc_, char** argv_, + void flagfn(char, char*()), void plainfn(char*)) +{ + argc = argc_; + argv = argv_; + for (argi = 1; argi < argc; argi++) { + char* arg = argv[argi]; + if (!arg[0]) + continue; + + /* if ... || arg == "-" */ + if (arg[0] != '-' || !arg[1]) { + if (plainfn) + plainfn(arg); + continue; + } + /* if arg == "--" */ + if (arg[1] == '-' && !arg[2]) + break; + + for (flag = arg + 1; *flag; flag++) { + flagfn(*flag, nextarg); + if (!flag) + break; + } + } + for (; argi < argc; argi++) + if (plainfn) + plainfn(argv[argi]); +} + diff --git a/args.h b/args.h index 05ed772..e1bcb29 100644 --- a/args.h +++ b/args.h @@ -5,182 +5,6 @@ * copy of the license along with this program; see the file LICENSE. */ -#ifndef ARGS_H_ -#define ARGS_H_ - -#include -#include -#include - -/* interface */ - -extern char args_info[]; -extern char args_usage[]; -extern void args_print_help_suffix(); - -extern const int args_switch_count; -extern char* args_switches[]; -extern void (*args_functions[])(); - -void args_handle(int argc, char* argv[]); -char* args_poll(); -void args_print_help(); - -/* implemenation */ - -static const int args_columns = 3; - -static char* args_program_name = NULL; - -static int args_argc = 0; -static char** args_argv = NULL; - -static int args_current = 0; -static int args_previous = 0; -static char* args_previous_name = NULL; - -static char args_is_blank(char* s) -{ - if (s == NULL || s[0] == '\0' || s[0] == ' ') - return 1; - return 0; -} - -static char args_is_short(char *s) -{ - if (!args_is_blank(s) && s[0] == '-' && s[1] != '\0' && s[1] != '-') - return 1; - return 0; -} - -static void args_print_info() -{ - printf(args_info); -} - -static void args_print_usage() -{ - printf(args_usage, args_program_name); -} - -static void args_print_switches() -{ - int i; - for (i = 0; i < args_switch_count * args_columns; i += args_columns) { - printf(" "); - if (args_is_blank(args_switches[i])) { - printf(" "); - } else { - printf("%s,", args_switches[i]); - } - printf(" %s %s\n", - args_switches[i + 1], - args_switches[i + 2]); - } - args_print_help_suffix(); -} - -void args_print_help() -{ - args_print_info(); - puts(""); - args_print_switches(); - exit(0); -} - -static void args_check_bounds() -{ - if (args_current >= args_argc) { - if (args_current - 1 == args_previous) - fprintf(stderr, "%s requires an argument.\n", - args_previous_name); - else - fprintf(stderr, "%s requires another argument.\n", - args_previous_name); - args_print_usage(); - exit(1); - } -} - -static int args_get_index(char* name) -{ - int i; - for (i = 0; i < args_switch_count * args_columns; i++) { - if (i % args_columns == args_columns - 1) - continue; /* skip checking the description column */ - if (args_is_blank(args_switches[i])) - continue; - if (!strcmp(args_switches[i], name)) - return i / args_columns; - } - return -1; -} - -static char* args__poll(char wants_switch) -{ - static char short_[3] = "--"; - static int pos = 0; - char* arg = NULL; - - args_check_bounds(); - - arg = args_argv[args_current]; - if (!wants_switch) { - args_current++; - arg += pos * sizeof(char); - pos = 0; - return arg; - } - if (args_is_short(arg)) { - if (pos == 0) - pos++; - short_[1] = arg[pos]; - pos++; - if (arg[pos] == '\0') { - pos = 0; - args_current++; - } - return short_; - } - args_current++; - return arg; -} - -static char* args_poll_for_switch() -{ - return args__poll(1); -} - -char* args_poll() -{ - return args__poll(0); -} - -void args_handle(int argc, char** argv) -{ - args_argc = argc; - args_argv = argv; - - args_current = 0; - args_program_name = args_poll(); - - while (args_current < args_argc) { - char* name; - int index; - - args_previous = args_current; - name = args_poll_for_switch(); - args_previous_name = name; - - index = args_get_index(name); - if (index < 0) { - fprintf(stderr, "Unknown option: %s\n", name); - args_print_usage(); - exit(1); - } - args_functions[index](); - } -} - -#endif +void args_parse(int argc, char** argv, + void flagfn(char, char*()), void plainfn(char*)); diff --git a/main.c b/main.c index 3efe2a0..2b8f0ab 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include #include +#include #include "crc32.h" #include "args.h" @@ -25,70 +26,56 @@ static char print_binary = 0; static char xor_output = 1; static char reflect_output = 0; -char args_info[] = "crc32 - 32-bit cyclic redundancy check calculator\n"; -char args_usage[] = "Usage: %s [-i f] [-s n] [-p n] [-e] [-x] [-r] [-b]\n"; -void args_print_help_suffix() -{ - puts("\n\ -numbers (n) can be entered as hexadecimal or octal with prefixes"); +const char help1[] = "\ +crc32 - a 32-bit cyclic rendundancy check calculator\n\ +\n\ + -h display this text\n\ + -i open file for reading (default: stdin)\n\ + -s start cycle with n (default: 0xFFFFFFFF)\n\ + -p use n as the crc divisor (default: 0x04C11DB7)\n\ + -e use big endian calculations\n\ + -b output as binary\n\ + -x xor the output by 0xFFFFFFFF\n\ + -r reverse the bits of the output\n\ +\n\ +"; +const char help2[] = "\ +numbers may be entered as hexadecimal or octal with prefixes\n\ +"; + +void handle_flag(char flag, char* (*nextarg)()) { + /* TODO: check for NULL on nextarg */ + switch (flag) { + case 'h': + printf(help1); + printf(help2); + exit(0); + case 'i': + input_filename = nextarg(); + break; + case 's': + remainder = strtoul(nextarg(), NULL, 0); + break; + case 'p': + crc_set_polynomial(strtoul(nextarg(), NULL, 0)); + break; + case 'e': + crc_set_big_endian(); + break; + case 'b': + print_binary = 1; + break; + case 'x': + xor_output = 0; + break; + case 'r': + reflect_output = 1; + break; + default: + exit(1); + } } -const int args_switch_count = 9; -char* args_switches[] = { -"-h","--help"," display this text", -" ","--license"," show copyright & license information", -"-i","--input","f open file f for reading (default: stdin)", -"-s","--start-at","n start cycle with n (default: 0xFFFFFFFF)", -"-p","--polynomial","n use n as the crc divisor (default: 0x04C11DB7)", -"-e","--big-endian"," use big endian calculations (default: little)", -"-b","--binary"," output as binary (default: hex with newline)", -"-x","--xor"," xor the output by 0xFFFFFFFF", -"-r","--reflect"," reverse the bits of the output", -}; - -void print_license() -{ - puts("crc32 Copyright (C) 2012 Connor Olding\n\ -This program comes with ABSOLUTELY NO WARRANTY, and is free software.\n\ -See the file \"LICENSE\" or for details."); - exit(0); -} - -void start_at() -{ - remainder = strtoul(args_poll(), NULL, 0); -} - -void set_input() -{ - input_filename = args_poll(); -} - -void set_polynomial() -{ - const int p = strtoul(args_poll(), NULL, 0); - crc_set_polynomial(p); -} - -void set_binary() -{ - print_binary = 1; -} - -void set_xor() -{ - xor_output = 0; -} - -void set_reflect() -{ - reflect_output = 1; -} - -void (*args_functions[])() = - {args_print_help, print_license, set_input, start_at, set_polynomial, - crc_set_big_endian, set_binary, set_xor, set_reflect}; - static void open_stream() { const char mode[] = "rb"; @@ -135,7 +122,7 @@ static void print_crc() int main(int argc, char** argv) { crc_set_little_endian(); - args_handle(argc, argv); + args_parse(argc, argv, handle_flag, NULL); cycle_input(); print_crc(); return 0;