Skip to content

Commit 968432f

Browse files
committed
Added a more informative example, updated Makefile and README
1 parent caccac5 commit 968432f

File tree

5 files changed

+180
-6
lines changed

5 files changed

+180
-6
lines changed

Makefile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
CC=gcc
2-
EXEC=test
32
LIB=argparse.a
43
SHARED_LIB=libargparse.so
54
SOURCE=argparse.c
65
INCLUDE=argparse.h
7-
TEST_S=test.c
6+
EXAMPLE=example
7+
EXAMPLE_S=example.c
88
CFLAGS=-fPIC -O2
99

1010
all: shared static
@@ -17,8 +17,11 @@ static: object
1717
shared: object
1818
gcc -shared -o $(SHARED_LIB) $(SOURCE:.c=.o)
1919

20+
example:
21+
gcc -o $(EXAMPLE) $(EXAMPLE_S) $(SOURCE)
22+
2023
clean:
21-
rm -f $(SHARED_LIB) $(LIB) $(SOURCE:.c=.o)
24+
rm -f $(SHARED_LIB) $(LIB) $(SOURCE:.c=.o) $(EXAMPLE)
2225

2326
install:
2427
cp $(INCLUDE) /usr/include

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,20 @@
22

33
argparse is a simple parser for the command line options, that implements the parser for the standart Unix-like options
44

5+
## Features
6+
7+
- Merged key-value arguments (i.e objdump -Mintel ...)
8+
- Values without keys can be ignored, saved or return an error code (i.e gcc *argparse.c* -o argparse ...)
9+
- Merged short arguments (i.e emerge -uavD ...)
10+
- Long arguments (i.e emerge --ask --update --verbose ...)
11+
- Arguments with an optional value
12+
- No dynamic allocations and copying
13+
- Can be compiled without stdlib (-ffreestanding)
14+
515
## Example
616

