Skip to content

Commit c596d6f

Browse files
committed
Improved docs and examples
Better document how to use `adopt_parse` as a single call to parse arguments.
1 parent 9bbc3d3 commit c596d6f

File tree

4 files changed

+162
-28
lines changed

4 files changed

+162
-28
lines changed

CMakeLists.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ ENDIF()
9494
FILE(GLOB ALL_SRC adopt.c adopt.h)
9595
INCLUDE_DIRECTORIES(.)
9696

97-
FILE(GLOB SRC_EXAMPLE ${ALL_SRC} example.c)
98-
9997
FIND_PACKAGE(PythonInterp REQUIRED)
10098

10199
SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests")
@@ -115,7 +113,8 @@ SET_SOURCE_FILES_PROPERTIES(
115113
PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite)
116114

117115
ADD_EXECUTABLE(adopt_tests ${SRC_TEST})
118-
ADD_EXECUTABLE(adopt_example ${SRC_EXAMPLE})
116+
ADD_EXECUTABLE(example_parse ${ALL_SRC} examples/parse.c)
117+
ADD_EXECUTABLE(example_loop ${ALL_SRC} examples/loop.c)
119118

120119
IF (WIN32)
121120
TARGET_LINK_LIBRARIES(adopt_tests ws2_32)

README.md

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,33 +83,62 @@ elements, terminated with an `adopt_spec` initialized to zeroes.
8383
Parsing arguments
8484
-----------------
8585

