Skip to content

Commit 5622ebe

Browse files
committed
Initial commit
0 parents  commit 5622ebe

File tree

2 files changed

+348
-0
lines changed

2 files changed

+348
-0
lines changed

argparse.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* argparse - fast argument parsing tool
2+
* Copyright (C) 2021 Sergey Lafin
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version 2
7+
* of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
17+
18+
#include "argparse.h"
19+
20+
/* The author is very lazy and, apparentely, also has very doubtful
21+
* knowledge of C, so, to avoid using all these fancy things like
22+
* __thread, he came up with the stupidest idea ever: "why don't I
23+
* pass the state of the parser to every single function?" */
24+
25+
/* Sub to parse long arguments
26+
* IN size_t * argc: -
27+
* IN char *** argv: pointer to the array
28+
* IN arg_list list: the list to parse from
29+
*
30+
* RETURN: Parse code */
31+
static arg_return arg_parse_long (int * argc, char *** argv, arg_list list, size_t len) {
32+
return ARG_SUCCESS;
33+
}
34+
35+
/* Sub to parse the value of the argument
36+
* IN int * argc: -
37+
* IN char *** argv: array pointer
38+
*
39+
* RETURN: return code */
40+
static arg_return arg_parse_value (int * argc, char *** argv, void ** data, size_t * size) {
41+
if (!(***argv)) {
42+
if (*argc == 1)
43+
return ARG_NVALUE;
44+
else {
45+
--argc;
46+
++(*argv);
47+
}
48+
}
49+
*size = ARG_STRLEN (**argv);
50+
if (*size == 0) {
51+
*data = NULL;
52+
return ARG_NVALUE;
53+
}
54+
*data = **argv;
55+
**argv += *size;
56+
return ARG_SUCCESS;
57+
}
58+
59+
/* Sub to parse short arguments
60+
* IN size_t * argc: -
61+
* IN char *** argv: pointer to the array
62+
* IN arg_list list: the list to parse from
63+
*
64+
* RETURN: Parse code */
65+
static arg_return arg_parse_short (int * argc, char *** argv, arg_list list, size_t len) {
66+
size_t i;
67+
for (i = 0; i < len; ++i) {
68+
if (!(***argv)) {
69+
return ARG_SUCCESS;
70+
}
71+
if (list[i].short_arg == ***argv) {
72+
void * data = NULL;
73+
size_t size = 0;
74+
75+
/* TODO: Add a freaking check for non-value arguments */
76+
if (list[i].handler) {
77+
arg_return ret_code;
78+
++(**argv);
79+
ret_code = arg_parse_value(argc, argv, &data, &size);
80+
if (ret_code == ARG_NVALUE) {
81+
return ret_code;
82+
}
83+
if ((ret_code = list[i].handler(data, size, list[i].retval)) != 0)
84+
return ret_code;
85+
}
86+
}
87+
}
88+
return ARG_NMATCH;
89+
}
90+
91+
/* Sub to parse non-arguments
92+
* IN size_t * argc: -
93+
* IN char *** argv: pointer to the array
94+
* IN arg_list list: the list to parse from
95+
*
96+
* RETURN: Parse code */
97+
static arg_return arg_parse_non (int * argc, char *** argv, arg_list list, size_t len) {
98+
return ARG_SUCCESS;
99+
}
100+
101+
/* Sub to determine the size of an arg_list
102+
* IN const arg_list list: the list
103+
*
104+
* RETURN: the size of the list */
105+
static ARG_INLINE size_t arg_list_len (const arg_list list) {
106+
size_t size = 0;
107+
while (*(struct arg_argument **)list) {
108+
++list; ++size;
109+
}
110+
return size;
111+
}
112+
113+
/* arg_parse implementation */
114+
char ** arg_parse (int argc, char ** argv, arg_list list, arg_return * code) {
115+
/* The idea of spliting these lines, is to keep track
116+
* of the exact cause */
117+
ARG_ASSERT(argc > 1);
118+
ARG_ASSERT(argv != NULL);
119+
ARG_ASSERT(list != NULL);
120+
121+
size_t list_len = arg_list_len (list);
122+
assert (list_len > 0);
123+
124+
if (argc == 1) {
125+
*code = ARG_ZERO;
126+
return argv;
127+
}
128+
129+
++argv;
130+
arg_return ret_code = 0;
131+
while (--argc) {
132+
if (**argv == '-') {
133+
if (*(++*argv) == '-' && **argv) { /* If the "--" is passed we have to stop accepting the arguments */
134+
if ((ret_code = arg_parse_long (&argc, &argv, list, list_len)) != 0) {
135+
*code = ret_code;
136+
return argv;
137+
}
138+
}
139+
140+
if ((ret_code = arg_parse_short (&argc, &argv, list, list_len)) != 0) {
141+
*code = ret_code;
142+
return argv;
143+
}
144+
145+
/* Not a key */
146+
arg_parse_non (&argc, &argv, list, list_len);
147+
}
148+
}
149+
*code = ARG_SUCCESS;
150+
return NULL;
151+
}

