initial commit

This commit is contained in:
nathants 2020-07-12 12:23:05 -07:00
commit d92b42f49c
6 changed files with 191 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
example

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
.PHONY: all clean
ALL=clean example
all: $(ALL)
clean:
rm -f example
example:
gcc example.c -o example

82
argh.h Normal file
View File

@ -0,0 +1,82 @@
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARGH_PARSE \
bool argh_used = true; \
bool argh_repeat = false; \
bool argh_val = false; \
char *ARGH_ARGV[argc]; \
char *argh_name; \
int ARGH_ARGC = 0; \
int argh_diff = 0; \
int argh_offset = 0; \
while(argh_offset < argc)
// check for a flag which is either present or not
#define ARGH_BOOL(short_name, long_name) \
/* ARGH_VAL cannot be used with ARGH_BOOL */ \
(argh_name = NULL, \
/* short name exact match */ \
(( 0 == strcmp(argv[argh_offset], short_name) \
/* short name prefix match, for specify multiple short names with a single param, -xyz instead -x -y -z. this mutates argv for the next pass, -xyz to -yz */ \
|| ((0 == strncmp(argv[argh_offset], short_name, 2) && strlen(argv[argh_offset]) > 2 && (argv[argh_offset]++, argv[argh_offset][0] = '-', argh_repeat = true))) \
/* long name exact match */ \
|| 0 == strcmp(argv[argh_offset], long_name)) \
/* set argh_used to avoid adding to ARGH_ARGV, return true */ \
? argh_used = true \
/* return false */ \
: false))
// check for a flag which if present is followed by a value
#define ARGH_FLAG(short_name, long_name) \
/* set argh_name so we can print it later as an error if no value is next in argv */ \
(argh_name = long_name, \
/* maybe set arg_diff=strlen(short_name) in case flag is "--nameVALUE" not "--name VALUE" */ \
( (argh_diff = strlen(argv[argh_offset]) != strlen(short_name) ? strlen(short_name) : 0, \
/* short name prefix match, if argh_diff == 0 then this is an exact match */ \
0 == strncmp(argv[argh_offset], short_name, strlen(short_name))) \
/* maybe set arg_diff=strlen(long_name) in case flag is "--nameVALUE" not "--name VALUE" */ \
|| (argh_diff = strlen(argv[argh_offset]) != strlen(long_name) ? strlen(long_name) : 0, \
/* long name prefix match, if argh_diff == 0 then this is an exact match */ \
0 == strncmp(argv[argh_offset], long_name, strlen(long_name)))) \
/* set argh_used to avoid adding to ARGH_ARGV, return true */ \
? argh_used = true \
/* return false */ \
: false)
// get value for the current flag
#define ARGH_VAL() \
/* assert can only be used with ARGH_FLAG */ \
((argh_name == NULL) \
? (fprintf(stderr, "fatal: ARGH_VAL can only be used with ARGH_FLAG\n", argh_name), exit(1), NULL) \
/* if argh_diff, use suffix of current argv instead of next argv */ \
: (argh_diff \
? (argv[argh_offset] + argh_diff) \
/* else use next argv as long as it exists and does not start with "-" */ \
: ((argh_offset < argc - 1 && strlen(argv[argh_offset + 1]) > 0 && argv[argh_offset + 1][0] != '-') \
/* set argh_val to offset argv one additional space, return val */ \
? (argh_val = true, argv[argh_offset + 1]) \
: (fprintf(stderr, "fatal: needs value %s\n", argh_name), exit(1), NULL))))
#define ARGH_NEXT() \
/* reset argh name, which is set by ARGH_FLAG */ \
argh_name = NULL; \
/* if not argh_used, save as a positional argument for later, then reset argh_used */ \
if (!argh_used) \
ARGH_ARGV[ARGH_ARGC++] = argv[argh_offset]; \
argh_used = false; \
/* if argh_val, offset argv an additional space because of ARGH_VAL, then reset argh_val */ \
if (argh_val) \
argh_offset++; \
argh_val = false; \
/* if not argh_repeat, offset argv, then reset */ \
if (!argh_repeat) \
argh_offset++; \
argh_repeat = false; \
/* check if we are done with all of argv and break is so */ \
if (argh_offset == argc) \
break;

25
example.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "argh.h"
int main(int argc, char **argv) {
if (strcmp(argv[argc - 1], "-h") == 0 || strcmp(argv[argc - 1], "--help") == 0) {
fprintf(stderr, "usage: example [-l|--lz4] [-h N|--head N] [-p|--prefix] POS1 ... POSN\n");
exit(1);
}
bool prefix = false;
bool lz4 = false;
int head = 0;
ARGH_PARSE {
ARGH_NEXT();
if ARGH_BOOL("-p", "--prefix") { prefix = true;}
else if ARGH_BOOL("-l", "--lz4") { lz4 = true; }
else if ARGH_FLAG("-h", "--head") { head = atol(ARGH_VAL()); }
}
printf("head: %d, prefix: %d, lz4: %d\n", head, prefix, lz4);
for (int i = 0; i < ARGH_ARGC; i++)
printf("positional arg %d: %s\n", i, ARGH_ARGV[i]);
}

21
license.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020-present Nathan Todd-Stone
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

52
readme.md Normal file
View File

@ -0,0 +1,52 @@
## why
minimal [argument parsing](./example.c) shouldn't require a hundred lines of code.
## what
header only argument parsing for c inspired by the simplicity of [argh](https://pythonhosted.org/argh/).
## example
```c
#include "argh.h"
int main(int argc, char **argv) {
if (strcmp(argv[argc - 1], "-h") == 0 || strcmp(argv[argc - 1], "--help") == 0) {
fprintf(stderr, "usage: example [-l|--lz4] [-h N|--head N] [-p|--prefix] POS1 ... POSN\n");
exit(1);
}
bool prefix = false;
bool lz4 = false;
int head = 0;
ARGH_PARSE {
ARGH_NEXT();
if ARGH_BOOL("-p", "--prefix") { prefix = true;}
else if ARGH_BOOL("-l", "--lz4") { lz4 = true; }
else if ARGH_FLAG("-h", "--head") { head = atol(ARGH_VAL()); }
}
printf("head: %d, prefix: %d, lz4: %d\n", head, prefix, lz4);
for (int i = 0; i < ARGH_ARGC; i++)
printf("pos arg %d: %s\n", i, ARGH_ARGV[i]);
}
```
```bash
>> make
>> ./example -lph5 asdf 123
head: 5, prefix: 1, lz4: 1
pos arg 0: asdf
pos arg 1: 123
>> ./example --lz4 asdf -p 123 --head 5
head: 5, prefix: 1, lz4: 1
pos arg 0: asdf
pos arg 1: 123
>> ./example asdf 123 --head 5 --lz4
head: 5, prefix: 0, lz4: 1
pos arg 0: asdf
pos arg 1: 123
```