rewrote args handler

This commit is contained in:
Connor Olding 2012-08-04 07:03:08 -07:00
parent 113e68a1f5
commit 2a770f0987
4 changed files with 108 additions and 242 deletions

View File

@ -1,6 +1,6 @@
PROGRAM = crc32
.PHONY: all clean install
FILES = main.c
FILES = main.c args.c
CFLAGS += -Wall -Werror -ansi -pedantic
LDFLAGS +=

55
args.c Normal file
View File

@ -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 <stddef.h>
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]);
}

180
args.h
View File

@ -5,182 +5,6 @@
* copy of the license along with this program; see the file LICENSE.
*/
#ifndef ARGS_H_
#define ARGS_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* 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*));

113
main.c
View File

@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <file> open file for reading (default: stdin)\n\
-s <n> start cycle with n (default: 0xFFFFFFFF)\n\
-p <n> 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 <n> 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 <http://gnu.org/licenses/gpl.txt> 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;