]> git.proxmox.com Git - libgit2.git/blame - src/refs.c
Merge pull request #3908 from libgit2/ethomson/patch_from_diff
[libgit2.git] / src / refs.c
CommitLineData
9282e921 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
9282e921 3 *
bb742ede
VM
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.
9282e921 6 */
7
8#include "refs.h"
9#include "hash.h"
10#include "repository.h"
11#include "fileops.h"
114f5a6c 12#include "filebuf.h"
01ad7b3a 13#include "pack.h"
a5cd086d 14#include "reflog.h"
d00d5464 15#include "refdb.h"
9282e921 16
87d3acf4
VM
17#include <git2/tag.h>
18#include <git2/object.h>
c07d9c95 19#include <git2/oid.h>
4ba23be1 20#include <git2/branch.h>
d00d5464
ET
21#include <git2/refs.h>
22#include <git2/refdb.h>
21ca0451 23#include <git2/sys/refs.h>
a57dd3b7 24#include <git2/signature.h>
a612a25f 25#include <git2/commit.h>
87d3acf4 26
c8e02b87 27GIT__USE_STRMAP
01fed0a8 28
f201d613
RB
29#define DEFAULT_NESTING_LEVEL 5
30#define MAX_NESTING_LEVEL 10
9282e921 31
d4a0b124
VM
32enum {
33 GIT_PACKREF_HAS_PEEL = 1,
34 GIT_PACKREF_WAS_LOOSE = 2
35};
86194b24 36
4e4eab52 37static git_reference *alloc_ref(const char *name)
3be933b1 38{
f1453c59
ET
39 git_reference *ref = NULL;
40 size_t namelen = strlen(name), reflen;
3be933b1 41
f1453c59
ET
42 if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
43 !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
44 (ref = git__calloc(1, reflen)) != NULL)
45 memcpy(ref->name, name, namelen + 1);
3be933b1
VM
46
47 return ref;
48}
49
50git_reference *git_reference__alloc_symbolic(
21ca0451 51 const char *name, const char *target)
2f8a8ab2 52{
d00d5464 53 git_reference *ref;
2f8a8ab2 54
4e4eab52 55 assert(name && target);
55e0f53d 56
4e4eab52 57 ref = alloc_ref(name);
3be933b1 58 if (!ref)
d00d5464 59 return NULL;
87d3acf4 60
3be933b1 61 ref->type = GIT_REF_SYMBOLIC;
87d3acf4 62
3be933b1
VM
63 if ((ref->target.symbolic = git__strdup(target)) == NULL) {
64 git__free(ref);
65 return NULL;
d79f1da6 66 }
55e0f53d 67
3be933b1
VM
68 return ref;
69}
70
71git_reference *git_reference__alloc(
3be933b1
VM
72 const char *name,
73 const git_oid *oid,
74 const git_oid *peel)
75{
76 git_reference *ref;
77
4e4eab52 78 assert(name && oid);
3be933b1 79
4e4eab52 80 ref = alloc_ref(name);
3be933b1
VM
81 if (!ref)
82 return NULL;
83
84 ref->type = GIT_REF_OID;
fedd0f9e 85 git_oid_cpy(&ref->target.oid, oid);
3be933b1
VM
86
87 if (peel != NULL)
fedd0f9e 88 git_oid_cpy(&ref->peel, peel);
55e0f53d 89
d00d5464 90 return ref;
2f8a8ab2 91}
9282e921 92
24c71f14
RB
93git_reference *git_reference__set_name(
94 git_reference *ref, const char *name)
95{
96 size_t namelen = strlen(name);
f1453c59 97 size_t reflen;
392702ee
ET
98 git_reference *rewrite = NULL;
99
f1453c59
ET
100 if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
101 !GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
102 (rewrite = git__realloc(ref, reflen)) != NULL)
24c71f14 103 memcpy(rewrite->name, name, namelen + 1);
392702ee 104
24c71f14
RB
105 return rewrite;
106}
107
908f24fd
AS
108int git_reference_dup(git_reference **dest, git_reference *source)
109{
110 if (source->type == GIT_REF_SYMBOLIC)
111 *dest = git_reference__alloc_symbolic(source->name, source->target.symbolic);
112 else
113 *dest = git_reference__alloc(source->name, &source->target.oid, &source->peel);
114
115 GITERR_CHECK_ALLOC(*dest);
116
117 return 0;
118}
119
d00d5464 120void git_reference_free(git_reference *reference)
2f8a8ab2 121{
d00d5464
ET
122 if (reference == NULL)
123 return;
2b397327 124
3be933b1 125 if (reference->type == GIT_REF_SYMBOLIC)
d00d5464 126 git__free(reference->target.symbolic);
2f8a8ab2 127
979f75d8
VM
128 if (reference->db)
129 GIT_REFCOUNT_DEC(reference->db, git_refdb__free);
d00d5464 130
d00d5464 131 git__free(reference);
d4a0b124 132}
2f8a8ab2 133
1a481123 134int git_reference_delete(git_reference *ref)
a46ec457 135{
f44fd59e
CMN
136 const git_oid *old_id = NULL;
137 const char *old_target = NULL;
138
139 if (ref->type == GIT_REF_OID)
140 old_id = &ref->target.oid;
141 else
142 old_target = ref->target.symbolic;
143
144 return git_refdb_delete(ref->db, ref->name, old_id, old_target);
a46ec457
MS
145}
146
5367ec4b
CMN
147int git_reference_remove(git_repository *repo, const char *name)
148{
149 git_refdb *db;
150 int error;
151
152 if ((error = git_repository_refdb__weakptr(&db, repo)) < 0)
153 return error;
154
155 return git_refdb_delete(db, name, NULL, NULL);
156}
157
d4a0b124 158int git_reference_lookup(git_reference **ref_out,
1a481123 159 git_repository *repo, const char *name)
a46ec457 160{
f201d613
RB
161 return git_reference_lookup_resolved(ref_out, repo, name, 0);
162}
163
2508cc66 164int git_reference_name_to_id(
f201d613
RB
165 git_oid *out, git_repository *repo, const char *name)
166{
167 int error;
168 git_reference *ref;
169
170 if ((error = git_reference_lookup_resolved(&ref, repo, name, -1)) < 0)
171 return error;
172
2508cc66 173 git_oid_cpy(out, git_reference_target(ref));
f201d613
RB
174 git_reference_free(ref);
175 return 0;
176}
177
92dac975 178static int reference_normalize_for_repo(
824f755f 179 git_refname_t out,
92dac975
RB
180 git_repository *repo,
181 const char *name)
182{
183 int precompose;
184 unsigned int flags = GIT_REF_FORMAT_ALLOW_ONELEVEL;
185
186 if (!git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) &&
187 precompose)
188 flags |= GIT_REF_FORMAT__PRECOMPOSE_UNICODE;
189
824f755f 190 return git_reference_normalize_name(out, GIT_REFNAME_MAX, name, flags);
92dac975
RB
191}
192
f201d613
RB
193int git_reference_lookup_resolved(
194 git_reference **ref_out,
195 git_repository *repo,
196 const char *name,
197 int max_nesting)
198{
824f755f 199 git_refname_t scan_name;
d00d5464
ET
200 git_ref_t scan_type;
201 int error = 0, nesting;
202 git_reference *ref = NULL;
203 git_refdb *refdb;
d4a0b124
VM
204
205 assert(ref_out && repo && name);
f201d613 206
1a481123 207 *ref_out = NULL;
d4a0b124 208
f201d613
RB
209 if (max_nesting > MAX_NESTING_LEVEL)
210 max_nesting = MAX_NESTING_LEVEL;
211 else if (max_nesting < 0)
212 max_nesting = DEFAULT_NESTING_LEVEL;
4dcd8780 213
d00d5464 214 scan_type = GIT_REF_SYMBOLIC;
4dcd8780 215
824f755f 216 if ((error = reference_normalize_for_repo(scan_name, repo, name)) < 0)
92dac975 217 return error;
a46ec457 218
92dac975 219 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
d00d5464 220 return error;
f201d613
RB
221
222 for (nesting = max_nesting;
d00d5464 223 nesting >= 0 && scan_type == GIT_REF_SYMBOLIC;
f201d613
RB
224 nesting--)
225 {
d00d5464 226 if (nesting != max_nesting) {
92dac975 227 strncpy(scan_name, ref->target.symbolic, sizeof(scan_name));
d00d5464
ET
228 git_reference_free(ref);
229 }
f201d613 230
d00d5464
ET
231 if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
232 return error;
4dcd8780 233
d00d5464 234 scan_type = ref->type;
f201d613
RB
235 }
236
d00d5464 237 if (scan_type != GIT_REF_OID && max_nesting != 0) {
f201d613
RB
238 giterr_set(GITERR_REFERENCE,
239 "Cannot resolve reference (>%u levels deep)", max_nesting);
d00d5464 240 git_reference_free(ref);
f201d613
RB
241 return -1;
242 }
243
d00d5464 244 *ref_out = ref;
f201d613 245 return 0;
a46ec457
MS
246}
247
98d633cc
CMN
248int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
249{
250 int error = 0, i;
251 bool fallbackmode = true, foundvalid = false;
252 git_reference *ref;
253 git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT;
254
255 static const char* formatters[] = {
256 "%s",
257 GIT_REFS_DIR "%s",
258 GIT_REFS_TAGS_DIR "%s",
259 GIT_REFS_HEADS_DIR "%s",
260 GIT_REFS_REMOTES_DIR "%s",
261 GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE,
262 NULL
263 };
264
265 if (*refname)
266 git_buf_puts(&name, refname);
267 else {
268 git_buf_puts(&name, GIT_HEAD_FILE);
269 fallbackmode = false;
270 }
271
272 for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) {
273
274 git_buf_clear(&refnamebuf);
275
276 if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0)
277 goto cleanup;
278
279 if (!git_reference_is_valid_name(git_buf_cstr(&refnamebuf))) {
280 error = GIT_EINVALIDSPEC;
281 continue;
282 }
283 foundvalid = true;
284
285 error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1);
286
287 if (!error) {
288 *out = ref;
289 error = 0;
290 goto cleanup;
291 }
292
293 if (error != GIT_ENOTFOUND)
294 goto cleanup;
295 }
296
297cleanup:
298 if (error && !foundvalid) {
299 /* never found a valid reference name */
300 giterr_set(GITERR_REFERENCE,
301 "Could not use '%s' as valid reference name", git_buf_cstr(&name));
302 }
303
77965c68
CMN
304 if (error == GIT_ENOTFOUND)
305 giterr_set(GITERR_REFERENCE, "no reference found for shorthand '%s'", refname);
306
98d633cc
CMN
307 git_buf_free(&name);
308 git_buf_free(&refnamebuf);
309 return error;
310}
311
d4a0b124
VM
312/**
313 * Getters
314 */
2508cc66 315git_ref_t git_reference_type(const git_reference *ref)
87d3acf4
VM
316{
317 assert(ref);
d00d5464 318 return ref->type;
87d3acf4
VM
319}
320
2508cc66 321const char *git_reference_name(const git_reference *ref)
87d3acf4
VM
322{
323 assert(ref);
d4a0b124 324 return ref->name;
87d3acf4
VM
325}
326
2508cc66 327git_repository *git_reference_owner(const git_reference *ref)
a46ec457 328{
d4a0b124 329 assert(ref);
d00d5464 330 return ref->db->repo;
a46ec457
MS
331}
332
2508cc66 333const git_oid *git_reference_target(const git_reference *ref)
87d3acf4
VM
334{
335 assert(ref);
336
d00d5464 337 if (ref->type != GIT_REF_OID)
87d3acf4
VM
338 return NULL;
339
fedd0f9e 340 return &ref->target.oid;
3be933b1
VM
341}
342
343const git_oid *git_reference_target_peel(const git_reference *ref)
344{
345 assert(ref);
346
fedd0f9e 347 if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel))
3be933b1
VM
348 return NULL;
349
fedd0f9e 350 return &ref->peel;
87d3acf4
VM
351}
352
2508cc66 353const char *git_reference_symbolic_target(const git_reference *ref)
a46ec457 354{
d4a0b124 355 assert(ref);
a46ec457 356
d00d5464 357 if (ref->type != GIT_REF_SYMBOLIC)
a46ec457
MS
358 return NULL;
359
d4a0b124 360 return ref->target.symbolic;
a46ec457
MS
361}
362
d00d5464 363static int reference__create(
d4a0b124
VM
364 git_reference **ref_out,
365 git_repository *repo,
366 const char *name,
d00d5464
ET
367 const git_oid *oid,
368 const char *symbolic,
bba25f39 369 int force,
370 const git_signature *signature,
9b148098 371 const char *log_message,
91123661
CMN
372 const git_oid *old_id,
373 const char *old_target)
d5afc039 374{
824f755f 375 git_refname_t normalized;
d00d5464 376 git_refdb *refdb;
d4a0b124 377 git_reference *ref = NULL;
d00d5464 378 int error = 0;
4dcd8780 379
92f95a17 380 assert(repo && name);
a57dd3b7 381 assert(symbolic || signature);
92f95a17 382
d00d5464
ET
383 if (ref_out)
384 *ref_out = NULL;
385
824f755f 386 error = reference_normalize_for_repo(normalized, repo, name);
4e6e2ff2
VM
387 if (error < 0)
388 return error;
389
390 error = git_repository_refdb__weakptr(&refdb, repo);
391 if (error < 0)
c1281493 392 return error;
3be933b1
VM
393
394 if (oid != NULL) {
395 assert(symbolic == NULL);
92f95a17 396
98c34149 397 if (!git_object__is_valid(repo, oid, GIT_OBJ_ANY)) {
92f95a17 398 giterr_set(GITERR_REFERENCE,
399 "Target OID for the reference doesn't exist on the repository");
400 return -1;
401 }
402
68f9d6b2 403 ref = git_reference__alloc(normalized, oid, NULL);
3be933b1 404 } else {
824f755f 405 git_refname_t normalized_target;
92f95a17 406
824f755f 407 if ((error = reference_normalize_for_repo(normalized_target, repo, symbolic)) < 0)
92f95a17 408 return error;
409
68f9d6b2 410 ref = git_reference__alloc_symbolic(normalized, normalized_target);
3be933b1 411 }
4dcd8780 412
13421eee 413 GITERR_CHECK_ALLOC(ref);
d5afc039 414
91123661 415 if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) {
45d387ac 416 git_reference_free(ref);
d00d5464 417 return error;
45d387ac 418 }
4dcd8780 419
d00d5464 420 if (ref_out == NULL)
d4a0b124 421 git_reference_free(ref);
d00d5464 422 else
d4a0b124 423 *ref_out = ref;
d5afc039 424
45d387ac 425 return 0;
d5afc039
VM
426}
427
659cf202
CMN
428int configured_ident(git_signature **out, const git_repository *repo)
429{
430 if (repo->ident_name && repo->ident_email)
431 return git_signature_now(out, repo->ident_name, repo->ident_email);
432
433 /* if not configured let us fall-through to the next method */
434 return -1;
435}
436
ab8d9242 437int git_reference__log_signature(git_signature **out, git_repository *repo)
a46ec457 438{
a57dd3b7 439 int error;
0b28217b 440 git_signature *who;
d5afc039 441
659cf202
CMN
442 if(((error = configured_ident(&who, repo)) < 0) &&
443 ((error = git_signature_default(&who, repo)) < 0) &&
0b28217b 444 ((error = git_signature_now(&who, "unknown", "unknown")) < 0))
c1281493 445 return error;
4dcd8780 446
0b28217b
CMN
447 *out = who;
448 return 0;
bba25f39 449}
450
5d96fe88 451int git_reference_create_matching(
9b148098
CMN
452 git_reference **ref_out,
453 git_repository *repo,
454 const char *name,
455 const git_oid *id,
456 int force,
15284a2c 457 const git_oid *old_id,
15284a2c 458 const char *log_message)
5d96fe88 459
bba25f39 460{
0b28217b
CMN
461 int error;
462 git_signature *who = NULL;
908f24fd 463
9b148098 464 assert(id);
bba25f39 465
659cf202
CMN
466 if ((error = git_reference__log_signature(&who, repo)) < 0)
467 return error;
0b28217b
CMN
468
469 error = reference__create(
659cf202 470 ref_out, repo, name, id, NULL, force, who, log_message, old_id, NULL);
87d3acf4 471
0b28217b
CMN
472 git_signature_free(who);
473 return error;
d00d5464 474}
4dcd8780 475
5d96fe88
CMN
476int git_reference_create(
477 git_reference **ref_out,
478 git_repository *repo,
479 const char *name,
480 const git_oid *id,
481 int force,
5d96fe88
CMN
482 const char *log_message)
483{
659cf202 484 return git_reference_create_matching(ref_out, repo, name, id, force, NULL, log_message);
5d96fe88
CMN
485}
486
878fb66f 487int git_reference_symbolic_create_matching(
e5994eb0
AS
488 git_reference **ref_out,
489 git_repository *repo,
490 const char *name,
491 const char *target,
492 int force,
15284a2c 493 const char *old_target,
15284a2c 494 const char *log_message)
e5994eb0 495{
0b28217b
CMN
496 int error;
497 git_signature *who = NULL;
498
499 assert(target);
500
659cf202
CMN
501 if ((error = git_reference__log_signature(&who, repo)) < 0)
502 return error;
e5994eb0 503
0b28217b 504 error = reference__create(
659cf202 505 ref_out, repo, name, NULL, target, force, who, log_message, NULL, old_target);
0b28217b
CMN
506
507 git_signature_free(who);
508 return error;
e5994eb0
AS
509}
510
878fb66f
CMN
511int git_reference_symbolic_create(
512 git_reference **ref_out,
513 git_repository *repo,
514 const char *name,
515 const char *target,
516 int force,
878fb66f
CMN
517 const char *log_message)
518{
659cf202 519 return git_reference_symbolic_create_matching(ref_out, repo, name, target, force, NULL, log_message);
878fb66f
CMN
520}
521
14ab0e10 522static int ensure_is_an_updatable_direct_reference(git_reference *ref)
523{
524 if (ref->type == GIT_REF_OID)
525 return 0;
9a53df7e 526
14ab0e10 527 giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference");
528 return -1;
d00d5464 529}
9462c471 530
5d96fe88 531int git_reference_set_target(
14ab0e10 532 git_reference **out,
533 git_reference *ref,
534 const git_oid *id,
5d96fe88 535 const char *log_message)
14ab0e10 536{
537 int error;
9b148098 538 git_repository *repo;
14ab0e10 539
540 assert(out && ref && id);
14ab0e10 541
9b148098
CMN
542 repo = ref->db->repo;
543
14ab0e10 544 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
545 return error;
546
659cf202 547 return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message);
14ab0e10 548}
549
ca84e058 550static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
551{
552 if (ref->type == GIT_REF_SYMBOLIC)
553 return 0;
554
555 giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference");
556 return -1;
557}
558
d00d5464
ET
559int git_reference_symbolic_set_target(
560 git_reference **out,
561 git_reference *ref,
0b28217b 562 const char *target,
0b28217b 563 const char *log_message)
87d3acf4 564{
ca84e058 565 int error;
566
d00d5464 567 assert(out && ref && target);
4dcd8780 568
ca84e058 569 if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
570 return error;
4dcd8780 571
878fb66f 572 return git_reference_symbolic_create_matching(
659cf202 573 out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
87d3acf4
VM
574}
575
a57dd3b7
CMN
576static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
577 const git_signature *signature, const char *message)
7376ad99 578{
824f755f 579 git_refname_t normalized;
f3cc7834 580 bool should_head_be_updated = false;
d00d5464 581 int error = 0;
a57dd3b7
CMN
582
583 assert(ref && new_name && signature);
4dcd8780 584
68f9d6b2 585 if ((error = reference_normalize_for_repo(
824f755f 586 normalized, git_reference_owner(ref), new_name)) < 0)
d00d5464 587 return error;
7376ad99 588
a57dd3b7 589
d00d5464 590 /* Check if we have to update HEAD. */
10c06114 591 if ((error = git_branch_is_head(ref)) < 0)
4e6e2ff2 592 return error;
d00d5464 593
10c06114
AS
594 should_head_be_updated = (error > 0);
595
68f9d6b2 596 if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
4e6e2ff2 597 return error;
4dcd8780 598
96869a4e 599 /* Update HEAD it was pointing to the reference being renamed */
4e6e2ff2 600 if (should_head_be_updated &&
4e498646 601 (error = git_repository_set_head(ref->db->repo, normalized)) < 0) {
d00d5464 602 giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference");
4e6e2ff2 603 return error;
d4a0b124
VM
604 }
605
a57dd3b7
CMN
606 return 0;
607}
608
7376ad99 609
a57dd3b7
CMN
610int git_reference_rename(
611 git_reference **out,
612 git_reference *ref,
613 const char *new_name,
ccf6ce5c 614 int force,
ccf6ce5c 615 const char *log_message)
a57dd3b7 616{
659cf202 617 git_signature *who;
a57dd3b7 618 int error;
7376ad99 619
659cf202 620 if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0)
4e6e2ff2 621 return error;
64093ce5 622
ccf6ce5c 623 error = reference__rename(out, ref, new_name, force, who, log_message);
659cf202 624 git_signature_free(who);
a57dd3b7
CMN
625
626 return error;
627}
628
2508cc66 629int git_reference_resolve(git_reference **ref_out, const git_reference *ref)
87d3acf4 630{
3be933b1
VM
631 switch (git_reference_type(ref)) {
632 case GIT_REF_OID:
d00d5464 633 return git_reference_lookup(ref_out, ref->db->repo, ref->name);
4dcd8780 634
3be933b1
VM
635 case GIT_REF_SYMBOLIC:
636 return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1);
637
638 default:
639 giterr_set(GITERR_REFERENCE, "Invalid reference");
640 return -1;
641 }
87d3acf4
VM
642}
643
d4a0b124
VM
644int git_reference_foreach(
645 git_repository *repo,
eecc8050 646 git_reference_foreach_cb callback,
1a481123 647 void *payload)
00571828 648{
95727245 649 git_reference_iterator *iter;
ec24e542 650 git_reference *ref;
95727245
CMN
651 int error;
652
dab89f9b
RB
653 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
654 return error;
00571828 655
f10d7a36
RB
656 while (!(error = git_reference_next(&ref, iter))) {
657 if ((error = callback(ref, payload)) != 0) {
26c1cb91 658 giterr_set_after_callback(error);
f10d7a36
RB
659 break;
660 }
661 }
ec24e542
VM
662
663 if (error == GIT_ITEROVER)
664 error = 0;
665
ec24e542
VM
666 git_reference_iterator_free(iter);
667 return error;
668}
669
670int git_reference_foreach_name(
671 git_repository *repo,
672 git_reference_foreach_name_cb callback,
673 void *payload)
674{
675 git_reference_iterator *iter;
676 const char *refname;
95727245
CMN
677 int error;
678
dab89f9b
RB
679 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
680 return error;
00571828 681
f10d7a36
RB
682 while (!(error = git_reference_next_name(&refname, iter))) {
683 if ((error = callback(refname, payload)) != 0) {
26c1cb91 684 giterr_set_after_callback(error);
f10d7a36
RB
685 break;
686 }
687 }
ec24e542
VM
688
689 if (error == GIT_ITEROVER)
690 error = 0;
691
ec24e542
VM
692 git_reference_iterator_free(iter);
693 return error;
694}
695
696int git_reference_foreach_glob(
697 git_repository *repo,
698 const char *glob,
699 git_reference_foreach_name_cb callback,
700 void *payload)
701{
702 git_reference_iterator *iter;
703 const char *refname;
704 int error;
705
dab89f9b
RB
706 if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0)
707 return error;
ec24e542 708
f10d7a36
RB
709 while (!(error = git_reference_next_name(&refname, iter))) {
710 if ((error = callback(refname, payload)) != 0) {
26c1cb91 711 giterr_set_after_callback(error);
f10d7a36
RB
712 break;
713 }
714 }
95727245
CMN
715
716 if (error == GIT_ITEROVER)
717 error = 0;
718
95727245
CMN
719 git_reference_iterator_free(iter);
720 return error;
09e8de0f
VM
721}
722
4def7035
CMN
723int git_reference_iterator_new(git_reference_iterator **out, git_repository *repo)
724{
725 git_refdb *refdb;
726
727 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
728 return -1;
729
ec24e542 730 return git_refdb_iterator(out, refdb, NULL);
4def7035
CMN
731}
732
ec24e542
VM
733int git_reference_iterator_glob_new(
734 git_reference_iterator **out, git_repository *repo, const char *glob)
00571828 735{
d00d5464 736 git_refdb *refdb;
00571828 737
c58cac12
CMN
738 if (git_repository_refdb__weakptr(&refdb, repo) < 0)
739 return -1;
740
ec24e542 741 return git_refdb_iterator(out, refdb, glob);
c58cac12
CMN
742}
743
56960b83 744int git_reference_next(git_reference **out, git_reference_iterator *iter)
4def7035 745{
ec24e542
VM
746 return git_refdb_iterator_next(out, iter);
747}
748
749int git_reference_next_name(const char **out, git_reference_iterator *iter)
750{
751 return git_refdb_iterator_next_name(out, iter);
4def7035
CMN
752}
753
754void git_reference_iterator_free(git_reference_iterator *iter)
755{
2ad45213
BR
756 if (iter == NULL)
757 return;
758
4def7035 759 git_refdb_iterator_free(iter);
09e8de0f
VM
760}
761
d568d585 762static int cb__reflist_add(const char *ref, void *data)
09e8de0f 763{
25e0b157
RB
764 char *name = git__strdup(ref);
765 GITERR_CHECK_ALLOC(name);
766 return git_vector_insert((git_vector *)data, name);
09e8de0f
VM
767}
768
4fbd1c00 769int git_reference_list(
d4a0b124 770 git_strarray *array,
2b562c3a 771 git_repository *repo)
09e8de0f 772{
09e8de0f
VM
773 git_vector ref_list;
774
775 assert(array && repo);
776
777 array->strings = NULL;
778 array->count = 0;
779
0d0fa7c3 780 if (git_vector_init(&ref_list, 8, NULL) < 0)
45d387ac 781 return -1;
7ad96e51 782
ec24e542 783 if (git_reference_foreach_name(
2b562c3a 784 repo, &cb__reflist_add, (void *)&ref_list) < 0) {
09e8de0f 785 git_vector_free(&ref_list);
45d387ac 786 return -1;
7ad96e51
VM
787 }
788
25e0b157
RB
789 array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list);
790
1a481123 791 return 0;
00571828 792}
87d3acf4 793
d4a0b124 794static int is_valid_ref_char(char ch)
aa2120e9 795{
50a8fd03 796 if ((unsigned) ch <= ' ')
d4a0b124 797 return 0;
aa2120e9 798
799 switch (ch) {
800 case '~':
801 case '^':
802 case ':':
803 case '\\':
804 case '?':
805 case '[':
e1be1028 806 case '*':
d4a0b124 807 return 0;
aa2120e9 808 default:
d4a0b124 809 return 1;
aa2120e9 810 }
811}
812
c030ada7 813static int ensure_segment_validity(const char *name)
aa2120e9 814{
c030ada7 815 const char *current = name;
816 char prev = '\0';
0d1b094b
RB
817 const int lock_len = (int)strlen(GIT_FILELOCK_EXTENSION);
818 int segment_len;
aa2120e9 819
c030ada7 820 if (*current == '.')
821 return -1; /* Refname starts with "." */
aa2120e9 822
c030ada7 823 for (current = name; ; current++) {
824 if (*current == '\0' || *current == '/')
825 break;
2e0c8816 826
c030ada7 827 if (!is_valid_ref_char(*current))
828 return -1; /* Illegal character in refname */
aa2120e9 829
c030ada7 830 if (prev == '.' && *current == '.')
831 return -1; /* Refname contains ".." */
3101a3e5 832
c030ada7 833 if (prev == '@' && *current == '{')
834 return -1; /* Refname contains "@{" */
aa2120e9 835
c030ada7 836 prev = *current;
837 }
aa2120e9 838
0d1b094b
RB
839 segment_len = (int)(current - name);
840
4d811c3b 841 /* A refname component can not end with ".lock" */
0d1b094b 842 if (segment_len >= lock_len &&
2bca5b67 843 !memcmp(current - lock_len, GIT_FILELOCK_EXTENSION, lock_len))
4d811c3b 844 return -1;
845
0d1b094b 846 return segment_len;
c030ada7 847}
aa2120e9 848
7c411fd9 849static bool is_all_caps_and_underscore(const char *name, size_t len)
77e06d7e 850{
7c411fd9 851 size_t i;
77e06d7e 852 char c;
853
854 assert(name && len > 0);
855
856 for (i = 0; i < len; i++)
857 {
858 c = name[i];
859 if ((c < 'A' || c > 'Z') && c != '_')
860 return false;
861 }
862
863 if (*name == '_' || name[len - 1] == '_')
864 return false;
865
866 return true;
867}
868
92dac975 869/* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */
c030ada7 870int git_reference__normalize_name(
871 git_buf *buf,
872 const char *name,
873 unsigned int flags)
874{
0f4d9c03 875 const char *current;
80d9d1df 876 int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC;
77e06d7e 877 unsigned int process_flags;
878 bool normalize = (buf != NULL);
0bfa7323
VM
879
880#ifdef GIT_USE_ICONV
92dac975 881 git_path_iconv_t ic = GIT_PATH_ICONV_INIT;
0bfa7323 882#endif
92dac975 883
77e06d7e 884 assert(name);
c030ada7 885
77e06d7e 886 process_flags = flags;
c030ada7 887 current = (char *)name;
888
bb45c57f
CMN
889 if (*current == '/')
890 goto cleanup;
891
77e06d7e 892 if (normalize)
893 git_buf_clear(buf);
c030ada7 894
0bfa7323 895#ifdef GIT_USE_ICONV
92dac975
RB
896 if ((flags & GIT_REF_FORMAT__PRECOMPOSE_UNICODE) != 0) {
897 size_t namelen = strlen(current);
898 if ((error = git_path_iconv_init_precompose(&ic)) < 0 ||
899 (error = git_path_iconv(&ic, &current, &namelen)) < 0)
900 goto cleanup;
74353137 901 error = GIT_EINVALIDSPEC;
92dac975 902 }
0bfa7323 903#endif
92dac975 904
c030ada7 905 while (true) {
906 segment_len = ensure_segment_validity(current);
907 if (segment_len < 0) {
77e06d7e 908 if ((process_flags & GIT_REF_FORMAT_REFSPEC_PATTERN) &&
c030ada7 909 current[0] == '*' &&
910 (current[1] == '\0' || current[1] == '/')) {
911 /* Accept one wildcard as a full refname component. */
77e06d7e 912 process_flags &= ~GIT_REF_FORMAT_REFSPEC_PATTERN;
c030ada7 913 segment_len = 1;
914 } else
915 goto cleanup;
916 }
aa2120e9 917
c030ada7 918 if (segment_len > 0) {
77e06d7e 919 if (normalize) {
7c411fd9 920 size_t cur_len = git_buf_len(buf);
aa2120e9 921
77e06d7e 922 git_buf_joinpath(buf, git_buf_cstr(buf), current);
7c411fd9 923 git_buf_truncate(buf,
77e06d7e 924 cur_len + segment_len + (segments_count ? 1 : 0));
aa2120e9 925
80d9d1df 926 if (git_buf_oom(buf)) {
927 error = -1;
77e06d7e 928 goto cleanup;
80d9d1df 929 }
77e06d7e 930 }
aa2120e9 931
77e06d7e 932 segments_count++;
0844ed06 933 }
2e0c8816 934
2bca5b67 935 /* No empty segment is allowed when not normalizing */
936 if (segment_len == 0 && !normalize)
e5ef0f18 937 goto cleanup;
0d1b094b 938
c030ada7 939 if (current[segment_len] == '\0')
940 break;
aa2120e9 941
c030ada7 942 current += segment_len + 1;
2e0c8816 943 }
3101a3e5 944
c030ada7 945 /* A refname can not be empty */
77e06d7e 946 if (segment_len == 0 && segments_count == 0)
c030ada7 947 goto cleanup;
948
949 /* A refname can not end with "." */
950 if (current[segment_len - 1] == '.')
951 goto cleanup;
952
953 /* A refname can not end with "/" */
954 if (current[segment_len - 1] == '/')
955 goto cleanup;
956
77e06d7e 957 if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL))
958 goto cleanup;
959
960 if ((segments_count == 1 ) &&
528a4e24 961 !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) &&
7c411fd9 962 !(is_all_caps_and_underscore(name, (size_t)segment_len) ||
77e06d7e 963 ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name))))
964 goto cleanup;
965
966 if ((segments_count > 1)
967 && (is_all_caps_and_underscore(name, strchr(name, '/') - name)))
968 goto cleanup;
aa2120e9 969
c030ada7 970 error = 0;
aa2120e9 971
c030ada7 972cleanup:
80d9d1df 973 if (error == GIT_EINVALIDSPEC)
c030ada7 974 giterr_set(
975 GITERR_REFERENCE,
976 "The given reference name '%s' is not valid", name);
aa2120e9 977
3865f7f6
RB
978 if (error && normalize)
979 git_buf_free(buf);
980
0bfa7323 981#ifdef GIT_USE_ICONV
92dac975 982 git_path_iconv_clear(&ic);
0bfa7323 983#endif
92dac975 984
c030ada7 985 return error;
986}
1a481123 987
c030ada7 988int git_reference_normalize_name(
989 char *buffer_out,
990 size_t buffer_size,
991 const char *name,
992 unsigned int flags)
993{
994 git_buf buf = GIT_BUF_INIT;
995 int error;
996
997 if ((error = git_reference__normalize_name(&buf, name, flags)) < 0)
998 goto cleanup;
999
1000 if (git_buf_len(&buf) > buffer_size - 1) {
1001 giterr_set(
2e0c8816 1002 GITERR_REFERENCE,
c030ada7 1003 "The provided buffer is too short to hold the normalization of '%s'", name);
1004 error = GIT_EBUFS;
1005 goto cleanup;
1006 }
1007
1008 git_buf_copy_cstr(buffer_out, buffer_size, &buf);
1009
1010 error = 0;
1011
1012cleanup:
1013 git_buf_free(&buf);
1014 return error;
aa2120e9 1015}
2f8a8ab2 1016
f201d613
RB
1017#define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
1018
3b4ba278
JG
1019int git_reference_cmp(
1020 const git_reference *ref1,
1021 const git_reference *ref2)
f201d613 1022{
3be933b1 1023 git_ref_t type1, type2;
f201d613
RB
1024 assert(ref1 && ref2);
1025
3be933b1
VM
1026 type1 = git_reference_type(ref1);
1027 type2 = git_reference_type(ref2);
1028
f201d613 1029 /* let's put symbolic refs before OIDs */
3be933b1
VM
1030 if (type1 != type2)
1031 return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1;
f201d613 1032
3be933b1 1033 if (type1 == GIT_REF_SYMBOLIC)
f201d613
RB
1034 return strcmp(ref1->target.symbolic, ref2->target.symbolic);
1035
b7f167da 1036 return git_oid__cmp(&ref1->target.oid, &ref2->target.oid);
f201d613
RB
1037}
1038
659cf202
CMN
1039/**
1040 * Get the end of a chain of references. If the final one is not
1041 * found, we return the reference just before that.
1042 */
1043static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting)
edebceff 1044{
1045 git_reference *ref;
d00d5464 1046 int error = 0;
edebceff 1047
41e93563
RB
1048 if (nesting > MAX_NESTING_LEVEL) {
1049 giterr_set(GITERR_REFERENCE, "Reference chain too deep (%d)", nesting);
d00d5464 1050 return GIT_ENOTFOUND;
41e93563 1051 }
4dcd8780 1052
659cf202
CMN
1053 /* set to NULL to let the caller know that they're at the end of the chain */
1054 if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) {
1055 *out = NULL;
d00d5464 1056 return error;
659cf202 1057 }
4dcd8780 1058
659cf202
CMN
1059 if (git_reference_type(ref) == GIT_REF_OID) {
1060 *out = ref;
1061 error = 0;
d00d5464 1062 } else {
659cf202 1063 error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1);
78db0239
ET
1064 if (error == GIT_ENOTFOUND && !*out)
1065 *out = ref;
1066 else
659cf202 1067 git_reference_free(ref);
edebceff 1068 }
4dcd8780 1069
d00d5464 1070 return error;
edebceff 1071}
527ed554 1072
d00d5464
ET
1073/*
1074 * Starting with the reference given by `ref_name`, follows symbolic
1075 * references until a direct reference is found and updated the OID
1076 * on that direct reference to `oid`.
1077 */
1078int git_reference__update_terminal(
1079 git_repository *repo,
1080 const char *ref_name,
0b28217b 1081 const git_oid *oid,
659cf202 1082 const git_signature *sig,
0b28217b 1083 const char *log_message)
527ed554 1084{
fe21d708 1085 git_reference *ref = NULL, *ref2 = NULL;
659cf202
CMN
1086 git_signature *who = NULL;
1087 const git_signature *to_use;
1088 int error = 0;
1089
1090 if (!sig && (error = git_reference__log_signature(&who, repo)) < 0)
1091 return error;
1092
1093 to_use = sig ? sig : who;
1094 error = get_terminal(&ref, repo, ref_name, 0);
1095
1096 /* found a dangling symref */
1097 if (error == GIT_ENOTFOUND && ref) {
1098 assert(git_reference_type(ref) == GIT_REF_SYMBOLIC);
1099 giterr_clear();
fe21d708 1100 error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use,
659cf202
CMN
1101 log_message, NULL, NULL);
1102 } else if (error == GIT_ENOTFOUND) {
1103 giterr_clear();
fe21d708 1104 error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
659cf202
CMN
1105 log_message, NULL, NULL);
1106 } else if (error == 0) {
1107 assert(git_reference_type(ref) == GIT_REF_OID);
fe21d708 1108 error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use,
659cf202
CMN
1109 log_message, &ref->target.oid, NULL);
1110 }
1111
fe21d708
CMN
1112 git_reference_free(ref2);
1113 git_reference_free(ref);
659cf202
CMN
1114 git_signature_free(who);
1115 return error;
527ed554 1116}
1117
a612a25f
ET
1118int git_reference__update_for_commit(
1119 git_repository *repo,
1120 git_reference *ref,
1121 const char *ref_name,
1122 const git_oid *id,
a612a25f
ET
1123 const char *operation)
1124{
1125 git_reference *ref_new = NULL;
1126 git_commit *commit = NULL;
1127 git_buf reflog_msg = GIT_BUF_INIT;
659cf202 1128 const git_signature *who;
a612a25f
ET
1129 int error;
1130
1131 if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
1132 (error = git_buf_printf(&reflog_msg, "%s%s: %s",
1133 operation ? operation : "commit",
1134 git_commit_parentcount(commit) == 0 ? " (initial)" : "",
1135 git_commit_summary(commit))) < 0)
1136 goto done;
1137
659cf202
CMN
1138 who = git_commit_committer(commit);
1139
1140 if (ref) {
1141 if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
1142 return error;
1143
1144 error = reference__create(&ref_new, repo, ref->name, id, NULL, 1, who,
1145 git_buf_cstr(&reflog_msg), &ref->target.oid, NULL);
1146 }
a612a25f
ET
1147 else
1148 error = git_reference__update_terminal(
659cf202 1149 repo, ref_name, id, who, git_buf_cstr(&reflog_msg));
a612a25f
ET
1150
1151done:
1152 git_reference_free(ref_new);
1153 git_buf_free(&reflog_msg);
1154 git_commit_free(commit);
1155 return error;
1156}
1157
f2105129 1158int git_reference_has_log(git_repository *repo, const char *refname)
75261421 1159{
f2105129
CMN
1160 int error;
1161 git_refdb *refdb;
75261421 1162
f2105129 1163 assert(repo && refname);
75261421 1164
f2105129
CMN
1165 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1166 return error;
75261421 1167
f2105129 1168 return git_refdb_has_log(refdb, refname);
75261421 1169}
84f18e35 1170
8d5ec910
CMN
1171int git_reference_ensure_log(git_repository *repo, const char *refname)
1172{
1173 int error;
1174 git_refdb *refdb;
1175
1176 assert(repo && refname);
1177
1178 if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
1179 return error;
75261421 1180
8d5ec910 1181 return git_refdb_ensure_log(refdb, refname);
75261421 1182}
84f18e35 1183
bf031581 1184int git_reference__is_branch(const char *ref_name)
1185{
1186 return git__prefixcmp(ref_name, GIT_REFS_HEADS_DIR) == 0;
1187}
1188
853b1407 1189int git_reference_is_branch(const git_reference *ref)
88bcd515 1190{
1191 assert(ref);
bf031581 1192 return git_reference__is_branch(ref->name);
88bcd515 1193}
1c947daa 1194
c1b5e8c4 1195int git_reference__is_remote(const char *ref_name)
1196{
1197 return git__prefixcmp(ref_name, GIT_REFS_REMOTES_DIR) == 0;
1198}
1199
3b4ba278 1200int git_reference_is_remote(const git_reference *ref)
1c947daa
VM
1201{
1202 assert(ref);
c1b5e8c4 1203 return git_reference__is_remote(ref->name);
1c947daa 1204}
31665948 1205
504850cd
NV
1206int git_reference__is_tag(const char *ref_name)
1207{
1208 return git__prefixcmp(ref_name, GIT_REFS_TAGS_DIR) == 0;
1209}
1210
3b4ba278 1211int git_reference_is_tag(const git_reference *ref)
504850cd
NV
1212{
1213 assert(ref);
1214 return git_reference__is_tag(ref->name);
1215}
1216
50ad7cc2
AS
1217int git_reference__is_note(const char *ref_name)
1218{
1219 return git__prefixcmp(ref_name, GIT_REFS_NOTES_DIR) == 0;
1220}
1221
3b4ba278 1222int git_reference_is_note(const git_reference *ref)
50ad7cc2
AS
1223{
1224 assert(ref);
1225 return git_reference__is_note(ref->name);
1226}
1227
31665948 1228static int peel_error(int error, git_reference *ref, const char* msg)
1229{
1230 giterr_set(
1231 GITERR_INVALID,
1232 "The reference '%s' cannot be peeled - %s", git_reference_name(ref), msg);
1233 return error;
1234}
1235
31665948 1236int git_reference_peel(
92dac975
RB
1237 git_object **peeled,
1238 git_reference *ref,
1239 git_otype target_type)
31665948 1240{
1241 git_reference *resolved = NULL;
1242 git_object *target = NULL;
1243 int error;
1244
1245 assert(ref);
1246
3be933b1
VM
1247 if (ref->type == GIT_REF_OID) {
1248 resolved = ref;
1249 } else {
1250 if ((error = git_reference_resolve(&resolved, ref)) < 0)
1251 return peel_error(error, ref, "Cannot resolve reference");
1252 }
1253
fedd0f9e 1254 if (!git_oid_iszero(&resolved->peel)) {
3be933b1 1255 error = git_object_lookup(&target,
fedd0f9e 1256 git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
3be933b1
VM
1257 } else {
1258 error = git_object_lookup(&target,
fedd0f9e 1259 git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY);
3be933b1 1260 }
31665948 1261
3be933b1 1262 if (error < 0) {
31665948 1263 peel_error(error, ref, "Cannot retrieve reference target");
1264 goto cleanup;
1265 }
b90500f0 1266
31665948 1267 if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG)
575a54db 1268 error = git_object_dup(peeled, target);
b90500f0 1269 else
31665948 1270 error = git_object_peel(peeled, target, target_type);
1271
1272cleanup:
1273 git_object_free(target);
3be933b1
VM
1274
1275 if (resolved != ref)
1276 git_reference_free(resolved);
1277
31665948 1278 return error;
1279}
77e06d7e 1280
92dac975 1281int git_reference__is_valid_name(const char *refname, unsigned int flags)
0adfa20a 1282{
92dac975
RB
1283 if (git_reference__normalize_name(NULL, refname, flags) < 0) {
1284 giterr_clear();
1285 return false;
1286 }
83458bb7 1287
92dac975 1288 return true;
0adfa20a 1289}
1290
92dac975 1291int git_reference_is_valid_name(const char *refname)
77e06d7e 1292{
92dac975 1293 return git_reference__is_valid_name(refname, GIT_REF_FORMAT_ALLOW_ONELEVEL);
77e06d7e 1294}
4f2eb2b7 1295
4e498646 1296const char *git_reference__shorthand(const char *name)
4f2eb2b7 1297{
4f2eb2b7
CMN
1298 if (!git__prefixcmp(name, GIT_REFS_HEADS_DIR))
1299 return name + strlen(GIT_REFS_HEADS_DIR);
1300 else if (!git__prefixcmp(name, GIT_REFS_TAGS_DIR))
1301 return name + strlen(GIT_REFS_TAGS_DIR);
1302 else if (!git__prefixcmp(name, GIT_REFS_REMOTES_DIR))
1303 return name + strlen(GIT_REFS_REMOTES_DIR);
1304 else if (!git__prefixcmp(name, GIT_REFS_DIR))
1305 return name + strlen(GIT_REFS_DIR);
1306
1307 /* No shorthands are avaiable, so just return the name */
1308 return name;
1309}
4e498646
CMN
1310
1311const char *git_reference_shorthand(const git_reference *ref)
1312{
1313 return git_reference__shorthand(ref->name);
1314}