Fossil SCM
Minor tweaks to the break_into_lines() algorithm. Add tests.
Commit
057e4b0a62eff884d1b15e75d5f3b3ca7a532313
Parent
a8484dc32721016…
2 files changed
+36
-17
+31
+36
-17
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -115,10 +115,34 @@ | ||
| 115 | 115 | int nFrom; /* Number of lines in aFrom[] */ |
| 116 | 116 | DLine *aTo; /* File on right side of the diff */ |
| 117 | 117 | int nTo; /* Number of lines in aTo[] */ |
| 118 | 118 | int (*same_fn)(const DLine*,const DLine*); /* comparison function */ |
| 119 | 119 | }; |
| 120 | + | |
| 121 | +/* | |
| 122 | +** Count the number of lines in the input string. Include the last line | |
| 123 | +** in the count even if it lacks the \n terminator. If an empty string | |
| 124 | +** is specified, the number of lines is zero. For the purposes of this | |
| 125 | +** function, a string is considered empty if it contains no characters | |
| 126 | +** -OR- it contains only NUL characters. | |
| 127 | +*/ | |
| 128 | +static int count_lines( | |
| 129 | + const char *z, | |
| 130 | + int n, | |
| 131 | + int *pnLine | |
| 132 | +){ | |
| 133 | + int nLine; | |
| 134 | + const char *zNL, *z2; | |
| 135 | + for(nLine=0, z2=z; (zNL = strchr(z2,'\n'))!=0; z2=zNL+1, nLine++){} | |
| 136 | + if( z2[0]!='\0' ){ | |
| 137 | + nLine++; | |
| 138 | + do{ z2++; }while( z2[0]!='\0' ); | |
| 139 | + } | |
| 140 | + if( n!=(int)(z2-z) ) return 0; | |
| 141 | + if( pnLine ) *pnLine = nLine; | |
| 142 | + return 1; | |
| 143 | +} | |
| 120 | 144 | |
| 121 | 145 | /* |
| 122 | 146 | ** Return an array of DLine objects containing a pointer to the |
| 123 | 147 | ** start of each line and a hash of that line. The lower |
| 124 | 148 | ** bits of the hash store the length of each line. |
| @@ -140,32 +164,26 @@ | ||
| 140 | 164 | u64 diffFlags |
| 141 | 165 | ){ |
| 142 | 166 | int nLine, i, k, nn, s, x; |
| 143 | 167 | unsigned int h, h2; |
| 144 | 168 | DLine *a; |
| 145 | - const char *zNL, *z2; | |
| 146 | - | |
| 147 | - /* Count the number of lines in the input file. Include the last line | |
| 148 | - ** in the count even if it lacks the \n terminator | |
| 149 | - */ | |
| 150 | - for(nLine=0, z2=z; (zNL = strchr(z2,'\n'))!=0; z2=zNL+1, nLine++){} | |
| 151 | - if( z2[0]!=0 ){ | |
| 152 | - nLine++; | |
| 153 | - do{ z2++; }while( z2[0] ); | |
| 154 | - } | |
| 155 | - if( n!=(int)(z2-z) ) return 0; | |
| 156 | - | |
| 169 | + const char *zNL; | |
| 170 | + | |
| 171 | + if( count_lines(z, n, &nLine)==0 ){ | |
| 172 | + return 0; | |
| 173 | + } | |
| 174 | + assert( nLine>0 || z[0]=='\0' ); | |
| 157 | 175 | a = fossil_malloc( sizeof(a[0])*nLine ); |
| 158 | 176 | memset(a, 0, sizeof(a[0])*nLine); |
| 159 | 177 | if( nLine==0 ){ |
| 160 | 178 | *pnLine = 0; |
| 161 | 179 | return a; |
| 162 | 180 | } |
| 163 | 181 | i = 0; |
| 164 | 182 | do{ |
| 165 | 183 | zNL = strchr(z,'\n'); |
| 166 | - if( zNL==0 ) zNL = z+strlen(z); | |
| 184 | + if( zNL==0 ) zNL = z+n; | |
| 167 | 185 | nn = (int)(zNL - z); |
| 168 | 186 | if( nn>LENGTH_MASK ){ |
| 169 | 187 | fossil_free(a); |
| 170 | 188 | return 0; |
| 171 | 189 | } |
| @@ -181,14 +199,15 @@ | ||
| 181 | 199 | } |
| 182 | 200 | if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 183 | 201 | int numws = 0; |
| 184 | 202 | while( s<k && fossil_isspace(z[s]) ){ s++; } |
| 185 | 203 | for(h=0, x=s; x<k; x++){ |
| 186 | - if( fossil_isspace(z[x]) ){ | |
| 204 | + char c = z[x]; | |
| 205 | + if( fossil_isspace(c) ){ | |
| 187 | 206 | ++numws; |
| 188 | 207 | }else{ |
| 189 | - h += z[x]; | |
| 208 | + h += c; | |
| 190 | 209 | h *= 0x9e3779b1; |
| 191 | 210 | } |
| 192 | 211 | } |
| 193 | 212 | k -= numws; |
| 194 | 213 | }else{ |
| @@ -200,13 +219,13 @@ | ||
| 200 | 219 | a[i].indent = s; |
| 201 | 220 | a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s); |
| 202 | 221 | h2 = h % nLine; |
| 203 | 222 | a[i].iNext = a[h2].iHash; |
| 204 | 223 | a[h2].iHash = i+1; |
| 205 | - z += nn+1; | |
| 224 | + z += nn+1; n -= nn+1; | |
| 206 | 225 | i++; |
| 207 | - }while( zNL[0] && zNL[1] ); | |
| 226 | + }while( zNL[0]!='\0' && zNL[1]!='\0' ); | |
| 208 | 227 | assert( i==nLine ); |
| 209 | 228 | |
| 210 | 229 | /* Return results */ |
| 211 | 230 | *pnLine = nLine; |
| 212 | 231 | return a; |
| 213 | 232 | |
| 214 | 233 | ADDED test/diff.test |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -115,10 +115,34 @@ | |
| 115 | int nFrom; /* Number of lines in aFrom[] */ |
| 116 | DLine *aTo; /* File on right side of the diff */ |
| 117 | int nTo; /* Number of lines in aTo[] */ |
| 118 | int (*same_fn)(const DLine*,const DLine*); /* comparison function */ |
| 119 | }; |
| 120 | |
| 121 | /* |
| 122 | ** Return an array of DLine objects containing a pointer to the |
| 123 | ** start of each line and a hash of that line. The lower |
| 124 | ** bits of the hash store the length of each line. |
| @@ -140,32 +164,26 @@ | |
| 140 | u64 diffFlags |
| 141 | ){ |
| 142 | int nLine, i, k, nn, s, x; |
| 143 | unsigned int h, h2; |
| 144 | DLine *a; |
| 145 | const char *zNL, *z2; |
| 146 | |
| 147 | /* Count the number of lines in the input file. Include the last line |
| 148 | ** in the count even if it lacks the \n terminator |
| 149 | */ |
| 150 | for(nLine=0, z2=z; (zNL = strchr(z2,'\n'))!=0; z2=zNL+1, nLine++){} |
| 151 | if( z2[0]!=0 ){ |
| 152 | nLine++; |
| 153 | do{ z2++; }while( z2[0] ); |
| 154 | } |
| 155 | if( n!=(int)(z2-z) ) return 0; |
| 156 | |
| 157 | a = fossil_malloc( sizeof(a[0])*nLine ); |
| 158 | memset(a, 0, sizeof(a[0])*nLine); |
| 159 | if( nLine==0 ){ |
| 160 | *pnLine = 0; |
| 161 | return a; |
| 162 | } |
| 163 | i = 0; |
| 164 | do{ |
| 165 | zNL = strchr(z,'\n'); |
| 166 | if( zNL==0 ) zNL = z+strlen(z); |
| 167 | nn = (int)(zNL - z); |
| 168 | if( nn>LENGTH_MASK ){ |
| 169 | fossil_free(a); |
| 170 | return 0; |
| 171 | } |
| @@ -181,14 +199,15 @@ | |
| 181 | } |
| 182 | if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 183 | int numws = 0; |
| 184 | while( s<k && fossil_isspace(z[s]) ){ s++; } |
| 185 | for(h=0, x=s; x<k; x++){ |
| 186 | if( fossil_isspace(z[x]) ){ |
| 187 | ++numws; |
| 188 | }else{ |
| 189 | h += z[x]; |
| 190 | h *= 0x9e3779b1; |
| 191 | } |
| 192 | } |
| 193 | k -= numws; |
| 194 | }else{ |
| @@ -200,13 +219,13 @@ | |
| 200 | a[i].indent = s; |
| 201 | a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s); |
| 202 | h2 = h % nLine; |
| 203 | a[i].iNext = a[h2].iHash; |
| 204 | a[h2].iHash = i+1; |
| 205 | z += nn+1; |
| 206 | i++; |
| 207 | }while( zNL[0] && zNL[1] ); |
| 208 | assert( i==nLine ); |
| 209 | |
| 210 | /* Return results */ |
| 211 | *pnLine = nLine; |
| 212 | return a; |
| 213 | |
| 214 | DDED test/diff.test |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -115,10 +115,34 @@ | |
| 115 | int nFrom; /* Number of lines in aFrom[] */ |
| 116 | DLine *aTo; /* File on right side of the diff */ |
| 117 | int nTo; /* Number of lines in aTo[] */ |
| 118 | int (*same_fn)(const DLine*,const DLine*); /* comparison function */ |
| 119 | }; |
| 120 | |
| 121 | /* |
| 122 | ** Count the number of lines in the input string. Include the last line |
| 123 | ** in the count even if it lacks the \n terminator. If an empty string |
| 124 | ** is specified, the number of lines is zero. For the purposes of this |
| 125 | ** function, a string is considered empty if it contains no characters |
| 126 | ** -OR- it contains only NUL characters. |
| 127 | */ |
| 128 | static int count_lines( |
| 129 | const char *z, |
| 130 | int n, |
| 131 | int *pnLine |
| 132 | ){ |
| 133 | int nLine; |
| 134 | const char *zNL, *z2; |
| 135 | for(nLine=0, z2=z; (zNL = strchr(z2,'\n'))!=0; z2=zNL+1, nLine++){} |
| 136 | if( z2[0]!='\0' ){ |
| 137 | nLine++; |
| 138 | do{ z2++; }while( z2[0]!='\0' ); |
| 139 | } |
| 140 | if( n!=(int)(z2-z) ) return 0; |
| 141 | if( pnLine ) *pnLine = nLine; |
| 142 | return 1; |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 | ** Return an array of DLine objects containing a pointer to the |
| 147 | ** start of each line and a hash of that line. The lower |
| 148 | ** bits of the hash store the length of each line. |
| @@ -140,32 +164,26 @@ | |
| 164 | u64 diffFlags |
| 165 | ){ |
| 166 | int nLine, i, k, nn, s, x; |
| 167 | unsigned int h, h2; |
| 168 | DLine *a; |
| 169 | const char *zNL; |
| 170 | |
| 171 | if( count_lines(z, n, &nLine)==0 ){ |
| 172 | return 0; |
| 173 | } |
| 174 | assert( nLine>0 || z[0]=='\0' ); |
| 175 | a = fossil_malloc( sizeof(a[0])*nLine ); |
| 176 | memset(a, 0, sizeof(a[0])*nLine); |
| 177 | if( nLine==0 ){ |
| 178 | *pnLine = 0; |
| 179 | return a; |
| 180 | } |
| 181 | i = 0; |
| 182 | do{ |
| 183 | zNL = strchr(z,'\n'); |
| 184 | if( zNL==0 ) zNL = z+n; |
| 185 | nn = (int)(zNL - z); |
| 186 | if( nn>LENGTH_MASK ){ |
| 187 | fossil_free(a); |
| 188 | return 0; |
| 189 | } |
| @@ -181,14 +199,15 @@ | |
| 199 | } |
| 200 | if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 201 | int numws = 0; |
| 202 | while( s<k && fossil_isspace(z[s]) ){ s++; } |
| 203 | for(h=0, x=s; x<k; x++){ |
| 204 | char c = z[x]; |
| 205 | if( fossil_isspace(c) ){ |
| 206 | ++numws; |
| 207 | }else{ |
| 208 | h += c; |
| 209 | h *= 0x9e3779b1; |
| 210 | } |
| 211 | } |
| 212 | k -= numws; |
| 213 | }else{ |
| @@ -200,13 +219,13 @@ | |
| 219 | a[i].indent = s; |
| 220 | a[i].h = h = (h<<LENGTH_MASK_SZ) | (k-s); |
| 221 | h2 = h % nLine; |
| 222 | a[i].iNext = a[h2].iHash; |
| 223 | a[h2].iHash = i+1; |
| 224 | z += nn+1; n -= nn+1; |
| 225 | i++; |
| 226 | }while( zNL[0]!='\0' && zNL[1]!='\0' ); |
| 227 | assert( i==nLine ); |
| 228 | |
| 229 | /* Return results */ |
| 230 | *pnLine = nLine; |
| 231 | return a; |
| 232 | |
| 233 | DDED test/diff.test |
+31
| --- a/test/diff.test | ||
| +++ b/test/diff.test | ||
| @@ -0,0 +1,31 @@ | ||
| 1 | +16384]" | |
| 2 | +write_file file4_file file4.dat "test file 4 (l16384]\ntwo" | |
| 3 | +write_file f163842016 D. Richard Hipp | |
| 4 | +# | |
| 5 | +# This program is free software; you can redistribute it and/or | |
| 6 | +# modify it under the terms of the Simplified BSD License (also | |
| 7 | +# known as the "2-Clause License" or "FreeBSD License".) | |
| 8 | +# | |
| 9 | +# This program is distributed in the hope that it will be useful, | |
| 10 | +# but without any warranty; without even the implied warranty of | |
| 11 | +# merchantability or fitness for a particular purpose. | |
| 12 | +# | |
| 13 | +# Author contact information: | |
| 14 | +# [email protected] | |
| 15 | +# http://www.hwaci.com/drh/ | |
| 16 | +# | |
| 17 | +############################################################################ | |
| 18 | +# | |
| 19 | +# Tests for the diff command. | |
| 20 | +# | |
| 21 | + | |
| 22 | +require_no_open_checkout | |
| 23 | + | |
| 24 | +test_setup; set rootDir [file normalize [pwd]] | |
| 25 | + | |
| 26 | +################################### | |
| 27 | +# Tests of binary file det# | |
| 28 | +# Coite_file file1.dat z 32768] | |
| 29 | +fossil diff file1.dat | |
| 30 | + | |
| 31 | +test diff-file1-1 {[normalize_restest_cleanup |
| --- a/test/diff.test | |
| +++ b/test/diff.test | |
| @@ -0,0 +1,31 @@ | |
| --- a/test/diff.test | |
| +++ b/test/diff.test | |
| @@ -0,0 +1,31 @@ | |
| 1 | 16384]" |
| 2 | write_file file4_file file4.dat "test file 4 (l16384]\ntwo" |
| 3 | write_file f163842016 D. Richard Hipp |
| 4 | # |
| 5 | # This program is free software; you can redistribute it and/or |
| 6 | # modify it under the terms of the Simplified BSD License (also |
| 7 | # known as the "2-Clause License" or "FreeBSD License".) |
| 8 | # |
| 9 | # This program is distributed in the hope that it will be useful, |
| 10 | # but without any warranty; without even the implied warranty of |
| 11 | # merchantability or fitness for a particular purpose. |
| 12 | # |
| 13 | # Author contact information: |
| 14 | # [email protected] |
| 15 | # http://www.hwaci.com/drh/ |
| 16 | # |
| 17 | ############################################################################ |
| 18 | # |
| 19 | # Tests for the diff command. |
| 20 | # |
| 21 | |
| 22 | require_no_open_checkout |
| 23 | |
| 24 | test_setup; set rootDir [file normalize [pwd]] |
| 25 | |
| 26 | ################################### |
| 27 | # Tests of binary file det# |
| 28 | # Coite_file file1.dat z 32768] |
| 29 | fossil diff file1.dat |
| 30 | |
| 31 | test diff-file1-1 {[normalize_restest_cleanup |