@@ -545,6 +545,107 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
545545 }
546546}
547547
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+
548649/*
549650 * Parse the object referred by ref, and grab needed value.
550651 */
@@ -570,13 +671,33 @@ static void populate_value(struct refinfo *ref)
570671 for (i = 0 ; i < used_atom_cnt ; i ++ ) {
571672 const char * name = used_atom [i ];
572673 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+ }
580701 }
581702 }
582703
0 commit comments