Skip to content

Commit 43e1cbb

Browse files
committed
Reworked the way arg_parse treats it's arguments
`arg_parse` function now reads `not_keys_size` argument's value at function invocation to determine the size of the `not_keys` array, then, after the function invocation, rewrites it with the the amount of "not key" arguments read. Fixed some illegal memory access bugs, changed the example.c file in accordance to the new behavior of the `arg_parse` function, changed the CMakeLists.txt to ease the debugging.
1 parent 804301c commit 43e1cbb

File tree

4 files changed

+102
-64
lines changed

4 files changed

+102
-64
lines changed

CMakeLists.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# This file is part of the argparse library.
2-
# Copyright (C) 2021 by Sergey Lafin
2+
# Copyright (C) 2021-2022 by Sergey Lafin
33
# Licensed under the LGPL v2.1, see the file LICENSE in base directory.
44

55
cmake_minimum_required (VERSION 3.12)
66
project (argparse)
77

8-
set (CMAKE_C_FLAGS "-O3")
8+
if (UNIX)
9+
set (CMAKE_C_FLAGS_RELEASE "-O2")
10+
set (CMAKE_C_FLAGS_DEBUG "-g -O0")
11+
elseif (MSVC)
12+
set (CMAKE_C_FLAGS_RELEASE "/O2")
13+
set (CMAKE_C_FLAGS_DEBUG "/g /O0")
14+
endif ()
15+
916
option (ARGPARSE_ERRORS "builtin error description via arg_geterror ()" ON)
1017
option (ARGPARSE_EXAMPLES "build examples" OFF)
1118

argparse.c

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* This file is part of the argparse library.
22
*
3-
* Copyright (C) 2021 by Sergey Lafin
3+
* Copyright (C) 2021-2022 by Sergey Lafin
44
*
55
* Licensed under the LGPL v2.1, see the file LICENSE in base directory. */
66

@@ -31,36 +31,36 @@
3131

3232
/* A simple implementation of some important "string.h" functions */
3333
#ifdef ARG_STANDALONE
34-
# define ARG_ASSERT(x)
34+
# define ARG_ASSRT(str) /* Pretty much impossible to implement in standalone */
3535
# define ARG_STRLEN(str) arg_strlen(str)
3636
# define ARG_STRCPY(dest, src) arg_strcpy(dest, src)
3737
# define ARG_MEMCPY(dest, src, n) arg_memcpy(dest, src, n)
3838
# define ARG_STRCMP(a, b) arg_strcmp(a, b)
3939

