545
}
546
}
547
548
+/*
549
+ * generate a format suitable for scanf from a ref_rev_parse_rules
550
+ * rule, that is replace the "%.*s" spec with a "%s" spec
551
+ */
552
+static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
553
+{
554
+ char *spec;
555
+
556
+ spec = strstr(rule, "%.*s");
557
+ if (!spec || strstr(spec + 4, "%.*s"))
558
+ die("invalid rule in ref_rev_parse_rules: %s", rule);
559
+
560
+ /* copy all until spec */
561
+ strncpy(scanf_fmt, rule, spec - rule);
562
+ scanf_fmt[spec - rule] = '\0';
563
+ /* copy new spec */
564
+ strcat(scanf_fmt, "%s");
565
+ /* copy remaining rule */
566
+ strcat(scanf_fmt, spec + 4);
567
+
568
+ return;
569
+}
570
+
571
+/*
572
+ * Shorten the refname to an non-ambiguous form
573
+ */
574
+static char *get_short_ref(struct refinfo *ref)
575
+{
576
+ int i;
577
+ static char **scanf_fmts;
578
+ static int nr_rules;
579
+ char *short_name;
580
+
581
+ /* pre generate scanf formats from ref_rev_parse_rules[] */
582
+ if (!nr_rules) {
583
+ size_t total_len = 0;
584
+
585
+ /* the rule list is NULL terminated, count them first */
586
+ for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
587
+ /* no +1 because strlen("%s") < strlen("%.*s") */
588
+ total_len += strlen(ref_rev_parse_rules[nr_rules]);
589
+
590
+ scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
591
+
592
+ total_len = 0;
593
+ for (i = 0; i < nr_rules; i++) {
594
+ scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
595
+ + total_len;
596
+ gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
597
+ total_len += strlen(ref_rev_parse_rules[i]);
598
+ }
599
+ }
600
+
601
+ /* bail out if there are no rules */
602
+ if (!nr_rules)
603
+ return ref->refname;
604
+
605
+ /* buffer for scanf result, at most ref->refname must fit */
606
+ short_name = xstrdup(ref->refname);
607
+
608
+ /* skip first rule, it will always match */
609
+ for (i = nr_rules - 1; i > 0 ; --i) {
610
+ int j;
611
+ int short_name_len;
612
+
613
+ if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
614
+ continue;
615
+
616
+ short_name_len = strlen(short_name);
617
+
618
+ /*
619
+ * check if the short name resolves to a valid ref,
620
+ * but use only rules prior to the matched one
621
+ */
622
+ for (j = 0; j < i; j++) {
623
+ const char *rule = ref_rev_parse_rules[j];
624
+ unsigned char short_objectname[20];
625
+
626
+ /*
627
+ * the short name is ambiguous, if it resolves
628
+ * (with this previous rule) to a valid ref
629
+ * read_ref() returns 0 on success
630
+ */
631
+ if (!read_ref(mkpath(rule, short_name_len, short_name),
632
+ short_objectname))
633
+ break;
634
+ }
635
+
636
+ /*
637
+ * short name is non-ambiguous if all previous rules
638
+ * haven't resolved to a valid ref
639
+ */
640
+ if (j == i)
641
+ return short_name;
642
+ }
643
+
644
+ free(short_name);
645
+ return ref->refname;
646
+}
647
+
648
+
649
/*
650
* Parse the object referred by ref, and grab needed value.
651
*/
671
for (i = 0; i < used_atom_cnt; i++) {
672
const char *name = used_atom[i];
673
struct atom_value *v = &ref->value[i];
573
- if (!strcmp(name, "refname"))
574
- v->s = ref->refname;
575
- else if (!strcmp(name, "*refname")) {
576
- int len = strlen(ref->refname);
577
- char *s = xmalloc(len + 4);
578
- sprintf(s, "%s^{}", ref->refname);
579
- v->s = s;
674
+ int deref = 0;
675
+ if (*name == '*') {
676
+ deref = 1;
677
+ name++;
678
+ }
679
+ if (!prefixcmp(name, "refname")) {
680
+ const char *formatp = strchr(name, ':');
681
+ const char *refname = ref->refname;
682
+
683
+ /* look for "short" refname format */
684
+ if (formatp) {
685
+ formatp++;
686
+ if (!strcmp(formatp, "short"))
687
+ refname = get_short_ref(ref);
688
+ else
689
+ die("unknown refname format %s",
690
+ formatp);
691
+ }
692
+
693
+ if (!deref)
694
+ v->s = refname;
695
+ else {
696
+ int len = strlen(refname);
697
+ char *s = xmalloc(len + 4);
698
+ sprintf(s, "%s^{}", refname);
699
+ v->s = s;
700
+ }
701
}
702
}
703