Skip to content

Commit dfea071

Browse files
authored
Merge pull request libgit2#5272 from tiennou/examples/cli-ification
Various examples shape-ups
2 parents b63ad95 + fe42557 commit dfea071

26 files changed

+521
-452
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
22
INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
33

4-
FILE(GLOB LG2_SOURCES *.c)
4+
FILE(GLOB LG2_SOURCES *.c *.h)
55
ADD_EXECUTABLE(lg2 ${LG2_SOURCES})
66
SET_TARGET_PROPERTIES(lg2 PROPERTIES C_STANDARD 90)
77

examples/add.c

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
*/
1414

1515
#include "common.h"
16-
#include <assert.h>
1716

1817
/**
1918
* The following example demonstrates how to add files with libgit2.
@@ -27,48 +26,50 @@
2726
* -u/--update: update the index instead of adding to it.
2827
*/
2928

30-
enum print_options {
31-
SKIP = 1,
32-
VERBOSE = 2,
33-
UPDATE = 4,
29+
enum index_mode {
30+
INDEX_NONE,
31+
INDEX_ADD,
3432
};
3533

36-
struct print_payload {
37-
enum print_options options;
34+
struct index_options {
35+
int dry_run;
36+
int verbose;
3837
git_repository *repo;
38+
enum index_mode mode;
39+
int add_update;
3940
};
4041

4142
/* Forward declarations for helpers */
42-
static void parse_opts(int *options, int *count, int argc, char *argv[]);
43-
void init_array(git_strarray *array, int argc, char **argv);
43+
static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args);
4444
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload);
4545