40-
static ARG_INLINE size_t arg_strlen (char * str) {
40+
static ARG_INLINE size_t arg_strlen (const char * str) {
4141
size_t len = 0;
4242
while (*str) {
4343
++str; ++len;
4444
}
4545
return len;
4646
}
4747

48-
static ARG_INLINE char * arg_strcpy (char * dest, char * src) {
48+
static ARG_INLINE char * arg_strcpy (char * dest, const char * src) {
4949
while (*src) {
5050
*dest++ = *src++;
5151
}
5252
dest = 0x0;
5353
return dest;
5454
}
5555

56-
static ARG_INLINE void * arg_memcpy (void * dest, void * src, size_t n) {
56+
static ARG_INLINE void * arg_memcpy (void * dest, const void * src, size_t n) {
5757
while (*(char *)dest) {
5858
*(char *)dest++ = *(char *)src++;
5959
}
6060
return dest;
6161
}
6262

63-
static ARG_INLINE int arg_strcmp (char * f, char * s) {
63+
static ARG_INLINE int arg_strcmp (const char * f, const char * s) {
6464
while (*f && *s) {
6565
if (!(*f++ == *s++)) {
6666
break;
@@ -71,18 +71,28 @@ static ARG_INLINE int arg_strcmp (char * f, char * s) {
7171

7272
#else
7373
# include <string.h>
74-
# include <assert.h>
75-
# define ARG_ASSERT(x) assert(x)
7674
# define ARG_STRLEN(str) strlen(str)
7775
# define ARG_STRCPY(dest, src) strcpy(dest, src)
7876
# define ARG_MEMCPY(dest, src, n) memcpy(dest, src, n)
7977
# define ARG_STRCMP(a, b) strcmp(a, b)
78+
79+
/* Uses my own simplified assert */
80+
81+
# include <stdio.h>
82+
# include <stdlib.h>
83+
# define ARG_ASSERT(x) { if (!(x)) arg_assert (#x); }
84+
static ARG_INLINE void arg_assert (const char *expr) {
85+
fprintf (stderr, "argparse: assertion failed: %s\n", expr);
86+
abort ();
87+
}
88+
8089
#endif
8190

8291
#define ARG_STREQ(a, b) (ARG_STRCMP(a, b) == 0)
92+
#define RETPTR(p) ((void **)p)
8393

8494
arg_return arg_string_handler (char * data_ptr, size_t blksize, void * retval) {
85-
void ** _retval = (void **)retval;
95+
void ** _retval = RETPTR (retval);
8696
*_retval = data_ptr;
8797
return 0;
8898
}
@@ -227,15 +237,23 @@ static ARG_INLINE arg_return arg_parse_long (struct arg_state * state) {
227237
return ARG_NMATCH;
228238
}
229239

230-
char * arg_parse (int * argc, char *** argv, arg_list list, char ** nk, size_t * nk_size, arg_flags flags, arg_return * code) {
240+
char *arg_parse (int *argc, char ***argv, arg_list list, char **nk_buf, size_t *nk_size, arg_flags flags, arg_return *code) {
231241
ARG_ASSERT (argv != NULL);
232242
ARG_ASSERT (list != NULL);
233243

234244
size_t len = arg_list_len (list);
235245
ARG_ASSERT (len > 0);
236246

237-
if (nk_size)
238-
*nk_size = 0;
247+
/* if nk_buf is specified, so should be the nk_size */
248+
if (nk_buf)
249+
ARG_ASSERT (nk_buf != NULL && nk_size != NULL);
250+
251+
size_t nk_lim = nk_buf ? *nk_size : 0;
252+
if (nk_buf)
253+
*nk_size = 0;
254+
255+
++(*argv);
256+
239257

240258
struct arg_state state;
241259
state.argc = argc;
@@ -247,50 +265,53 @@ char * arg_parse (int * argc, char *** argv, arg_list list, char ** nk, size_t *
247265

248266
char accept_args = 1;
249267

250-
arg_return _code;
251-
while (--(*state.argc)) {
252-
++state.argv;
253-
char * arg = *state.argv;
254-
/* Not a key */
255-
if ((*arg) != '-' || !accept_args) {
256-
if (!nk) {
257-
*code = ARG_UNEXP;
258-
*argv = state.argv;
259-
return arg;
260-
}
261-
if (nk_size) ++(*nk_size);
262-
*nk = *state.argv;
263-
++nk;
264-
continue;
265-
}
266-
267-
/* long */
268-
if (*(arg + 1) == '-') {
269-
*state.argv += 2;
270-
if (!(**state.argv)) {
271-
accept_args = 0;
272-
continue;
273-
}
274-
state.type = ARG_LONG;
275-
if ((_code = arg_parse_long (&state)) != ARG_SUCCESS) {
276-
*code = _code;
277-
*argv = state.argv;
278-
return arg;
279-
}
280-
continue;
281-
}
282-
283-
/* short */
284-
++(*state.argv);
285-
state.type = ARG_SHORT;
286-
if ((_code = arg_parse_short (&state)) != ARG_SUCCESS) {
287-
*code = _code;
288-
*argv = state.argv;
289-
return arg;
290-
}
291-
}
292-
293-
return NULL;
268+
arg_return retcode;
269+
#define arg (*state.argv)
270+
for ((*state.argc)--; *state.argc; ++state.argv, --(*state.argc)) {
271+
if (*arg != '-' || !accept_args) {
272+
/* if nkbuf is null, we considered the argument malformed */
273+
if (!nk_buf) {
274+
*code = ARG_UNEXP;
275+
*argv = state.argv;
276+
277+
return arg;
278+
}
279+
280+
if ((*nk_size)++ < nk_lim) {
281+
*nk_buf++ = arg;
282+
}
283+
continue;
284+
}
285+
286+
if (*arg == '-') {
287+
++arg;
288+
if (*arg == '-') {
289+
++arg;
290+
/* just "--" */
291+
if (!(*arg)) {
292+
accept_args = 0;
293+
} else {
294+
state.type = ARG_LONG;
295+
if ((*code = arg_parse_long (&state)) != ARG_SUCCESS) {
296+
*argv = state.argv;
297+
return arg - 2;
298+
}
299+
}
300+
301+
continue;
302+
}
303+
else {
304+
state.type = ARG_SHORT;
305+
if ((*code = arg_parse_short (&state)) != ARG_SUCCESS) {
306+
*argv = state.argv;
307+
308+
return arg - 1;
309+
}
310+
}
311+
}
312+
}
313+
314+
return NULL;
294315
}
295316

296317
const char * arg_geterror (arg_return code) {

argparse.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* argparse - fast argument parsing library
2-
* Copyright (C) 2021 Sergey Lafin
2+
* Copyright (C) 2021-2022 Sergey Lafin
33
*
44
* This library is free software; you can redistribute it and/or
55
* modify it under the terms of the GNU Lesser General Public
@@ -122,7 +122,11 @@ typedef struct arg_argument arg_list[];
122122
* @param not_keys
123123
* a buffer for random values
124124
* @param not_keys_size
125-
* size of the not_keys buffer
125+
* size of the not_keys buffer.
126+
* This variable should be initialized to represent the size of the
127+
* not_keys array. It will be overwritten after the invocation to
128+
* the amount of entries read to the not_keys array. (See par. 3
129+
* in NOTES)
126130
* @param flags
127131
* flags, defining the behaviour of the parser
128132
* @param return_code
@@ -139,7 +143,11 @@ typedef struct arg_argument arg_list[];
139143
* can call this function again with the same set of variables and
140144
* continue parsing.
141145
* 2 this function changes the addresses of the pointers, to save them
142-
* as they were, consider writing them into another set of variables. */
146+
* as they were, consider writing them into another set of variables.
147+
* 3 this function READS the not_keys_size variable (unless not_keys is
148+
* not NULL in which case not_keys_size won't be read from and can be
149+
* left as NULL), so the variable should be initialized with a value,
150+
* that represents the size of the not_keys array */
143151
ARGPARSE_API char * arg_parse (int * argc, char *** argv, arg_list list, char ** not_keys, size_t * not_keys_size, arg_flags flags, arg_return * return_code);
144152

145153
/* const char * arg_geterror:

example.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ int main (int argc, char ** argv) {
9292

9393
/* the buffer for the *not-a-key* value (value, not preceeded by a key) */
9494
char * nk_buf[2];
95-
/* size of the written buffer */
96-
size_t nk_siz;
95+
/* size of the written buffer (Should be initialized, as this variable defines the
96+
* size of the existing buffer (which is of size 2 in this example)) */
97+
size_t nk_siz = 2;
9798

9899
/* call the parser
99100
* if an error occured, the parser will stop and return the faulty argument and will write the error
@@ -104,7 +105,8 @@ int main (int argc, char ** argv) {
104105
* &argv is a pointer to the argv variable
105106
* list is the argument list
106107
* 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+
* &nk_siz is the variable, that contains the size of the buffer, and then is going to store the amount of
109+
* entries of the nk_buf array that were actually filled after parsing.
108110
* ARG_PARSE_MERGED is a flag, that tells the parser, that we allow merged key-value arguments (i.e -o+)
109111
* &code is a variable that is going to store the return code of the parser */
110112
if ((err_arg = arg_parse (&argc, &argv, list, nk_buf, &nk_siz, ARG_PARSE_MERGED, &code)) != NULL) {

0 commit comments

Comments
 (0)