Skip to content

Commit 66902d4

Browse files
committed
Extract common example helpers and reorg examples
This reorganizes a few of the examples so that the main function comes first with the argument parsing extracted into a helper that can come at the end of the file (so the example focuses more on the use of libgit2 instead of command line support). This also creates a shared examples/common.[ch] so that useful helper funcs can be shared across examples instead of repeated.
1 parent 5c50f22 commit 66902d4

File tree

7 files changed

+808
-540
lines changed

7 files changed

+808
-540
lines changed

examples/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ ENDIF()
99
FILE(GLOB SRC_EXAMPLE_APPS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c)
1010
FOREACH(src_app ${SRC_EXAMPLE_APPS})
1111
STRING(REPLACE ".c" "" app_name ${src_app})
12-
ADD_EXECUTABLE(${app_name} ${src_app})
13-
TARGET_LINK_LIBRARIES(${app_name} git2)
12+
IF(NOT ${app_name} STREQUAL "common")
13+
ADD_EXECUTABLE(${app_name} ${src_app} "common.c")
14+
TARGET_LINK_LIBRARIES(${app_name} git2)
15+
ENDIF()
1416
ENDFOREACH()

examples/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ APPS = general showindex diff rev-list cat-file status log rev-parse init
88
all: $(APPS)
99

1010
% : %.c
11-
$(CC) -o $@ $(CFLAGS) $< $(LFLAGS)
11+
$(CC) -o $@ common.c $(CFLAGS) $< $(LFLAGS)
1212

1313
clean:
1414
$(RM) $(APPS)

examples/common.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "common.h"
9+
10+
void check_lg2(int error, const char *message, const char *extra)
11+
{
12+
const git_error *lg2err;
13+
const char *lg2msg = "", *lg2spacer = "";
14+
15+
if (!error)
16+
return;
17+
18+
if ((lg2err = giterr_last()) != NULL && lg2err->message != NULL) {
19+
lg2msg = lg2err->message;
20+
lg2spacer = " - ";
21+
}
22+
23+
if (extra)
24+
fprintf(stderr, "%s '%s' [%d]%s%s\n",
25+
message, extra, error, lg2spacer, lg2msg);
26+
else
27+
fprintf(stderr, "%s [%d]%s%s\n",
28+
message, error, lg2spacer, lg2msg);
29+
30+
exit(1);
31+
}
32+
33+
void fatal(const char *message, const char *extra)
34+
{
35+
if (extra)
36+
fprintf(stderr, "%s %s\n", message, extra);
37+
else
38+
fprintf(stderr, "%s\n", message);
39+
40+
exit(1);
41+
}
42+
43+
size_t is_prefixed(const char *str, const char *pfx)
44+
{
45+
size_t len = strlen(pfx);
46+
return strncmp(str, pfx, len) ? 0 : len;
47+
}
48+
49+
int match_str_arg(
50+
const char **out, struct args_info *args, const char *opt)
51+
{
52+
const char *found = args->argv[args->pos];
53+
size_t len = is_prefixed(found, opt);
54+
55+
if (!len)
56+
return 0;
57+
58+
if (!found[len]) {
59+
if (args->pos + 1 == args->argc)
60+
fatal("expected value following argument", opt);
61+
args->pos += 1;
62+
*out = args->argv[args->pos];
63+
return 1;
64+
}
65+
66+
if (found[len] == '=') {
67+
*out = found + len + 1;
68+
return 1;
69+
}
70+
71+
return 0;
72+
}
73+
74+
static const char *match_numeric_arg(struct args_info *args, const char *opt)
75+
{
76+
const char *found = args->argv[args->pos];
77+
size_t len = is_prefixed(found, opt);
78+
79+
if (!len)
80+
return NULL;
81+
82+
if (!found[len]) {
83+
if (args->pos + 1 == args->argc)
84+
fatal("expected numeric value following argument", opt);
85+
args->pos += 1;
86+
found = args->argv[args->pos];
87+
} else {
88+
found = found + len;
89+
if (*found == '=')
90+
found++;
91+
}
92+
93+
return found;
94+
}
95+
96+
int match_uint16_arg(
97+
uint16_t *out, struct args_info *args, const char *opt)
98+
{
99+
const char *found = match_numeric_arg(args, opt);
100+
uint16_t val;
101+
char *endptr = NULL;
102+
103+
if (!found)
104+
return 0;
105+
106+
val = (uint16_t)strtoul(found, &endptr, 0);
107+
if (!endptr || *endptr != '\0')
108+
fatal("expected number after argument", opt);
109+
110+
if (out)
111+
*out = val;
112+
return 1;
113+
}
114+
115+
static int match_int_internal(
116+
int *out, const char *str, int allow_negative, const char *opt)
117+
{
118+
char *endptr = NULL;
119+
int val = (int)strtol(str, &endptr, 10);
120+
121+
if (!endptr || *endptr != '\0')
122+
fatal("expected number", opt);
123+
else if (val < 0 && !allow_negative)
124+
fatal("negative values are not allowed", opt);
125+
126+
if (out)
127+
*out = val;
128+
129+
return 1;
130+
}
131+
132+
int is_integer(int *out, const char *str, int allow_negative)
133+
{
134+
return match_int_internal(out, str, allow_negative, NULL);
135+
}
136+
137+
int match_int_arg(
138+
int *out, struct args_info *args, const char *opt, int allow_negative)
139+
{
140+
const char *found = match_numeric_arg(args, opt);
141+
if (!found)
142+
return 0;
143+
return match_int_internal(out, found, allow_negative, opt);
144+
}
145+
146+
int diff_output(
147+
const git_diff_delta *d,
148+
const git_diff_hunk *h,
149+
const git_diff_line *l,
150+
void *p)
151+
{
152+
FILE *fp = p;
153+
154+
(void)d; (void)h;
155+
156+
if (!fp)
157+
fp = stdout;
158+
159+
if (l->origin == GIT_DIFF_LINE_CONTEXT ||
160+
l->origin == GIT_DIFF_LINE_ADDITION ||
161+
l->origin == GIT_DIFF_LINE_DELETION)
162+
fputc(l->origin, fp);
163+
164+
fwrite(l->content, 1, l->content_len, fp);
165+
166+
return 0;
167+
}
168+
169+
void treeish_to_tree(
170+
git_tree **out, git_repository *repo, const char *treeish)
171+
{
172+
git_object *obj = NULL;
173+
174+
check_lg2(
175+
git_revparse_single(&obj, repo, treeish),
176+
"looking up object", treeish);
177+
178+
check_lg2(
179+
git_object_peel((git_object **)out, obj, GIT_OBJ_TREE),
180+
"resolving object to tree", treeish);
181+
182+
git_object_free(obj);
183+
}
184+

