@@ -669,55 +669,131 @@ static int write_author_script(const char *message)
669
669
return res ;
670
670
}
671
671
672
+ /**
673
+ * Take a series of KEY='VALUE' lines where VALUE part is
674
+ * sq-quoted, and append <KEY, VALUE> at the end of the string list
675
+ */
676
+ static int parse_key_value_squoted (char * buf , struct string_list * list )
677
+ {
678
+ while (* buf ) {
679
+ struct string_list_item * item ;
680
+ char * np ;
681
+ char * cp = strchr (buf , '=' );
682
+ if (!cp ) {
683
+ np = strchrnul (buf , '\n' );
684
+ return error (_ ("no key present in '%.*s'" ),
685
+ (int ) (np - buf ), buf );
686
+ }
687
+ np = strchrnul (cp , '\n' );
688
+ * cp ++ = '\0' ;
689
+ item = string_list_append (list , buf );
690
+
691
+ buf = np + (* np == '\n' );
692
+ * np = '\0' ;
693
+ cp = sq_dequote (cp );
694
+ if (!cp )
695
+ return error (_ ("unable to dequote value of '%s'" ),
696
+ item -> string );
697
+ item -> util = xstrdup (cp );
698
+ }
699
+ return 0 ;
700
+ }
672
701
673
- /*
674
- * write_author_script() used to fail to terminate the last line with a "'" and
675
- * also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
676
- * the terminating "'" on the last line to see how "'" has been escaped in case
677
- * git was upgraded while rebase was stopped.
702
+ /**
703
+ * Reads and parses the state directory's "author-script" file, and sets name,
704
+ * email and date accordingly.
705
+ * Returns 0 on success, -1 if the file could not be parsed.
706
+ *
707
+ * The author script is of the format:
708
+ *
709
+ * GIT_AUTHOR_NAME='$author_name'
710
+ * GIT_AUTHOR_EMAIL='$author_email'
711
+ * GIT_AUTHOR_DATE='$author_date'
712
+ *
713
+ * where $author_name, $author_email and $author_date are quoted. We are strict
714
+ * with our parsing, as the file was meant to be eval'd in the old
715
+ * git-am.sh/git-rebase--interactive.sh scripts, and thus if the file differs
716
+ * from what this function expects, it is better to bail out than to do
717
+ * something that the user does not expect.
678
718
*/
679
- static int quoting_is_broken (const char * s , size_t n )
719
+ int read_author_script (const char * path , char * * name , char * * email , char * * date ,
720
+ int allow_missing )
680
721
{
681
- /* Skip any empty lines in case the file was hand edited */
682
- while (n > 0 && s [-- n ] == '\n' )
683
- ; /* empty */
684
- if (n > 0 && s [n ] != '\'' )
685
- return 1 ;
722
+ struct strbuf buf = STRBUF_INIT ;
723
+ struct string_list kv = STRING_LIST_INIT_DUP ;
724
+ int retval = -1 ; /* assume failure */
725
+ int i , name_i = -2 , email_i = -2 , date_i = -2 , err = 0 ;
686
726
687
- return 0 ;
727
+ if (strbuf_read_file (& buf , path , 256 ) <= 0 ) {
728
+ strbuf_release (& buf );
729
+ if (errno == ENOENT && allow_missing )
730
+ return 0 ;
731
+ else
732
+ return error_errno (_ ("could not open '%s' for reading" ),
733
+ path );
734
+ }
735
+
736
+ if (parse_key_value_squoted (buf .buf , & kv ))
737
+ goto finish ;
738
+
739
+ for (i = 0 ; i < kv .nr ; i ++ ) {
740
+ if (!strcmp (kv .items [i ].string , "GIT_AUTHOR_NAME" )) {
741
+ if (name_i != -2 )
742
+ name_i = error (_ ("'GIT_AUTHOR_NAME' already given" ));
743
+ else
744
+ name_i = i ;
745
+ } else if (!strcmp (kv .items [i ].string , "GIT_AUTHOR_EMAIL" )) {
746
+ if (email_i != -2 )
747
+ email_i = error (_ ("'GIT_AUTHOR_EMAIL' already given" ));
748
+ else
749
+ email_i = i ;
750
+ } else if (!strcmp (kv .items [i ].string , "GIT_AUTHOR_DATE" )) {
751
+ if (date_i != -2 )
752
+ date_i = error (_ ("'GIT_AUTHOR_DATE' already given" ));
753
+ else
754
+ date_i = i ;
755
+ } else {
756
+ err = error (_ ("unknown variable '%s'" ),
757
+ kv .items [i ].string );
758
+ }
759
+ }
760
+ if (name_i == -2 )
761
+ error (_ ("missing 'GIT_AUTHOR_NAME'" ));
762
+ if (email_i == -2 )
763
+ error (_ ("missing 'GIT_AUTHOR_EMAIL'" ));
764
+ if (date_i == -2 )
765
+ error (_ ("missing 'GIT_AUTHOR_DATE'" ));
766
+ if (date_i < 0 || email_i < 0 || date_i < 0 || err )
767
+ goto finish ;
768
+ * name = kv .items [name_i ].util ;
769
+ * email = kv .items [email_i ].util ;
770
+ * date = kv .items [date_i ].util ;
771
+ retval = 0 ;
772
+ finish :
773
+ string_list_clear (& kv , !!retval );
774
+ strbuf_release (& buf );
775
+ return retval ;
688
776
}
689
777
690
778
/*
691
- * Read a list of environment variable assignments (such as the author-script
692
- * file) into an environment block. Returns -1 on error, 0 otherwise.
779
+ * Read a GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL AND GIT_AUTHOR_DATE from a
780
+ * file with shell quoting into struct argv_array. Returns -1 on
781
+ * error, 0 otherwise.
693
782
*/
694
783
static int read_env_script (struct argv_array * env )
695
784
{
696
- struct strbuf script = STRBUF_INIT ;
697
- int i , count = 0 , sq_bug ;
698
- const char * p2 ;
699
- char * p ;
785
+ char * name , * email , * date ;
700
786
701
- if (strbuf_read_file (& script , rebase_path_author_script (), 256 ) <= 0 )
787
+ if (read_author_script (rebase_path_author_script (),
788
+ & name , & email , & date , 0 ))
702
789
return -1 ;
703
- /* write_author_script() used to quote incorrectly */
704
- sq_bug = quoting_is_broken (script .buf , script .len );
705
- for (p = script .buf ; * p ; p ++ )
706
- if (sq_bug && skip_prefix (p , "'\\\\''" , & p2 ))
707
- strbuf_splice (& script , p - script .buf , p2 - p , "'" , 1 );
708
- else if (skip_prefix (p , "'\\''" , & p2 ))
709
- strbuf_splice (& script , p - script .buf , p2 - p , "'" , 1 );
710
- else if (* p == '\'' )
711
- strbuf_splice (& script , p -- - script .buf , 1 , "" , 0 );
712
- else if (* p == '\n' ) {
713
- * p = '\0' ;
714
- count ++ ;
715
- }
716
790
717
- for (i = 0 , p = script .buf ; i < count ; i ++ ) {
718
- argv_array_push (env , p );
719
- p += strlen (p ) + 1 ;
720
- }
791
+ argv_array_pushf (env , "GIT_AUTHOR_NAME=%s" , name );
792
+ argv_array_pushf (env , "GIT_AUTHOR_EMAIL=%s" , email );
793
+ argv_array_pushf (env , "GIT_AUTHOR_DATE=%s" , date );
794
+ free (name );
795
+ free (email );
796
+ free (date );
721
797
722
798
return 0 ;
723
799
}
@@ -737,54 +813,28 @@ static char *get_author(const char *message)
737
813
/* Read author-script and return an ident line (author <email> timestamp) */
738
814
static const char * read_author_ident (struct strbuf * buf )
739
815
{
740
- const char * keys [] = {
741
- "GIT_AUTHOR_NAME=" , "GIT_AUTHOR_EMAIL=" , "GIT_AUTHOR_DATE="
742
- };
743
816
struct strbuf out = STRBUF_INIT ;
744
- char * in , * eol ;
745
- const char * val [3 ];
746
- int i = 0 ;
817
+ char * name , * email , * date ;
747
818
748
- if (strbuf_read_file (buf , rebase_path_author_script (), 256 ) <= 0 )
819
+ if (read_author_script (rebase_path_author_script (),
820
+ & name , & email , & date , 0 ))
749
821
return NULL ;
750
822
751
- /* dequote values and construct ident line in-place */
752
- for (in = buf -> buf ; i < 3 && in - buf -> buf < buf -> len ; i ++ ) {
753
- if (!skip_prefix (in , keys [i ], (const char * * )& in )) {
754
- warning (_ ("could not parse '%s' (looking for '%s')" ),
755
- rebase_path_author_script (), keys [i ]);
756
- return NULL ;
757
- }
758
-
759
- eol = strchrnul (in , '\n' );
760
- * eol = '\0' ;
761
- if (!sq_dequote (in )) {
762
- warning (_ ("bad quoting on %s value in '%s'" ),
763
- keys [i ], rebase_path_author_script ());
764
- return NULL ;
765
- }
766
- val [i ] = in ;
767
- in = eol + 1 ;
768
- }
769
-
770
- if (i < 3 ) {
771
- warning (_ ("could not parse '%s' (looking for '%s')" ),
772
- rebase_path_author_script (), keys [i ]);
773
- return NULL ;
774
- }
775
-
776
823
/* validate date since fmt_ident() will die() on bad value */
777
- if (parse_date (val [ 2 ] , & out )){
824
+ if (parse_date (date , & out )){
778
825
warning (_ ("invalid date format '%s' in '%s'" ),
779
- val [ 2 ] , rebase_path_author_script ());
826
+ date , rebase_path_author_script ());
780
827
strbuf_release (& out );
781
828
return NULL ;
782
829
}
783
830
784
831
strbuf_reset (& out );
785
- strbuf_addstr (& out , fmt_ident (val [ 0 ], val [ 1 ], val [ 2 ] , 0 ));
832
+ strbuf_addstr (& out , fmt_ident (name , email , date , 0 ));
786
833
strbuf_swap (buf , & out );
787
834
strbuf_release (& out );
835
+ free (name );
836
+ free (email );
837
+ free (date );
788
838
return buf -> buf ;
789
839
}
790
840
0 commit comments