@@ -127,8 +127,8 @@ static struct used_atom {
127127 unsigned int nobracket : 1 , push : 1 , push_remote : 1 ;
128128 } remote_ref ;
129129 struct {
130- enum { C_BARE , C_BODY , C_BODY_DEP , C_LENGTH ,
131- C_LINES , C_SIG , C_SUB , C_TRAILERS } option ;
130+ enum { C_BARE , C_BODY , C_BODY_DEP , C_LENGTH , C_LINES ,
131+ C_SIG , C_SUB , C_SUB_SANITIZE , C_TRAILERS } option ;
132132 struct process_trailer_options trailer_opts ;
133133 unsigned int nlines ;
134134 } contents ;
@@ -139,7 +139,10 @@ static struct used_atom {
139139 struct {
140140 enum { O_FULL , O_LENGTH , O_SHORT } option ;
141141 unsigned int length ;
142- } objectname ;
142+ } oid ;
143+ struct email_option {
144+ enum { EO_RAW , EO_TRIM , EO_LOCALPART } option ;
145+ } email_option ;
143146 struct refname_atom refname ;
144147 char * head ;
145148 } u ;
@@ -298,9 +301,12 @@ static int body_atom_parser(const struct ref_format *format, struct used_atom *a
298301static int subject_atom_parser (const struct ref_format * format , struct used_atom * atom ,
299302 const char * arg , struct strbuf * err )
300303{
301- if (arg )
302- return strbuf_addf_ret (err , -1 , _ ("%%(subject) does not take arguments" ));
303- atom -> u .contents .option = C_SUB ;
304+ if (!arg )
305+ atom -> u .contents .option = C_SUB ;
306+ else if (!strcmp (arg , "sanitize" ))
307+ atom -> u .contents .option = C_SUB_SANITIZE ;
308+ else
309+ return strbuf_addf_ret (err , -1 , _ ("unrecognized %%(subject) argument: %s" ), arg );
304310 return 0 ;
305311}
306312
@@ -360,22 +366,36 @@ static int contents_atom_parser(const struct ref_format *format, struct used_ato
360366 return 0 ;
361367}
362368
363- static int objectname_atom_parser (const struct ref_format * format , struct used_atom * atom ,
364- const char * arg , struct strbuf * err )
369+ static int oid_atom_parser (const struct ref_format * format , struct used_atom * atom ,
370+ const char * arg , struct strbuf * err )
365371{
366372 if (!arg )
367- atom -> u .objectname .option = O_FULL ;
373+ atom -> u .oid .option = O_FULL ;
368374 else if (!strcmp (arg , "short" ))
369- atom -> u .objectname .option = O_SHORT ;
375+ atom -> u .oid .option = O_SHORT ;
370376 else if (skip_prefix (arg , "short=" , & arg )) {
371- atom -> u .objectname .option = O_LENGTH ;
372- if (strtoul_ui (arg , 10 , & atom -> u .objectname .length ) ||
373- atom -> u .objectname .length == 0 )
374- return strbuf_addf_ret (err , -1 , _ ("positive value expected objectname:short=%s " ), arg );
375- if (atom -> u .objectname .length < MINIMUM_ABBREV )
376- atom -> u .objectname .length = MINIMUM_ABBREV ;
377+ atom -> u .oid .option = O_LENGTH ;
378+ if (strtoul_ui (arg , 10 , & atom -> u .oid .length ) ||
379+ atom -> u .oid .length == 0 )
380+ return strbuf_addf_ret (err , -1 , _ ("positive value expected '%s' in %%(%s) " ), arg , atom -> name );
381+ if (atom -> u .oid .length < MINIMUM_ABBREV )
382+ atom -> u .oid .length = MINIMUM_ABBREV ;
377383 } else
378- return strbuf_addf_ret (err , -1 , _ ("unrecognized %%(objectname) argument: %s" ), arg );
384+ return strbuf_addf_ret (err , -1 , _ ("unrecognized argument '%s' in %%(%s)" ), arg , atom -> name );
385+ return 0 ;
386+ }
387+
388+ static int person_email_atom_parser (const struct ref_format * format , struct used_atom * atom ,
389+ const char * arg , struct strbuf * err )
390+ {
391+ if (!arg )
392+ atom -> u .email_option .option = EO_RAW ;
393+ else if (!strcmp (arg , "trim" ))
394+ atom -> u .email_option .option = EO_TRIM ;
395+ else if (!strcmp (arg , "localpart" ))
396+ atom -> u .email_option .option = EO_LOCALPART ;
397+ else
398+ return strbuf_addf_ret (err , -1 , _ ("unrecognized email option: %s" ), arg );
379399 return 0 ;
380400}
381401
@@ -480,25 +500,25 @@ static struct {
480500 { "refname" , SOURCE_NONE , FIELD_STR , refname_atom_parser },
481501 { "objecttype" , SOURCE_OTHER , FIELD_STR , objecttype_atom_parser },
482502 { "objectsize" , SOURCE_OTHER , FIELD_ULONG , objectsize_atom_parser },
483- { "objectname" , SOURCE_OTHER , FIELD_STR , objectname_atom_parser },
503+ { "objectname" , SOURCE_OTHER , FIELD_STR , oid_atom_parser },
484504 { "deltabase" , SOURCE_OTHER , FIELD_STR , deltabase_atom_parser },
485- { "tree" , SOURCE_OBJ },
486- { "parent" , SOURCE_OBJ },
505+ { "tree" , SOURCE_OBJ , FIELD_STR , oid_atom_parser },
506+ { "parent" , SOURCE_OBJ , FIELD_STR , oid_atom_parser },
487507 { "numparent" , SOURCE_OBJ , FIELD_ULONG },
488508 { "object" , SOURCE_OBJ },
489509 { "type" , SOURCE_OBJ },
490510 { "tag" , SOURCE_OBJ },
491511 { "author" , SOURCE_OBJ },
492512 { "authorname" , SOURCE_OBJ },
493- { "authoremail" , SOURCE_OBJ },
513+ { "authoremail" , SOURCE_OBJ , FIELD_STR , person_email_atom_parser },
494514 { "authordate" , SOURCE_OBJ , FIELD_TIME },
495515 { "committer" , SOURCE_OBJ },
496516 { "committername" , SOURCE_OBJ },
497- { "committeremail" , SOURCE_OBJ },
517+ { "committeremail" , SOURCE_OBJ , FIELD_STR , person_email_atom_parser },
498518 { "committerdate" , SOURCE_OBJ , FIELD_TIME },
499519 { "tagger" , SOURCE_OBJ },
500520 { "taggername" , SOURCE_OBJ },
501- { "taggeremail" , SOURCE_OBJ },
521+ { "taggeremail" , SOURCE_OBJ , FIELD_STR , person_email_atom_parser },
502522 { "taggerdate" , SOURCE_OBJ , FIELD_TIME },
503523 { "creator" , SOURCE_OBJ },
504524 { "creatordate" , SOURCE_OBJ , FIELD_TIME },
@@ -903,21 +923,27 @@ int verify_ref_format(struct ref_format *format)
903923 return 0 ;
904924}
905925
906- static int grab_objectname (const char * name , const struct object_id * oid ,
907- struct atom_value * v , struct used_atom * atom )
926+ static const char * do_grab_oid (const char * field , const struct object_id * oid ,
927+ struct used_atom * atom )
908928{
909- if (starts_with (name , "objectname" )) {
910- if (atom -> u .objectname .option == O_SHORT ) {
911- v -> s = xstrdup (find_unique_abbrev (oid , DEFAULT_ABBREV ));
912- return 1 ;
913- } else if (atom -> u .objectname .option == O_FULL ) {
914- v -> s = xstrdup (oid_to_hex (oid ));
915- return 1 ;
916- } else if (atom -> u .objectname .option == O_LENGTH ) {
917- v -> s = xstrdup (find_unique_abbrev (oid , atom -> u .objectname .length ));
918- return 1 ;
919- } else
920- BUG ("unknown %%(objectname) option" );
929+ switch (atom -> u .oid .option ) {
930+ case O_FULL :
931+ return oid_to_hex (oid );
932+ case O_LENGTH :
933+ return find_unique_abbrev (oid , atom -> u .oid .length );
934+ case O_SHORT :
935+ return find_unique_abbrev (oid , DEFAULT_ABBREV );
936+ default :
937+ BUG ("unknown %%(%s) option" , field );
938+ }
939+ }
940+
941+ static int grab_oid (const char * name , const char * field , const struct object_id * oid ,
942+ struct atom_value * v , struct used_atom * atom )
943+ {
944+ if (starts_with (name , field )) {
945+ v -> s = xstrdup (do_grab_oid (field , oid , atom ));
946+ return 1 ;
921947 }
922948 return 0 ;
923949}
@@ -945,7 +971,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_
945971 } else if (!strcmp (name , "deltabase" ))
946972 v -> s = xstrdup (oid_to_hex (& oi -> delta_base_oid ));
947973 else if (deref )
948- grab_objectname (name , & oi -> oid , v , & used_atom [i ]);
974+ grab_oid (name , "objectname" , & oi -> oid , v , & used_atom [i ]);
949975 }
950976}
951977
@@ -984,21 +1010,20 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
9841010 continue ;
9851011 if (deref )
9861012 name ++ ;
987- if (!strcmp (name , "tree" )) {
988- v -> s = xstrdup (oid_to_hex (get_commit_tree_oid (commit )));
989- }
990- else if (!strcmp (name , "numparent" )) {
1013+ if (grab_oid (name , "tree" , get_commit_tree_oid (commit ), v , & used_atom [i ]))
1014+ continue ;
1015+ if (!strcmp (name , "numparent" )) {
9911016 v -> value = commit_list_count (commit -> parents );
9921017 v -> s = xstrfmt ("%lu" , (unsigned long )v -> value );
9931018 }
994- else if (! strcmp (name , "parent" )) {
1019+ else if (starts_with (name , "parent" )) {
9951020 struct commit_list * parents ;
9961021 struct strbuf s = STRBUF_INIT ;
9971022 for (parents = commit -> parents ; parents ; parents = parents -> next ) {
998- struct commit * parent = parents -> item ;
1023+ struct object_id * oid = & parents -> item -> object . oid ;
9991024 if (parents != commit -> parents )
10001025 strbuf_addch (& s , ' ' );
1001- strbuf_addstr (& s , oid_to_hex ( & parent -> object . oid ));
1026+ strbuf_addstr (& s , do_grab_oid ( " parent" , oid , & used_atom [ i ] ));
10021027 }
10031028 v -> s = strbuf_detach (& s , NULL );
10041029 }
@@ -1039,16 +1064,35 @@ static const char *copy_name(const char *buf)
10391064 return xstrdup ("" );
10401065}
10411066
1042- static const char * copy_email (const char * buf )
1067+ static const char * copy_email (const char * buf , struct used_atom * atom )
10431068{
10441069 const char * email = strchr (buf , '<' );
10451070 const char * eoemail ;
10461071 if (!email )
10471072 return xstrdup ("" );
1048- eoemail = strchr (email , '>' );
1073+ switch (atom -> u .email_option .option ) {
1074+ case EO_RAW :
1075+ eoemail = strchr (email , '>' );
1076+ if (eoemail )
1077+ eoemail ++ ;
1078+ break ;
1079+ case EO_TRIM :
1080+ email ++ ;
1081+ eoemail = strchr (email , '>' );
1082+ break ;
1083+ case EO_LOCALPART :
1084+ email ++ ;
1085+ eoemail = strchr (email , '@' );
1086+ if (!eoemail )
1087+ eoemail = strchr (email , '>' );
1088+ break ;
1089+ default :
1090+ BUG ("unknown email option" );
1091+ }
1092+
10491093 if (!eoemail )
10501094 return xstrdup ("" );
1051- return xmemdupz (email , eoemail + 1 - email );
1095+ return xmemdupz (email , eoemail - email );
10521096}
10531097
10541098static char * copy_subject (const char * buf , unsigned long len )
@@ -1118,7 +1162,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
11181162 continue ;
11191163 if (name [wholen ] != 0 &&
11201164 strcmp (name + wholen , "name" ) &&
1121- strcmp (name + wholen , "email" ) &&
1165+ ! starts_with (name + wholen , "email" ) &&
11221166 !starts_with (name + wholen , "date" ))
11231167 continue ;
11241168 if (!wholine )
@@ -1129,8 +1173,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
11291173 v -> s = copy_line (wholine );
11301174 else if (!strcmp (name + wholen , "name" ))
11311175 v -> s = copy_name (wholine );
1132- else if (! strcmp (name + wholen , "email" ))
1133- v -> s = copy_email (wholine );
1176+ else if (starts_with (name + wholen , "email" ))
1177+ v -> s = copy_email (wholine , & used_atom [ i ] );
11341178 else if (starts_with (name + wholen , "date" ))
11351179 grab_date (wholine , v , name );
11361180 }
@@ -1243,8 +1287,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
12431287 continue ;
12441288 if (deref )
12451289 name ++ ;
1246- if (strcmp (name , "subject " ) &&
1247- strcmp (name , "body " ) &&
1290+ if (strcmp (name , "body " ) &&
1291+ ! starts_with (name , "subject " ) &&
12481292 !starts_with (name , "trailers" ) &&
12491293 !starts_with (name , "contents" ))
12501294 continue ;
@@ -1256,7 +1300,11 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
12561300
12571301 if (atom -> u .contents .option == C_SUB )
12581302 v -> s = copy_subject (subpos , sublen );
1259- else if (atom -> u .contents .option == C_BODY_DEP )
1303+ else if (atom -> u .contents .option == C_SUB_SANITIZE ) {
1304+ struct strbuf sb = STRBUF_INIT ;
1305+ format_sanitized_subject (& sb , subpos , sublen );
1306+ v -> s = strbuf_detach (& sb , NULL );
1307+ } else if (atom -> u .contents .option == C_BODY_DEP )
12601308 v -> s = xmemdupz (bodypos , bodylen );
12611309 else if (atom -> u .contents .option == C_LENGTH )
12621310 v -> s = xstrfmt ("%" PRIuMAX , (uintmax_t )strlen (subpos ));
@@ -1706,7 +1754,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
17061754 v -> s = xstrdup (buf + 1 );
17071755 }
17081756 continue ;
1709- } else if (!deref && grab_objectname (name , & ref -> objectname , v , atom )) {
1757+ } else if (!deref && grab_oid (name , "objectname" , & ref -> objectname , v , atom )) {
17101758 continue ;
17111759 } else if (!strcmp (name , "HEAD" )) {
17121760 if (atom -> u .head && !strcmp (ref -> refname , atom -> u .head ))
0 commit comments