46-
int lg2_add(git_repository *repo, int argc, char** argv)
46+
int lg2_add(git_repository *repo, int argc, char **argv)
4747
{
4848
git_index_matched_path_cb matched_cb = NULL;
4949
git_index *index;
5050
git_strarray array = {0};
51-
int options = 0, count = 0;
52-
struct print_payload payload = {0};
51+
struct index_options options;
52+
struct args_info args = ARGS_INFO_INIT;
5353

54-
parse_opts(&options, &count, argc, argv);
55-
init_array(&array, argc-count, argv+count);
54+
/* Parse the options & arguments. */
55+
parse_opts(NULL, &options, &args);
56+
strarray_from_args(&array, &args);
5657

58+
/* Grab the repository's index. */
5759
check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
5860

5961
/* Setup a callback if the requested options need it */
60-
if ((options & VERBOSE) || (options & SKIP)) {
62+
if (options.verbose || options.dry_run) {
6163
matched_cb = &print_matched_cb;
6264
}
6365

64-
/* Perform the requested action with the index and files */
65-
payload.options = options;
66-
payload.repo = repo;
66+
options.repo = repo;
6767

68-
if (options & UPDATE) {
69-
git_index_update_all(index, &array, matched_cb, &payload);
68+
/* Perform the requested action with the index and files */
69+
if (options.add_update) {
70+
git_index_update_all(index, &array, matched_cb, &options);
7071
} else {
71-
git_index_add_all(index, &array, 0, matched_cb, &payload);
72+
git_index_add_all(index, &array, 0, matched_cb, &options);
7273
}
7374

7475
/* Cleanup memory */
@@ -85,15 +86,14 @@ int lg2_add(git_repository *repo, int argc, char** argv)
8586
*/
8687
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload)
8788
{
88-
struct print_payload p = *(struct print_payload*)(payload);
89+
struct index_options *opts = (struct index_options *)(payload);
8990
int ret;
9091
unsigned status;
9192
(void)matched_pathspec;
9293

9394
/* Get the file status */
94-
if (git_status_file(&status, p.repo, path)) {
95+
if (git_status_file(&status, opts->repo, path) < 0)
9596
return -1;
96-
}
9797

9898
if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {
9999
printf("add '%s'\n", path);
@@ -102,9 +102,8 @@ int print_matched_cb(const char *path, const char *matched_pathspec, void *paylo
102102
ret = 1;
103103
}
104104

105-
if ((p.options & SKIP)) {
105+
if (opts->dry_run)
106106
ret = 1;
107-
}
108107

109108
return ret;
110109
}
@@ -133,33 +132,39 @@ void print_usage(void)
133132
exit(1);
134133
}
135134

136-
static void parse_opts(int *options, int *count, int argc, char *argv[])
135+
static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args)
137136
{
138-
int i;
137+
if (args->argc <= 1)
138+
print_usage();
139139

140-
for (i = 1; i < argc; ++i) {
141-
if (argv[i][0] != '-')
142-
break;
143-
else if (!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v"))
144-
*options |= VERBOSE;
145-
else if (!strcmp(argv[i], "--dry-run") || !strcmp(argv[i], "-n"))
146-
*options |= SKIP;
147-
else if (!strcmp(argv[i], "--update") || !strcmp(argv[i], "-u"))
148-
*options |= UPDATE;
149-
else if (!strcmp(argv[i], "-h")) {
140+
for (args->pos = 1; args->pos < args->argc; ++args->pos) {
141+
const char *curr = args->argv[args->pos];
142+
143+
if (curr[0] != '-') {
144+
if (!strcmp("add", curr)) {
145+
opts->mode = INDEX_ADD;
146+
continue;
147+
} else if (opts->mode == INDEX_NONE) {
148+
fprintf(stderr, "missing command: %s", curr);
149+
print_usage();
150+
break;
151+
} else {
152+
/* We might be looking at a filename */
153+
break;
154+
}
155+
} else if (match_bool_arg(&opts->verbose, args, "--verbose") ||
156+
match_bool_arg(&opts->dry_run, args, "--dry-run") ||
157+
match_str_arg(repo_path, args, "--git-dir") ||
158+
(opts->mode == INDEX_ADD && match_bool_arg(&opts->add_update, args, "--update"))) {
159+
continue;
160+
} else if (match_bool_arg(NULL, args, "--help")) {
150161
print_usage();
151162
break;
152-
} else if (!strcmp(argv[i], "--")) {
153-
i++;
163+
} else if (match_arg_separator(args)) {
154164
break;
155165
} else {
156-
fprintf(stderr, "Unsupported option %s.\n", argv[i]);
166+
fprintf(stderr, "Unsupported option %s.\n", curr);
157167
print_usage();
158168
}
159169
}
160-
161-
if (argc <= i)
162-
print_usage();
163-
164-
*count = i;
165170
}

examples/args.c

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#include "common.h"
2+
#include "args.h"
3+
4+
size_t is_prefixed(const char *str, const char *pfx)
5+
{
6+
size_t len = strlen(pfx);
7+
return strncmp(str, pfx, len) ? 0 : len;
8+
}
9+
10+
int optional_str_arg(
11+
const char **out, struct args_info *args, const char *opt, const char *def)
12+
{
13+
const char *found = args->argv[args->pos];
14+
size_t len = is_prefixed(found, opt);
15+
16+
if (!len)
17+
return 0;
18+
19+
if (!found[len]) {
20+
if (args->pos + 1 == args->argc) {
21+
*out = def;
22+
return 1;
23+
}
24+
args->pos += 1;
25+
*out = args->argv[args->pos];
26+
return 1;
27+
}
28+
29+
if (found[len] == '=') {
30+
*out = found + len + 1;
31+
return 1;
32+
}
33+
34+
return 0;
35+
}
36+
37+
int match_str_arg(
38+
const char **out, struct args_info *args, const char *opt)
39+
{
40+
const char *found = args->argv[args->pos];
41+
size_t len = is_prefixed(found, opt);
42+
43+
if (!len)
44+
return 0;
45+
46+
if (!found[len]) {
47+
if (args->pos + 1 == args->argc)
48+
fatal("expected value following argument", opt);
49+
args->pos += 1;
50+
*out = args->argv[args->pos];
51+
return 1;
52+
}
53+
54+
if (found[len] == '=') {
55+
*out = found + len + 1;
56+
return 1;
57+
}
58+
59+
return 0;
60+
}
61+
62+
static const char *match_numeric_arg(struct args_info *args, const char *opt)
63+
{
64+
const char *found = args->argv[args->pos];
65+
size_t len = is_prefixed(found, opt);
66+
67+
if (!len)
68+
return NULL;
69+
70+
if (!found[len]) {
71+
if (args->pos + 1 == args->argc)
72+
fatal("expected numeric value following argument", opt);
73+
args->pos += 1;
74+
found = args->argv[args->pos];
75+
} else {
76+
found = found + len;
77+
if (*found == '=')
78+
found++;
79+
}
80+
81+
return found;
82+
}
83+
84+
int match_uint16_arg(
85+
uint16_t *out, struct args_info *args, const char *opt)
86+
{
87+
const char *found = match_numeric_arg(args, opt);
88+
uint16_t val;
89+
char *endptr = NULL;
90+
91+
if (!found)
92+
return 0;
93+
94+
val = (uint16_t)strtoul(found, &endptr, 0);
95+
if (!endptr || *endptr != '\0')
96+
fatal("expected number after argument", opt);
97+
98+
if (out)
99+
*out = val;
100+
return 1;
101+
}
102+
103+
int match_uint32_arg(
104+
uint32_t *out, struct args_info *args, const char *opt)
105+
{
106+
const char *found = match_numeric_arg(args, opt);
107+
uint16_t val;
108+
char *endptr = NULL;
109+
110+
if (!found)
111+
return 0;
112+
113+
val = (uint32_t)strtoul(found, &endptr, 0);
114+
if (!endptr || *endptr != '\0')
115+
fatal("expected number after argument", opt);
116+
117+
if (out)
118+
*out = val;
119+
return 1;
120+
}
121+
122+
static int match_int_internal(
123+
int *out, const char *str, int allow_negative, const char *opt)
124+
{
125+
char *endptr = NULL;
126+
int val = (int)strtol(str, &endptr, 10);
127+
128+
if (!endptr || *endptr != '\0')
129+
fatal("expected number", opt);
130+
else if (val < 0 && !allow_negative)
131+
fatal("negative values are not allowed", opt);
132+
133+
if (out)
134+
*out = val;
135+
136+
return 1;
137+
}
138+
139+
int match_bool_arg(int *out, struct args_info *args, const char *opt)
140+
{
141+
const char *found = args->argv[args->pos];
142+
143+
if (!strcmp(found, opt)) {
144+
*out = 1;
145+
return 1;
146+
}
147+
148+
if (!strncmp(found, "--no-", strlen("--no-")) &&
149+
!strcmp(found + strlen("--no-"), opt + 2)) {
150+
*out = 0;
151+
return 1;
152+
}
153+
154+
*out = -1;
155+
return 0;
156+
}
157+
158+
int is_integer(int *out, const char *str, int allow_negative)
159+
{
160+
return match_int_internal(out, str, allow_negative, NULL);
161+
}
162+
163+
int match_int_arg(
164+
int *out, struct args_info *args, const char *opt, int allow_negative)
165+
{
166+
const char *found = match_numeric_arg(args, opt);
167+
if (!found)
168+
return 0;
169+
return match_int_internal(out, found, allow_negative, opt);
170+
}
171+
172+
int match_arg_separator(struct args_info *args)
173+
{
174+
if (args->opts_done)
175+
return 1;
176+
177+
if (strcmp(args->argv[args->pos], "--") != 0)
178+
return 0;
179+
180+
args->opts_done = 1;
181+
args->pos++;
182+
return 1;
183+
}
184+
185+
void strarray_from_args(git_strarray *array, struct args_info *args)
186+
{
187+
size_t i;
188+
189+
array->count = args->argc - args->pos;
190+
array->strings = calloc(array->count, sizeof(char *));
191+
assert(array->strings != NULL);
192+
193+
for (i = 0; args->pos < args->argc; ++args->pos) {
194+
array->strings[i++] = args->argv[args->pos];
195+
}
196+
args->pos = args->argc;
197+
}

0 commit comments

Comments
 (0)