@@ -102,12 +102,12 @@ static int same_trailer(struct trailer_item *a, struct arg_item *b)
102102 return same_token (a , b ) && same_value (a , b );
103103}
104104
105- static inline int contains_only_spaces (const char * str )
105+ static inline int is_blank_line (const char * str )
106106{
107107 const char * s = str ;
108- while (* s && isspace (* s ))
108+ while (* s && * s != '\n' && isspace (* s ))
109109 s ++ ;
110- return !* s ;
110+ return !* s || * s == '\n' ;
111111}
112112
113113static inline void strbuf_replace (struct strbuf * sb , const char * a , const char * b )
@@ -702,51 +702,71 @@ static void process_command_line_args(struct list_head *arg_head,
702702 free (cl_separators );
703703}
704704
705- static struct strbuf * * read_input_file ( const char * file )
705+ static void read_input_file ( struct strbuf * sb , const char * file )
706706{
707- struct strbuf * * lines ;
708- struct strbuf sb = STRBUF_INIT ;
709-
710707 if (file ) {
711- if (strbuf_read_file (& sb , file , 0 ) < 0 )
708+ if (strbuf_read_file (sb , file , 0 ) < 0 )
712709 die_errno (_ ("could not read input file '%s'" ), file );
713710 } else {
714- if (strbuf_read (& sb , fileno (stdin ), 0 ) < 0 )
711+ if (strbuf_read (sb , fileno (stdin ), 0 ) < 0 )
715712 die_errno (_ ("could not read from stdin" ));
716713 }
714+ }
717715
718- lines = strbuf_split (& sb , '\n' );
716+ static const char * next_line (const char * str )
717+ {
718+ const char * nl = strchrnul (str , '\n' );
719+ return nl + !!* nl ;
720+ }
719721
720- strbuf_release (& sb );
722+ /*
723+ * Return the position of the start of the last line. If len is 0, return -1.
724+ */
725+ static int last_line (const char * buf , size_t len )
726+ {
727+ int i ;
728+ if (len == 0 )
729+ return -1 ;
730+ if (len == 1 )
731+ return 0 ;
732+ /*
733+ * Skip the last character (in addition to the null terminator),
734+ * because if the last character is a newline, it is considered as part
735+ * of the last line anyway.
736+ */
737+ i = len - 2 ;
721738
722- return lines ;
739+ for (; i >= 0 ; i -- ) {
740+ if (buf [i ] == '\n' )
741+ return i + 1 ;
742+ }
743+ return 0 ;
723744}
724745
725746/*
726- * Return the (0 based) index of the start of the patch or the line
727- * count if there is no patch in the message.
747+ * Return the position of the start of the patch or the length of str if there
748+ * is no patch in the message.
728749 */
729- static int find_patch_start (struct strbuf * * lines , int count )
750+ static int find_patch_start (const char * str )
730751{
731- int i ;
752+ const char * s ;
732753
733- /* Get the start of the patch part if any */
734- for (i = 0 ; i < count ; i ++ ) {
735- if (starts_with (lines [i ]-> buf , "---" ))
736- return i ;
754+ for (s = str ; * s ; s = next_line (s )) {
755+ if (starts_with (s , "---" ))
756+ return s - str ;
737757 }
738758
739- return count ;
759+ return s - str ;
740760}
741761
742762/*
743- * Return the (0 based) index of the first trailer line or count if
744- * there are no trailers. Trailers are searched only in the lines from
745- * index (count - 1) down to index 0.
763+ * Return the position of the first trailer line or len if there are no
764+ * trailers.
746765 */
747- static int find_trailer_start (struct strbuf * * lines , int count )
766+ static int find_trailer_start (const char * buf , size_t len )
748767{
749- int start , end_of_title , only_spaces = 1 ;
768+ const char * s ;
769+ int end_of_title , l , only_spaces = 1 ;
750770 int recognized_prefix = 0 , trailer_lines = 0 , non_trailer_lines = 0 ;
751771 /*
752772 * Number of possible continuation lines encountered. This will be
@@ -758,53 +778,56 @@ static int find_trailer_start(struct strbuf **lines, int count)
758778 int possible_continuation_lines = 0 ;
759779
760780 /* The first paragraph is the title and cannot be trailers */
761- for (start = 0 ; start < count ; start ++ ) {
762- if (lines [ start ] -> buf [0 ] == comment_line_char )
781+ for (s = buf ; s < buf + len ; s = next_line ( s ) ) {
782+ if (s [0 ] == comment_line_char )
763783 continue ;
764- if (contains_only_spaces ( lines [ start ] -> buf ))
784+ if (is_blank_line ( s ))
765785 break ;
766786 }
767- end_of_title = start ;
787+ end_of_title = s - buf ;
768788
769789 /*
770790 * Get the start of the trailers by looking starting from the end for a
771791 * blank line before a set of non-blank lines that (i) are all
772792 * trailers, or (ii) contains at least one Git-generated trailer and
773793 * consists of at least 25% trailers.
774794 */
775- for (start = count - 1 ; start >= end_of_title ; start -- ) {
795+ for (l = last_line (buf , len );
796+ l >= end_of_title ;
797+ l = last_line (buf , l )) {
798+ const char * bol = buf + l ;
776799 const char * * p ;
777800 int separator_pos ;
778801
779- if (lines [ start ] -> buf [0 ] == comment_line_char ) {
802+ if (bol [0 ] == comment_line_char ) {
780803 non_trailer_lines += possible_continuation_lines ;
781804 possible_continuation_lines = 0 ;
782805 continue ;
783806 }
784- if (contains_only_spaces ( lines [ start ] -> buf )) {
807+ if (is_blank_line ( bol )) {
785808 if (only_spaces )
786809 continue ;
787810 non_trailer_lines += possible_continuation_lines ;
788811 if (recognized_prefix &&
789812 trailer_lines * 3 >= non_trailer_lines )
790- return start + 1 ;
791- if (trailer_lines && !non_trailer_lines )
792- return start + 1 ;
793- return count ;
813+ return next_line ( bol ) - buf ;
814+ else if (trailer_lines && !non_trailer_lines )
815+ return next_line ( bol ) - buf ;
816+ return len ;
794817 }
795818 only_spaces = 0 ;
796819
797820 for (p = git_generated_prefixes ; * p ; p ++ ) {
798- if (starts_with (lines [ start ] -> buf , * p )) {
821+ if (starts_with (bol , * p )) {
799822 trailer_lines ++ ;
800823 possible_continuation_lines = 0 ;
801824 recognized_prefix = 1 ;
802825 goto continue_outer_loop ;
803826 }
804827 }
805828
806- separator_pos = find_separator (lines [ start ] -> buf , separators );
807- if (separator_pos >= 1 && !isspace (lines [ start ] -> buf [0 ])) {
829+ separator_pos = find_separator (bol , separators );
830+ if (separator_pos >= 1 && !isspace (bol [0 ])) {
808831 struct list_head * pos ;
809832
810833 trailer_lines ++ ;
@@ -814,13 +837,13 @@ static int find_trailer_start(struct strbuf **lines, int count)
814837 list_for_each (pos , & conf_head ) {
815838 struct arg_item * item ;
816839 item = list_entry (pos , struct arg_item , list );
817- if (token_matches_item (lines [ start ] -> buf , item ,
840+ if (token_matches_item (bol , item ,
818841 separator_pos )) {
819842 recognized_prefix = 1 ;
820843 break ;
821844 }
822845 }
823- } else if (isspace (lines [ start ] -> buf [0 ]))
846+ } else if (isspace (bol [0 ]))
824847 possible_continuation_lines ++ ;
825848 else {
826849 non_trailer_lines ++ ;
@@ -831,95 +854,78 @@ static int find_trailer_start(struct strbuf **lines, int count)
831854 ;
832855 }
833856
834- return count ;
835- }
836-
837- /* Get the index of the end of the trailers */
838- static int find_trailer_end (struct strbuf * * lines , int patch_start )
839- {
840- struct strbuf sb = STRBUF_INIT ;
841- int i , ignore_bytes ;
842-
843- for (i = 0 ; i < patch_start ; i ++ )
844- strbuf_addbuf (& sb , lines [i ]);
845- ignore_bytes = ignore_non_trailer (sb .buf , sb .len );
846- strbuf_release (& sb );
847- for (i = patch_start - 1 ; i >= 0 && ignore_bytes > 0 ; i -- )
848- ignore_bytes -= lines [i ]-> len ;
849-
850- return i + 1 ;
857+ return len ;
851858}
852859
853- static int has_blank_line_before (struct strbuf * * lines , int start )
860+ /* Return the position of the end of the trailers. */
861+ static int find_trailer_end (const char * buf , size_t len )
854862{
855- for (;start >= 0 ; start -- ) {
856- if (lines [start ]-> buf [0 ] == comment_line_char )
857- continue ;
858- return contains_only_spaces (lines [start ]-> buf );
859- }
860- return 0 ;
863+ return len - ignore_non_trailer (buf , len );
861864}
862865
863- static void print_lines ( FILE * outfile , struct strbuf * * lines , int start , int end )
866+ static int ends_with_blank_line ( const char * buf , size_t len )
864867{
865- int i ;
866- for (i = start ; lines [i ] && i < end ; i ++ )
867- fprintf (outfile , "%s" , lines [i ]-> buf );
868+ int ll = last_line (buf , len );
869+ if (ll < 0 )
870+ return 0 ;
871+ return is_blank_line (buf + ll );
868872}
869873
870874static int process_input_file (FILE * outfile ,
871- struct strbuf * * lines ,
875+ const char * str ,
872876 struct list_head * head )
873877{
874- int count = 0 ;
875- int patch_start , trailer_start , trailer_end , i ;
878+ int patch_start , trailer_start , trailer_end ;
876879 struct strbuf tok = STRBUF_INIT ;
877880 struct strbuf val = STRBUF_INIT ;
878881 struct trailer_item * last = NULL ;
882+ struct strbuf * trailer , * * trailer_lines , * * ptr ;
879883
880- /* Get the line count */
881- while (lines [count ])
882- count ++ ;
883-
884- patch_start = find_patch_start (lines , count );
885- trailer_end = find_trailer_end (lines , patch_start );
886- trailer_start = find_trailer_start (lines , trailer_end );
884+ patch_start = find_patch_start (str );
885+ trailer_end = find_trailer_end (str , patch_start );
886+ trailer_start = find_trailer_start (str , trailer_end );
887887
888888 /* Print lines before the trailers as is */
889- print_lines ( outfile , lines , 0 , trailer_start );
889+ fwrite ( str , 1 , trailer_start , outfile );
890890
891- if (!has_blank_line_before ( lines , trailer_start - 1 ))
891+ if (!ends_with_blank_line ( str , trailer_start ))
892892 fprintf (outfile , "\n" );
893893
894894 /* Parse trailer lines */
895- for (i = trailer_start ; i < trailer_end ; i ++ ) {
895+ trailer_lines = strbuf_split_buf (str + trailer_start ,
896+ trailer_end - trailer_start ,
897+ '\n' ,
898+ 0 );
899+ for (ptr = trailer_lines ; * ptr ; ptr ++ ) {
896900 int separator_pos ;
897- if (lines [i ]-> buf [0 ] == comment_line_char )
901+ trailer = * ptr ;
902+ if (trailer -> buf [0 ] == comment_line_char )
898903 continue ;
899- if (last && isspace (lines [ i ] -> buf [0 ])) {
904+ if (last && isspace (trailer -> buf [0 ])) {
900905 struct strbuf sb = STRBUF_INIT ;
901- strbuf_addf (& sb , "%s\n%s" , last -> value , lines [ i ] -> buf );
906+ strbuf_addf (& sb , "%s\n%s" , last -> value , trailer -> buf );
902907 strbuf_strip_suffix (& sb , "\n" );
903908 free (last -> value );
904909 last -> value = strbuf_detach (& sb , NULL );
905910 continue ;
906911 }
907- separator_pos = find_separator (lines [ i ] -> buf , separators );
912+ separator_pos = find_separator (trailer -> buf , separators );
908913 if (separator_pos >= 1 ) {
909- parse_trailer (& tok , & val , NULL , lines [ i ] -> buf ,
914+ parse_trailer (& tok , & val , NULL , trailer -> buf ,
910915 separator_pos );
911916 last = add_trailer_item (head ,
912917 strbuf_detach (& tok , NULL ),
913918 strbuf_detach (& val , NULL ));
914919 } else {
915- strbuf_addbuf (& val , lines [ i ] );
920+ strbuf_addbuf (& val , trailer );
916921 strbuf_strip_suffix (& val , "\n" );
917922 add_trailer_item (head ,
918923 NULL ,
919924 strbuf_detach (& val , NULL ));
920925 last = NULL ;
921926 }
922927 }
928+ strbuf_list_free (trailer_lines );
923929
924930 return trailer_end ;
925931}
@@ -968,21 +974,21 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str
968974{
969975 LIST_HEAD (head );
970976 LIST_HEAD (arg_head );
971- struct strbuf * * lines ;
977+ struct strbuf sb = STRBUF_INIT ;
972978 int trailer_end ;
973979 FILE * outfile = stdout ;
974980
975981 /* Default config must be setup first */
976982 git_config (git_trailer_default_config , NULL );
977983 git_config (git_trailer_config , NULL );
978984
979- lines = read_input_file (file );
985+ read_input_file (& sb , file );
980986
981987 if (in_place )
982988 outfile = create_in_place_tempfile (file );
983989
984990 /* Print the lines before the trailers */
985- trailer_end = process_input_file (outfile , lines , & head );
991+ trailer_end = process_input_file (outfile , sb . buf , & head );
986992
987993 process_command_line_args (& arg_head , trailers );
988994
@@ -993,11 +999,11 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str
993999 free_all (& head );
9941000
9951001 /* Print the lines after the trailers as is */
996- print_lines ( outfile , lines , trailer_end , INT_MAX );
1002+ fwrite ( sb . buf + trailer_end , 1 , sb . len - trailer_end , outfile );
9971003
9981004 if (in_place )
9991005 if (rename_tempfile (& trailers_tempfile , file ))
10001006 die_errno (_ ("could not rename temporary file to %s" ), file );
10011007
1002- strbuf_list_free ( lines );
1008+ strbuf_release ( & sb );
10031009}
0 commit comments