86-
After initializing the parser by calling `adopt_parser_init`
87-
with the `adopt_spec`s and the command-line arguments given
88-
to your program, you can call `adopt_parser_next` in a loop
89-
to handle each option.
86+
The simplest way to parse arguments is by calling `adopt_parse`.
87+
This will parse the arguments given to it, will set the given
88+
`spec->value`s to the appropriate arguments, and will stop and
89+
return an error on any invalid input. If there are errors, you
90+
can display that information with `adopt_status_fprint`.
91+
92+
```c
93+
int main(int argc, const char **argv)
94+
{
95+
adopt_parser parser;
96+
adopt_opt result;
97+
const char *value;
98+
const char *file;
99+
100+
if (adopt_parse(&result, opt_specs, argv + 1, argc - 1) < 0) {
101+
adopt_status_fprint(stderr, &opt);
102+
adopt_usage_fprint(stderr, argv[0], opt_specs);
103+
return 129;
104+
}
105+
}
106+
```
107+
108+
Parsing arguments individually
109+
-------------------------------
110+
111+
For more control over your parsing, you may iterate over the
112+
parser in a loop. After initializing the parser by calling
113+
`adopt_parser_init` with the `adopt_spec`s and the command-line
114+
arguments given to your program, you can call `adopt_parser_next`
115+
in a loop to handle each option.
90116
91-
int main(int argc, const char **argv)
92-
{
93-
adopt_parser parser;
94-
adopt_opt opt;
95-
const char *value;
96-
const char *file;
97-
98-
adopt_parser_init(&parser, opt_specs, argv + 1, argc - 1);
99-
100-
while (adopt_parser_next(&opt, &parser)) {
101-
/* Although regular practice would be to simply let the parser
102-
* set the variables for you, there is information about the
103-
* parsed argument available in the `opt` struct. For example,
104-
* `opt.spec` will point to the `adopt_spec` that was parsed,
105-
* or `NULL` if it did not match a specification.
106-
*/
107-
if (!opt.spec) {
108-
fprintf(stderr, "Unknown option: %s\n", opt.arg);
109-
return 129;
110-
}
117+
```c
118+
int main(int argc, const char **argv)
119+
{
120+
adopt_parser parser;
121+
adopt_opt opt;
122+
const char *value;
123+
const char *file;
124+
125+
adopt_parser_init(&parser, opt_specs, argv + 1, argc - 1);
126+
127+
while (adopt_parser_next(&opt, &parser)) {
128+
/*
129+
* Although regular practice would be to simply let the parser
130+
* set the variables for you, there is information about the
131+
* parsed argument available in the `opt` struct. For example,
132+
* `opt.spec` will point to the `adopt_spec` that was parsed,
133+
* or `NULL` if it did not match a specification.
134+
*/
135+
if (!opt.spec) {
136+
fprintf(stderr, "Unknown option: %s\n", opt.arg);
137+
return 129;
111138
}
112139
}
140+
}
141+
```
113142

114143
Required arguments
115144
------------------

example.c renamed to examples/loop.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ static int volume = 1;
1515
static char *channel = "default";
1616
static char *filename1 = NULL;
1717
static char *filename2 = NULL;
18+
static char **other = NULL;
1819

1920
adopt_spec opt_specs[] = {
2021
{ ADOPT_BOOL, "verbose", 'v', &verbose, 0,
@@ -30,7 +31,7 @@ adopt_spec opt_specs[] = {
3031
"file1", "The first filename", ADOPT_USAGE_REQUIRED },
3132
{ ADOPT_ARG, NULL, 0, &filename2, 0,
3233
"file2", "The second (optional) filename", 0 },
33-
{ ADOPT_ARGS, NULL, 0, NULL, 0,
34+
{ ADOPT_ARGS, NULL, 0, &other, 0,
3435
"other", "The other (optional) arguments", 0 },
3536
{ 0 }
3637
};
@@ -53,6 +54,7 @@ int main(int argc, char **argv)
5354
{
5455
adopt_parser parser;
5556
adopt_opt opt;
57+
size_t i;
5658

5759
adopt_parser_init(&parser, opt_specs, argv + 1, argc - 1);
5860

@@ -75,5 +77,19 @@ int main(int argc, char **argv)
7577
printf("channel: %s\n", channel ? channel : "(null)");
7678
printf("filename one: %s\n", filename1 ? filename1 : "(null)");
7779
printf("filename two: %s\n", filename2 ? filename2 : "(null)");
80+
81+
/* display other args */
82+
if (other) {
83+
printf("other args [%d]: ", (int)opt.args_len);
84+
85+
for (i = 0; i < opt.args_len; i++) {
86+
if (i)
87+
printf(", ");
88+
89+
printf("%s", other[i]);
90+
}
91+
92+
printf("\n");
93+
}
7894
}
7995

examples/parse.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c), Edward Thomson <ethomson@edwardthomson.com>
3+
* All rights reserved.
4+
*
5+
* This file is part of adopt, distributed under the MIT license.
6+
* For full terms and conditions, see the included LICENSE file.
7+
*/
8+
9+
#include <stdio.h>
10+
11+
#include "adopt.h"
12+
13+
static int verbose = 0;
14+
static int volume = 1;
15+
static char *channel = "default";
16+
static char *filename1 = NULL;
17+
static char *filename2 = NULL;
18+
static char **other = NULL;
19+
20+
adopt_spec opt_specs[] = {
21+
{ ADOPT_BOOL, "verbose", 'v', &verbose, 0,
22+
NULL, "Turn on verbose information", 0 },
23+
{ ADOPT_SWITCH, "quiet", 'q', &volume, 0,
24+
NULL, "Emit no output", 0 },
25+
{ ADOPT_SWITCH, "loud", 'l', &volume, 2,
26+
NULL, "Emit louder than usual output", ADOPT_USAGE_CHOICE },
27+
{ ADOPT_VALUE, "channel", 'c', &channel, 0,
28+
"channel", "Set the channel", 0 },
29+
{ ADOPT_LITERAL },
30+
{ ADOPT_ARG, NULL, 0, &filename1, 0,
31+
"file1", "The first filename", ADOPT_USAGE_REQUIRED },
32+
{ ADOPT_ARG, NULL, 0, &filename2, 0,
33+
"file2", "The second (optional) filename", 0 },
34+
{ ADOPT_ARGS, NULL, 0, &other, 0,
35+
"other", "The other (optional) arguments", 0 },
36+
{ 0 }
37+
};
38+
39+
static const char *volume_tostr(int volume)
40+
{
41+
switch(volume) {
42+
case 0:
43+
return "quiet";
44+
case 1:
45+
return "normal";
46+
case 2:
47+
return "loud";
48+
}
49+
50+
return "unknown";
51+
}
52+
53+
int main(int argc, char **argv)
54+
{
55+
adopt_opt result;
56+
size_t i;
57+
58+
if (adopt_parse(&result, opt_specs, argv + 1, argc - 1) < 0) {
59+
adopt_status_fprint(stderr, &result);
60+
adopt_usage_fprint(stderr, argv[0], opt_specs);
61+
return 129;
62+
}
63+
64+
if (!filename1) {
65+
fprintf(stderr, "filename is required\n");
66+
adopt_usage_fprint(stderr, argv[0], opt_specs);
67+
return 129;
68+
}
69+
70+
printf("verbose: %d\n", verbose);
71+
printf("volume: %s\n", volume_tostr(volume));
72+
printf("channel: %s\n", channel ? channel : "(null)");
73+
printf("filename one: %s\n", filename1 ? filename1 : "(null)");
74+
printf("filename two: %s\n", filename2 ? filename2 : "(null)");
75+
76+
/* display other args */
77+
if (other) {
78+
printf("other args [%d]: ", (int)result.args_len);
79+
80+
for (i = 0; i < result.args_len; i++) {
81+
if (i)
82+
printf(", ");
83+
84+
printf("%s", other[i]);
85+
}
86+
87+
printf("\n");
88+
}
89+
}
90+

0 commit comments

Comments
 (0)