Fossil SCM
modify looks_like_binary() to looks_like_text() such that it is usable in cr_warning() as well
Commit
1bffce5230e5d9f5d5142fa479adcc5d3e05d933
Parent
6feba0dba57a814…
2 files changed
+1
-23
+32
-26
+1
-23
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -885,38 +885,16 @@ | ||
| 885 | 885 | /* |
| 886 | 886 | ** Issue a warning and give the user an opportunity to abandon out |
| 887 | 887 | ** if a \r\n line ending is seen in a text file. |
| 888 | 888 | */ |
| 889 | 889 | static void cr_warning(const Blob *p, const char *zFilename){ |
| 890 | - int nCrNl = 0; /* Number of \r\n line endings seen */ | |
| 891 | - const unsigned char *z; /* File text */ | |
| 892 | - int n; /* Size of the file in bytes */ | |
| 893 | - int lastNl = 0; /* Characters since last \n */ | |
| 894 | - int i; /* Loop counter */ | |
| 895 | 890 | char *zMsg; /* Warning message */ |
| 896 | 891 | Blob fname; /* Relative pathname of the file */ |
| 897 | 892 | static int allOk = 0; /* Set to true to disable this routine */ |
| 898 | 893 | |
| 899 | 894 | if( allOk ) return; |
| 900 | - z = (unsigned char*)blob_buffer(p); | |
| 901 | - n = blob_size(p); | |
| 902 | - for(i=0; i<n-1; i++){ | |
| 903 | - unsigned char c = z[i]; | |
| 904 | - if( c==0 ) return; /* It's binary */ | |
| 905 | - if( c=='\n' ){ | |
| 906 | - if( i>0 && z[i-1]=='\r' ){ | |
| 907 | - nCrNl = 1; | |
| 908 | - if( i>8191 ) break; | |
| 909 | - } | |
| 910 | - lastNl = 0; | |
| 911 | - }else{ | |
| 912 | - lastNl++; | |
| 913 | - /* Binary if any line longer than 8191, see looks_like_binary() */ | |
| 914 | - if( lastNl>8191 ) return; | |
| 915 | - } | |
| 916 | - } | |
| 917 | - if( nCrNl ){ | |
| 895 | + if( looks_like_text(p)<0 ){ | |
| 918 | 896 | Blob ans; |
| 919 | 897 | char cReply; |
| 920 | 898 | |
| 921 | 899 | file_relative_name(zFilename, &fname, 0); |
| 922 | 900 | blob_zero(&ans); |
| 923 | 901 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -885,38 +885,16 @@ | |
| 885 | /* |
| 886 | ** Issue a warning and give the user an opportunity to abandon out |
| 887 | ** if a \r\n line ending is seen in a text file. |
| 888 | */ |
| 889 | static void cr_warning(const Blob *p, const char *zFilename){ |
| 890 | int nCrNl = 0; /* Number of \r\n line endings seen */ |
| 891 | const unsigned char *z; /* File text */ |
| 892 | int n; /* Size of the file in bytes */ |
| 893 | int lastNl = 0; /* Characters since last \n */ |
| 894 | int i; /* Loop counter */ |
| 895 | char *zMsg; /* Warning message */ |
| 896 | Blob fname; /* Relative pathname of the file */ |
| 897 | static int allOk = 0; /* Set to true to disable this routine */ |
| 898 | |
| 899 | if( allOk ) return; |
| 900 | z = (unsigned char*)blob_buffer(p); |
| 901 | n = blob_size(p); |
| 902 | for(i=0; i<n-1; i++){ |
| 903 | unsigned char c = z[i]; |
| 904 | if( c==0 ) return; /* It's binary */ |
| 905 | if( c=='\n' ){ |
| 906 | if( i>0 && z[i-1]=='\r' ){ |
| 907 | nCrNl = 1; |
| 908 | if( i>8191 ) break; |
| 909 | } |
| 910 | lastNl = 0; |
| 911 | }else{ |
| 912 | lastNl++; |
| 913 | /* Binary if any line longer than 8191, see looks_like_binary() */ |
| 914 | if( lastNl>8191 ) return; |
| 915 | } |
| 916 | } |
| 917 | if( nCrNl ){ |
| 918 | Blob ans; |
| 919 | char cReply; |
| 920 | |
| 921 | file_relative_name(zFilename, &fname, 0); |
| 922 | blob_zero(&ans); |
| 923 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -885,38 +885,16 @@ | |
| 885 | /* |
| 886 | ** Issue a warning and give the user an opportunity to abandon out |
| 887 | ** if a \r\n line ending is seen in a text file. |
| 888 | */ |
| 889 | static void cr_warning(const Blob *p, const char *zFilename){ |
| 890 | char *zMsg; /* Warning message */ |
| 891 | Blob fname; /* Relative pathname of the file */ |
| 892 | static int allOk = 0; /* Set to true to disable this routine */ |
| 893 | |
| 894 | if( allOk ) return; |
| 895 | if( looks_like_text(p)<0 ){ |
| 896 | Blob ans; |
| 897 | char cReply; |
| 898 | |
| 899 | file_relative_name(zFilename, &fname, 0); |
| 900 | blob_zero(&ans); |
| 901 |
+32
-26
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -48,10 +48,11 @@ | ||
| 48 | 48 | "cannot compute difference between binary files\n" |
| 49 | 49 | |
| 50 | 50 | #define DIFF_CANNOT_COMPUTE_SYMLINK \ |
| 51 | 51 | "cannot compute difference between symlink and regular file\n" |
| 52 | 52 | |
| 53 | +#define looks_like_binary(blob) (!(looks_like_text(blob)&1)) | |
| 53 | 54 | #endif /* INTERFACE */ |
| 54 | 55 | |
| 55 | 56 | /* |
| 56 | 57 | ** Maximum length of a line in a text file. (8192) |
| 57 | 58 | */ |
| @@ -106,11 +107,11 @@ | ||
| 106 | 107 | int nTo; /* Number of lines in aTo[] */ |
| 107 | 108 | }; |
| 108 | 109 | |
| 109 | 110 | /* |
| 110 | 111 | ** Return an array of DLine objects containing a pointer to the |
| 111 | -** start of each line and a hash of that line. The lower | |
| 112 | +** start of each line and a hash of that line. The lower | |
| 112 | 113 | ** bits of the hash store the length of each line. |
| 113 | 114 | ** |
| 114 | 115 | ** Trailing whitespace is removed from each line. 2010-08-20: Not any |
| 115 | 116 | ** more. If trailing whitespace is ignored, the "patch" command gets |
| 116 | 117 | ** confused by the diff output. Ticket [a9f7b23c2e376af5b0e5b] |
| @@ -169,35 +170,40 @@ | ||
| 169 | 170 | *pnLine = nLine; |
| 170 | 171 | return a; |
| 171 | 172 | } |
| 172 | 173 | |
| 173 | 174 | /* |
| 174 | -** Returns non-zero if the specified content appears to be binary or | |
| 175 | -** contains a line that is too long. | |
| 175 | +** Returns 1, if the file appears text, and does not contain CrLf | |
| 176 | +** Returns 0 if the specified content appears to be binary or | |
| 177 | +** contains a line that is too long | |
| 178 | +** Returns -1, if the file appears text, but it contains CrLf | |
| 176 | 179 | */ |
| 177 | -int looks_like_binary(const Blob *pContent){ | |
| 180 | +int looks_like_text(const Blob *pContent){ | |
| 178 | 181 | const char *z = blob_buffer(pContent); |
| 179 | 182 | int n = blob_size(pContent); |
| 180 | 183 | int i, j; |
| 184 | + int result = 1; | |
| 181 | 185 | |
| 182 | - /* Count the number of lines. Allocate space to hold | |
| 183 | - ** the returned array. | |
| 186 | + /* Check individual lines. | |
| 184 | 187 | */ |
| 185 | 188 | for(i=j=0; i<n; i++, j++){ |
| 186 | 189 | int c = z[i]; |
| 187 | 190 | if( c==0 ) return 1; /* \000 byte in a file -> binary */ |
| 188 | 191 | if( c=='\n' ){ |
| 192 | + if( i>0 && z[i-1]=='\r' ){ | |
| 193 | + result = -1; /* Contains CrLf, continue */ | |
| 194 | + } | |
| 189 | 195 | if( j>LENGTH_MASK ){ |
| 190 | - return 1; /* Very long line -> binary */ | |
| 196 | + return 0; /* Very long line -> binary */ | |
| 191 | 197 | } |
| 192 | 198 | j = 0; |
| 193 | 199 | } |
| 194 | 200 | } |
| 195 | 201 | if( j>LENGTH_MASK ){ |
| 196 | - return 1; /* Very long line -> binary */ | |
| 202 | + return 0; /* Very long line -> binary */ | |
| 197 | 203 | } |
| 198 | - return 0; /* No problems seen -> not binary */ | |
| 204 | + return result; /* No problems seen -> not binary */ | |
| 199 | 205 | } |
| 200 | 206 | |
| 201 | 207 | /* |
| 202 | 208 | ** Return true if two DLine elements are identical. |
| 203 | 209 | */ |
| @@ -241,11 +247,11 @@ | ||
| 241 | 247 | |
| 242 | 248 | /* |
| 243 | 249 | ** Add two line numbers to the beginning of an output line for a context |
| 244 | 250 | ** diff. One or of the other of the two numbers might be zero, which means |
| 245 | 251 | ** to leave that number field blank. The "html" parameter means to format |
| 246 | -** the output for HTML. | |
| 252 | +** the output for HTML. | |
| 247 | 253 | */ |
| 248 | 254 | static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){ |
| 249 | 255 | if( html ) blob_append(pOut, "<span class=\"diffln\">", -1); |
| 250 | 256 | if( lnA>0 ){ |
| 251 | 257 | blob_appendf(pOut, "%6d ", lnA); |
| @@ -271,11 +277,11 @@ | ||
| 271 | 277 | int nContext, /* Number of lines of context */ |
| 272 | 278 | int showLn, /* Show line numbers */ |
| 273 | 279 | int html /* Render as HTML */ |
| 274 | 280 | ){ |
| 275 | 281 | DLine *A; /* Left side of the diff */ |
| 276 | - DLine *B; /* Right side of the diff */ | |
| 282 | + DLine *B; /* Right side of the diff */ | |
| 277 | 283 | int a = 0; /* Index of next line in A[] */ |
| 278 | 284 | int b = 0; /* Index of next line in B[] */ |
| 279 | 285 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 280 | 286 | int r; /* Index into R[] */ |
| 281 | 287 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -527,11 +533,11 @@ | ||
| 527 | 533 | sbsWriteHtml(p, "</span>"); |
| 528 | 534 | p->zLine[p->n++] = ' '; |
| 529 | 535 | } |
| 530 | 536 | |
| 531 | 537 | /* |
| 532 | -** The two text segments zLeft and zRight are known to be different on | |
| 538 | +** The two text segments zLeft and zRight are known to be different on | |
| 533 | 539 | ** both ends, but they might have a common segment in the middle. If |
| 534 | 540 | ** they do not have a common segment, return 0. If they do have a large |
| 535 | 541 | ** common segment, return 1 and before doing so set: |
| 536 | 542 | ** |
| 537 | 543 | ** aLCS[0] = start of the common segment in zLeft |
| @@ -712,11 +718,11 @@ | ||
| 712 | 718 | p->iEnd = p->iEnd2; |
| 713 | 719 | p->zStart = p->zStart2; |
| 714 | 720 | p->iStart2 = 0; |
| 715 | 721 | p->iEnd2 = 0; |
| 716 | 722 | } |
| 717 | - if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1; | |
| 723 | + if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1; | |
| 718 | 724 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 719 | 725 | return; |
| 720 | 726 | } |
| 721 | 727 | |
| 722 | 728 | /* If all else fails, show a single big change between left and right */ |
| @@ -928,11 +934,11 @@ | ||
| 928 | 934 | int nContext, /* Number of lines of context around each change */ |
| 929 | 935 | int width, /* Width of each column of output */ |
| 930 | 936 | int escHtml /* True to generate HTML output */ |
| 931 | 937 | ){ |
| 932 | 938 | DLine *A; /* Left side of the diff */ |
| 933 | - DLine *B; /* Right side of the diff */ | |
| 939 | + DLine *B; /* Right side of the diff */ | |
| 934 | 940 | int a = 0; /* Index of next line in A[] */ |
| 935 | 941 | int b = 0; /* Index of next line in B[] */ |
| 936 | 942 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 937 | 943 | int r; /* Index into R[] */ |
| 938 | 944 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -1024,11 +1030,11 @@ | ||
| 1024 | 1030 | unsigned char *alignment; |
| 1025 | 1031 | ma = R[r+i*3+1]; /* Lines on left but not on right */ |
| 1026 | 1032 | mb = R[r+i*3+2]; /* Lines on right but not on left */ |
| 1027 | 1033 | |
| 1028 | 1034 | /* If the gap between the current diff and then next diff within the |
| 1029 | - ** same block is not too great, then render them as if they are a | |
| 1035 | + ** same block is not too great, then render them as if they are a | |
| 1030 | 1036 | ** single diff. */ |
| 1031 | 1037 | while( i<nr-1 && smallGap(&R[r+i*3]) ){ |
| 1032 | 1038 | i++; |
| 1033 | 1039 | m = R[r+i*3]; |
| 1034 | 1040 | ma += R[r+i*3+1] + m; |
| @@ -1170,11 +1176,11 @@ | ||
| 1170 | 1176 | ** input range. |
| 1171 | 1177 | ** |
| 1172 | 1178 | ** Ideally, the common sequence should be the longest possible common |
| 1173 | 1179 | ** sequence. However, an exact computation of LCS is O(N*N) which is |
| 1174 | 1180 | ** way too slow for larger files. So this routine uses an O(N) |
| 1175 | -** heuristic approximation based on hashing that usually works about | |
| 1181 | +** heuristic approximation based on hashing that usually works about | |
| 1176 | 1182 | ** as well. But if the O(N) algorithm doesn't get a good solution |
| 1177 | 1183 | ** and N is not too large, we fall back to an exact solution by |
| 1178 | 1184 | ** calling optimalLCS(). |
| 1179 | 1185 | */ |
| 1180 | 1186 | static void longestCommonSequence( |
| @@ -1203,11 +1209,11 @@ | ||
| 1203 | 1209 | iEYb = iEYp = iS2; |
| 1204 | 1210 | mid = (iE1 + iS1)/2; |
| 1205 | 1211 | for(i=iS1; i<iE1; i++){ |
| 1206 | 1212 | int limit = 0; |
| 1207 | 1213 | j = p->aTo[p->aFrom[i].h % p->nTo].iHash; |
| 1208 | - while( j>0 | |
| 1214 | + while( j>0 | |
| 1209 | 1215 | && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1])) |
| 1210 | 1216 | ){ |
| 1211 | 1217 | if( limit++ > 10 ){ |
| 1212 | 1218 | j = 0; |
| 1213 | 1219 | break; |
| @@ -1260,11 +1266,11 @@ | ||
| 1260 | 1266 | *piSX = iSXb; |
| 1261 | 1267 | *piSY = iSYb; |
| 1262 | 1268 | *piEX = iEXb; |
| 1263 | 1269 | *piEY = iEYb; |
| 1264 | 1270 | } |
| 1265 | - /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", | |
| 1271 | + /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", | |
| 1266 | 1272 | iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY); */ |
| 1267 | 1273 | } |
| 1268 | 1274 | |
| 1269 | 1275 | /* |
| 1270 | 1276 | ** Expand the size of aEdit[] array to hold at least nEdit elements. |
| @@ -1295,11 +1301,11 @@ | ||
| 1295 | 1301 | } |
| 1296 | 1302 | if( nCopy==0 && nDel==0 ){ |
| 1297 | 1303 | p->aEdit[p->nEdit-1] += nIns; |
| 1298 | 1304 | return; |
| 1299 | 1305 | } |
| 1300 | - } | |
| 1306 | + } | |
| 1301 | 1307 | if( p->nEdit+3>p->nEditAlloc ){ |
| 1302 | 1308 | expandEdit(p, p->nEdit*2 + 15); |
| 1303 | 1309 | if( p->aEdit==0 ) return; |
| 1304 | 1310 | } |
| 1305 | 1311 | p->aEdit[p->nEdit++] = nCopy; |
| @@ -1523,11 +1529,11 @@ | ||
| 1523 | 1529 | |
| 1524 | 1530 | /* |
| 1525 | 1531 | ** Generate a report of the differences between files pA and pB. |
| 1526 | 1532 | ** If pOut is not NULL then a unified diff is appended there. It |
| 1527 | 1533 | ** is assumed that pOut has already been initialized. If pOut is |
| 1528 | -** NULL, then a pointer to an array of integers is returned. | |
| 1534 | +** NULL, then a pointer to an array of integers is returned. | |
| 1529 | 1535 | ** The integers come in triples. For each triple, |
| 1530 | 1536 | ** the elements are the number of lines copied, the number of |
| 1531 | 1537 | ** lines deleted, and the number of lines inserted. The vector |
| 1532 | 1538 | ** is terminated by a triple of all zeros. |
| 1533 | 1539 | ** |
| @@ -1540,11 +1546,11 @@ | ||
| 1540 | 1546 | Blob *pB_Blob, /* TO file */ |
| 1541 | 1547 | Blob *pOut, /* Write diff here if not NULL */ |
| 1542 | 1548 | u64 diffFlags /* DIFF_* flags defined above */ |
| 1543 | 1549 | ){ |
| 1544 | 1550 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 1545 | - int nContext; /* Amount of context to display */ | |
| 1551 | + int nContext; /* Amount of context to display */ | |
| 1546 | 1552 | DContext c; |
| 1547 | 1553 | |
| 1548 | 1554 | if( diffFlags & DIFF_INVERT ){ |
| 1549 | 1555 | Blob *pTemp = pA_Blob; |
| 1550 | 1556 | pA_Blob = pB_Blob; |
| @@ -1596,11 +1602,11 @@ | ||
| 1596 | 1602 | } |
| 1597 | 1603 | } |
| 1598 | 1604 | |
| 1599 | 1605 | /* |
| 1600 | 1606 | ** Process diff-related command-line options and return an appropriate |
| 1601 | -** "diffFlags" integer. | |
| 1607 | +** "diffFlags" integer. | |
| 1602 | 1608 | ** |
| 1603 | 1609 | ** --brief Show filenames only DIFF_BRIEF |
| 1604 | 1610 | ** --context|-c N N lines of context. DIFF_CONTEXT_MASK |
| 1605 | 1611 | ** --html Format for HTML DIFF_HTML |
| 1606 | 1612 | ** --invert Invert the diff DIFF_INVERT |
| @@ -1767,11 +1773,11 @@ | ||
| 1767 | 1773 | p->c.aEdit = 0; |
| 1768 | 1774 | p->c.nEdit = 0; |
| 1769 | 1775 | p->c.nEditAlloc = 0; |
| 1770 | 1776 | |
| 1771 | 1777 | /* Clear out the from file */ |
| 1772 | - free(p->c.aFrom); | |
| 1778 | + free(p->c.aFrom); | |
| 1773 | 1779 | |
| 1774 | 1780 | /* Return no errors */ |
| 1775 | 1781 | return 0; |
| 1776 | 1782 | } |
| 1777 | 1783 | |
| @@ -1838,11 +1844,11 @@ | ||
| 1838 | 1844 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1839 | 1845 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1840 | 1846 | compute_direct_ancestors(mid, iLimit); |
| 1841 | 1847 | annotation_start(p, &toAnnotate); |
| 1842 | 1848 | |
| 1843 | - db_prepare(&q, | |
| 1849 | + db_prepare(&q, | |
| 1844 | 1850 | "SELECT mlink.fid," |
| 1845 | 1851 | " (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 1846 | 1852 | " date(event.mtime), " |
| 1847 | 1853 | " coalesce(event.euser,event.user) " |
| 1848 | 1854 | " FROM ancestor, mlink, event" |
| @@ -1860,11 +1866,11 @@ | ||
| 1860 | 1866 | const char *zUuid = db_column_text(&q, 1); |
| 1861 | 1867 | const char *zDate = db_column_text(&q, 2); |
| 1862 | 1868 | const char *zUser = db_column_text(&q, 3); |
| 1863 | 1869 | if( webLabel ){ |
| 1864 | 1870 | zLabel = mprintf( |
| 1865 | - "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", | |
| 1871 | + "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", | |
| 1866 | 1872 | zUuid, zUuid, zDate, zUser |
| 1867 | 1873 | ); |
| 1868 | 1874 | }else{ |
| 1869 | 1875 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 1870 | 1876 | } |
| @@ -1995,9 +2001,9 @@ | ||
| 1995 | 2001 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 1996 | 2002 | } |
| 1997 | 2003 | printf("---------------------------------------------------\n"); |
| 1998 | 2004 | } |
| 1999 | 2005 | for(i=0; i<ann.nOrig; i++){ |
| 2000 | - fossil_print("%s: %.*s\n", | |
| 2006 | + fossil_print("%s: %.*s\n", | |
| 2001 | 2007 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 2002 | 2008 | } |
| 2003 | 2009 | } |
| 2004 | 2010 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -48,10 +48,11 @@ | |
| 48 | "cannot compute difference between binary files\n" |
| 49 | |
| 50 | #define DIFF_CANNOT_COMPUTE_SYMLINK \ |
| 51 | "cannot compute difference between symlink and regular file\n" |
| 52 | |
| 53 | #endif /* INTERFACE */ |
| 54 | |
| 55 | /* |
| 56 | ** Maximum length of a line in a text file. (8192) |
| 57 | */ |
| @@ -106,11 +107,11 @@ | |
| 106 | int nTo; /* Number of lines in aTo[] */ |
| 107 | }; |
| 108 | |
| 109 | /* |
| 110 | ** Return an array of DLine objects containing a pointer to the |
| 111 | ** start of each line and a hash of that line. The lower |
| 112 | ** bits of the hash store the length of each line. |
| 113 | ** |
| 114 | ** Trailing whitespace is removed from each line. 2010-08-20: Not any |
| 115 | ** more. If trailing whitespace is ignored, the "patch" command gets |
| 116 | ** confused by the diff output. Ticket [a9f7b23c2e376af5b0e5b] |
| @@ -169,35 +170,40 @@ | |
| 169 | *pnLine = nLine; |
| 170 | return a; |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | ** Returns non-zero if the specified content appears to be binary or |
| 175 | ** contains a line that is too long. |
| 176 | */ |
| 177 | int looks_like_binary(const Blob *pContent){ |
| 178 | const char *z = blob_buffer(pContent); |
| 179 | int n = blob_size(pContent); |
| 180 | int i, j; |
| 181 | |
| 182 | /* Count the number of lines. Allocate space to hold |
| 183 | ** the returned array. |
| 184 | */ |
| 185 | for(i=j=0; i<n; i++, j++){ |
| 186 | int c = z[i]; |
| 187 | if( c==0 ) return 1; /* \000 byte in a file -> binary */ |
| 188 | if( c=='\n' ){ |
| 189 | if( j>LENGTH_MASK ){ |
| 190 | return 1; /* Very long line -> binary */ |
| 191 | } |
| 192 | j = 0; |
| 193 | } |
| 194 | } |
| 195 | if( j>LENGTH_MASK ){ |
| 196 | return 1; /* Very long line -> binary */ |
| 197 | } |
| 198 | return 0; /* No problems seen -> not binary */ |
| 199 | } |
| 200 | |
| 201 | /* |
| 202 | ** Return true if two DLine elements are identical. |
| 203 | */ |
| @@ -241,11 +247,11 @@ | |
| 241 | |
| 242 | /* |
| 243 | ** Add two line numbers to the beginning of an output line for a context |
| 244 | ** diff. One or of the other of the two numbers might be zero, which means |
| 245 | ** to leave that number field blank. The "html" parameter means to format |
| 246 | ** the output for HTML. |
| 247 | */ |
| 248 | static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){ |
| 249 | if( html ) blob_append(pOut, "<span class=\"diffln\">", -1); |
| 250 | if( lnA>0 ){ |
| 251 | blob_appendf(pOut, "%6d ", lnA); |
| @@ -271,11 +277,11 @@ | |
| 271 | int nContext, /* Number of lines of context */ |
| 272 | int showLn, /* Show line numbers */ |
| 273 | int html /* Render as HTML */ |
| 274 | ){ |
| 275 | DLine *A; /* Left side of the diff */ |
| 276 | DLine *B; /* Right side of the diff */ |
| 277 | int a = 0; /* Index of next line in A[] */ |
| 278 | int b = 0; /* Index of next line in B[] */ |
| 279 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 280 | int r; /* Index into R[] */ |
| 281 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -527,11 +533,11 @@ | |
| 527 | sbsWriteHtml(p, "</span>"); |
| 528 | p->zLine[p->n++] = ' '; |
| 529 | } |
| 530 | |
| 531 | /* |
| 532 | ** The two text segments zLeft and zRight are known to be different on |
| 533 | ** both ends, but they might have a common segment in the middle. If |
| 534 | ** they do not have a common segment, return 0. If they do have a large |
| 535 | ** common segment, return 1 and before doing so set: |
| 536 | ** |
| 537 | ** aLCS[0] = start of the common segment in zLeft |
| @@ -712,11 +718,11 @@ | |
| 712 | p->iEnd = p->iEnd2; |
| 713 | p->zStart = p->zStart2; |
| 714 | p->iStart2 = 0; |
| 715 | p->iEnd2 = 0; |
| 716 | } |
| 717 | if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1; |
| 718 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 719 | return; |
| 720 | } |
| 721 | |
| 722 | /* If all else fails, show a single big change between left and right */ |
| @@ -928,11 +934,11 @@ | |
| 928 | int nContext, /* Number of lines of context around each change */ |
| 929 | int width, /* Width of each column of output */ |
| 930 | int escHtml /* True to generate HTML output */ |
| 931 | ){ |
| 932 | DLine *A; /* Left side of the diff */ |
| 933 | DLine *B; /* Right side of the diff */ |
| 934 | int a = 0; /* Index of next line in A[] */ |
| 935 | int b = 0; /* Index of next line in B[] */ |
| 936 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 937 | int r; /* Index into R[] */ |
| 938 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -1024,11 +1030,11 @@ | |
| 1024 | unsigned char *alignment; |
| 1025 | ma = R[r+i*3+1]; /* Lines on left but not on right */ |
| 1026 | mb = R[r+i*3+2]; /* Lines on right but not on left */ |
| 1027 | |
| 1028 | /* If the gap between the current diff and then next diff within the |
| 1029 | ** same block is not too great, then render them as if they are a |
| 1030 | ** single diff. */ |
| 1031 | while( i<nr-1 && smallGap(&R[r+i*3]) ){ |
| 1032 | i++; |
| 1033 | m = R[r+i*3]; |
| 1034 | ma += R[r+i*3+1] + m; |
| @@ -1170,11 +1176,11 @@ | |
| 1170 | ** input range. |
| 1171 | ** |
| 1172 | ** Ideally, the common sequence should be the longest possible common |
| 1173 | ** sequence. However, an exact computation of LCS is O(N*N) which is |
| 1174 | ** way too slow for larger files. So this routine uses an O(N) |
| 1175 | ** heuristic approximation based on hashing that usually works about |
| 1176 | ** as well. But if the O(N) algorithm doesn't get a good solution |
| 1177 | ** and N is not too large, we fall back to an exact solution by |
| 1178 | ** calling optimalLCS(). |
| 1179 | */ |
| 1180 | static void longestCommonSequence( |
| @@ -1203,11 +1209,11 @@ | |
| 1203 | iEYb = iEYp = iS2; |
| 1204 | mid = (iE1 + iS1)/2; |
| 1205 | for(i=iS1; i<iE1; i++){ |
| 1206 | int limit = 0; |
| 1207 | j = p->aTo[p->aFrom[i].h % p->nTo].iHash; |
| 1208 | while( j>0 |
| 1209 | && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1])) |
| 1210 | ){ |
| 1211 | if( limit++ > 10 ){ |
| 1212 | j = 0; |
| 1213 | break; |
| @@ -1260,11 +1266,11 @@ | |
| 1260 | *piSX = iSXb; |
| 1261 | *piSY = iSYb; |
| 1262 | *piEX = iEXb; |
| 1263 | *piEY = iEYb; |
| 1264 | } |
| 1265 | /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", |
| 1266 | iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY); */ |
| 1267 | } |
| 1268 | |
| 1269 | /* |
| 1270 | ** Expand the size of aEdit[] array to hold at least nEdit elements. |
| @@ -1295,11 +1301,11 @@ | |
| 1295 | } |
| 1296 | if( nCopy==0 && nDel==0 ){ |
| 1297 | p->aEdit[p->nEdit-1] += nIns; |
| 1298 | return; |
| 1299 | } |
| 1300 | } |
| 1301 | if( p->nEdit+3>p->nEditAlloc ){ |
| 1302 | expandEdit(p, p->nEdit*2 + 15); |
| 1303 | if( p->aEdit==0 ) return; |
| 1304 | } |
| 1305 | p->aEdit[p->nEdit++] = nCopy; |
| @@ -1523,11 +1529,11 @@ | |
| 1523 | |
| 1524 | /* |
| 1525 | ** Generate a report of the differences between files pA and pB. |
| 1526 | ** If pOut is not NULL then a unified diff is appended there. It |
| 1527 | ** is assumed that pOut has already been initialized. If pOut is |
| 1528 | ** NULL, then a pointer to an array of integers is returned. |
| 1529 | ** The integers come in triples. For each triple, |
| 1530 | ** the elements are the number of lines copied, the number of |
| 1531 | ** lines deleted, and the number of lines inserted. The vector |
| 1532 | ** is terminated by a triple of all zeros. |
| 1533 | ** |
| @@ -1540,11 +1546,11 @@ | |
| 1540 | Blob *pB_Blob, /* TO file */ |
| 1541 | Blob *pOut, /* Write diff here if not NULL */ |
| 1542 | u64 diffFlags /* DIFF_* flags defined above */ |
| 1543 | ){ |
| 1544 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 1545 | int nContext; /* Amount of context to display */ |
| 1546 | DContext c; |
| 1547 | |
| 1548 | if( diffFlags & DIFF_INVERT ){ |
| 1549 | Blob *pTemp = pA_Blob; |
| 1550 | pA_Blob = pB_Blob; |
| @@ -1596,11 +1602,11 @@ | |
| 1596 | } |
| 1597 | } |
| 1598 | |
| 1599 | /* |
| 1600 | ** Process diff-related command-line options and return an appropriate |
| 1601 | ** "diffFlags" integer. |
| 1602 | ** |
| 1603 | ** --brief Show filenames only DIFF_BRIEF |
| 1604 | ** --context|-c N N lines of context. DIFF_CONTEXT_MASK |
| 1605 | ** --html Format for HTML DIFF_HTML |
| 1606 | ** --invert Invert the diff DIFF_INVERT |
| @@ -1767,11 +1773,11 @@ | |
| 1767 | p->c.aEdit = 0; |
| 1768 | p->c.nEdit = 0; |
| 1769 | p->c.nEditAlloc = 0; |
| 1770 | |
| 1771 | /* Clear out the from file */ |
| 1772 | free(p->c.aFrom); |
| 1773 | |
| 1774 | /* Return no errors */ |
| 1775 | return 0; |
| 1776 | } |
| 1777 | |
| @@ -1838,11 +1844,11 @@ | |
| 1838 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1839 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1840 | compute_direct_ancestors(mid, iLimit); |
| 1841 | annotation_start(p, &toAnnotate); |
| 1842 | |
| 1843 | db_prepare(&q, |
| 1844 | "SELECT mlink.fid," |
| 1845 | " (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 1846 | " date(event.mtime), " |
| 1847 | " coalesce(event.euser,event.user) " |
| 1848 | " FROM ancestor, mlink, event" |
| @@ -1860,11 +1866,11 @@ | |
| 1860 | const char *zUuid = db_column_text(&q, 1); |
| 1861 | const char *zDate = db_column_text(&q, 2); |
| 1862 | const char *zUser = db_column_text(&q, 3); |
| 1863 | if( webLabel ){ |
| 1864 | zLabel = mprintf( |
| 1865 | "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", |
| 1866 | zUuid, zUuid, zDate, zUser |
| 1867 | ); |
| 1868 | }else{ |
| 1869 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 1870 | } |
| @@ -1995,9 +2001,9 @@ | |
| 1995 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 1996 | } |
| 1997 | printf("---------------------------------------------------\n"); |
| 1998 | } |
| 1999 | for(i=0; i<ann.nOrig; i++){ |
| 2000 | fossil_print("%s: %.*s\n", |
| 2001 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 2002 | } |
| 2003 | } |
| 2004 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -48,10 +48,11 @@ | |
| 48 | "cannot compute difference between binary files\n" |
| 49 | |
| 50 | #define DIFF_CANNOT_COMPUTE_SYMLINK \ |
| 51 | "cannot compute difference between symlink and regular file\n" |
| 52 | |
| 53 | #define looks_like_binary(blob) (!(looks_like_text(blob)&1)) |
| 54 | #endif /* INTERFACE */ |
| 55 | |
| 56 | /* |
| 57 | ** Maximum length of a line in a text file. (8192) |
| 58 | */ |
| @@ -106,11 +107,11 @@ | |
| 107 | int nTo; /* Number of lines in aTo[] */ |
| 108 | }; |
| 109 | |
| 110 | /* |
| 111 | ** Return an array of DLine objects containing a pointer to the |
| 112 | ** start of each line and a hash of that line. The lower |
| 113 | ** bits of the hash store the length of each line. |
| 114 | ** |
| 115 | ** Trailing whitespace is removed from each line. 2010-08-20: Not any |
| 116 | ** more. If trailing whitespace is ignored, the "patch" command gets |
| 117 | ** confused by the diff output. Ticket [a9f7b23c2e376af5b0e5b] |
| @@ -169,35 +170,40 @@ | |
| 170 | *pnLine = nLine; |
| 171 | return a; |
| 172 | } |
| 173 | |
| 174 | /* |
| 175 | ** Returns 1, if the file appears text, and does not contain CrLf |
| 176 | ** Returns 0 if the specified content appears to be binary or |
| 177 | ** contains a line that is too long |
| 178 | ** Returns -1, if the file appears text, but it contains CrLf |
| 179 | */ |
| 180 | int looks_like_text(const Blob *pContent){ |
| 181 | const char *z = blob_buffer(pContent); |
| 182 | int n = blob_size(pContent); |
| 183 | int i, j; |
| 184 | int result = 1; |
| 185 | |
| 186 | /* Check individual lines. |
| 187 | */ |
| 188 | for(i=j=0; i<n; i++, j++){ |
| 189 | int c = z[i]; |
| 190 | if( c==0 ) return 1; /* \000 byte in a file -> binary */ |
| 191 | if( c=='\n' ){ |
| 192 | if( i>0 && z[i-1]=='\r' ){ |
| 193 | result = -1; /* Contains CrLf, continue */ |
| 194 | } |
| 195 | if( j>LENGTH_MASK ){ |
| 196 | return 0; /* Very long line -> binary */ |
| 197 | } |
| 198 | j = 0; |
| 199 | } |
| 200 | } |
| 201 | if( j>LENGTH_MASK ){ |
| 202 | return 0; /* Very long line -> binary */ |
| 203 | } |
| 204 | return result; /* No problems seen -> not binary */ |
| 205 | } |
| 206 | |
| 207 | /* |
| 208 | ** Return true if two DLine elements are identical. |
| 209 | */ |
| @@ -241,11 +247,11 @@ | |
| 247 | |
| 248 | /* |
| 249 | ** Add two line numbers to the beginning of an output line for a context |
| 250 | ** diff. One or of the other of the two numbers might be zero, which means |
| 251 | ** to leave that number field blank. The "html" parameter means to format |
| 252 | ** the output for HTML. |
| 253 | */ |
| 254 | static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){ |
| 255 | if( html ) blob_append(pOut, "<span class=\"diffln\">", -1); |
| 256 | if( lnA>0 ){ |
| 257 | blob_appendf(pOut, "%6d ", lnA); |
| @@ -271,11 +277,11 @@ | |
| 277 | int nContext, /* Number of lines of context */ |
| 278 | int showLn, /* Show line numbers */ |
| 279 | int html /* Render as HTML */ |
| 280 | ){ |
| 281 | DLine *A; /* Left side of the diff */ |
| 282 | DLine *B; /* Right side of the diff */ |
| 283 | int a = 0; /* Index of next line in A[] */ |
| 284 | int b = 0; /* Index of next line in B[] */ |
| 285 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 286 | int r; /* Index into R[] */ |
| 287 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -527,11 +533,11 @@ | |
| 533 | sbsWriteHtml(p, "</span>"); |
| 534 | p->zLine[p->n++] = ' '; |
| 535 | } |
| 536 | |
| 537 | /* |
| 538 | ** The two text segments zLeft and zRight are known to be different on |
| 539 | ** both ends, but they might have a common segment in the middle. If |
| 540 | ** they do not have a common segment, return 0. If they do have a large |
| 541 | ** common segment, return 1 and before doing so set: |
| 542 | ** |
| 543 | ** aLCS[0] = start of the common segment in zLeft |
| @@ -712,11 +718,11 @@ | |
| 718 | p->iEnd = p->iEnd2; |
| 719 | p->zStart = p->zStart2; |
| 720 | p->iStart2 = 0; |
| 721 | p->iEnd2 = 0; |
| 722 | } |
| 723 | if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1; |
| 724 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 725 | return; |
| 726 | } |
| 727 | |
| 728 | /* If all else fails, show a single big change between left and right */ |
| @@ -928,11 +934,11 @@ | |
| 934 | int nContext, /* Number of lines of context around each change */ |
| 935 | int width, /* Width of each column of output */ |
| 936 | int escHtml /* True to generate HTML output */ |
| 937 | ){ |
| 938 | DLine *A; /* Left side of the diff */ |
| 939 | DLine *B; /* Right side of the diff */ |
| 940 | int a = 0; /* Index of next line in A[] */ |
| 941 | int b = 0; /* Index of next line in B[] */ |
| 942 | int *R; /* Array of COPY/DELETE/INSERT triples */ |
| 943 | int r; /* Index into R[] */ |
| 944 | int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| @@ -1024,11 +1030,11 @@ | |
| 1030 | unsigned char *alignment; |
| 1031 | ma = R[r+i*3+1]; /* Lines on left but not on right */ |
| 1032 | mb = R[r+i*3+2]; /* Lines on right but not on left */ |
| 1033 | |
| 1034 | /* If the gap between the current diff and then next diff within the |
| 1035 | ** same block is not too great, then render them as if they are a |
| 1036 | ** single diff. */ |
| 1037 | while( i<nr-1 && smallGap(&R[r+i*3]) ){ |
| 1038 | i++; |
| 1039 | m = R[r+i*3]; |
| 1040 | ma += R[r+i*3+1] + m; |
| @@ -1170,11 +1176,11 @@ | |
| 1176 | ** input range. |
| 1177 | ** |
| 1178 | ** Ideally, the common sequence should be the longest possible common |
| 1179 | ** sequence. However, an exact computation of LCS is O(N*N) which is |
| 1180 | ** way too slow for larger files. So this routine uses an O(N) |
| 1181 | ** heuristic approximation based on hashing that usually works about |
| 1182 | ** as well. But if the O(N) algorithm doesn't get a good solution |
| 1183 | ** and N is not too large, we fall back to an exact solution by |
| 1184 | ** calling optimalLCS(). |
| 1185 | */ |
| 1186 | static void longestCommonSequence( |
| @@ -1203,11 +1209,11 @@ | |
| 1209 | iEYb = iEYp = iS2; |
| 1210 | mid = (iE1 + iS1)/2; |
| 1211 | for(i=iS1; i<iE1; i++){ |
| 1212 | int limit = 0; |
| 1213 | j = p->aTo[p->aFrom[i].h % p->nTo].iHash; |
| 1214 | while( j>0 |
| 1215 | && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1])) |
| 1216 | ){ |
| 1217 | if( limit++ > 10 ){ |
| 1218 | j = 0; |
| 1219 | break; |
| @@ -1260,11 +1266,11 @@ | |
| 1266 | *piSX = iSXb; |
| 1267 | *piSY = iSYb; |
| 1268 | *piEX = iEXb; |
| 1269 | *piEY = iEYb; |
| 1270 | } |
| 1271 | /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", |
| 1272 | iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY); */ |
| 1273 | } |
| 1274 | |
| 1275 | /* |
| 1276 | ** Expand the size of aEdit[] array to hold at least nEdit elements. |
| @@ -1295,11 +1301,11 @@ | |
| 1301 | } |
| 1302 | if( nCopy==0 && nDel==0 ){ |
| 1303 | p->aEdit[p->nEdit-1] += nIns; |
| 1304 | return; |
| 1305 | } |
| 1306 | } |
| 1307 | if( p->nEdit+3>p->nEditAlloc ){ |
| 1308 | expandEdit(p, p->nEdit*2 + 15); |
| 1309 | if( p->aEdit==0 ) return; |
| 1310 | } |
| 1311 | p->aEdit[p->nEdit++] = nCopy; |
| @@ -1523,11 +1529,11 @@ | |
| 1529 | |
| 1530 | /* |
| 1531 | ** Generate a report of the differences between files pA and pB. |
| 1532 | ** If pOut is not NULL then a unified diff is appended there. It |
| 1533 | ** is assumed that pOut has already been initialized. If pOut is |
| 1534 | ** NULL, then a pointer to an array of integers is returned. |
| 1535 | ** The integers come in triples. For each triple, |
| 1536 | ** the elements are the number of lines copied, the number of |
| 1537 | ** lines deleted, and the number of lines inserted. The vector |
| 1538 | ** is terminated by a triple of all zeros. |
| 1539 | ** |
| @@ -1540,11 +1546,11 @@ | |
| 1546 | Blob *pB_Blob, /* TO file */ |
| 1547 | Blob *pOut, /* Write diff here if not NULL */ |
| 1548 | u64 diffFlags /* DIFF_* flags defined above */ |
| 1549 | ){ |
| 1550 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 1551 | int nContext; /* Amount of context to display */ |
| 1552 | DContext c; |
| 1553 | |
| 1554 | if( diffFlags & DIFF_INVERT ){ |
| 1555 | Blob *pTemp = pA_Blob; |
| 1556 | pA_Blob = pB_Blob; |
| @@ -1596,11 +1602,11 @@ | |
| 1602 | } |
| 1603 | } |
| 1604 | |
| 1605 | /* |
| 1606 | ** Process diff-related command-line options and return an appropriate |
| 1607 | ** "diffFlags" integer. |
| 1608 | ** |
| 1609 | ** --brief Show filenames only DIFF_BRIEF |
| 1610 | ** --context|-c N N lines of context. DIFF_CONTEXT_MASK |
| 1611 | ** --html Format for HTML DIFF_HTML |
| 1612 | ** --invert Invert the diff DIFF_INVERT |
| @@ -1767,11 +1773,11 @@ | |
| 1773 | p->c.aEdit = 0; |
| 1774 | p->c.nEdit = 0; |
| 1775 | p->c.nEditAlloc = 0; |
| 1776 | |
| 1777 | /* Clear out the from file */ |
| 1778 | free(p->c.aFrom); |
| 1779 | |
| 1780 | /* Return no errors */ |
| 1781 | return 0; |
| 1782 | } |
| 1783 | |
| @@ -1838,11 +1844,11 @@ | |
| 1844 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1845 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1846 | compute_direct_ancestors(mid, iLimit); |
| 1847 | annotation_start(p, &toAnnotate); |
| 1848 | |
| 1849 | db_prepare(&q, |
| 1850 | "SELECT mlink.fid," |
| 1851 | " (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 1852 | " date(event.mtime), " |
| 1853 | " coalesce(event.euser,event.user) " |
| 1854 | " FROM ancestor, mlink, event" |
| @@ -1860,11 +1866,11 @@ | |
| 1866 | const char *zUuid = db_column_text(&q, 1); |
| 1867 | const char *zDate = db_column_text(&q, 2); |
| 1868 | const char *zUser = db_column_text(&q, 3); |
| 1869 | if( webLabel ){ |
| 1870 | zLabel = mprintf( |
| 1871 | "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", |
| 1872 | zUuid, zUuid, zDate, zUser |
| 1873 | ); |
| 1874 | }else{ |
| 1875 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 1876 | } |
| @@ -1995,9 +2001,9 @@ | |
| 2001 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 2002 | } |
| 2003 | printf("---------------------------------------------------\n"); |
| 2004 | } |
| 2005 | for(i=0; i<ann.nOrig; i++){ |
| 2006 | fossil_print("%s: %.*s\n", |
| 2007 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 2008 | } |
| 2009 | } |
| 2010 |