]> git.proxmox.com Git - libgit2.git/blob - examples/common.c
e20767a9e942bb32156a318d64f4b492b63858e4
[libgit2.git] / examples / common.c
1 /*
2 * Utilities library for libgit2 examples
3 *
4 * Written by the libgit2 contributors
5 *
6 * To the extent possible under law, the author(s) have dedicated all copyright
7 * and related and neighboring rights to this software to the public domain
8 * worldwide. This software is distributed without any warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication along
11 * with this software. If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
13 */
14
15 #include <assert.h>
16
17 #include "common.h"
18
19 void check_lg2(int error, const char *message, const char *extra)
20 {
21 const git_error *lg2err;
22 const char *lg2msg = "", *lg2spacer = "";
23
24 if (!error)
25 return;
26
27 if ((lg2err = git_error_last()) != NULL && lg2err->message != NULL) {
28 lg2msg = lg2err->message;
29 lg2spacer = " - ";
30 }
31
32 if (extra)
33 fprintf(stderr, "%s '%s' [%d]%s%s\n",
34 message, extra, error, lg2spacer, lg2msg);
35 else
36 fprintf(stderr, "%s [%d]%s%s\n",
37 message, error, lg2spacer, lg2msg);
38
39 exit(1);
40 }
41
42 void fatal(const char *message, const char *extra)
43 {
44 if (extra)
45 fprintf(stderr, "%s %s\n", message, extra);
46 else
47 fprintf(stderr, "%s\n", message);
48
49 exit(1);
50 }
51
52 size_t is_prefixed(const char *str, const char *pfx)
53 {
54 size_t len = strlen(pfx);
55 return strncmp(str, pfx, len) ? 0 : len;
56 }
57
58 int optional_str_arg(
59 const char **out, struct args_info *args, const char *opt, const char *def)
60 {
61 const char *found = args->argv[args->pos];
62 size_t len = is_prefixed(found, opt);
63
64 if (!len)
65 return 0;
66
67 if (!found[len]) {
68 if (args->pos + 1 == args->argc) {
69 *out = def;
70 return 1;
71 }
72 args->pos += 1;
73 *out = args->argv[args->pos];
74 return 1;
75 }
76
77 if (found[len] == '=') {
78 *out = found + len + 1;
79 return 1;
80 }
81
82 return 0;
83 }
84
85 int match_str_arg(
86 const char **out, struct args_info *args, const char *opt)
87 {
88 const char *found = args->argv[args->pos];
89 size_t len = is_prefixed(found, opt);
90
91 if (!len)
92 return 0;
93
94 if (!found[len]) {
95 if (args->pos + 1 == args->argc)
96 fatal("expected value following argument", opt);
97 args->pos += 1;
98 *out = args->argv[args->pos];
99 return 1;
100 }
101
102 if (found[len] == '=') {
103 *out = found + len + 1;
104 return 1;
105 }
106
107 return 0;
108 }
109
110 static const char *match_numeric_arg(struct args_info *args, const char *opt)
111 {
112 const char *found = args->argv[args->pos];
113 size_t len = is_prefixed(found, opt);
114
115 if (!len)
116 return NULL;
117
118 if (!found[len]) {
119 if (args->pos + 1 == args->argc)
120 fatal("expected numeric value following argument", opt);
121 args->pos += 1;
122 found = args->argv[args->pos];
123 } else {
124 found = found + len;
125 if (*found == '=')
126 found++;
127 }
128
129 return found;
130 }
131
132 int match_uint16_arg(
133 uint16_t *out, struct args_info *args, const char *opt)
134 {
135 const char *found = match_numeric_arg(args, opt);
136 uint16_t val;
137 char *endptr = NULL;
138
139 if (!found)
140 return 0;
141
142 val = (uint16_t)strtoul(found, &endptr, 0);
143 if (!endptr || *endptr != '\0')
144 fatal("expected number after argument", opt);
145
146 if (out)
147 *out = val;
148 return 1;
149 }
150
151 int match_uint32_arg(
152 uint32_t *out, struct args_info *args, const char *opt)
153 {
154 const char *found = match_numeric_arg(args, opt);
155 uint16_t val;
156 char *endptr = NULL;
157
158 if (!found)
159 return 0;
160
161 val = (uint32_t)strtoul(found, &endptr, 0);
162 if (!endptr || *endptr != '\0')
163 fatal("expected number after argument", opt);
164
165 if (out)
166 *out = val;
167 return 1;
168 }
169
170 static int match_int_internal(
171 int *out, const char *str, int allow_negative, const char *opt)
172 {
173 char *endptr = NULL;
174 int val = (int)strtol(str, &endptr, 10);
175
176 if (!endptr || *endptr != '\0')
177 fatal("expected number", opt);
178 else if (val < 0 && !allow_negative)
179 fatal("negative values are not allowed", opt);
180
181 if (out)
182 *out = val;
183
184 return 1;
185 }
186
187 int match_bool_arg(int *out, struct args_info *args, const char *opt)
188 {
189 const char *found = args->argv[args->pos];
190
191 if (!strcmp(found, opt)) {
192 *out = 1;
193 return 1;
194 }
195
196 if (!strncmp(found, "--no-", strlen("--no-")) &&
197 !strcmp(found + strlen("--no-"), opt + 2)) {
198 *out = 0;
199 return 1;
200 }
201
202 *out = -1;
203 return 0;
204 }
205
206 int is_integer(int *out, const char *str, int allow_negative)
207 {
208 return match_int_internal(out, str, allow_negative, NULL);
209 }
210
211 int match_int_arg(
212 int *out, struct args_info *args, const char *opt, int allow_negative)
213 {
214 const char *found = match_numeric_arg(args, opt);
215 if (!found)
216 return 0;
217 return match_int_internal(out, found, allow_negative, opt);
218 }
219
220 int diff_output(
221 const git_diff_delta *d,
222 const git_diff_hunk *h,
223 const git_diff_line *l,
224 void *p)
225 {
226 FILE *fp = (FILE*)p;
227
228 (void)d; (void)h;
229
230 if (!fp)
231 fp = stdout;
232
233 if (l->origin == GIT_DIFF_LINE_CONTEXT ||
234 l->origin == GIT_DIFF_LINE_ADDITION ||
235 l->origin == GIT_DIFF_LINE_DELETION)
236 fputc(l->origin, fp);
237
238 fwrite(l->content, 1, l->content_len, fp);
239
240 return 0;
241 }
242
243 void treeish_to_tree(
244 git_tree **out, git_repository *repo, const char *treeish)
245 {
246 git_object *obj = NULL;
247
248 check_lg2(
249 git_revparse_single(&obj, repo, treeish),
250 "looking up object", treeish);
251
252 check_lg2(
253 git_object_peel((git_object **)out, obj, GIT_OBJECT_TREE),
254 "resolving object to tree", treeish);
255
256 git_object_free(obj);
257 }
258
259 void *xrealloc(void *oldp, size_t newsz)
260 {
261 void *p = realloc(oldp, newsz);
262 if (p == NULL) {
263 fprintf(stderr, "Cannot allocate memory, exiting.\n");
264 exit(1);
265 }
266 return p;
267 }
268
269 int resolve_refish(git_annotated_commit **commit, git_repository *repo, const char *refish)
270 {
271 git_reference *ref;
272 git_object *obj;
273 int err = 0;
274
275 assert(commit != NULL);
276
277 err = git_reference_dwim(&ref, repo, refish);
278 if (err == GIT_OK) {
279 git_annotated_commit_from_ref(commit, repo, ref);
280 git_reference_free(ref);
281 return 0;
282 }
283
284 err = git_revparse_single(&obj, repo, refish);
285 if (err == GIT_OK) {
286 err = git_annotated_commit_lookup(commit, repo, git_object_id(obj));
287 git_object_free(obj);
288 }
289
290 return err;
291 }