17+
Note: a more informative example can be found in example.c
18+
719
```c
820
/* <this_example> --verbose -cj --move "/some/where/" test_project */
921
#include "argparse.h"
@@ -75,3 +87,4 @@ int main (int argc, char ** argv) {
7587
## Installation
7688
7789
To install argparse on a unix system just type `make && sudo make install`
90+
You can also compile the example.c file with `make example` without installing the library on your system

argparse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ char * arg_parse (int * argc, char *** argv, arg_list list, char ** nk, size_t *
259259
*argv = state.argv;
260260
return arg;
261261
}
262-
++nk_size;
262+
++(*nk_size);
263263
*nk = *state.argv;
264264
++nk;
265265
continue;

argparse.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232

3333
#include <stddef.h>
3434

35-
#define ARG_BUFSIZ 20
36-
3735
#define ARG_SUCCESS 0
3836

3937
#define ARG_ZERO -1
@@ -61,6 +59,8 @@ p_arg_handler arg_string_handler;
6159
* to the static buffer */
6260
p_arg_handler arg_strcpy_handler;
6361

62+
/* Defaults */
63+
#define ARG_FLAG_DEFAULT 0x0
6464
/* This flag tells the parser to set the flag argument value to 0 instead of 1 */
6565
#define ARG_FLAG_UNSET 0x01
6666
/* This flag tells the parser that the value for this argument is optional */

example.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include <argparse.h>
2+
#include <stdio.h>
3+
#include <stdint.h>
4+
#include <string.h>
5+
#include <stdlib.h>
6+
7+
/* This is a very simple implementation of a calculator
8+
* usage:
9+
* example -o[+, -, /, *, %] op1 op2
10+
* or
11+
* example --operator [+, -, /, *, %] op1 op2 */
12+
13+
/* define a very simple list of operators */
14+
enum operator {
15+
plus,
16+
minus,
17+
multiply,
18+
divide,
19+
modulo,
20+
undef
21+
};
22+
23+
/* convinient macro */
24+
#define STREQ(a, b) (strcmp (a, b) == 0)
25+
26+
/* Usage info */
27+
#define USAGE \
28+
"Usage:\n" \
29+
"\texample -o[+, -, /, *, %] op1 op2\n" \
30+
"or\n" \
31+
"\texample --operator [+, -, /, *, %] op1 op2"
32+
33+
static char op = undef;
34+
35+
/* the custom handler for our enumerator
36+
*
37+
* handlers modify the value of the argument
38+
* to write it in retval the right way */
39+
arg_return custom_enum_handler (void * data, size_t size, void * retval) {
40+
if (STREQ (data, "+")) {
41+
op = plus;
42+
}
43+
else if (STREQ (data, "-")) {
44+
op = minus;
45+
}
46+
else if (STREQ (data, "/")) {
47+
op = divide;
48+
}
49+
else if (STREQ (data, "*")) {
50+
op = multiply;
51+
}
52+
else if (STREQ (data, "%")) {
53+
op = modulo;
54+
}
55+
else {
56+
/* The value is not an operator, so we return ARG_NMATCH */
57+
return ARG_NMATCH;
58+
}
59+
/* Everything is good, return ARG_SUCCESS */
60+
return ARG_SUCCESS;
61+
}
62+
63+
int main (int argc, char ** argv) {
64+
if (argc == 1) {
65+
puts ("You haven't specified any arguments");
66+
return 0;
67+
}
68+
/* A description of the parser rules
69+
* a full argument rule would look like this:
70+
* { 'o', "operator", custom_enum_handler, &op, ARG_FLAG_DEFAULT }
71+
*
72+
* Where:
73+
* 'o' is the short key
74+
* "operator" is the long key
75+
* custom_enum_handler is the handler
76+
* &op is the return value for the handler
77+
* ARG_FLAG_DEFAULT is flag, defining the parser's behaviour, when the key is met */
78+
arg_list list = {
79+
{ 'o', "operator", custom_enum_handler, &op }, /* C allows to drop ARG_FLAGS_DEFAULT */
80+
/* if the handler == NULL, the parser will consider the argument a flag and write
81+
* 1 into the return value (unless ARG_FLAG_UNSET is passed, which will write 0 in the ret. val).
82+
* If the return value passed == 0, nothing will happen.
83+
* Here, because `flags` is set to ARG_FLAG_HALT, the parser will stop, when the key is met. */
84+
{ 'h', "help", NULL, NULL, ARG_FLAG_HALT },
85+
{ 0 } /* any argument list should end with 0, so the parser could count the number of rules */
86+
};
87+
88+
/* this variable will store the faulty argument (if there are any) */
89+
char * err_arg;
90+
/* the return code of the parser (should be ARG_SUCCESS <0>) */
91+
arg_return code;
92+
93+
/* the buffer for the *not-a-key* value (value, not preceeded by a key) */
94+
char * nk_buf[2];
95+
/* size of the written buffer */
96+
size_t nk_siz;
97+
98+
/* call the parser
99+
* if an error occured, the parser will stop and return the faulty argument and will write the error
100+
* code to `code`. On success it will return NULL, and the return code will be ARG_SUCCESS.
101+
*
102+
* here:
103+
* &argc is a pointer to the argc variable
104+
* &argv is a pointer to the argv variable
105+
* list is the argument list
106+
* nk_buf is the buffer for storing *not-a-key* values
107+
* &nk_siz is the variable, that is going to store the size of the nk_buf
108+
* ARG_PARSE_MERGED is a flag, that tells the parser, that we allow merged key-value arguments (i.e -o+)
109+
* &code is a variable that is going to store the return code of the parser */
110+
if ((err_arg = arg_parse (&argc, &argv, list, nk_buf, &nk_siz, ARG_PARSE_MERGED, &code)) != NULL) {
111+
/* if --help or -h is met, the return code will be set to ARG_HALT as defined in the parser rules*/
112+
if (code == ARG_HALT) {
113+
puts (USAGE);
114+
return 0;
115+
}
116+
/* if an error occured */
117+
printf ("Could not parse argument: %s\n", err_arg);
118+
return 1;
119+
}
120+
121+
if (op == undef) {
122+
puts ("Specify an operator with -o [+, -, /, *, %]");
123+
return 1;
124+
}
125+
126+
/* Check, if user passed 2 arguments */
127+
if (nk_siz != 2) {
128+
puts ("You have to specify two operands");
129+
return 2;
130+
}
131+
132+
int64_t a, b;
133+
/* write them into a and b */
134+
a = atol (nk_buf[0]);
135+
b = atol (nk_buf[1]);
136+
137+
switch (op) {
138+
case plus:
139+
a += b;
140+
break;
141+
case minus:
142+
a -= b;
143+
break;
144+
case divide:
145+
a /= b;
146+
break;
147+
case multiply:
148+
a *= b;
149+
break;
150+
case modulo:
151+
a %= b;
152+
break;
153+
}
154+
155+
printf ("The result is %li\n", a);
156+
157+
return 0;
158+
}

0 commit comments

Comments
 (0)