@@ -661,14 +661,31 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
661661 mm -> size = size ;
662662}
663663
664- /* Low-level merge functions */
665- typedef int (* ll_merge_fn )(const char * cmd ,
664+ /*
665+ * Customizable low-level merge drivers support.
666+ */
667+
668+ struct ll_merge_driver ;
669+ typedef int (* ll_merge_fn )(const struct ll_merge_driver * ,
670+ const char * path ,
666671 mmfile_t * orig ,
667672 mmfile_t * src1 , const char * name1 ,
668673 mmfile_t * src2 , const char * name2 ,
669674 mmbuffer_t * result );
670675
671- static int ll_xdl_merge (const char * cmd__unused ,
676+ struct ll_merge_driver {
677+ const char * name ;
678+ const char * description ;
679+ ll_merge_fn fn ;
680+ struct ll_merge_driver * next ;
681+ char * cmdline ;
682+ };
683+
684+ /*
685+ * Built-in low-levels
686+ */
687+ static int ll_xdl_merge (const struct ll_merge_driver * drv_unused ,
688+ const char * path_unused ,
672689 mmfile_t * orig ,
673690 mmfile_t * src1 , const char * name1 ,
674691 mmfile_t * src2 , const char * name2 ,
@@ -684,7 +701,8 @@ static int ll_xdl_merge(const char *cmd__unused,
684701 result );
685702}
686703
687- static int ll_union_merge (const char * cmd__unused ,
704+ static int ll_union_merge (const struct ll_merge_driver * drv_unused ,
705+ const char * path_unused ,
688706 mmfile_t * orig ,
689707 mmfile_t * src1 , const char * name1 ,
690708 mmfile_t * src2 , const char * name2 ,
@@ -694,8 +712,8 @@ static int ll_union_merge(const char *cmd__unused,
694712 long size ;
695713 const int marker_size = 7 ;
696714
697- int status = ll_xdl_merge (cmd__unused , orig ,
698- src1 , NULL , src2 , NULL , result );
715+ int status = ll_xdl_merge (drv_unused , path_unused ,
716+ orig , src1 , NULL , src2 , NULL , result );
699717 if (status <= 0 )
700718 return status ;
701719 size = result -> size ;
@@ -726,7 +744,8 @@ static int ll_union_merge(const char *cmd__unused,
726744 return 0 ;
727745}
728746
729- static int ll_binary_merge (const char * cmd__unused ,
747+ static int ll_binary_merge (const struct ll_merge_driver * drv_unused ,
748+ const char * path_unused ,
730749 mmfile_t * orig ,
731750 mmfile_t * src1 , const char * name1 ,
732751 mmfile_t * src2 , const char * name2 ,
@@ -745,14 +764,13 @@ static int ll_binary_merge(const char *cmd__unused,
745764 return 1 ;
746765}
747766
748- static struct {
749- const char * name ;
750- ll_merge_fn fn ;
751- } ll_merge_fns [] = {
752- { "binary" , ll_binary_merge },
753- { "text" , ll_xdl_merge },
754- { "union" , ll_union_merge },
755- { NULL , NULL },
767+ #define LL_BINARY_MERGE 0
768+ #define LL_TEXT_MERGE 1
769+ #define LL_UNION_MERGE 2
770+ static struct ll_merge_driver ll_merge_drv [] = {
771+ { "binary" , "built-in binary merge" , ll_binary_merge },
772+ { "text" , "built-in 3-way text merge" , ll_xdl_merge },
773+ { "union" , "built-in union merge" , ll_union_merge },
756774};
757775
758776static void create_temp (mmfile_t * src , char * path )
@@ -768,7 +786,11 @@ static void create_temp(mmfile_t *src, char *path)
768786 close (fd );
769787}
770788
771- static int ll_ext_merge (const char * cmd ,
789+ /*
790+ * User defined low-level merge driver support.
791+ */
792+ static int ll_ext_merge (const struct ll_merge_driver * fn ,
793+ const char * path ,
772794 mmfile_t * orig ,
773795 mmfile_t * src1 , const char * name1 ,
774796 mmfile_t * src2 , const char * name2 ,
@@ -796,7 +818,10 @@ static int ll_ext_merge(const char *cmd,
796818 interp_set_entry (table , 1 , temp [1 ]);
797819 interp_set_entry (table , 2 , temp [2 ]);
798820
799- interpolate (cmdbuf , sizeof (cmdbuf ), cmd , table , 3 );
821+ output (1 , "merging %s using %s" , path ,
822+ fn -> description ? fn -> description : fn -> name );
823+
824+ interpolate (cmdbuf , sizeof (cmdbuf ), fn -> cmdline , table , 3 );
800825
801826 memset (& child , 0 , sizeof (child ));
802827 child .argv = args ;
@@ -833,101 +858,124 @@ static int ll_ext_merge(const char *cmd,
833858/*
834859 * merge.default and merge.driver configuration items
835860 */
836- static struct user_merge_fn {
837- struct user_merge_fn * next ;
838- const char * name ;
839- char * cmdline ;
840- char b_ [1 ];
841- } * ll_user_merge_fns , * * ll_user_merge_fns_tail ;
861+ static struct ll_merge_driver * ll_user_merge , * * ll_user_merge_tail ;
842862static const char * default_ll_merge ;
843863
844864static int read_merge_config (const char * var , const char * value )
845865{
846- struct user_merge_fn * fn ;
847- int blen , nlen ;
866+ struct ll_merge_driver * fn ;
867+ const char * ep , * name ;
868+ int namelen ;
848869
849870 if (!strcmp (var , "merge.default" )) {
850- default_ll_merge = strdup (value );
871+ if (value )
872+ default_ll_merge = strdup (value );
851873 return 0 ;
852874 }
853875
854- if (strcmp (var , "merge.driver" ))
876+ /*
877+ * We are not interested in anything but "merge.<name>.variable";
878+ * especially, we do not want to look at variables such as
879+ * "merge.summary", "merge.tool", and "merge.verbosity".
880+ */
881+ if (prefixcmp (var , "merge." ) || (ep = strrchr (var , '.' )) == var + 6 )
855882 return 0 ;
856- if (!value )
857- return error ("%s: lacks value" , var );
883+
858884 /*
859- * merge.driver is a multi-valued configuration, whose value is
860- * of form:
861- *
862- * name command-line
863- *
864- * The command-line will be interpolated with the following
865- * tokens and is given to the shell:
866- *
867- * %O - temporary file name for the merge base.
868- * %A - temporary file name for our version.
869- * %B - temporary file name for the other branches' version.
870- *
871- * The external merge driver should write the results in the file
872- * named by %A, and signal that it has done with exit status 0.
885+ * Find existing one as we might be processing merge.<name>.var2
886+ * after seeing merge.<name>.var1.
873887 */
874- for (nlen = -1 , blen = 0 ; value [blen ]; blen ++ )
875- if (nlen < 0 && isspace (value [blen ]))
876- nlen = blen ;
877- if (nlen < 0 )
878- return error ("%s '%s': lacks command line" , var , value );
879- fn = xcalloc (1 , sizeof (struct user_merge_fn ) + blen + 1 );
880- memcpy (fn -> b_ , value , blen + 1 );
881- fn -> name = fn -> b_ ;
882- fn -> b_ [nlen ] = 0 ;
883- fn -> cmdline = fn -> b_ + nlen + 1 ;
884- fn -> next = * ll_user_merge_fns_tail ;
885- * ll_user_merge_fns_tail = fn ;
888+ name = var + 6 ;
889+ namelen = ep - name ;
890+ for (fn = ll_user_merge ; fn ; fn = fn -> next )
891+ if (!strncmp (fn -> name , name , namelen ) && !fn -> name [namelen ])
892+ break ;
893+ if (!fn ) {
894+ char * namebuf ;
895+ fn = xcalloc (1 , sizeof (struct ll_merge_driver ));
896+ namebuf = xmalloc (namelen + 1 );
897+ memcpy (namebuf , name , namelen );
898+ namebuf [namelen ] = 0 ;
899+ fn -> name = namebuf ;
900+ fn -> fn = ll_ext_merge ;
901+ fn -> next = * ll_user_merge_tail ;
902+ * ll_user_merge_tail = fn ;
903+ }
904+
905+ ep ++ ;
906+
907+ if (!strcmp ("name" , ep )) {
908+ if (!value )
909+ return error ("%s: lacks value" , var );
910+ fn -> description = strdup (value );
911+ return 0 ;
912+ }
913+
914+ if (!strcmp ("driver" , ep )) {
915+ if (!value )
916+ return error ("%s: lacks value" , var );
917+ /*
918+ * merge.<name>.driver specifies the command line:
919+ *
920+ * command-line
921+ *
922+ * The command-line will be interpolated with the following
923+ * tokens and is given to the shell:
924+ *
925+ * %O - temporary file name for the merge base.
926+ * %A - temporary file name for our version.
927+ * %B - temporary file name for the other branches' version.
928+ *
929+ * The external merge driver should write the results in the
930+ * file named by %A, and signal that it has done with zero exit
931+ * status.
932+ */
933+ fn -> cmdline = strdup (value );
934+ return 0 ;
935+ }
936+
886937 return 0 ;
887938}
888939
889940static void initialize_ll_merge (void )
890941{
891- if (ll_user_merge_fns_tail )
942+ if (ll_user_merge_tail )
892943 return ;
893- ll_user_merge_fns_tail = & ll_user_merge_fns ;
944+ ll_user_merge_tail = & ll_user_merge ;
894945 git_config (read_merge_config );
895946}
896947
897- static ll_merge_fn find_ll_merge_fn (void * merge_attr , const char * * cmdline )
948+ static const struct ll_merge_driver * find_ll_merge_driver (void * merge_attr )
898949{
899- struct user_merge_fn * fn ;
950+ struct ll_merge_driver * fn ;
900951 const char * name ;
901952 int i ;
902953
903954 initialize_ll_merge ();
904955
905956 if (ATTR_TRUE (merge_attr ))
906- return ll_xdl_merge ;
957+ return & ll_merge_drv [ LL_TEXT_MERGE ] ;
907958 else if (ATTR_FALSE (merge_attr ))
908- return ll_binary_merge ;
959+ return & ll_merge_drv [ LL_BINARY_MERGE ] ;
909960 else if (ATTR_UNSET (merge_attr )) {
910961 if (!default_ll_merge )
911- return ll_xdl_merge ;
962+ return & ll_merge_drv [ LL_TEXT_MERGE ] ;
912963 else
913964 name = default_ll_merge ;
914965 }
915966 else
916967 name = merge_attr ;
917968
918- for (fn = ll_user_merge_fns ; fn ; fn = fn -> next ) {
919- if (!strcmp (fn -> name , name )) {
920- * cmdline = fn -> cmdline ;
921- return ll_ext_merge ;
922- }
923- }
969+ for (fn = ll_user_merge ; fn ; fn = fn -> next )
970+ if (!strcmp (fn -> name , name ))
971+ return fn ;
924972
925- for (i = 0 ; ll_merge_fns [ i ]. name ; i ++ )
926- if (!strcmp (ll_merge_fns [i ].name , name ))
927- return ll_merge_fns [i ]. fn ;
973+ for (i = 0 ; i < ARRAY_SIZE ( ll_merge_drv ) ; i ++ )
974+ if (!strcmp (ll_merge_drv [i ].name , name ))
975+ return & ll_merge_drv [i ];
928976
929977 /* default to the 3-way */
930- return ll_xdl_merge ;
978+ return & ll_merge_drv [ LL_TEXT_MERGE ] ;
931979}
932980
933981static void * git_path_check_merge (const char * path )
@@ -953,8 +1001,7 @@ static int ll_merge(mmbuffer_t *result_buf,
9531001 char * name1 , * name2 ;
9541002 int merge_status ;
9551003 void * merge_attr ;
956- ll_merge_fn fn ;
957- const char * driver = NULL ;
1004+ const struct ll_merge_driver * driver ;
9581005
9591006 name1 = xstrdup (mkpath ("%s:%s" , branch1 , a -> path ));
9601007 name2 = xstrdup (mkpath ("%s:%s" , branch2 , b -> path ));
@@ -964,10 +1011,11 @@ static int ll_merge(mmbuffer_t *result_buf,
9641011 fill_mm (b -> sha1 , & src2 );
9651012
9661013 merge_attr = git_path_check_merge (a -> path );
967- fn = find_ll_merge_fn (merge_attr , & driver );
1014+ driver = find_ll_merge_driver (merge_attr );
9681015
969- merge_status = fn (driver , & orig ,
970- & src1 , name1 , & src2 , name2 , result_buf );
1016+ merge_status = driver -> fn (driver , a -> path ,
1017+ & orig , & src1 , name1 , & src2 , name2 ,
1018+ result_buf );
9711019
9721020 free (name1 );
9731021 free (name2 );
0 commit comments