argparse.h

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/* argparse - fast argument parsing tool
2+
* Copyright (C) 2021 Sergey Lafin
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version 2
7+
* of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
17+
18+
/* Parsing:
19+
* check whether or not the argument belongs in line
20+
* check if its long or short type
21+
* parse accordingly:
22+
* short, meaning that the data can be inserted after the argument key or after a space
23+
* long, meaning that the data can be inserted after a space or after a '=' char
24+
* The ordering plays some role */
25+
26+
27+
#ifndef __SL_ARGPARSE_H__
28+
#define __SL_ARGPARSE_H__
29+
30+
#include <malloc.h>
31+
32+
/* A simple implementation of some important "string.h" functions */
33+
#ifdef ARG_STANDALONE
34+
# define ARG_ASSERT(x)
35+
# define ARG_STRCMP(a, b) arg_lstrcmp(a, b)
36+
# define ARG_STRLEN(str) arg_strlen(str)
37+
# define ARG_STRCPY(dest, src) arg_strcpy(dest, src)
38+
# define ARG_MEMCPY(dest, src, n) arg_memcpy(dest, src, n)
39+
static size_t arg_strlen (char * str) {
40+
size_t len = 0;
41+
while (*str) {
42+
++str; ++len;
43+
}
44+
return len;
45+
}
46+
static char * arg_strcpy (char * dest, char * src) {
47+
while (*src) {
48+
*dest = *src;
49+
++dest; ++src;
50+
}
51+
dest = 0x0;
52+
return dest;
53+
}
54+
static void * arg_memcpy (void * dest, void * src, size_t n) {
55+
while (*dest) {
56+
*(char)dest = *(char *)src;
57+
++dest; ++src;
58+
}
59+
return dest;
60+
}
61+
62+
63+
#else
64+
# include <string.h>
65+
# include <assert.h>
66+
# define ARG_ASSERT(x) assert(x)
67+
# define ARG_STRCMP(a, b) arg_lstrcmp(a, b)
68+
# define ARG_STRLEN(str) strlen(str)
69+
# define ARG_STRCPY(dest, src) strcpy(dest, src)
70+
# define ARG_MEMCPY(dest, src, n) memcpy(dest, src, n)
71+
#endif
72+
73+
#if __STDC_VERSION__ >= 199903L
74+
# define ARG_INLINE inline
75+
#else
76+
# define ARG_INLINE
77+
#endif
78+
79+
#define ARG_BUFSIZ 20
80+
81+
#define ARG_ZERO -1
82+
#define ARG_INVAL -2
83+
#define ARG_NFOUND -3
84+
#define ARG_NOMEM -4
85+
#define ARG_UNEXP -5
86+
#define ARG_NMATCH -6
87+
#define ARG_NVALUE -7
88+
89+
#define ARG_ORDER 0x0001
90+
91+
92+
#ifndef ARG_TRUE_EQ_ONE
93+
# define ARG_SUCCESS 0
94+
#else
95+
# define ARG_SUCCESS 1
96+
#endif
97+
98+
#define ARG_STREQ(a, b) (ARG_STRCMP(a, b) == 0)
99+
100+
/* A slightly altered strcmp(), will return 0 even if the strings
101+
* don't match after the first one ended (i.e: abc = abcde, but
102+
* abc != abdc)
103+
* IN char * f: first string
104+
* IN char * f: second string
105+
*
106+
* RETURN int:
107+
* non-zero, if the strings don't match */
108+
static int arg_lstrcmp (char * f, char * s) {
109+
while (*f) {
110+
if (!(*f == *s))
111+
break;
112+
++f; ++s;
113+
}
114+
return *(unsigned char *)f - *(unsigned char *)s;
115+
}
116+
117+
typedef int arg_callback ();
118+
typedef int p_arg_handler (void * data_ptr, size_t blksize, void * retval);
119+
120+
/* The handler is the parser for the value of the argument
121+
* if NULL is passed instead of a valid handler function,
122+
* the argument will be considered as a flag.
123+
* Otherwise it will wait for the data to be passed. */
124+
typedef p_arg_handler * arg_handler;
125+
126+
/* A handler for a generic string. */
127+
static p_arg_handler arg_string_handler;
128+
/* A handler for a raw data, meaning that the raw byte
129+
* data will be stored inside a pointer. Acts almost the
130+
* same way as the arg_string_handler does. */
131+
static p_arg_handler arg_raw_handler;
132+
133+
static int arg_string_handler (void * data_ptr, size_t blksize, void * retval) {
134+
if (blksize == 0) {
135+
retval = NULL;
136+
return 0;
137+
}
138+
ARG_STRCPY((char *)retval, (char *)data_ptr);
139+
return 0;
140+
}
141+
142+
static int arg_raw_handler (void * data_ptr, size_t blksize, void * retval) {
143+
if (blksize == 0) {
144+
retval = NULL;
145+
return 0;
146+
}
147+
ARG_MEMCPY(retval, data_ptr, blksize);
148+
return 0;
149+
}
150+
151+
/* Flags define the behaviour of the arguments parser
152+
* As example, ARG_FLAG_HALT will cause parser to be stopped when
153+
* the specified argument is met. */
154+
typedef unsigned char arg_flags;
155+
156+
/* Type for the return codes */
157+
typedef signed char arg_return;
158+
159+
/* struct arg_argument
160+
* Contains a basic description of the argument list
161+
* char short_arg: a short variant of the argument's key (i.e: -r)
162+
* char * long_arg: a long variant of the argument's key (i.e: --recursive)
163+
* arg_handler handler: a handler for the value to be parsed
164+
* void * retval: the variable, which accepts the parsed value
165+
* arg_flags flags: flags, which define the argument's parsing behavior */
166+
struct arg_argument {
167+
char short_arg;
168+
char * long_arg;
169+
arg_handler handler;
170+
void * retval;
171+
arg_flags flags;
172+
};
173+
174+
/* Contains a list of the arguments, defining their descriptions.
175+
* Put a {0} to mark the end of the list */
176+
typedef struct arg_argument arg_list[];
177+
178+
/* char ** arg_parse:
179+
* IN int argc: argument count
180+
* IN char ** argv: arguments array
181+
* IN arg_list list: list, defining the accepted arguments
182+
* OUT arg_return * return_code: a return code of the status
183+
* ARG_SUCCESS [0] if the parsing is done without failures
184+
*
185+
* RETURN char ** arg:
186+
* - NULL on a complete success.
187+
* - A pointer to the argv list's element which failed the parsing on
188+
* a failure.
189+
* - in case of a halt, return the pointer
190+
* to the last argument parsed.
191+
*
192+
* NOTE:
193+
* this function changes the addresses of the pointers, to save them
194+
* as they were, consider writing them into another set of variables.*/
195+
char ** arg_parse (int argc, char ** argv, arg_list list, arg_return * return_code);
196+
197+
#endif

0 commit comments

Comments
 (0)