@@ -1310,65 +1310,68 @@ int update_ref(const char *msg, const char *refname,
13101310 old_oid , flags , onerr );
13111311}
13121312
1313+ /*
1314+ * Check that the string refname matches a rule of the form
1315+ * "{prefix}%.*s{suffix}". So "foo/bar/baz" would match the rule
1316+ * "foo/%.*s/baz", and return the string "bar".
1317+ */
1318+ static const char * match_parse_rule (const char * refname , const char * rule ,
1319+ size_t * len )
1320+ {
1321+ /*
1322+ * Check that rule matches refname up to the first percent in the rule.
1323+ * We can bail immediately if not, but otherwise we leave "rule" at the
1324+ * %-placeholder, and "refname" at the start of the potential matched
1325+ * name.
1326+ */
1327+ while (* rule != '%' ) {
1328+ if (!* rule )
1329+ BUG ("rev-parse rule did not have percent" );
1330+ if (* refname ++ != * rule ++ )
1331+ return NULL ;
1332+ }
1333+
1334+ /*
1335+ * Check that our "%" is the expected placeholder. This assumes there
1336+ * are no other percents (placeholder or quoted) in the string, but
1337+ * that is sufficient for our rev-parse rules.
1338+ */
1339+ if (!skip_prefix (rule , "%.*s" , & rule ))
1340+ return NULL ;
1341+
1342+ /*
1343+ * And now check that our suffix (if any) matches.
1344+ */
1345+ if (!strip_suffix (refname , rule , len ))
1346+ return NULL ;
1347+
1348+ return refname ; /* len set by strip_suffix() */
1349+ }
1350+
13131351char * refs_shorten_unambiguous_ref (struct ref_store * refs ,
13141352 const char * refname , int strict )
13151353{
13161354 int i ;
1317- static char * * scanf_fmts ;
1318- static int nr_rules ;
1319- char * short_name ;
13201355 struct strbuf resolved_buf = STRBUF_INIT ;
13211356
1322- if (!nr_rules ) {
1323- /*
1324- * Pre-generate scanf formats from ref_rev_parse_rules[].
1325- * Generate a format suitable for scanf from a
1326- * ref_rev_parse_rules rule by interpolating "%s" at the
1327- * location of the "%.*s".
1328- */
1329- size_t total_len = 0 ;
1330- size_t offset = 0 ;
1331-
1332- /* the rule list is NULL terminated, count them first */
1333- for (nr_rules = 0 ; ref_rev_parse_rules [nr_rules ]; nr_rules ++ )
1334- /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
1335- total_len += strlen (ref_rev_parse_rules [nr_rules ]) - 2 + 1 ;
1336-
1337- scanf_fmts = xmalloc (st_add (st_mult (sizeof (char * ), nr_rules ), total_len ));
1338-
1339- offset = 0 ;
1340- for (i = 0 ; i < nr_rules ; i ++ ) {
1341- assert (offset < total_len );
1342- scanf_fmts [i ] = (char * )& scanf_fmts [nr_rules ] + offset ;
1343- offset += xsnprintf (scanf_fmts [i ], total_len - offset ,
1344- ref_rev_parse_rules [i ], 2 , "%s" ) + 1 ;
1345- }
1346- }
1347-
1348- /* bail out if there are no rules */
1349- if (!nr_rules )
1350- return xstrdup (refname );
1351-
1352- /* buffer for scanf result, at most refname must fit */
1353- short_name = xstrdup (refname );
1354-
13551357 /* skip first rule, it will always match */
1356- for (i = nr_rules - 1 ; i > 0 ; -- i ) {
1358+ for (i = NUM_REV_PARSE_RULES - 1 ; i > 0 ; -- i ) {
13571359 int j ;
13581360 int rules_to_fail = i ;
1359- int short_name_len ;
1361+ const char * short_name ;
1362+ size_t short_name_len ;
13601363
1361- if (1 != sscanf (refname , scanf_fmts [i ], short_name ))
1364+ short_name = match_parse_rule (refname , ref_rev_parse_rules [i ],
1365+ & short_name_len );
1366+ if (!short_name )
13621367 continue ;
13631368
1364- short_name_len = strlen (short_name );
1365-
13661369 /*
13671370 * in strict mode, all (except the matched one) rules
13681371 * must fail to resolve to a valid non-ambiguous ref
13691372 */
13701373 if (strict )
1371- rules_to_fail = nr_rules ;
1374+ rules_to_fail = NUM_REV_PARSE_RULES ;
13721375
13731376 /*
13741377 * check if the short name resolves to a valid ref,
@@ -1388,7 +1391,8 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
13881391 */
13891392 strbuf_reset (& resolved_buf );
13901393 strbuf_addf (& resolved_buf , rule ,
1391- short_name_len , short_name );
1394+ cast_size_t_to_int (short_name_len ),
1395+ short_name );
13921396 if (refs_ref_exists (refs , resolved_buf .buf ))
13931397 break ;
13941398 }
@@ -1399,12 +1403,11 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
13991403 */
14001404 if (j == rules_to_fail ) {
14011405 strbuf_release (& resolved_buf );
1402- return short_name ;
1406+ return xmemdupz ( short_name , short_name_len ) ;
14031407 }
14041408 }
14051409
14061410 strbuf_release (& resolved_buf );
1407- free (short_name );
14081411 return xstrdup (refname );
14091412}
14101413
0 commit comments