examples/common.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include <stdio.h>
9+
#include <string.h>
10+
#include <stdlib.h>
11+
#include <git2.h>
12+
13+
/**
14+
* Check libgit2 error code, printing error to stderr on failure and
15+
* exiting the program.
16+
*/
17+
extern void check_lg2(int error, const char *message, const char *extra);
18+
19+
/**
20+
* Exit the program, printing error to stderr
21+
*/
22+
extern void fatal(const char *message, const char *extra);
23+
24+
/**
25+
* Check if a string has the given prefix. Returns 0 if not prefixed
26+
* or the length of the prefix if it is.
27+
*/
28+
extern size_t is_prefixed(const char *str, const char *pfx);
29+
30+
/**
31+
* Match an integer string, returning 1 if matched, 0 if not.
32+
*/
33+
extern int is_integer(int *out, const char *str, int allow_negative);
34+
35+
struct args_info {
36+
int argc;
37+
char **argv;
38+
int pos;
39+
};
40+
#define ARGS_INFO_INIT { argc, argv, 0 }
41+
42+
/**
43+
* Check current `args` entry against `opt` string. If it matches
44+
* exactly, take the next arg as a string; if it matches as a prefix with
45+
* an equal sign, take the remainder as a string; otherwise return 0.
46+
*/
47+
extern int match_str_arg(
48+
const char **out, struct args_info *args, const char *opt);
49+
50+
/**
51+
* Check current `args` entry against `opt` string parsing as uint16. If
52+
* `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
53+
* is a prefix (equal sign optional), take the remainder of the arg as a
54+
* uint16_t value; otherwise return 0.
55+
*/
56+
extern int match_uint16_arg(
57+
uint16_t *out, struct args_info *args, const char *opt);
58+
59+
/**
60+
* Check current `args` entry against `opt` string parsing as int. If
61+
* `opt` matches exactly, take the next arg as an int value; if it matches
62+
* as a prefix (equal sign optional), take the remainder of the arg as a
63+
* int value; otherwise return 0.
64+
*/
65+
extern int match_int_arg(
66+
int *out, struct args_info *args, const char *opt, int allow_negative);
67+
68+
/**
69+
* Basic output function for plain text diff output
70+
* Pass `FILE*` such as `stdout` or `stderr` as payload (or NULL == `stdout`)
71+
*/
72+
extern int diff_output(
73+
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
74+
75+
/**
76+
* Convert a treeish argument to an actual tree; this will call check_lg2
77+
* and exit the program if `treeish` cannot be resolved to a tree
78+
*/
79+
extern void treeish_to_tree(
80+
git_tree **out, git_repository *repo, const char *treeish);

0 commit comments

Comments
 (0)