Fossil SCM
Internally, use the new DiffConfig object to pass around diff settings, rather than the legacy u64 bit array. This provides increased flexibility to the internals. There should be no user-visible changes (unless I made a mistake). Note that more parameters could be folded into the DiffConfig object. This check-in is just a start.
Commit
1347a1ddb9a565e93005f65cdfc6d773ab3b2e5292a38163972fe4c5c21c823a
Parent
68d728867f6fa0f…
12 files changed
+3
-1
+4
-2
+111
-75
+90
-68
+41
-31
+3
-1
+3
-3
+4
-2
+14
-14
+9
-6
+17
-18
+4
-3
+3
-1
| --- src/ajax.c | ||
| +++ src/ajax.c | ||
| @@ -152,12 +152,14 @@ | ||
| 152 | 152 | ** and pContent is the locally-edited (v2) content. diffFlags is any |
| 153 | 153 | ** set of flags suitable for passing to text_diff(). |
| 154 | 154 | */ |
| 155 | 155 | void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){ |
| 156 | 156 | Blob out = empty_blob; |
| 157 | + DiffConfig DCfg; | |
| 157 | 158 | |
| 158 | - text_diff(pOrig, pContent, &out, 0, diffFlags); | |
| 159 | + diff_config_init(&DCfg, diffFlags); | |
| 160 | + text_diff(pOrig, pContent, &out, &DCfg); | |
| 159 | 161 | if(blob_size(&out)==0){ |
| 160 | 162 | /* nothing to do */ |
| 161 | 163 | }else if(DIFF_SIDEBYSIDE & diffFlags){ |
| 162 | 164 | CX("%b",&out); |
| 163 | 165 | }else{ |
| 164 | 166 |
| --- src/ajax.c | |
| +++ src/ajax.c | |
| @@ -152,12 +152,14 @@ | |
| 152 | ** and pContent is the locally-edited (v2) content. diffFlags is any |
| 153 | ** set of flags suitable for passing to text_diff(). |
| 154 | */ |
| 155 | void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){ |
| 156 | Blob out = empty_blob; |
| 157 | |
| 158 | text_diff(pOrig, pContent, &out, 0, diffFlags); |
| 159 | if(blob_size(&out)==0){ |
| 160 | /* nothing to do */ |
| 161 | }else if(DIFF_SIDEBYSIDE & diffFlags){ |
| 162 | CX("%b",&out); |
| 163 | }else{ |
| 164 |
| --- src/ajax.c | |
| +++ src/ajax.c | |
| @@ -152,12 +152,14 @@ | |
| 152 | ** and pContent is the locally-edited (v2) content. diffFlags is any |
| 153 | ** set of flags suitable for passing to text_diff(). |
| 154 | */ |
| 155 | void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){ |
| 156 | Blob out = empty_blob; |
| 157 | DiffConfig DCfg; |
| 158 | |
| 159 | diff_config_init(&DCfg, diffFlags); |
| 160 | text_diff(pOrig, pContent, &out, &DCfg); |
| 161 | if(blob_size(&out)==0){ |
| 162 | /* nothing to do */ |
| 163 | }else if(DIFF_SIDEBYSIDE & diffFlags){ |
| 164 | CX("%b",&out); |
| 165 | }else{ |
| 166 |
+4
-2
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1338,15 +1338,17 @@ | ||
| 1338 | 1338 | "# All merged-in branches will be closed due to the --integrate flag\n" |
| 1339 | 1339 | "#\n", -1 |
| 1340 | 1340 | ); |
| 1341 | 1341 | } |
| 1342 | 1342 | if( p->verboseFlag ){ |
| 1343 | + DiffConfig DCfg; | |
| 1343 | 1344 | blob_appendf(&prompt, |
| 1344 | 1345 | "#\n%.78c\n" |
| 1345 | 1346 | "# The following diff is excluded from the commit message:\n#\n", |
| 1346 | 1347 | '#' |
| 1347 | 1348 | ); |
| 1349 | + diff_config_init(&DCfg, DIFF_VERBOSE); | |
| 1348 | 1350 | if( g.aCommitFile ){ |
| 1349 | 1351 | FileDirList *diffFiles; |
| 1350 | 1352 | int i; |
| 1351 | 1353 | diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles)); |
| 1352 | 1354 | for( i=0; g.aCommitFile[i]!=0; ++i ){ |
| @@ -1360,19 +1362,19 @@ | ||
| 1360 | 1362 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1361 | 1363 | diffFiles[i].nUsed = 0; |
| 1362 | 1364 | } |
| 1363 | 1365 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1364 | 1366 | db_get_boolean("diff-binary", 1), |
| 1365 | - DIFF_VERBOSE, diffFiles, &prompt); | |
| 1367 | + &DCfg, diffFiles, &prompt); | |
| 1366 | 1368 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1367 | 1369 | fossil_free(diffFiles[i].zName); |
| 1368 | 1370 | } |
| 1369 | 1371 | fossil_free(diffFiles); |
| 1370 | 1372 | }else{ |
| 1371 | 1373 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1372 | 1374 | db_get_boolean("diff-binary", 1), |
| 1373 | - DIFF_VERBOSE, 0, &prompt); | |
| 1375 | + &DCfg, 0, &prompt); | |
| 1374 | 1376 | } |
| 1375 | 1377 | } |
| 1376 | 1378 | prompt_for_user_comment(pComment, &prompt); |
| 1377 | 1379 | blob_reset(&prompt); |
| 1378 | 1380 | } |
| 1379 | 1381 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1338,15 +1338,17 @@ | |
| 1338 | "# All merged-in branches will be closed due to the --integrate flag\n" |
| 1339 | "#\n", -1 |
| 1340 | ); |
| 1341 | } |
| 1342 | if( p->verboseFlag ){ |
| 1343 | blob_appendf(&prompt, |
| 1344 | "#\n%.78c\n" |
| 1345 | "# The following diff is excluded from the commit message:\n#\n", |
| 1346 | '#' |
| 1347 | ); |
| 1348 | if( g.aCommitFile ){ |
| 1349 | FileDirList *diffFiles; |
| 1350 | int i; |
| 1351 | diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles)); |
| 1352 | for( i=0; g.aCommitFile[i]!=0; ++i ){ |
| @@ -1360,19 +1362,19 @@ | |
| 1360 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1361 | diffFiles[i].nUsed = 0; |
| 1362 | } |
| 1363 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1364 | db_get_boolean("diff-binary", 1), |
| 1365 | DIFF_VERBOSE, diffFiles, &prompt); |
| 1366 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1367 | fossil_free(diffFiles[i].zName); |
| 1368 | } |
| 1369 | fossil_free(diffFiles); |
| 1370 | }else{ |
| 1371 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1372 | db_get_boolean("diff-binary", 1), |
| 1373 | DIFF_VERBOSE, 0, &prompt); |
| 1374 | } |
| 1375 | } |
| 1376 | prompt_for_user_comment(pComment, &prompt); |
| 1377 | blob_reset(&prompt); |
| 1378 | } |
| 1379 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1338,15 +1338,17 @@ | |
| 1338 | "# All merged-in branches will be closed due to the --integrate flag\n" |
| 1339 | "#\n", -1 |
| 1340 | ); |
| 1341 | } |
| 1342 | if( p->verboseFlag ){ |
| 1343 | DiffConfig DCfg; |
| 1344 | blob_appendf(&prompt, |
| 1345 | "#\n%.78c\n" |
| 1346 | "# The following diff is excluded from the commit message:\n#\n", |
| 1347 | '#' |
| 1348 | ); |
| 1349 | diff_config_init(&DCfg, DIFF_VERBOSE); |
| 1350 | if( g.aCommitFile ){ |
| 1351 | FileDirList *diffFiles; |
| 1352 | int i; |
| 1353 | diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles)); |
| 1354 | for( i=0; g.aCommitFile[i]!=0; ++i ){ |
| @@ -1360,19 +1362,19 @@ | |
| 1362 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1363 | diffFiles[i].nUsed = 0; |
| 1364 | } |
| 1365 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1366 | db_get_boolean("diff-binary", 1), |
| 1367 | &DCfg, diffFiles, &prompt); |
| 1368 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1369 | fossil_free(diffFiles[i].zName); |
| 1370 | } |
| 1371 | fossil_free(diffFiles); |
| 1372 | }else{ |
| 1373 | diff_against_disk(0, 0, diff_get_binary_glob(), |
| 1374 | db_get_boolean("diff-binary", 1), |
| 1375 | &DCfg, 0, &prompt); |
| 1376 | } |
| 1377 | } |
| 1378 | prompt_for_user_comment(pComment, &prompt); |
| 1379 | blob_reset(&prompt); |
| 1380 | } |
| 1381 |
+111
-75
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -70,12 +70,47 @@ | ||
| 70 | 70 | /* |
| 71 | 71 | ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes) |
| 72 | 72 | */ |
| 73 | 73 | #define LENGTH_MASK_SZ 15 |
| 74 | 74 | #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) |
| 75 | + | |
| 76 | +/* | |
| 77 | +** An instance of this object describes the formatting and processing | |
| 78 | +** details desired of a "diff" operation. | |
| 79 | +** | |
| 80 | +** Conceptually, this object is as an encoding of the command-line options | |
| 81 | +** for the "fossil diff" command. That is not a precise description, though, | |
| 82 | +** because not all diff operations are started from the command-line. But | |
| 83 | +** the idea is sound. | |
| 84 | +** | |
| 85 | +** Information encoded by this object includes but is not limited to: | |
| 86 | +** | |
| 87 | +** * The desired output format (unified vs. side-by-side, | |
| 88 | +** TCL, JSON, HTML vs. plain-text). | |
| 89 | +** | |
| 90 | +** * Number of lines of context surrounding each difference block | |
| 91 | +** | |
| 92 | +** * Width of output columns for text side-by-side diffop | |
| 93 | +*/ | |
| 94 | +struct DiffConfig { | |
| 95 | + u64 diffFlags; /* Diff flags */ | |
| 96 | + u32 nFile; /* Number of files diffed so far */ | |
| 97 | + const char *zDiffCmd; /* External diff command to use instead of builtin */ | |
| 98 | + const char *zBinGlob; /* GLOB pattern for binary files */ | |
| 99 | + ReCompiled *pRe; /* Show only changes matching this pattern */ | |
| 100 | +}; | |
| 75 | 101 | |
| 76 | 102 | #endif /* INTERFACE */ |
| 103 | + | |
| 104 | +/* | |
| 105 | +** Initialize memory for a DiffConfig based on just a diffFlags integer. | |
| 106 | +*/ | |
| 107 | +DiffConfig *diff_config_init(DiffConfig *pCfg, u64 diffFlags){ | |
| 108 | + memset(pCfg, 0, sizeof(*pCfg)); | |
| 109 | + pCfg->diffFlags = diffFlags; | |
| 110 | + return pCfg; | |
| 111 | +} | |
| 77 | 112 | |
| 78 | 113 | /* |
| 79 | 114 | ** Information about each line of a file being diffed. |
| 80 | 115 | ** |
| 81 | 116 | ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length |
| @@ -332,11 +367,11 @@ | ||
| 332 | 367 | ** Output a patch-style text diff. |
| 333 | 368 | */ |
| 334 | 369 | static void contextDiff( |
| 335 | 370 | DContext *p, /* The difference */ |
| 336 | 371 | Blob *pOut, /* Output a context diff to here */ |
| 337 | - u64 diffFlags /* Flags controlling the diff format */ | |
| 372 | + DiffConfig *pCfg /* Configuration options */ | |
| 338 | 373 | ){ |
| 339 | 374 | DLine *A; /* Left side of the diff */ |
| 340 | 375 | DLine *B; /* Right side of the diff */ |
| 341 | 376 | int a = 0; /* Index of next line in A[] */ |
| 342 | 377 | int b = 0; /* Index of next line in B[] */ |
| @@ -351,12 +386,12 @@ | ||
| 351 | 386 | static int nChunk = 0; /* Number of diff chunks seen so far */ |
| 352 | 387 | int nContext; /* Number of lines of context */ |
| 353 | 388 | int showLn; /* Show line numbers */ |
| 354 | 389 | int showDivider = 0; /* True to show the divider between diff blocks */ |
| 355 | 390 | |
| 356 | - nContext = diff_context_lines(diffFlags); | |
| 357 | - showLn = (diffFlags & DIFF_LINENO)!=0; | |
| 391 | + nContext = diff_context_lines(pCfg); | |
| 392 | + showLn = (pCfg->diffFlags & DIFF_LINENO)!=0; | |
| 358 | 393 | A = p->aFrom; |
| 359 | 394 | B = p->aTo; |
| 360 | 395 | R = p->aEdit; |
| 361 | 396 | mxr = p->nEdit; |
| 362 | 397 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1119,11 +1154,11 @@ | ||
| 1119 | 1154 | blob_append_char(p->pOut, ','); |
| 1120 | 1155 | blob_append_json_literal(p->pOut, pX->z + x, pX->n - x); |
| 1121 | 1156 | blob_append(p->pOut, "],\n",3); |
| 1122 | 1157 | } |
| 1123 | 1158 | static void dfjsonEnd(DiffBuilder *p){ |
| 1124 | - blob_append(p->pOut, "0]", 2); | |
| 1159 | + blob_append(p->pOut, "0]}", 3); | |
| 1125 | 1160 | fossil_free(p); |
| 1126 | 1161 | } |
| 1127 | 1162 | static DiffBuilder *dfjsonNew(Blob *pOut){ |
| 1128 | 1163 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1129 | 1164 | p->xSkip = dfjsonSkip; |
| @@ -1631,21 +1666,21 @@ | ||
| 1631 | 1666 | blob_append_char(p->pOut, '\n'); |
| 1632 | 1667 | } |
| 1633 | 1668 | static void dfsbsEnd(DiffBuilder *p){ |
| 1634 | 1669 | fossil_free(p); |
| 1635 | 1670 | } |
| 1636 | -static DiffBuilder *dfsbsNew(Blob *pOut, u64 diffFlags){ | |
| 1671 | +static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){ | |
| 1637 | 1672 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1638 | 1673 | p->xSkip = dfsbsSkip; |
| 1639 | 1674 | p->xCommon = dfsbsCommon; |
| 1640 | 1675 | p->xInsert = dfsbsInsert; |
| 1641 | 1676 | p->xDelete = dfsbsDelete; |
| 1642 | 1677 | p->xReplace = dfsbsEdit; |
| 1643 | 1678 | p->xEdit = dfsbsEdit; |
| 1644 | 1679 | p->xEnd = dfsbsEnd; |
| 1645 | 1680 | p->lnLeft = p->lnRight = 0; |
| 1646 | - p->width = diff_width(diffFlags); | |
| 1681 | + p->width = diff_width(pCfg); | |
| 1647 | 1682 | p->pOut = pOut; |
| 1648 | 1683 | return p; |
| 1649 | 1684 | } |
| 1650 | 1685 | /****************************************************************************/ |
| 1651 | 1686 | /* |
| @@ -1767,11 +1802,11 @@ | ||
| 1767 | 1802 | ** mismatch. |
| 1768 | 1803 | */ |
| 1769 | 1804 | static unsigned char *diffBlockAlignment( |
| 1770 | 1805 | const DLine *aLeft, int nLeft, /* Text on the left */ |
| 1771 | 1806 | const DLine *aRight, int nRight, /* Text on the right */ |
| 1772 | - u64 diffFlags, /* Flags passed into the original diff */ | |
| 1807 | + DiffConfig *pCfg, /* Configuration options */ | |
| 1773 | 1808 | int *pNResult /* OUTPUT: Bytes of result */ |
| 1774 | 1809 | ){ |
| 1775 | 1810 | int i, j, k; /* Loop counters */ |
| 1776 | 1811 | int *a; /* One row of the Wagner matrix */ |
| 1777 | 1812 | int *pToFree; /* Space that needs to be freed */ |
| @@ -1795,11 +1830,11 @@ | ||
| 1795 | 1830 | /* For large alignments, use a divide and conquer algorithm that is |
| 1796 | 1831 | ** O(NlogN). The result is not as precise, but this whole thing is an |
| 1797 | 1832 | ** approximation anyhow, and the faster response time is an acceptable |
| 1798 | 1833 | ** trade-off for reduced precision. |
| 1799 | 1834 | */ |
| 1800 | - if( nLeft*nRight>DIFF_ALIGN_MX && (diffFlags & DIFF_SLOW_SBS)==0 ){ | |
| 1835 | + if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){ | |
| 1801 | 1836 | const DLine *aSmall; /* The smaller of aLeft and aRight */ |
| 1802 | 1837 | const DLine *aBig; /* The larger of aLeft and aRight */ |
| 1803 | 1838 | int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */ |
| 1804 | 1839 | int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */ |
| 1805 | 1840 | int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */ |
| @@ -1832,14 +1867,14 @@ | ||
| 1832 | 1867 | iDivLeft = iDivBig; |
| 1833 | 1868 | }else{ |
| 1834 | 1869 | iDivRight = iDivBig; |
| 1835 | 1870 | iDivLeft = iDivSmall; |
| 1836 | 1871 | } |
| 1837 | - a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,diffFlags,&n1); | |
| 1872 | + a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1); | |
| 1838 | 1873 | a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft, |
| 1839 | 1874 | aRight+iDivRight, nRight-iDivRight, |
| 1840 | - diffFlags, &n2); | |
| 1875 | + pCfg, &n2); | |
| 1841 | 1876 | a1 = fossil_realloc(a1, n1+n2 ); |
| 1842 | 1877 | memcpy(a1+n1,a2,n2); |
| 1843 | 1878 | fossil_free(a2); |
| 1844 | 1879 | *pNResult = n1+n2; |
| 1845 | 1880 | return a1; |
| @@ -1938,12 +1973,11 @@ | ||
| 1938 | 1973 | /* |
| 1939 | 1974 | ** Format a diff using a DiffBuilder object |
| 1940 | 1975 | */ |
| 1941 | 1976 | static void formatDiff( |
| 1942 | 1977 | DContext *p, /* The computed diff */ |
| 1943 | - ReCompiled *pRe, /* Only show changes that match this regex */ | |
| 1944 | - u64 diffFlags, /* Flags controlling the diff */ | |
| 1978 | + DiffConfig *pCfg, /* Configuration options */ | |
| 1945 | 1979 | DiffBuilder *pBuilder /* The formatter object */ |
| 1946 | 1980 | ){ |
| 1947 | 1981 | const DLine *A; /* Left side of the diff */ |
| 1948 | 1982 | const DLine *B; /* Right side of the diff */ |
| 1949 | 1983 | unsigned int a = 0; /* Index of next line in A[] */ |
| @@ -1956,11 +1990,11 @@ | ||
| 1956 | 1990 | unsigned int i, j; /* Loop counters */ |
| 1957 | 1991 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1958 | 1992 | signed int skip = 0; /* Number of lines to skip */ |
| 1959 | 1993 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1960 | 1994 | |
| 1961 | - nContext = diff_context_lines(diffFlags); | |
| 1995 | + nContext = diff_context_lines(pCfg); | |
| 1962 | 1996 | A = p->aFrom; |
| 1963 | 1997 | B = p->aTo; |
| 1964 | 1998 | R = p->aEdit; |
| 1965 | 1999 | mxr = p->nEdit; |
| 1966 | 2000 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1972,19 +2006,19 @@ | ||
| 1972 | 2006 | /* If there is a regex, skip this block (generate no diff output) |
| 1973 | 2007 | ** if the regex matches or does not match both insert and delete. |
| 1974 | 2008 | ** Only display the block if one side matches but the other side does |
| 1975 | 2009 | ** not. |
| 1976 | 2010 | */ |
| 1977 | - if( pRe ){ | |
| 2011 | + if( pCfg->pRe ){ | |
| 1978 | 2012 | int hideBlock = 1; |
| 1979 | 2013 | int xa = a, xb = b; |
| 1980 | 2014 | for(i=0; hideBlock && i<nr; i++){ |
| 1981 | 2015 | int c1, c2; |
| 1982 | 2016 | xa += R[r+i*3]; |
| 1983 | 2017 | xb += R[r+i*3]; |
| 1984 | - c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]); | |
| 1985 | - c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]); | |
| 2018 | + c1 = re_dline_match(pCfg->pRe, &A[xa], R[r+i*3+1]); | |
| 2019 | + c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]); | |
| 1986 | 2020 | hideBlock = c1==c2; |
| 1987 | 2021 | xa += R[r+i*3+1]; |
| 1988 | 2022 | xb += R[r+i*3+2]; |
| 1989 | 2023 | } |
| 1990 | 2024 | if( hideBlock ){ |
| @@ -2050,11 +2084,11 @@ | ||
| 2050 | 2084 | ma += R[r+i*3+1] + m; |
| 2051 | 2085 | mb += R[r+i*3+2] + m; |
| 2052 | 2086 | } |
| 2053 | 2087 | |
| 2054 | 2088 | /* Try to find an alignment for the lines within this one block */ |
| 2055 | - alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, diffFlags, &nAlign); | |
| 2089 | + alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign); | |
| 2056 | 2090 | |
| 2057 | 2091 | for(j=0; ma+mb>0; j++){ |
| 2058 | 2092 | assert( j<nAlign ); |
| 2059 | 2093 | switch( alignment[j] ){ |
| 2060 | 2094 | case 1: { |
| @@ -2511,13 +2545,13 @@ | ||
| 2511 | 2545 | |
| 2512 | 2546 | /* |
| 2513 | 2547 | ** Extract the number of lines of context from diffFlags. Supply an |
| 2514 | 2548 | ** appropriate default if no context width is specified. |
| 2515 | 2549 | */ |
| 2516 | -int diff_context_lines(u64 diffFlags){ | |
| 2517 | - int n = diffFlags & DIFF_CONTEXT_MASK; | |
| 2518 | - if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; | |
| 2550 | +int diff_context_lines(DiffConfig *pCfg){ | |
| 2551 | + int n = pCfg->diffFlags & DIFF_CONTEXT_MASK; | |
| 2552 | + if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; | |
| 2519 | 2553 | return n; |
| 2520 | 2554 | } |
| 2521 | 2555 | |
| 2522 | 2556 | /* |
| 2523 | 2557 | ** Extract the width of columns for side-by-side diff. Supply an |
| @@ -2527,12 +2561,12 @@ | ||
| 2527 | 2561 | ** term-width = 2*diff-col + diff-marker + 1 |
| 2528 | 2562 | ** diff-col = lineno + lmargin + text-width + rmargin |
| 2529 | 2563 | ** |
| 2530 | 2564 | ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin |
| 2531 | 2565 | */ |
| 2532 | -int diff_width(u64 diffFlags){ | |
| 2533 | - int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); | |
| 2566 | +int diff_width(DiffConfig *pCfg){ | |
| 2567 | + int w = (pCfg->diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); | |
| 2534 | 2568 | if( w==0 ){ |
| 2535 | 2569 | static struct { |
| 2536 | 2570 | unsigned int lineno, lmargin, text, rmargin, marker; |
| 2537 | 2571 | } sbsW = { 5, 2, 0, 0, 3 }; |
| 2538 | 2572 | const unsigned int wMin = 24, wMax = 132; |
| @@ -2589,41 +2623,40 @@ | ||
| 2589 | 2623 | */ |
| 2590 | 2624 | int *text_diff( |
| 2591 | 2625 | Blob *pA_Blob, /* FROM file */ |
| 2592 | 2626 | Blob *pB_Blob, /* TO file */ |
| 2593 | 2627 | Blob *pOut, /* Write diff here if not NULL */ |
| 2594 | - ReCompiled *pRe, /* Only output changes where this Regexp matches */ | |
| 2595 | - u64 diffFlags /* DIFF_* flags defined above */ | |
| 2628 | + DiffConfig *pCfg /* Configuration options */ | |
| 2596 | 2629 | ){ |
| 2597 | 2630 | int ignoreWs; /* Ignore whitespace */ |
| 2598 | 2631 | DContext c; |
| 2599 | 2632 | |
| 2600 | - if( diffFlags & DIFF_INVERT ){ | |
| 2633 | + if( pCfg->diffFlags & DIFF_INVERT ){ | |
| 2601 | 2634 | Blob *pTemp = pA_Blob; |
| 2602 | 2635 | pA_Blob = pB_Blob; |
| 2603 | 2636 | pB_Blob = pTemp; |
| 2604 | 2637 | } |
| 2605 | - ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0; | |
| 2638 | + ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0; | |
| 2606 | 2639 | blob_to_utf8_no_bom(pA_Blob, 0); |
| 2607 | 2640 | blob_to_utf8_no_bom(pB_Blob, 0); |
| 2608 | 2641 | |
| 2609 | 2642 | /* Prepare the input files */ |
| 2610 | 2643 | memset(&c, 0, sizeof(c)); |
| 2611 | - if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ | |
| 2644 | + if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ | |
| 2612 | 2645 | c.xDiffer = compare_dline_ignore_allws; |
| 2613 | 2646 | }else{ |
| 2614 | 2647 | c.xDiffer = compare_dline; |
| 2615 | 2648 | } |
| 2616 | 2649 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 2617 | - &c.nFrom, diffFlags); | |
| 2650 | + &c.nFrom, pCfg->diffFlags); | |
| 2618 | 2651 | c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), |
| 2619 | - &c.nTo, diffFlags); | |
| 2652 | + &c.nTo, pCfg->diffFlags); | |
| 2620 | 2653 | if( c.aFrom==0 || c.aTo==0 ){ |
| 2621 | 2654 | fossil_free(c.aFrom); |
| 2622 | 2655 | fossil_free(c.aTo); |
| 2623 | 2656 | if( pOut ){ |
| 2624 | - diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags); | |
| 2657 | + diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags); | |
| 2625 | 2658 | } |
| 2626 | 2659 | return 0; |
| 2627 | 2660 | } |
| 2628 | 2661 | |
| 2629 | 2662 | /* Compute the difference */ |
| @@ -2630,32 +2663,32 @@ | ||
| 2630 | 2663 | diff_all(&c); |
| 2631 | 2664 | if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ |
| 2632 | 2665 | fossil_free(c.aFrom); |
| 2633 | 2666 | fossil_free(c.aTo); |
| 2634 | 2667 | fossil_free(c.aEdit); |
| 2635 | - if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags); | |
| 2668 | + if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags); | |
| 2636 | 2669 | return 0; |
| 2637 | 2670 | } |
| 2638 | - if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){ | |
| 2671 | + if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){ | |
| 2639 | 2672 | int i, m, n; |
| 2640 | 2673 | int *a = c.aEdit; |
| 2641 | 2674 | int mx = c.nEdit; |
| 2642 | 2675 | for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; } |
| 2643 | 2676 | if( n>10000 ){ |
| 2644 | 2677 | fossil_free(c.aFrom); |
| 2645 | 2678 | fossil_free(c.aTo); |
| 2646 | 2679 | fossil_free(c.aEdit); |
| 2647 | - if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); | |
| 2680 | + if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags); | |
| 2648 | 2681 | return 0; |
| 2649 | 2682 | } |
| 2650 | 2683 | } |
| 2651 | - if( (diffFlags & DIFF_NOOPT)==0 ){ | |
| 2684 | + if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){ | |
| 2652 | 2685 | diff_optimize(&c); |
| 2653 | 2686 | } |
| 2654 | 2687 | |
| 2655 | 2688 | if( pOut ){ |
| 2656 | - if( diffFlags & DIFF_NUMSTAT ){ | |
| 2689 | + if( pCfg->diffFlags & DIFF_NUMSTAT ){ | |
| 2657 | 2690 | int nDel = 0, nIns = 0, i; |
| 2658 | 2691 | for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){ |
| 2659 | 2692 | nDel += c.aEdit[i+1]; |
| 2660 | 2693 | nIns += c.aEdit[i+2]; |
| 2661 | 2694 | } |
| @@ -2663,40 +2696,40 @@ | ||
| 2663 | 2696 | g.diffCnt[2] += nDel; |
| 2664 | 2697 | if( nIns+nDel ){ |
| 2665 | 2698 | g.diffCnt[0]++; |
| 2666 | 2699 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2667 | 2700 | } |
| 2668 | - }else if( diffFlags & DIFF_RAW ){ | |
| 2701 | + }else if( pCfg->diffFlags & DIFF_RAW ){ | |
| 2669 | 2702 | const int *R = c.aEdit; |
| 2670 | 2703 | unsigned int r; |
| 2671 | 2704 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 2672 | 2705 | blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", |
| 2673 | 2706 | R[r], R[r+1], R[r+2]); |
| 2674 | 2707 | } |
| 2675 | - }else if( diffFlags & DIFF_JSON ){ | |
| 2708 | + }else if( pCfg->diffFlags & DIFF_JSON ){ | |
| 2676 | 2709 | DiffBuilder *pBuilder = dfjsonNew(pOut); |
| 2677 | - formatDiff(&c, pRe, diffFlags, pBuilder); | |
| 2710 | + formatDiff(&c, pCfg, pBuilder); | |
| 2678 | 2711 | blob_append_char(pOut, '\n'); |
| 2679 | - }else if( diffFlags & DIFF_TCL ){ | |
| 2712 | + }else if( pCfg->diffFlags & DIFF_TCL ){ | |
| 2680 | 2713 | DiffBuilder *pBuilder = dftclNew(pOut); |
| 2681 | - formatDiff(&c, pRe, diffFlags, pBuilder); | |
| 2682 | - }else if( diffFlags & DIFF_SIDEBYSIDE ){ | |
| 2714 | + formatDiff(&c, pCfg, pBuilder); | |
| 2715 | + }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ | |
| 2683 | 2716 | DiffBuilder *pBuilder; |
| 2684 | - if( diffFlags & DIFF_HTML ){ | |
| 2717 | + if( pCfg->diffFlags & DIFF_HTML ){ | |
| 2685 | 2718 | pBuilder = dfsplitNew(pOut); |
| 2686 | 2719 | }else{ |
| 2687 | - pBuilder = dfsbsNew(pOut, diffFlags); | |
| 2720 | + pBuilder = dfsbsNew(pOut, pCfg); | |
| 2688 | 2721 | } |
| 2689 | - formatDiff(&c, pRe, diffFlags, pBuilder); | |
| 2690 | - }else if( diffFlags & DIFF_DEBUG ){ | |
| 2722 | + formatDiff(&c, pCfg, pBuilder); | |
| 2723 | + }else if( pCfg->diffFlags & DIFF_DEBUG ){ | |
| 2691 | 2724 | DiffBuilder *pBuilder = dfdebugNew(pOut); |
| 2692 | - formatDiff(&c, pRe, diffFlags, pBuilder); | |
| 2693 | - }else if( diffFlags & DIFF_HTML ){ | |
| 2725 | + formatDiff(&c, pCfg, pBuilder); | |
| 2726 | + }else if( pCfg->diffFlags & DIFF_HTML ){ | |
| 2694 | 2727 | DiffBuilder *pBuilder = dfunifiedNew(pOut); |
| 2695 | - formatDiff(&c, pRe, diffFlags, pBuilder); | |
| 2728 | + formatDiff(&c, pCfg, pBuilder); | |
| 2696 | 2729 | }else{ |
| 2697 | - contextDiff(&c, pOut, diffFlags); | |
| 2730 | + contextDiff(&c, pOut, pCfg); | |
| 2698 | 2731 | } |
| 2699 | 2732 | fossil_free(c.aFrom); |
| 2700 | 2733 | fossil_free(c.aTo); |
| 2701 | 2734 | fossil_free(c.aEdit); |
| 2702 | 2735 | return 0; |
| @@ -2709,31 +2742,35 @@ | ||
| 2709 | 2742 | return c.aEdit; |
| 2710 | 2743 | } |
| 2711 | 2744 | } |
| 2712 | 2745 | |
| 2713 | 2746 | /* |
| 2747 | +** Initialize the DiffConfig object using command-line options. | |
| 2748 | +** | |
| 2714 | 2749 | ** Process diff-related command-line options and return an appropriate |
| 2715 | 2750 | ** "diffFlags" integer. |
| 2716 | 2751 | ** |
| 2717 | -** --brief Show filenames only DIFF_BRIEF | |
| 2718 | -** -c|--context N N lines of context. DIFF_CONTEXT_MASK | |
| 2719 | -** --html Format for HTML DIFF_HTML | |
| 2720 | -** --invert Invert the diff DIFF_INVERT | |
| 2721 | -** -n|--linenum Show line numbers DIFF_LINENO | |
| 2722 | -** --noopt Disable optimization DIFF_NOOPT | |
| 2723 | -** --numstat Show change counts DIFF_NUMSTAT | |
| 2724 | -** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR | |
| 2725 | -** --unified Unified diff. ~DIFF_SIDEBYSIDE | |
| 2726 | -** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS | |
| 2727 | -** -W|--width N N character lines. DIFF_WIDTH_MASK | |
| 2728 | -** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE | |
| 2729 | -** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS | |
| 2752 | +** --brief Show filenames only DIFF_BRIEF | |
| 2753 | +** -c|--context N N lines of context. DIFF_CONTEXT_MASK | |
| 2754 | +** --html Format for HTML DIFF_HTML | |
| 2755 | +** --invert Invert the diff DIFF_INVERT | |
| 2756 | +** -n|--linenum Show line numbers DIFF_LINENO | |
| 2757 | +** --noopt Disable optimization DIFF_NOOPT | |
| 2758 | +** --numstat Show change counts DIFF_NUMSTAT | |
| 2759 | +** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR | |
| 2760 | +** --unified Unified diff. ~DIFF_SIDEBYSIDE | |
| 2761 | +** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS | |
| 2762 | +** -W|--width N N character lines. DIFF_WIDTH_MASK | |
| 2763 | +** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE | |
| 2764 | +** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS | |
| 2730 | 2765 | */ |
| 2731 | -u64 diff_options(void){ | |
| 2766 | +void diff_options(DiffConfig *pCfg, int isGDiff){ | |
| 2732 | 2767 | u64 diffFlags = 0; |
| 2733 | 2768 | const char *z; |
| 2734 | 2769 | int f; |
| 2770 | + | |
| 2771 | + memset(pCfg, 0, sizeof(*pCfg)); | |
| 2735 | 2772 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2736 | 2773 | diffFlags = DIFF_IGNORE_EOLWS; |
| 2737 | 2774 | } |
| 2738 | 2775 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| 2739 | 2776 | diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ |
| @@ -2780,11 +2817,11 @@ | ||
| 2780 | 2817 | |
| 2781 | 2818 | /* Undocumented and unsupported flags used for development |
| 2782 | 2819 | ** debugging and analysis: */ |
| 2783 | 2820 | if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; |
| 2784 | 2821 | if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; |
| 2785 | - return diffFlags; | |
| 2822 | + pCfg->diffFlags = diffFlags; | |
| 2786 | 2823 | } |
| 2787 | 2824 | |
| 2788 | 2825 | /* |
| 2789 | 2826 | ** COMMAND: test-diff |
| 2790 | 2827 | ** COMMAND: xdiff |
| @@ -2802,39 +2839,38 @@ | ||
| 2802 | 2839 | ** See the "diff" command for a full list of command-line options. |
| 2803 | 2840 | ** |
| 2804 | 2841 | ** This command used to be called "test-diff". The older "test-diff" spelling |
| 2805 | 2842 | ** still works, for compatibility. |
| 2806 | 2843 | */ |
| 2807 | -void test_diff_cmd(void){ | |
| 2844 | +void xdiff_cmd(void){ | |
| 2808 | 2845 | Blob a, b, out; |
| 2809 | - u64 diffFlag; | |
| 2810 | 2846 | const char *zRe; /* Regex filter for diff output */ |
| 2811 | - ReCompiled *pRe = 0; /* Regex filter for diff output */ | |
| 2847 | + DiffConfig DCfg; | |
| 2812 | 2848 | |
| 2813 | 2849 | if( find_option("tk",0,0)!=0 ){ |
| 2814 | - diff_tk("test-diff", 2); | |
| 2850 | + diff_tk("xdiff", 2); | |
| 2815 | 2851 | return; |
| 2816 | 2852 | } |
| 2817 | 2853 | find_option("i",0,0); |
| 2818 | 2854 | find_option("v",0,0); |
| 2855 | + diff_options(&DCfg, 0); | |
| 2819 | 2856 | zRe = find_option("regexp","e",1); |
| 2820 | 2857 | if( zRe ){ |
| 2821 | - const char *zErr = re_compile(&pRe, zRe, 0); | |
| 2858 | + const char *zErr = re_compile(&DCfg.pRe, zRe, 0); | |
| 2822 | 2859 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2823 | 2860 | } |
| 2824 | - diffFlag = diff_options(); | |
| 2825 | 2861 | verify_all_options(); |
| 2826 | 2862 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2827 | 2863 | blob_zero(&out); |
| 2828 | - diff_begin(diffFlag); | |
| 2829 | - diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); | |
| 2864 | + diff_begin(&DCfg); | |
| 2865 | + diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out); | |
| 2830 | 2866 | blob_read_from_file(&a, g.argv[2], ExtFILE); |
| 2831 | 2867 | blob_read_from_file(&b, g.argv[3], ExtFILE); |
| 2832 | - text_diff(&a, &b, &out, pRe, diffFlag); | |
| 2868 | + text_diff(&a, &b, &out, &DCfg); | |
| 2833 | 2869 | blob_write_to_file(&out, "-"); |
| 2834 | - diff_end(diffFlag, 0); | |
| 2835 | - re_free(pRe); | |
| 2870 | + diff_end(&DCfg, 0); | |
| 2871 | + re_free(DCfg.pRe); | |
| 2836 | 2872 | } |
| 2837 | 2873 | |
| 2838 | 2874 | /************************************************************************** |
| 2839 | 2875 | ** The basic difference engine is above. What follows is the annotation |
| 2840 | 2876 | ** engine. Both are in the same file since they share many components. |
| 2841 | 2877 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -70,12 +70,47 @@ | |
| 70 | /* |
| 71 | ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes) |
| 72 | */ |
| 73 | #define LENGTH_MASK_SZ 15 |
| 74 | #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) |
| 75 | |
| 76 | #endif /* INTERFACE */ |
| 77 | |
| 78 | /* |
| 79 | ** Information about each line of a file being diffed. |
| 80 | ** |
| 81 | ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length |
| @@ -332,11 +367,11 @@ | |
| 332 | ** Output a patch-style text diff. |
| 333 | */ |
| 334 | static void contextDiff( |
| 335 | DContext *p, /* The difference */ |
| 336 | Blob *pOut, /* Output a context diff to here */ |
| 337 | u64 diffFlags /* Flags controlling the diff format */ |
| 338 | ){ |
| 339 | DLine *A; /* Left side of the diff */ |
| 340 | DLine *B; /* Right side of the diff */ |
| 341 | int a = 0; /* Index of next line in A[] */ |
| 342 | int b = 0; /* Index of next line in B[] */ |
| @@ -351,12 +386,12 @@ | |
| 351 | static int nChunk = 0; /* Number of diff chunks seen so far */ |
| 352 | int nContext; /* Number of lines of context */ |
| 353 | int showLn; /* Show line numbers */ |
| 354 | int showDivider = 0; /* True to show the divider between diff blocks */ |
| 355 | |
| 356 | nContext = diff_context_lines(diffFlags); |
| 357 | showLn = (diffFlags & DIFF_LINENO)!=0; |
| 358 | A = p->aFrom; |
| 359 | B = p->aTo; |
| 360 | R = p->aEdit; |
| 361 | mxr = p->nEdit; |
| 362 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1119,11 +1154,11 @@ | |
| 1119 | blob_append_char(p->pOut, ','); |
| 1120 | blob_append_json_literal(p->pOut, pX->z + x, pX->n - x); |
| 1121 | blob_append(p->pOut, "],\n",3); |
| 1122 | } |
| 1123 | static void dfjsonEnd(DiffBuilder *p){ |
| 1124 | blob_append(p->pOut, "0]", 2); |
| 1125 | fossil_free(p); |
| 1126 | } |
| 1127 | static DiffBuilder *dfjsonNew(Blob *pOut){ |
| 1128 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1129 | p->xSkip = dfjsonSkip; |
| @@ -1631,21 +1666,21 @@ | |
| 1631 | blob_append_char(p->pOut, '\n'); |
| 1632 | } |
| 1633 | static void dfsbsEnd(DiffBuilder *p){ |
| 1634 | fossil_free(p); |
| 1635 | } |
| 1636 | static DiffBuilder *dfsbsNew(Blob *pOut, u64 diffFlags){ |
| 1637 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1638 | p->xSkip = dfsbsSkip; |
| 1639 | p->xCommon = dfsbsCommon; |
| 1640 | p->xInsert = dfsbsInsert; |
| 1641 | p->xDelete = dfsbsDelete; |
| 1642 | p->xReplace = dfsbsEdit; |
| 1643 | p->xEdit = dfsbsEdit; |
| 1644 | p->xEnd = dfsbsEnd; |
| 1645 | p->lnLeft = p->lnRight = 0; |
| 1646 | p->width = diff_width(diffFlags); |
| 1647 | p->pOut = pOut; |
| 1648 | return p; |
| 1649 | } |
| 1650 | /****************************************************************************/ |
| 1651 | /* |
| @@ -1767,11 +1802,11 @@ | |
| 1767 | ** mismatch. |
| 1768 | */ |
| 1769 | static unsigned char *diffBlockAlignment( |
| 1770 | const DLine *aLeft, int nLeft, /* Text on the left */ |
| 1771 | const DLine *aRight, int nRight, /* Text on the right */ |
| 1772 | u64 diffFlags, /* Flags passed into the original diff */ |
| 1773 | int *pNResult /* OUTPUT: Bytes of result */ |
| 1774 | ){ |
| 1775 | int i, j, k; /* Loop counters */ |
| 1776 | int *a; /* One row of the Wagner matrix */ |
| 1777 | int *pToFree; /* Space that needs to be freed */ |
| @@ -1795,11 +1830,11 @@ | |
| 1795 | /* For large alignments, use a divide and conquer algorithm that is |
| 1796 | ** O(NlogN). The result is not as precise, but this whole thing is an |
| 1797 | ** approximation anyhow, and the faster response time is an acceptable |
| 1798 | ** trade-off for reduced precision. |
| 1799 | */ |
| 1800 | if( nLeft*nRight>DIFF_ALIGN_MX && (diffFlags & DIFF_SLOW_SBS)==0 ){ |
| 1801 | const DLine *aSmall; /* The smaller of aLeft and aRight */ |
| 1802 | const DLine *aBig; /* The larger of aLeft and aRight */ |
| 1803 | int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */ |
| 1804 | int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */ |
| 1805 | int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */ |
| @@ -1832,14 +1867,14 @@ | |
| 1832 | iDivLeft = iDivBig; |
| 1833 | }else{ |
| 1834 | iDivRight = iDivBig; |
| 1835 | iDivLeft = iDivSmall; |
| 1836 | } |
| 1837 | a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,diffFlags,&n1); |
| 1838 | a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft, |
| 1839 | aRight+iDivRight, nRight-iDivRight, |
| 1840 | diffFlags, &n2); |
| 1841 | a1 = fossil_realloc(a1, n1+n2 ); |
| 1842 | memcpy(a1+n1,a2,n2); |
| 1843 | fossil_free(a2); |
| 1844 | *pNResult = n1+n2; |
| 1845 | return a1; |
| @@ -1938,12 +1973,11 @@ | |
| 1938 | /* |
| 1939 | ** Format a diff using a DiffBuilder object |
| 1940 | */ |
| 1941 | static void formatDiff( |
| 1942 | DContext *p, /* The computed diff */ |
| 1943 | ReCompiled *pRe, /* Only show changes that match this regex */ |
| 1944 | u64 diffFlags, /* Flags controlling the diff */ |
| 1945 | DiffBuilder *pBuilder /* The formatter object */ |
| 1946 | ){ |
| 1947 | const DLine *A; /* Left side of the diff */ |
| 1948 | const DLine *B; /* Right side of the diff */ |
| 1949 | unsigned int a = 0; /* Index of next line in A[] */ |
| @@ -1956,11 +1990,11 @@ | |
| 1956 | unsigned int i, j; /* Loop counters */ |
| 1957 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1958 | signed int skip = 0; /* Number of lines to skip */ |
| 1959 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1960 | |
| 1961 | nContext = diff_context_lines(diffFlags); |
| 1962 | A = p->aFrom; |
| 1963 | B = p->aTo; |
| 1964 | R = p->aEdit; |
| 1965 | mxr = p->nEdit; |
| 1966 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1972,19 +2006,19 @@ | |
| 1972 | /* If there is a regex, skip this block (generate no diff output) |
| 1973 | ** if the regex matches or does not match both insert and delete. |
| 1974 | ** Only display the block if one side matches but the other side does |
| 1975 | ** not. |
| 1976 | */ |
| 1977 | if( pRe ){ |
| 1978 | int hideBlock = 1; |
| 1979 | int xa = a, xb = b; |
| 1980 | for(i=0; hideBlock && i<nr; i++){ |
| 1981 | int c1, c2; |
| 1982 | xa += R[r+i*3]; |
| 1983 | xb += R[r+i*3]; |
| 1984 | c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]); |
| 1985 | c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]); |
| 1986 | hideBlock = c1==c2; |
| 1987 | xa += R[r+i*3+1]; |
| 1988 | xb += R[r+i*3+2]; |
| 1989 | } |
| 1990 | if( hideBlock ){ |
| @@ -2050,11 +2084,11 @@ | |
| 2050 | ma += R[r+i*3+1] + m; |
| 2051 | mb += R[r+i*3+2] + m; |
| 2052 | } |
| 2053 | |
| 2054 | /* Try to find an alignment for the lines within this one block */ |
| 2055 | alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, diffFlags, &nAlign); |
| 2056 | |
| 2057 | for(j=0; ma+mb>0; j++){ |
| 2058 | assert( j<nAlign ); |
| 2059 | switch( alignment[j] ){ |
| 2060 | case 1: { |
| @@ -2511,13 +2545,13 @@ | |
| 2511 | |
| 2512 | /* |
| 2513 | ** Extract the number of lines of context from diffFlags. Supply an |
| 2514 | ** appropriate default if no context width is specified. |
| 2515 | */ |
| 2516 | int diff_context_lines(u64 diffFlags){ |
| 2517 | int n = diffFlags & DIFF_CONTEXT_MASK; |
| 2518 | if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; |
| 2519 | return n; |
| 2520 | } |
| 2521 | |
| 2522 | /* |
| 2523 | ** Extract the width of columns for side-by-side diff. Supply an |
| @@ -2527,12 +2561,12 @@ | |
| 2527 | ** term-width = 2*diff-col + diff-marker + 1 |
| 2528 | ** diff-col = lineno + lmargin + text-width + rmargin |
| 2529 | ** |
| 2530 | ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin |
| 2531 | */ |
| 2532 | int diff_width(u64 diffFlags){ |
| 2533 | int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); |
| 2534 | if( w==0 ){ |
| 2535 | static struct { |
| 2536 | unsigned int lineno, lmargin, text, rmargin, marker; |
| 2537 | } sbsW = { 5, 2, 0, 0, 3 }; |
| 2538 | const unsigned int wMin = 24, wMax = 132; |
| @@ -2589,41 +2623,40 @@ | |
| 2589 | */ |
| 2590 | int *text_diff( |
| 2591 | Blob *pA_Blob, /* FROM file */ |
| 2592 | Blob *pB_Blob, /* TO file */ |
| 2593 | Blob *pOut, /* Write diff here if not NULL */ |
| 2594 | ReCompiled *pRe, /* Only output changes where this Regexp matches */ |
| 2595 | u64 diffFlags /* DIFF_* flags defined above */ |
| 2596 | ){ |
| 2597 | int ignoreWs; /* Ignore whitespace */ |
| 2598 | DContext c; |
| 2599 | |
| 2600 | if( diffFlags & DIFF_INVERT ){ |
| 2601 | Blob *pTemp = pA_Blob; |
| 2602 | pA_Blob = pB_Blob; |
| 2603 | pB_Blob = pTemp; |
| 2604 | } |
| 2605 | ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0; |
| 2606 | blob_to_utf8_no_bom(pA_Blob, 0); |
| 2607 | blob_to_utf8_no_bom(pB_Blob, 0); |
| 2608 | |
| 2609 | /* Prepare the input files */ |
| 2610 | memset(&c, 0, sizeof(c)); |
| 2611 | if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 2612 | c.xDiffer = compare_dline_ignore_allws; |
| 2613 | }else{ |
| 2614 | c.xDiffer = compare_dline; |
| 2615 | } |
| 2616 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 2617 | &c.nFrom, diffFlags); |
| 2618 | c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), |
| 2619 | &c.nTo, diffFlags); |
| 2620 | if( c.aFrom==0 || c.aTo==0 ){ |
| 2621 | fossil_free(c.aFrom); |
| 2622 | fossil_free(c.aTo); |
| 2623 | if( pOut ){ |
| 2624 | diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags); |
| 2625 | } |
| 2626 | return 0; |
| 2627 | } |
| 2628 | |
| 2629 | /* Compute the difference */ |
| @@ -2630,32 +2663,32 @@ | |
| 2630 | diff_all(&c); |
| 2631 | if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ |
| 2632 | fossil_free(c.aFrom); |
| 2633 | fossil_free(c.aTo); |
| 2634 | fossil_free(c.aEdit); |
| 2635 | if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags); |
| 2636 | return 0; |
| 2637 | } |
| 2638 | if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){ |
| 2639 | int i, m, n; |
| 2640 | int *a = c.aEdit; |
| 2641 | int mx = c.nEdit; |
| 2642 | for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; } |
| 2643 | if( n>10000 ){ |
| 2644 | fossil_free(c.aFrom); |
| 2645 | fossil_free(c.aTo); |
| 2646 | fossil_free(c.aEdit); |
| 2647 | if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); |
| 2648 | return 0; |
| 2649 | } |
| 2650 | } |
| 2651 | if( (diffFlags & DIFF_NOOPT)==0 ){ |
| 2652 | diff_optimize(&c); |
| 2653 | } |
| 2654 | |
| 2655 | if( pOut ){ |
| 2656 | if( diffFlags & DIFF_NUMSTAT ){ |
| 2657 | int nDel = 0, nIns = 0, i; |
| 2658 | for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){ |
| 2659 | nDel += c.aEdit[i+1]; |
| 2660 | nIns += c.aEdit[i+2]; |
| 2661 | } |
| @@ -2663,40 +2696,40 @@ | |
| 2663 | g.diffCnt[2] += nDel; |
| 2664 | if( nIns+nDel ){ |
| 2665 | g.diffCnt[0]++; |
| 2666 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2667 | } |
| 2668 | }else if( diffFlags & DIFF_RAW ){ |
| 2669 | const int *R = c.aEdit; |
| 2670 | unsigned int r; |
| 2671 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 2672 | blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", |
| 2673 | R[r], R[r+1], R[r+2]); |
| 2674 | } |
| 2675 | }else if( diffFlags & DIFF_JSON ){ |
| 2676 | DiffBuilder *pBuilder = dfjsonNew(pOut); |
| 2677 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2678 | blob_append_char(pOut, '\n'); |
| 2679 | }else if( diffFlags & DIFF_TCL ){ |
| 2680 | DiffBuilder *pBuilder = dftclNew(pOut); |
| 2681 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2682 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 2683 | DiffBuilder *pBuilder; |
| 2684 | if( diffFlags & DIFF_HTML ){ |
| 2685 | pBuilder = dfsplitNew(pOut); |
| 2686 | }else{ |
| 2687 | pBuilder = dfsbsNew(pOut, diffFlags); |
| 2688 | } |
| 2689 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2690 | }else if( diffFlags & DIFF_DEBUG ){ |
| 2691 | DiffBuilder *pBuilder = dfdebugNew(pOut); |
| 2692 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2693 | }else if( diffFlags & DIFF_HTML ){ |
| 2694 | DiffBuilder *pBuilder = dfunifiedNew(pOut); |
| 2695 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2696 | }else{ |
| 2697 | contextDiff(&c, pOut, diffFlags); |
| 2698 | } |
| 2699 | fossil_free(c.aFrom); |
| 2700 | fossil_free(c.aTo); |
| 2701 | fossil_free(c.aEdit); |
| 2702 | return 0; |
| @@ -2709,31 +2742,35 @@ | |
| 2709 | return c.aEdit; |
| 2710 | } |
| 2711 | } |
| 2712 | |
| 2713 | /* |
| 2714 | ** Process diff-related command-line options and return an appropriate |
| 2715 | ** "diffFlags" integer. |
| 2716 | ** |
| 2717 | ** --brief Show filenames only DIFF_BRIEF |
| 2718 | ** -c|--context N N lines of context. DIFF_CONTEXT_MASK |
| 2719 | ** --html Format for HTML DIFF_HTML |
| 2720 | ** --invert Invert the diff DIFF_INVERT |
| 2721 | ** -n|--linenum Show line numbers DIFF_LINENO |
| 2722 | ** --noopt Disable optimization DIFF_NOOPT |
| 2723 | ** --numstat Show change counts DIFF_NUMSTAT |
| 2724 | ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR |
| 2725 | ** --unified Unified diff. ~DIFF_SIDEBYSIDE |
| 2726 | ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS |
| 2727 | ** -W|--width N N character lines. DIFF_WIDTH_MASK |
| 2728 | ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE |
| 2729 | ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS |
| 2730 | */ |
| 2731 | u64 diff_options(void){ |
| 2732 | u64 diffFlags = 0; |
| 2733 | const char *z; |
| 2734 | int f; |
| 2735 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2736 | diffFlags = DIFF_IGNORE_EOLWS; |
| 2737 | } |
| 2738 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| 2739 | diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ |
| @@ -2780,11 +2817,11 @@ | |
| 2780 | |
| 2781 | /* Undocumented and unsupported flags used for development |
| 2782 | ** debugging and analysis: */ |
| 2783 | if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; |
| 2784 | if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; |
| 2785 | return diffFlags; |
| 2786 | } |
| 2787 | |
| 2788 | /* |
| 2789 | ** COMMAND: test-diff |
| 2790 | ** COMMAND: xdiff |
| @@ -2802,39 +2839,38 @@ | |
| 2802 | ** See the "diff" command for a full list of command-line options. |
| 2803 | ** |
| 2804 | ** This command used to be called "test-diff". The older "test-diff" spelling |
| 2805 | ** still works, for compatibility. |
| 2806 | */ |
| 2807 | void test_diff_cmd(void){ |
| 2808 | Blob a, b, out; |
| 2809 | u64 diffFlag; |
| 2810 | const char *zRe; /* Regex filter for diff output */ |
| 2811 | ReCompiled *pRe = 0; /* Regex filter for diff output */ |
| 2812 | |
| 2813 | if( find_option("tk",0,0)!=0 ){ |
| 2814 | diff_tk("test-diff", 2); |
| 2815 | return; |
| 2816 | } |
| 2817 | find_option("i",0,0); |
| 2818 | find_option("v",0,0); |
| 2819 | zRe = find_option("regexp","e",1); |
| 2820 | if( zRe ){ |
| 2821 | const char *zErr = re_compile(&pRe, zRe, 0); |
| 2822 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2823 | } |
| 2824 | diffFlag = diff_options(); |
| 2825 | verify_all_options(); |
| 2826 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2827 | blob_zero(&out); |
| 2828 | diff_begin(diffFlag); |
| 2829 | diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); |
| 2830 | blob_read_from_file(&a, g.argv[2], ExtFILE); |
| 2831 | blob_read_from_file(&b, g.argv[3], ExtFILE); |
| 2832 | text_diff(&a, &b, &out, pRe, diffFlag); |
| 2833 | blob_write_to_file(&out, "-"); |
| 2834 | diff_end(diffFlag, 0); |
| 2835 | re_free(pRe); |
| 2836 | } |
| 2837 | |
| 2838 | /************************************************************************** |
| 2839 | ** The basic difference engine is above. What follows is the annotation |
| 2840 | ** engine. Both are in the same file since they share many components. |
| 2841 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -70,12 +70,47 @@ | |
| 70 | /* |
| 71 | ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes) |
| 72 | */ |
| 73 | #define LENGTH_MASK_SZ 15 |
| 74 | #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) |
| 75 | |
| 76 | /* |
| 77 | ** An instance of this object describes the formatting and processing |
| 78 | ** details desired of a "diff" operation. |
| 79 | ** |
| 80 | ** Conceptually, this object is as an encoding of the command-line options |
| 81 | ** for the "fossil diff" command. That is not a precise description, though, |
| 82 | ** because not all diff operations are started from the command-line. But |
| 83 | ** the idea is sound. |
| 84 | ** |
| 85 | ** Information encoded by this object includes but is not limited to: |
| 86 | ** |
| 87 | ** * The desired output format (unified vs. side-by-side, |
| 88 | ** TCL, JSON, HTML vs. plain-text). |
| 89 | ** |
| 90 | ** * Number of lines of context surrounding each difference block |
| 91 | ** |
| 92 | ** * Width of output columns for text side-by-side diffop |
| 93 | */ |
| 94 | struct DiffConfig { |
| 95 | u64 diffFlags; /* Diff flags */ |
| 96 | u32 nFile; /* Number of files diffed so far */ |
| 97 | const char *zDiffCmd; /* External diff command to use instead of builtin */ |
| 98 | const char *zBinGlob; /* GLOB pattern for binary files */ |
| 99 | ReCompiled *pRe; /* Show only changes matching this pattern */ |
| 100 | }; |
| 101 | |
| 102 | #endif /* INTERFACE */ |
| 103 | |
| 104 | /* |
| 105 | ** Initialize memory for a DiffConfig based on just a diffFlags integer. |
| 106 | */ |
| 107 | DiffConfig *diff_config_init(DiffConfig *pCfg, u64 diffFlags){ |
| 108 | memset(pCfg, 0, sizeof(*pCfg)); |
| 109 | pCfg->diffFlags = diffFlags; |
| 110 | return pCfg; |
| 111 | } |
| 112 | |
| 113 | /* |
| 114 | ** Information about each line of a file being diffed. |
| 115 | ** |
| 116 | ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length |
| @@ -332,11 +367,11 @@ | |
| 367 | ** Output a patch-style text diff. |
| 368 | */ |
| 369 | static void contextDiff( |
| 370 | DContext *p, /* The difference */ |
| 371 | Blob *pOut, /* Output a context diff to here */ |
| 372 | DiffConfig *pCfg /* Configuration options */ |
| 373 | ){ |
| 374 | DLine *A; /* Left side of the diff */ |
| 375 | DLine *B; /* Right side of the diff */ |
| 376 | int a = 0; /* Index of next line in A[] */ |
| 377 | int b = 0; /* Index of next line in B[] */ |
| @@ -351,12 +386,12 @@ | |
| 386 | static int nChunk = 0; /* Number of diff chunks seen so far */ |
| 387 | int nContext; /* Number of lines of context */ |
| 388 | int showLn; /* Show line numbers */ |
| 389 | int showDivider = 0; /* True to show the divider between diff blocks */ |
| 390 | |
| 391 | nContext = diff_context_lines(pCfg); |
| 392 | showLn = (pCfg->diffFlags & DIFF_LINENO)!=0; |
| 393 | A = p->aFrom; |
| 394 | B = p->aTo; |
| 395 | R = p->aEdit; |
| 396 | mxr = p->nEdit; |
| 397 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1119,11 +1154,11 @@ | |
| 1154 | blob_append_char(p->pOut, ','); |
| 1155 | blob_append_json_literal(p->pOut, pX->z + x, pX->n - x); |
| 1156 | blob_append(p->pOut, "],\n",3); |
| 1157 | } |
| 1158 | static void dfjsonEnd(DiffBuilder *p){ |
| 1159 | blob_append(p->pOut, "0]}", 3); |
| 1160 | fossil_free(p); |
| 1161 | } |
| 1162 | static DiffBuilder *dfjsonNew(Blob *pOut){ |
| 1163 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1164 | p->xSkip = dfjsonSkip; |
| @@ -1631,21 +1666,21 @@ | |
| 1666 | blob_append_char(p->pOut, '\n'); |
| 1667 | } |
| 1668 | static void dfsbsEnd(DiffBuilder *p){ |
| 1669 | fossil_free(p); |
| 1670 | } |
| 1671 | static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){ |
| 1672 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1673 | p->xSkip = dfsbsSkip; |
| 1674 | p->xCommon = dfsbsCommon; |
| 1675 | p->xInsert = dfsbsInsert; |
| 1676 | p->xDelete = dfsbsDelete; |
| 1677 | p->xReplace = dfsbsEdit; |
| 1678 | p->xEdit = dfsbsEdit; |
| 1679 | p->xEnd = dfsbsEnd; |
| 1680 | p->lnLeft = p->lnRight = 0; |
| 1681 | p->width = diff_width(pCfg); |
| 1682 | p->pOut = pOut; |
| 1683 | return p; |
| 1684 | } |
| 1685 | /****************************************************************************/ |
| 1686 | /* |
| @@ -1767,11 +1802,11 @@ | |
| 1802 | ** mismatch. |
| 1803 | */ |
| 1804 | static unsigned char *diffBlockAlignment( |
| 1805 | const DLine *aLeft, int nLeft, /* Text on the left */ |
| 1806 | const DLine *aRight, int nRight, /* Text on the right */ |
| 1807 | DiffConfig *pCfg, /* Configuration options */ |
| 1808 | int *pNResult /* OUTPUT: Bytes of result */ |
| 1809 | ){ |
| 1810 | int i, j, k; /* Loop counters */ |
| 1811 | int *a; /* One row of the Wagner matrix */ |
| 1812 | int *pToFree; /* Space that needs to be freed */ |
| @@ -1795,11 +1830,11 @@ | |
| 1830 | /* For large alignments, use a divide and conquer algorithm that is |
| 1831 | ** O(NlogN). The result is not as precise, but this whole thing is an |
| 1832 | ** approximation anyhow, and the faster response time is an acceptable |
| 1833 | ** trade-off for reduced precision. |
| 1834 | */ |
| 1835 | if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){ |
| 1836 | const DLine *aSmall; /* The smaller of aLeft and aRight */ |
| 1837 | const DLine *aBig; /* The larger of aLeft and aRight */ |
| 1838 | int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */ |
| 1839 | int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */ |
| 1840 | int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */ |
| @@ -1832,14 +1867,14 @@ | |
| 1867 | iDivLeft = iDivBig; |
| 1868 | }else{ |
| 1869 | iDivRight = iDivBig; |
| 1870 | iDivLeft = iDivSmall; |
| 1871 | } |
| 1872 | a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1); |
| 1873 | a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft, |
| 1874 | aRight+iDivRight, nRight-iDivRight, |
| 1875 | pCfg, &n2); |
| 1876 | a1 = fossil_realloc(a1, n1+n2 ); |
| 1877 | memcpy(a1+n1,a2,n2); |
| 1878 | fossil_free(a2); |
| 1879 | *pNResult = n1+n2; |
| 1880 | return a1; |
| @@ -1938,12 +1973,11 @@ | |
| 1973 | /* |
| 1974 | ** Format a diff using a DiffBuilder object |
| 1975 | */ |
| 1976 | static void formatDiff( |
| 1977 | DContext *p, /* The computed diff */ |
| 1978 | DiffConfig *pCfg, /* Configuration options */ |
| 1979 | DiffBuilder *pBuilder /* The formatter object */ |
| 1980 | ){ |
| 1981 | const DLine *A; /* Left side of the diff */ |
| 1982 | const DLine *B; /* Right side of the diff */ |
| 1983 | unsigned int a = 0; /* Index of next line in A[] */ |
| @@ -1956,11 +1990,11 @@ | |
| 1990 | unsigned int i, j; /* Loop counters */ |
| 1991 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1992 | signed int skip = 0; /* Number of lines to skip */ |
| 1993 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1994 | |
| 1995 | nContext = diff_context_lines(pCfg); |
| 1996 | A = p->aFrom; |
| 1997 | B = p->aTo; |
| 1998 | R = p->aEdit; |
| 1999 | mxr = p->nEdit; |
| 2000 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -1972,19 +2006,19 @@ | |
| 2006 | /* If there is a regex, skip this block (generate no diff output) |
| 2007 | ** if the regex matches or does not match both insert and delete. |
| 2008 | ** Only display the block if one side matches but the other side does |
| 2009 | ** not. |
| 2010 | */ |
| 2011 | if( pCfg->pRe ){ |
| 2012 | int hideBlock = 1; |
| 2013 | int xa = a, xb = b; |
| 2014 | for(i=0; hideBlock && i<nr; i++){ |
| 2015 | int c1, c2; |
| 2016 | xa += R[r+i*3]; |
| 2017 | xb += R[r+i*3]; |
| 2018 | c1 = re_dline_match(pCfg->pRe, &A[xa], R[r+i*3+1]); |
| 2019 | c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]); |
| 2020 | hideBlock = c1==c2; |
| 2021 | xa += R[r+i*3+1]; |
| 2022 | xb += R[r+i*3+2]; |
| 2023 | } |
| 2024 | if( hideBlock ){ |
| @@ -2050,11 +2084,11 @@ | |
| 2084 | ma += R[r+i*3+1] + m; |
| 2085 | mb += R[r+i*3+2] + m; |
| 2086 | } |
| 2087 | |
| 2088 | /* Try to find an alignment for the lines within this one block */ |
| 2089 | alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign); |
| 2090 | |
| 2091 | for(j=0; ma+mb>0; j++){ |
| 2092 | assert( j<nAlign ); |
| 2093 | switch( alignment[j] ){ |
| 2094 | case 1: { |
| @@ -2511,13 +2545,13 @@ | |
| 2545 | |
| 2546 | /* |
| 2547 | ** Extract the number of lines of context from diffFlags. Supply an |
| 2548 | ** appropriate default if no context width is specified. |
| 2549 | */ |
| 2550 | int diff_context_lines(DiffConfig *pCfg){ |
| 2551 | int n = pCfg->diffFlags & DIFF_CONTEXT_MASK; |
| 2552 | if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; |
| 2553 | return n; |
| 2554 | } |
| 2555 | |
| 2556 | /* |
| 2557 | ** Extract the width of columns for side-by-side diff. Supply an |
| @@ -2527,12 +2561,12 @@ | |
| 2561 | ** term-width = 2*diff-col + diff-marker + 1 |
| 2562 | ** diff-col = lineno + lmargin + text-width + rmargin |
| 2563 | ** |
| 2564 | ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin |
| 2565 | */ |
| 2566 | int diff_width(DiffConfig *pCfg){ |
| 2567 | int w = (pCfg->diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); |
| 2568 | if( w==0 ){ |
| 2569 | static struct { |
| 2570 | unsigned int lineno, lmargin, text, rmargin, marker; |
| 2571 | } sbsW = { 5, 2, 0, 0, 3 }; |
| 2572 | const unsigned int wMin = 24, wMax = 132; |
| @@ -2589,41 +2623,40 @@ | |
| 2623 | */ |
| 2624 | int *text_diff( |
| 2625 | Blob *pA_Blob, /* FROM file */ |
| 2626 | Blob *pB_Blob, /* TO file */ |
| 2627 | Blob *pOut, /* Write diff here if not NULL */ |
| 2628 | DiffConfig *pCfg /* Configuration options */ |
| 2629 | ){ |
| 2630 | int ignoreWs; /* Ignore whitespace */ |
| 2631 | DContext c; |
| 2632 | |
| 2633 | if( pCfg->diffFlags & DIFF_INVERT ){ |
| 2634 | Blob *pTemp = pA_Blob; |
| 2635 | pA_Blob = pB_Blob; |
| 2636 | pB_Blob = pTemp; |
| 2637 | } |
| 2638 | ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0; |
| 2639 | blob_to_utf8_no_bom(pA_Blob, 0); |
| 2640 | blob_to_utf8_no_bom(pB_Blob, 0); |
| 2641 | |
| 2642 | /* Prepare the input files */ |
| 2643 | memset(&c, 0, sizeof(c)); |
| 2644 | if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ |
| 2645 | c.xDiffer = compare_dline_ignore_allws; |
| 2646 | }else{ |
| 2647 | c.xDiffer = compare_dline; |
| 2648 | } |
| 2649 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 2650 | &c.nFrom, pCfg->diffFlags); |
| 2651 | c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), |
| 2652 | &c.nTo, pCfg->diffFlags); |
| 2653 | if( c.aFrom==0 || c.aTo==0 ){ |
| 2654 | fossil_free(c.aFrom); |
| 2655 | fossil_free(c.aTo); |
| 2656 | if( pOut ){ |
| 2657 | diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags); |
| 2658 | } |
| 2659 | return 0; |
| 2660 | } |
| 2661 | |
| 2662 | /* Compute the difference */ |
| @@ -2630,32 +2663,32 @@ | |
| 2663 | diff_all(&c); |
| 2664 | if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ |
| 2665 | fossil_free(c.aFrom); |
| 2666 | fossil_free(c.aTo); |
| 2667 | fossil_free(c.aEdit); |
| 2668 | if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags); |
| 2669 | return 0; |
| 2670 | } |
| 2671 | if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){ |
| 2672 | int i, m, n; |
| 2673 | int *a = c.aEdit; |
| 2674 | int mx = c.nEdit; |
| 2675 | for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; } |
| 2676 | if( n>10000 ){ |
| 2677 | fossil_free(c.aFrom); |
| 2678 | fossil_free(c.aTo); |
| 2679 | fossil_free(c.aEdit); |
| 2680 | if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags); |
| 2681 | return 0; |
| 2682 | } |
| 2683 | } |
| 2684 | if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){ |
| 2685 | diff_optimize(&c); |
| 2686 | } |
| 2687 | |
| 2688 | if( pOut ){ |
| 2689 | if( pCfg->diffFlags & DIFF_NUMSTAT ){ |
| 2690 | int nDel = 0, nIns = 0, i; |
| 2691 | for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){ |
| 2692 | nDel += c.aEdit[i+1]; |
| 2693 | nIns += c.aEdit[i+2]; |
| 2694 | } |
| @@ -2663,40 +2696,40 @@ | |
| 2696 | g.diffCnt[2] += nDel; |
| 2697 | if( nIns+nDel ){ |
| 2698 | g.diffCnt[0]++; |
| 2699 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2700 | } |
| 2701 | }else if( pCfg->diffFlags & DIFF_RAW ){ |
| 2702 | const int *R = c.aEdit; |
| 2703 | unsigned int r; |
| 2704 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 2705 | blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", |
| 2706 | R[r], R[r+1], R[r+2]); |
| 2707 | } |
| 2708 | }else if( pCfg->diffFlags & DIFF_JSON ){ |
| 2709 | DiffBuilder *pBuilder = dfjsonNew(pOut); |
| 2710 | formatDiff(&c, pCfg, pBuilder); |
| 2711 | blob_append_char(pOut, '\n'); |
| 2712 | }else if( pCfg->diffFlags & DIFF_TCL ){ |
| 2713 | DiffBuilder *pBuilder = dftclNew(pOut); |
| 2714 | formatDiff(&c, pCfg, pBuilder); |
| 2715 | }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ |
| 2716 | DiffBuilder *pBuilder; |
| 2717 | if( pCfg->diffFlags & DIFF_HTML ){ |
| 2718 | pBuilder = dfsplitNew(pOut); |
| 2719 | }else{ |
| 2720 | pBuilder = dfsbsNew(pOut, pCfg); |
| 2721 | } |
| 2722 | formatDiff(&c, pCfg, pBuilder); |
| 2723 | }else if( pCfg->diffFlags & DIFF_DEBUG ){ |
| 2724 | DiffBuilder *pBuilder = dfdebugNew(pOut); |
| 2725 | formatDiff(&c, pCfg, pBuilder); |
| 2726 | }else if( pCfg->diffFlags & DIFF_HTML ){ |
| 2727 | DiffBuilder *pBuilder = dfunifiedNew(pOut); |
| 2728 | formatDiff(&c, pCfg, pBuilder); |
| 2729 | }else{ |
| 2730 | contextDiff(&c, pOut, pCfg); |
| 2731 | } |
| 2732 | fossil_free(c.aFrom); |
| 2733 | fossil_free(c.aTo); |
| 2734 | fossil_free(c.aEdit); |
| 2735 | return 0; |
| @@ -2709,31 +2742,35 @@ | |
| 2742 | return c.aEdit; |
| 2743 | } |
| 2744 | } |
| 2745 | |
| 2746 | /* |
| 2747 | ** Initialize the DiffConfig object using command-line options. |
| 2748 | ** |
| 2749 | ** Process diff-related command-line options and return an appropriate |
| 2750 | ** "diffFlags" integer. |
| 2751 | ** |
| 2752 | ** --brief Show filenames only DIFF_BRIEF |
| 2753 | ** -c|--context N N lines of context. DIFF_CONTEXT_MASK |
| 2754 | ** --html Format for HTML DIFF_HTML |
| 2755 | ** --invert Invert the diff DIFF_INVERT |
| 2756 | ** -n|--linenum Show line numbers DIFF_LINENO |
| 2757 | ** --noopt Disable optimization DIFF_NOOPT |
| 2758 | ** --numstat Show change counts DIFF_NUMSTAT |
| 2759 | ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR |
| 2760 | ** --unified Unified diff. ~DIFF_SIDEBYSIDE |
| 2761 | ** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS |
| 2762 | ** -W|--width N N character lines. DIFF_WIDTH_MASK |
| 2763 | ** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE |
| 2764 | ** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS |
| 2765 | */ |
| 2766 | void diff_options(DiffConfig *pCfg, int isGDiff){ |
| 2767 | u64 diffFlags = 0; |
| 2768 | const char *z; |
| 2769 | int f; |
| 2770 | |
| 2771 | memset(pCfg, 0, sizeof(*pCfg)); |
| 2772 | if( find_option("ignore-trailing-space","Z",0)!=0 ){ |
| 2773 | diffFlags = DIFF_IGNORE_EOLWS; |
| 2774 | } |
| 2775 | if( find_option("ignore-all-space","w",0)!=0 ){ |
| 2776 | diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ |
| @@ -2780,11 +2817,11 @@ | |
| 2817 | |
| 2818 | /* Undocumented and unsupported flags used for development |
| 2819 | ** debugging and analysis: */ |
| 2820 | if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; |
| 2821 | if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; |
| 2822 | pCfg->diffFlags = diffFlags; |
| 2823 | } |
| 2824 | |
| 2825 | /* |
| 2826 | ** COMMAND: test-diff |
| 2827 | ** COMMAND: xdiff |
| @@ -2802,39 +2839,38 @@ | |
| 2839 | ** See the "diff" command for a full list of command-line options. |
| 2840 | ** |
| 2841 | ** This command used to be called "test-diff". The older "test-diff" spelling |
| 2842 | ** still works, for compatibility. |
| 2843 | */ |
| 2844 | void xdiff_cmd(void){ |
| 2845 | Blob a, b, out; |
| 2846 | const char *zRe; /* Regex filter for diff output */ |
| 2847 | DiffConfig DCfg; |
| 2848 | |
| 2849 | if( find_option("tk",0,0)!=0 ){ |
| 2850 | diff_tk("xdiff", 2); |
| 2851 | return; |
| 2852 | } |
| 2853 | find_option("i",0,0); |
| 2854 | find_option("v",0,0); |
| 2855 | diff_options(&DCfg, 0); |
| 2856 | zRe = find_option("regexp","e",1); |
| 2857 | if( zRe ){ |
| 2858 | const char *zErr = re_compile(&DCfg.pRe, zRe, 0); |
| 2859 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2860 | } |
| 2861 | verify_all_options(); |
| 2862 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2863 | blob_zero(&out); |
| 2864 | diff_begin(&DCfg); |
| 2865 | diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out); |
| 2866 | blob_read_from_file(&a, g.argv[2], ExtFILE); |
| 2867 | blob_read_from_file(&b, g.argv[3], ExtFILE); |
| 2868 | text_diff(&a, &b, &out, &DCfg); |
| 2869 | blob_write_to_file(&out, "-"); |
| 2870 | diff_end(&DCfg, 0); |
| 2871 | re_free(DCfg.pRe); |
| 2872 | } |
| 2873 | |
| 2874 | /************************************************************************** |
| 2875 | ** The basic difference engine is above. What follows is the annotation |
| 2876 | ** engine. Both are in the same file since they share many components. |
| 2877 |
+90
-68
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -113,13 +113,15 @@ | ||
| 113 | 113 | } |
| 114 | 114 | |
| 115 | 115 | /* |
| 116 | 116 | ** Print the "Index:" message that patches wants to see at the top of a diff. |
| 117 | 117 | */ |
| 118 | -void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){ | |
| 119 | - if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| | |
| 120 | - DIFF_WEBPAGE|DIFF_TCL))==0 ){ | |
| 118 | +void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *diffBlob){ | |
| 119 | + if( (pCfg->diffFlags & | |
| 120 | + (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| | |
| 121 | + DIFF_WEBPAGE|DIFF_TCL))==0 | |
| 122 | + ){ | |
| 121 | 123 | char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); |
| 122 | 124 | if( !diffBlob ){ |
| 123 | 125 | fossil_print("%s", z); |
| 124 | 126 | }else{ |
| 125 | 127 | blob_appendf(diffBlob, "%s", z); |
| @@ -127,20 +129,22 @@ | ||
| 127 | 129 | fossil_free(z); |
| 128 | 130 | } |
| 129 | 131 | } |
| 130 | 132 | |
| 131 | 133 | /* |
| 132 | -** Print the +++/--- filename lines for a diff operation. | |
| 134 | +** Print the +++/--- filename lines or whatever filename information | |
| 135 | +** is appropriate for the output format. | |
| 133 | 136 | */ |
| 134 | 137 | void diff_print_filenames( |
| 135 | - const char *zLeft, | |
| 136 | - const char *zRight, | |
| 137 | - u64 diffFlags, | |
| 138 | - Blob *diffBlob | |
| 138 | + const char *zLeft, /* Name of the left file */ | |
| 139 | + const char *zRight, /* Name of the right file */ | |
| 140 | + DiffConfig *pCfg, /* Diff configuration */ | |
| 141 | + Blob *diffBlob /* Write to this blob, or stdout of this is NULL */ | |
| 139 | 142 | ){ |
| 140 | 143 | char *z = 0; |
| 141 | - if( diffFlags & (DIFF_BRIEF|DIFF_RAW|DIFF_JSON) ){ | |
| 144 | + u64 diffFlags = pCfg->diffFlags; | |
| 145 | + if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ | |
| 142 | 146 | /* no-op */ |
| 143 | 147 | }else if( diffFlags & DIFF_DEBUG ){ |
| 144 | 148 | fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", |
| 145 | 149 | zLeft, zRight); |
| 146 | 150 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| @@ -147,31 +151,42 @@ | ||
| 147 | 151 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 148 | 152 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 149 | 153 | }else{ |
| 150 | 154 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 151 | 155 | } |
| 152 | - }else if( diffFlags & DIFF_TCL ){ | |
| 156 | + }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){ | |
| 153 | 157 | Blob *pOut; |
| 154 | 158 | Blob x; |
| 155 | 159 | if( diffBlob ){ |
| 156 | 160 | pOut = diffBlob; |
| 157 | 161 | }else{ |
| 158 | 162 | blob_init(&x, 0, 0); |
| 159 | 163 | pOut = &x; |
| 160 | 164 | } |
| 161 | - blob_append(pOut, "FILE ", 5); | |
| 162 | - blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); | |
| 163 | - blob_append_char(pOut, ' '); | |
| 164 | - blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); | |
| 165 | - blob_append_char(pOut, '\n'); | |
| 165 | + if( diffFlags & DIFF_TCL ){ | |
| 166 | + blob_append(pOut, "FILE ", 5); | |
| 167 | + blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); | |
| 168 | + blob_append_char(pOut, ' '); | |
| 169 | + blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); | |
| 170 | + blob_append_char(pOut, '\n'); | |
| 171 | + }else{ | |
| 172 | + blob_trim(pOut); | |
| 173 | + blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1); | |
| 174 | + pCfg->nFile++; | |
| 175 | + blob_append(pOut, "\n \"leftname\":", -1); | |
| 176 | + blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft)); | |
| 177 | + blob_append(pOut, ",\n \"rightname\":", -1); | |
| 178 | + blob_append_json_literal(pOut, zRight, (int)strlen(zRight)); | |
| 179 | + blob_append(pOut, ",\n \"diff\":\n", -1); | |
| 180 | + } | |
| 166 | 181 | if( !diffBlob ){ |
| 167 | 182 | fossil_print("%s", blob_str(pOut)); |
| 168 | 183 | blob_reset(&x); |
| 169 | 184 | } |
| 170 | 185 | return; |
| 171 | 186 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 172 | - int w = diff_width(diffFlags); | |
| 187 | + int w = diff_width(pCfg); | |
| 173 | 188 | int n1 = strlen(zLeft); |
| 174 | 189 | int n2 = strlen(zRight); |
| 175 | 190 | int x; |
| 176 | 191 | if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ |
| 177 | 192 | if( n1>w*2 ) n1 = w*2; |
| @@ -282,11 +297,13 @@ | ||
| 282 | 297 | @ </body> |
| 283 | 298 | @ </html> |
| 284 | 299 | ; |
| 285 | 300 | |
| 286 | 301 | /* |
| 287 | -** State variables used by the --browser option for diff | |
| 302 | +** State variables used by the --browser option for diff. These must | |
| 303 | +** be static variables, not elements of DiffConfig, since they are | |
| 304 | +** used by the interrupt handler. | |
| 288 | 305 | */ |
| 289 | 306 | static char *tempDiffFilename; /* File holding the diff HTML */ |
| 290 | 307 | static FILE *diffOut; /* Open to write into tempDiffFilename */ |
| 291 | 308 | |
| 292 | 309 | /* Amount of delay (in milliseconds) between launching the |
| @@ -321,12 +338,12 @@ | ||
| 321 | 338 | ** hold the result. Make arrangements to delete that temporary |
| 322 | 339 | ** file if the diff is interrupted. |
| 323 | 340 | ** |
| 324 | 341 | ** For --browser and --webpage, output the HTML header. |
| 325 | 342 | */ |
| 326 | -void diff_begin(u64 diffFlags){ | |
| 327 | - if( (diffFlags & DIFF_BROWSER)!=0 ){ | |
| 343 | +void diff_begin(DiffConfig *pCfg){ | |
| 344 | + if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){ | |
| 328 | 345 | tempDiffFilename = fossil_temp_filename(); |
| 329 | 346 | tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename); |
| 330 | 347 | diffOut = fossil_freopen(tempDiffFilename,"wb",stdout); |
| 331 | 348 | if( diffOut==0 ){ |
| 332 | 349 | fossil_fatal("unable to create temporary file \"%s\"", |
| @@ -336,11 +353,11 @@ | ||
| 336 | 353 | signal(SIGINT, diff_www_interrupt); |
| 337 | 354 | #else |
| 338 | 355 | SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE); |
| 339 | 356 | #endif |
| 340 | 357 | } |
| 341 | - if( (diffFlags & DIFF_WEBPAGE)!=0 ){ | |
| 358 | + if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ | |
| 342 | 359 | fossil_print("%s",zWebpageHdr); |
| 343 | 360 | fflush(stdout); |
| 344 | 361 | } |
| 345 | 362 | } |
| 346 | 363 | |
| @@ -352,19 +369,19 @@ | ||
| 352 | 369 | ** |
| 353 | 370 | ** For --browser, close the connection to the temporary file, then |
| 354 | 371 | ** launch a web browser to view the file. After a delay |
| 355 | 372 | ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file. |
| 356 | 373 | */ |
| 357 | -void diff_end(u64 diffFlags, int nErr){ | |
| 358 | - if( (diffFlags & DIFF_WEBPAGE)!=0 ){ | |
| 359 | - if( diffFlags & DIFF_SIDEBYSIDE ){ | |
| 374 | +void diff_end(DiffConfig *pCfg, int nErr){ | |
| 375 | + if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ | |
| 376 | + if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ | |
| 360 | 377 | const unsigned char *zJs = builtin_file("diff.js", 0); |
| 361 | 378 | fossil_print("<script>\n%s</script>\n", zJs); |
| 362 | 379 | } |
| 363 | 380 | fossil_print("%s", zWebpageEnd); |
| 364 | 381 | } |
| 365 | - if( (diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ | |
| 382 | + if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ | |
| 366 | 383 | char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename); |
| 367 | 384 | fclose(diffOut); |
| 368 | 385 | diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout); |
| 369 | 386 | fossil_system(zCmd); |
| 370 | 387 | fossil_free(zCmd); |
| @@ -371,10 +388,13 @@ | ||
| 371 | 388 | diffOut = 0; |
| 372 | 389 | sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY); |
| 373 | 390 | file_delete(tempDiffFilename); |
| 374 | 391 | sqlite3_free(tempDiffFilename); |
| 375 | 392 | tempDiffFilename = 0; |
| 393 | + } | |
| 394 | + if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){ | |
| 395 | + fossil_print("]\n"); | |
| 376 | 396 | } |
| 377 | 397 | } |
| 378 | 398 | |
| 379 | 399 | /* |
| 380 | 400 | ** Show the difference between two files, one in memory and one on disk. |
| @@ -398,11 +418,11 @@ | ||
| 398 | 418 | const char *zFile2, /* On disk content to compare to */ |
| 399 | 419 | const char *zName, /* Display name of the file */ |
| 400 | 420 | const char *zDiffCmd, /* Command for comparison */ |
| 401 | 421 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 402 | 422 | int fIncludeBinary, /* Include binary files for external diff */ |
| 403 | - u64 diffFlags, /* Flags to control the diff */ | |
| 423 | + DiffConfig *pCfg, /* Flags to control the diff */ | |
| 404 | 424 | int fSwapDiff, /* Diff from Zfile2 to Pfile1 */ |
| 405 | 425 | Blob *diffBlob /* Blob to store diff output */ |
| 406 | 426 | ){ |
| 407 | 427 | if( zDiffCmd==0 ){ |
| 408 | 428 | Blob out; /* Diff output text */ |
| @@ -417,34 +437,33 @@ | ||
| 417 | 437 | blob_read_from_file(&file2, zFile2, ExtFILE); |
| 418 | 438 | zName2 = zName; |
| 419 | 439 | } |
| 420 | 440 | |
| 421 | 441 | /* Compute and output the differences */ |
| 422 | - if( diffFlags & DIFF_BRIEF ){ | |
| 442 | + if( pCfg->diffFlags & DIFF_BRIEF ){ | |
| 423 | 443 | if( blob_compare(pFile1, &file2) ){ |
| 424 | 444 | fossil_print("CHANGED %s\n", zName); |
| 425 | 445 | } |
| 426 | 446 | }else{ |
| 427 | 447 | blob_zero(&out); |
| 428 | 448 | if( fSwapDiff ){ |
| 429 | - text_diff(&file2, pFile1, &out, 0, diffFlags); | |
| 449 | + text_diff(&file2, pFile1, &out, pCfg); | |
| 430 | 450 | }else{ |
| 431 | - text_diff(pFile1, &file2, &out, 0, diffFlags); | |
| 451 | + text_diff(pFile1, &file2, &out, pCfg); | |
| 432 | 452 | } |
| 433 | 453 | if( blob_size(&out) ){ |
| 434 | - if( diffFlags & DIFF_NUMSTAT ){ | |
| 454 | + if( pCfg->diffFlags & DIFF_NUMSTAT ){ | |
| 435 | 455 | if( !diffBlob ){ |
| 436 | 456 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 437 | 457 | }else{ |
| 438 | 458 | blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName); |
| 439 | 459 | } |
| 440 | 460 | }else{ |
| 461 | + diff_print_filenames(zName, zName2, pCfg, diffBlob); | |
| 441 | 462 | if( !diffBlob ){ |
| 442 | - diff_print_filenames(zName, zName2, diffFlags, 0); | |
| 443 | 463 | fossil_print("%s\n", blob_str(&out)); |
| 444 | 464 | }else{ |
| 445 | - diff_print_filenames(zName, zName2, diffFlags, diffBlob); | |
| 446 | 465 | blob_appendf(diffBlob, "%s\n", blob_str(&out)); |
| 447 | 466 | } |
| 448 | 467 | } |
| 449 | 468 | } |
| 450 | 469 | blob_reset(&out); |
| @@ -529,22 +548,22 @@ | ||
| 529 | 548 | int isBin2, /* Does the 'to' content appear to be binary */ |
| 530 | 549 | const char *zName, /* Display name of the file */ |
| 531 | 550 | const char *zDiffCmd, /* Command for comparison */ |
| 532 | 551 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 533 | 552 | int fIncludeBinary, /* Include binary files for external diff */ |
| 534 | - u64 diffFlags /* Diff flags */ | |
| 553 | + DiffConfig *pCfg /* Diff flags */ | |
| 535 | 554 | ){ |
| 536 | - if( diffFlags & DIFF_BRIEF ) return; | |
| 555 | + if( pCfg->diffFlags & DIFF_BRIEF ) return; | |
| 537 | 556 | if( zDiffCmd==0 ){ |
| 538 | 557 | Blob out; /* Diff output text */ |
| 539 | 558 | |
| 540 | 559 | blob_zero(&out); |
| 541 | - text_diff(pFile1, pFile2, &out, 0, diffFlags); | |
| 542 | - if( diffFlags & DIFF_NUMSTAT ){ | |
| 560 | + text_diff(pFile1, pFile2, &out, pCfg); | |
| 561 | + if( pCfg->diffFlags & DIFF_NUMSTAT ){ | |
| 543 | 562 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 544 | 563 | }else{ |
| 545 | - diff_print_filenames(zName, zName, diffFlags, 0); | |
| 564 | + diff_print_filenames(zName, zName, pCfg, 0); | |
| 546 | 565 | fossil_print("%s\n", blob_str(&out)); |
| 547 | 566 | } |
| 548 | 567 | |
| 549 | 568 | /* Release memory resources */ |
| 550 | 569 | blob_reset(&out); |
| @@ -609,22 +628,22 @@ | ||
| 609 | 628 | void diff_against_disk( |
| 610 | 629 | const char *zFrom, /* Version to difference from */ |
| 611 | 630 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 612 | 631 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 613 | 632 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 614 | - u64 diffFlags, /* Flags controlling diff output */ | |
| 633 | + DiffConfig *pCfg, /* Flags controlling diff output */ | |
| 615 | 634 | FileDirList *pFileDir, /* Which files to diff */ |
| 616 | 635 | Blob *diffBlob /* Blob to output diff instead of stdout */ |
| 617 | 636 | ){ |
| 618 | 637 | int vid; |
| 619 | 638 | Blob sql; |
| 620 | 639 | Stmt q; |
| 621 | 640 | int asNewFile; /* Treat non-existant files as empty files */ |
| 622 | 641 | int isNumStat; /* True for --numstat */ |
| 623 | 642 | |
| 624 | - asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; | |
| 625 | - isNumStat = (diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; | |
| 643 | + asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; | |
| 644 | + isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; | |
| 626 | 645 | vid = db_lget_int("checkout", 0); |
| 627 | 646 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 628 | 647 | blob_zero(&sql); |
| 629 | 648 | db_begin_transaction(); |
| 630 | 649 | if( zFrom ){ |
| @@ -706,24 +725,24 @@ | ||
| 706 | 725 | } |
| 707 | 726 | if( showDiff ){ |
| 708 | 727 | Blob content; |
| 709 | 728 | int isBin; |
| 710 | 729 | if( !isLink != !file_islink(zFullName) ){ |
| 711 | - diff_print_index(zPathname, diffFlags, 0); | |
| 712 | - diff_print_filenames(zPathname, zPathname, diffFlags, 0); | |
| 730 | + diff_print_index(zPathname, pCfg, 0); | |
| 731 | + diff_print_filenames(zPathname, zPathname, pCfg, 0); | |
| 713 | 732 | fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); |
| 714 | 733 | continue; |
| 715 | 734 | } |
| 716 | 735 | if( srcid>0 ){ |
| 717 | 736 | content_get(srcid, &content); |
| 718 | 737 | }else{ |
| 719 | 738 | blob_zero(&content); |
| 720 | 739 | } |
| 721 | 740 | isBin = fIncludeBinary ? 0 : looks_like_binary(&content); |
| 722 | - diff_print_index(zPathname, diffFlags, diffBlob); | |
| 741 | + diff_print_index(zPathname, pCfg, diffBlob); | |
| 723 | 742 | diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, |
| 724 | - zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob); | |
| 743 | + zBinGlob, fIncludeBinary, pCfg, 0, diffBlob); | |
| 725 | 744 | blob_reset(&content); |
| 726 | 745 | } |
| 727 | 746 | blob_reset(&fname); |
| 728 | 747 | } |
| 729 | 748 | db_finalize(&q); |
| @@ -742,11 +761,11 @@ | ||
| 742 | 761 | */ |
| 743 | 762 | static void diff_against_undo( |
| 744 | 763 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 745 | 764 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 746 | 765 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 747 | - u64 diffFlags, /* Flags controlling diff output */ | |
| 766 | + DiffConfig *pCfg, /* Flags controlling diff output */ | |
| 748 | 767 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 749 | 768 | ){ |
| 750 | 769 | Stmt q; |
| 751 | 770 | Blob content; |
| 752 | 771 | db_prepare(&q, "SELECT pathname, content FROM undo"); |
| @@ -756,11 +775,11 @@ | ||
| 756 | 775 | const char *zFile = (const char*)db_column_text(&q, 0); |
| 757 | 776 | if( !file_dir_match(pFileDir, zFile) ) continue; |
| 758 | 777 | zFullName = mprintf("%s%s", g.zLocalRoot, zFile); |
| 759 | 778 | db_column_blob(&q, 1, &content); |
| 760 | 779 | diff_file(&content, 0, zFullName, zFile, |
| 761 | - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0); | |
| 780 | + zDiffCmd, zBinGlob, fIncludeBinary, pCfg, 0, 0); | |
| 762 | 781 | fossil_free(zFullName); |
| 763 | 782 | blob_reset(&content); |
| 764 | 783 | } |
| 765 | 784 | db_finalize(&q); |
| 766 | 785 | } |
| @@ -780,11 +799,11 @@ | ||
| 780 | 799 | struct ManifestFile *pFrom, |
| 781 | 800 | struct ManifestFile *pTo, |
| 782 | 801 | const char *zDiffCmd, |
| 783 | 802 | const char *zBinGlob, |
| 784 | 803 | int fIncludeBinary, |
| 785 | - u64 diffFlags | |
| 804 | + DiffConfig *pCfg | |
| 786 | 805 | ){ |
| 787 | 806 | Blob f1, f2; |
| 788 | 807 | int isBin1, isBin2; |
| 789 | 808 | int rid; |
| 790 | 809 | const char *zName; |
| @@ -793,12 +812,12 @@ | ||
| 793 | 812 | }else if( pTo ){ |
| 794 | 813 | zName = pTo->zName; |
| 795 | 814 | }else{ |
| 796 | 815 | zName = DIFF_NO_NAME; |
| 797 | 816 | } |
| 798 | - if( diffFlags & DIFF_BRIEF ) return; | |
| 799 | - diff_print_index(zName, diffFlags, 0); | |
| 817 | + if( pCfg->diffFlags & DIFF_BRIEF ) return; | |
| 818 | + diff_print_index(zName, pCfg, 0); | |
| 800 | 819 | if( pFrom ){ |
| 801 | 820 | rid = uuid_to_rid(pFrom->zUuid, 0); |
| 802 | 821 | content_get(rid, &f1); |
| 803 | 822 | }else{ |
| 804 | 823 | blob_zero(&f1); |
| @@ -810,11 +829,11 @@ | ||
| 810 | 829 | blob_zero(&f2); |
| 811 | 830 | } |
| 812 | 831 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1); |
| 813 | 832 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2); |
| 814 | 833 | diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, |
| 815 | - zBinGlob, fIncludeBinary, diffFlags); | |
| 834 | + zBinGlob, fIncludeBinary, pCfg); | |
| 816 | 835 | blob_reset(&f1); |
| 817 | 836 | blob_reset(&f2); |
| 818 | 837 | } |
| 819 | 838 | |
| 820 | 839 | /* |
| @@ -831,16 +850,16 @@ | ||
| 831 | 850 | const char *zFrom, |
| 832 | 851 | const char *zTo, |
| 833 | 852 | const char *zDiffCmd, |
| 834 | 853 | const char *zBinGlob, |
| 835 | 854 | int fIncludeBinary, |
| 836 | - u64 diffFlags, | |
| 855 | + DiffConfig *pCfg, | |
| 837 | 856 | FileDirList *pFileDir |
| 838 | 857 | ){ |
| 839 | 858 | Manifest *pFrom, *pTo; |
| 840 | 859 | ManifestFile *pFromFile, *pToFile; |
| 841 | - int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; | |
| 860 | + int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; | |
| 842 | 861 | |
| 843 | 862 | pFrom = manifest_get_by_name(zFrom, 0); |
| 844 | 863 | manifest_file_rewind(pFrom); |
| 845 | 864 | pFromFile = manifest_file_next(pFrom,0); |
| 846 | 865 | pTo = manifest_get_by_name(zTo, 0); |
| @@ -856,27 +875,28 @@ | ||
| 856 | 875 | }else{ |
| 857 | 876 | cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); |
| 858 | 877 | } |
| 859 | 878 | if( cmp<0 ){ |
| 860 | 879 | if( file_dir_match(pFileDir, pFromFile->zName) ){ |
| 861 | - if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ | |
| 880 | + if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ | |
| 862 | 881 | fossil_print("DELETED %s\n", pFromFile->zName); |
| 863 | 882 | } |
| 864 | 883 | if( asNewFlag ){ |
| 865 | 884 | diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, |
| 866 | - fIncludeBinary, diffFlags); | |
| 885 | + fIncludeBinary, pCfg); | |
| 867 | 886 | } |
| 868 | 887 | } |
| 869 | 888 | pFromFile = manifest_file_next(pFrom,0); |
| 870 | 889 | }else if( cmp>0 ){ |
| 871 | 890 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 872 | - if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ | |
| 891 | + if( (pCfg->diffFlags & | |
| 892 | + (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ | |
| 873 | 893 | fossil_print("ADDED %s\n", pToFile->zName); |
| 874 | 894 | } |
| 875 | 895 | if( asNewFlag ){ |
| 876 | 896 | diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, |
| 877 | - fIncludeBinary, diffFlags); | |
| 897 | + fIncludeBinary, pCfg); | |
| 878 | 898 | } |
| 879 | 899 | } |
| 880 | 900 | pToFile = manifest_file_next(pTo,0); |
| 881 | 901 | }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ |
| 882 | 902 | /* No changes */ |
| @@ -883,15 +903,15 @@ | ||
| 883 | 903 | (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ |
| 884 | 904 | pFromFile = manifest_file_next(pFrom,0); |
| 885 | 905 | pToFile = manifest_file_next(pTo,0); |
| 886 | 906 | }else{ |
| 887 | 907 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 888 | - if( diffFlags & DIFF_BRIEF ){ | |
| 908 | + if( pCfg->diffFlags & DIFF_BRIEF ){ | |
| 889 | 909 | fossil_print("CHANGED %s\n", pFromFile->zName); |
| 890 | 910 | }else{ |
| 891 | 911 | diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, |
| 892 | - fIncludeBinary, diffFlags); | |
| 912 | + fIncludeBinary, pCfg); | |
| 893 | 913 | } |
| 894 | 914 | } |
| 895 | 915 | pFromFile = manifest_file_next(pFrom,0); |
| 896 | 916 | pToFile = manifest_file_next(pTo,0); |
| 897 | 917 | } |
| @@ -1107,12 +1127,12 @@ | ||
| 1107 | 1127 | const char *zBranch; /* Branch to diff */ |
| 1108 | 1128 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 1109 | 1129 | const char *zBinGlob = 0; /* Treat file names matching this as binary */ |
| 1110 | 1130 | int fIncludeBinary = 0; /* Include binary files for external diff */ |
| 1111 | 1131 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1112 | - u64 diffFlags = 0; /* Flags to control the DIFF */ | |
| 1113 | 1132 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1133 | + DiffConfig DCfg; /* Diff configuration object */ | |
| 1114 | 1134 | |
| 1115 | 1135 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| 1116 | 1136 | diff_tk("diff", 2); |
| 1117 | 1137 | return; |
| 1118 | 1138 | } |
| @@ -1121,16 +1141,16 @@ | ||
| 1121 | 1141 | zFrom = find_option("from", "r", 1); |
| 1122 | 1142 | zTo = find_option("to", 0, 1); |
| 1123 | 1143 | zCheckin = find_option("checkin", 0, 1); |
| 1124 | 1144 | zBranch = find_option("branch", 0, 1); |
| 1125 | 1145 | againstUndo = find_option("undo",0,0)!=0; |
| 1126 | - diffFlags = diff_options(); | |
| 1146 | + diff_options(&DCfg, isGDiff); | |
| 1127 | 1147 | verboseFlag = find_option("verbose","v",0)!=0; |
| 1128 | 1148 | if( !verboseFlag ){ |
| 1129 | 1149 | verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ |
| 1130 | 1150 | } |
| 1131 | - if( verboseFlag ) diffFlags |= DIFF_VERBOSE; | |
| 1151 | + if( verboseFlag ) DCfg.diffFlags |= DIFF_VERBOSE; | |
| 1132 | 1152 | if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
| 1133 | 1153 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1134 | 1154 | " or --branch"); |
| 1135 | 1155 | } |
| 1136 | 1156 | if( zBranch ){ |
| @@ -1150,11 +1170,11 @@ | ||
| 1150 | 1170 | fossil_fatal("must use --from if --to is present"); |
| 1151 | 1171 | }else{ |
| 1152 | 1172 | db_find_and_open_repository(0, 0); |
| 1153 | 1173 | } |
| 1154 | 1174 | if( !isInternDiff |
| 1155 | - && (diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ | |
| 1175 | + && (DCfg.diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ | |
| 1156 | 1176 | ){ |
| 1157 | 1177 | zDiffCmd = find_option("command", 0, 1); |
| 1158 | 1178 | if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff); |
| 1159 | 1179 | } |
| 1160 | 1180 | zBinGlob = diff_get_binary_glob(); |
| @@ -1188,24 +1208,24 @@ | ||
| 1188 | 1208 | ridTo); |
| 1189 | 1209 | if( zFrom==0 ){ |
| 1190 | 1210 | fossil_fatal("check-in %s has no parent", zTo); |
| 1191 | 1211 | } |
| 1192 | 1212 | } |
| 1193 | - diff_begin(diffFlags); | |
| 1213 | + diff_begin(&DCfg); | |
| 1194 | 1214 | if( againstUndo ){ |
| 1195 | 1215 | if( db_lget_int("undo_available",0)==0 ){ |
| 1196 | 1216 | fossil_print("No undo or redo is available\n"); |
| 1197 | 1217 | return; |
| 1198 | 1218 | } |
| 1199 | 1219 | diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, |
| 1200 | - diffFlags, pFileDir); | |
| 1220 | + &DCfg, pFileDir); | |
| 1201 | 1221 | }else if( zTo==0 ){ |
| 1202 | 1222 | diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1203 | - diffFlags, pFileDir, 0); | |
| 1223 | + &DCfg, pFileDir, 0); | |
| 1204 | 1224 | }else{ |
| 1205 | 1225 | diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1206 | - diffFlags, pFileDir); | |
| 1226 | + &DCfg, pFileDir); | |
| 1207 | 1227 | } |
| 1208 | 1228 | if( pFileDir ){ |
| 1209 | 1229 | int i; |
| 1210 | 1230 | for(i=0; pFileDir[i].zName; i++){ |
| 1211 | 1231 | if( pFileDir[i].nUsed==0 |
| @@ -1216,12 +1236,12 @@ | ||
| 1216 | 1236 | } |
| 1217 | 1237 | fossil_free(pFileDir[i].zName); |
| 1218 | 1238 | } |
| 1219 | 1239 | fossil_free(pFileDir); |
| 1220 | 1240 | } |
| 1221 | - diff_end(diffFlags, 0); | |
| 1222 | - if ( diffFlags & DIFF_NUMSTAT ){ | |
| 1241 | + diff_end(&DCfg, 0); | |
| 1242 | + if ( DCfg.diffFlags & DIFF_NUMSTAT ){ | |
| 1223 | 1243 | fossil_print("%10d %10d TOTAL over %d changed files\n", |
| 1224 | 1244 | g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]); |
| 1225 | 1245 | } |
| 1226 | 1246 | } |
| 1227 | 1247 | |
| @@ -1232,12 +1252,14 @@ | ||
| 1232 | 1252 | ** Show a patch that goes from check-in FROM to check-in TO. |
| 1233 | 1253 | */ |
| 1234 | 1254 | void vpatch_page(void){ |
| 1235 | 1255 | const char *zFrom = P("from"); |
| 1236 | 1256 | const char *zTo = P("to"); |
| 1257 | + DiffConfig DCfg; | |
| 1237 | 1258 | login_check_credentials(); |
| 1238 | 1259 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1239 | 1260 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1240 | 1261 | |
| 1241 | 1262 | cgi_set_content_type("text/plain"); |
| 1242 | - diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0); | |
| 1263 | + diff_config_init(&DCfg, DIFF_VERBOSE); | |
| 1264 | + diff_two_versions(zFrom, zTo, 0, 0, 0, &DCfg, 0); | |
| 1243 | 1265 | } |
| 1244 | 1266 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -113,13 +113,15 @@ | |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** Print the "Index:" message that patches wants to see at the top of a diff. |
| 117 | */ |
| 118 | void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){ |
| 119 | if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| |
| 120 | DIFF_WEBPAGE|DIFF_TCL))==0 ){ |
| 121 | char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); |
| 122 | if( !diffBlob ){ |
| 123 | fossil_print("%s", z); |
| 124 | }else{ |
| 125 | blob_appendf(diffBlob, "%s", z); |
| @@ -127,20 +129,22 @@ | |
| 127 | fossil_free(z); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | ** Print the +++/--- filename lines for a diff operation. |
| 133 | */ |
| 134 | void diff_print_filenames( |
| 135 | const char *zLeft, |
| 136 | const char *zRight, |
| 137 | u64 diffFlags, |
| 138 | Blob *diffBlob |
| 139 | ){ |
| 140 | char *z = 0; |
| 141 | if( diffFlags & (DIFF_BRIEF|DIFF_RAW|DIFF_JSON) ){ |
| 142 | /* no-op */ |
| 143 | }else if( diffFlags & DIFF_DEBUG ){ |
| 144 | fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", |
| 145 | zLeft, zRight); |
| 146 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| @@ -147,31 +151,42 @@ | |
| 147 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 148 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 149 | }else{ |
| 150 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 151 | } |
| 152 | }else if( diffFlags & DIFF_TCL ){ |
| 153 | Blob *pOut; |
| 154 | Blob x; |
| 155 | if( diffBlob ){ |
| 156 | pOut = diffBlob; |
| 157 | }else{ |
| 158 | blob_init(&x, 0, 0); |
| 159 | pOut = &x; |
| 160 | } |
| 161 | blob_append(pOut, "FILE ", 5); |
| 162 | blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); |
| 163 | blob_append_char(pOut, ' '); |
| 164 | blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); |
| 165 | blob_append_char(pOut, '\n'); |
| 166 | if( !diffBlob ){ |
| 167 | fossil_print("%s", blob_str(pOut)); |
| 168 | blob_reset(&x); |
| 169 | } |
| 170 | return; |
| 171 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 172 | int w = diff_width(diffFlags); |
| 173 | int n1 = strlen(zLeft); |
| 174 | int n2 = strlen(zRight); |
| 175 | int x; |
| 176 | if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ |
| 177 | if( n1>w*2 ) n1 = w*2; |
| @@ -282,11 +297,13 @@ | |
| 282 | @ </body> |
| 283 | @ </html> |
| 284 | ; |
| 285 | |
| 286 | /* |
| 287 | ** State variables used by the --browser option for diff |
| 288 | */ |
| 289 | static char *tempDiffFilename; /* File holding the diff HTML */ |
| 290 | static FILE *diffOut; /* Open to write into tempDiffFilename */ |
| 291 | |
| 292 | /* Amount of delay (in milliseconds) between launching the |
| @@ -321,12 +338,12 @@ | |
| 321 | ** hold the result. Make arrangements to delete that temporary |
| 322 | ** file if the diff is interrupted. |
| 323 | ** |
| 324 | ** For --browser and --webpage, output the HTML header. |
| 325 | */ |
| 326 | void diff_begin(u64 diffFlags){ |
| 327 | if( (diffFlags & DIFF_BROWSER)!=0 ){ |
| 328 | tempDiffFilename = fossil_temp_filename(); |
| 329 | tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename); |
| 330 | diffOut = fossil_freopen(tempDiffFilename,"wb",stdout); |
| 331 | if( diffOut==0 ){ |
| 332 | fossil_fatal("unable to create temporary file \"%s\"", |
| @@ -336,11 +353,11 @@ | |
| 336 | signal(SIGINT, diff_www_interrupt); |
| 337 | #else |
| 338 | SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE); |
| 339 | #endif |
| 340 | } |
| 341 | if( (diffFlags & DIFF_WEBPAGE)!=0 ){ |
| 342 | fossil_print("%s",zWebpageHdr); |
| 343 | fflush(stdout); |
| 344 | } |
| 345 | } |
| 346 | |
| @@ -352,19 +369,19 @@ | |
| 352 | ** |
| 353 | ** For --browser, close the connection to the temporary file, then |
| 354 | ** launch a web browser to view the file. After a delay |
| 355 | ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file. |
| 356 | */ |
| 357 | void diff_end(u64 diffFlags, int nErr){ |
| 358 | if( (diffFlags & DIFF_WEBPAGE)!=0 ){ |
| 359 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 360 | const unsigned char *zJs = builtin_file("diff.js", 0); |
| 361 | fossil_print("<script>\n%s</script>\n", zJs); |
| 362 | } |
| 363 | fossil_print("%s", zWebpageEnd); |
| 364 | } |
| 365 | if( (diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ |
| 366 | char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename); |
| 367 | fclose(diffOut); |
| 368 | diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout); |
| 369 | fossil_system(zCmd); |
| 370 | fossil_free(zCmd); |
| @@ -371,10 +388,13 @@ | |
| 371 | diffOut = 0; |
| 372 | sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY); |
| 373 | file_delete(tempDiffFilename); |
| 374 | sqlite3_free(tempDiffFilename); |
| 375 | tempDiffFilename = 0; |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | /* |
| 380 | ** Show the difference between two files, one in memory and one on disk. |
| @@ -398,11 +418,11 @@ | |
| 398 | const char *zFile2, /* On disk content to compare to */ |
| 399 | const char *zName, /* Display name of the file */ |
| 400 | const char *zDiffCmd, /* Command for comparison */ |
| 401 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 402 | int fIncludeBinary, /* Include binary files for external diff */ |
| 403 | u64 diffFlags, /* Flags to control the diff */ |
| 404 | int fSwapDiff, /* Diff from Zfile2 to Pfile1 */ |
| 405 | Blob *diffBlob /* Blob to store diff output */ |
| 406 | ){ |
| 407 | if( zDiffCmd==0 ){ |
| 408 | Blob out; /* Diff output text */ |
| @@ -417,34 +437,33 @@ | |
| 417 | blob_read_from_file(&file2, zFile2, ExtFILE); |
| 418 | zName2 = zName; |
| 419 | } |
| 420 | |
| 421 | /* Compute and output the differences */ |
| 422 | if( diffFlags & DIFF_BRIEF ){ |
| 423 | if( blob_compare(pFile1, &file2) ){ |
| 424 | fossil_print("CHANGED %s\n", zName); |
| 425 | } |
| 426 | }else{ |
| 427 | blob_zero(&out); |
| 428 | if( fSwapDiff ){ |
| 429 | text_diff(&file2, pFile1, &out, 0, diffFlags); |
| 430 | }else{ |
| 431 | text_diff(pFile1, &file2, &out, 0, diffFlags); |
| 432 | } |
| 433 | if( blob_size(&out) ){ |
| 434 | if( diffFlags & DIFF_NUMSTAT ){ |
| 435 | if( !diffBlob ){ |
| 436 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 437 | }else{ |
| 438 | blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName); |
| 439 | } |
| 440 | }else{ |
| 441 | if( !diffBlob ){ |
| 442 | diff_print_filenames(zName, zName2, diffFlags, 0); |
| 443 | fossil_print("%s\n", blob_str(&out)); |
| 444 | }else{ |
| 445 | diff_print_filenames(zName, zName2, diffFlags, diffBlob); |
| 446 | blob_appendf(diffBlob, "%s\n", blob_str(&out)); |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | blob_reset(&out); |
| @@ -529,22 +548,22 @@ | |
| 529 | int isBin2, /* Does the 'to' content appear to be binary */ |
| 530 | const char *zName, /* Display name of the file */ |
| 531 | const char *zDiffCmd, /* Command for comparison */ |
| 532 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 533 | int fIncludeBinary, /* Include binary files for external diff */ |
| 534 | u64 diffFlags /* Diff flags */ |
| 535 | ){ |
| 536 | if( diffFlags & DIFF_BRIEF ) return; |
| 537 | if( zDiffCmd==0 ){ |
| 538 | Blob out; /* Diff output text */ |
| 539 | |
| 540 | blob_zero(&out); |
| 541 | text_diff(pFile1, pFile2, &out, 0, diffFlags); |
| 542 | if( diffFlags & DIFF_NUMSTAT ){ |
| 543 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 544 | }else{ |
| 545 | diff_print_filenames(zName, zName, diffFlags, 0); |
| 546 | fossil_print("%s\n", blob_str(&out)); |
| 547 | } |
| 548 | |
| 549 | /* Release memory resources */ |
| 550 | blob_reset(&out); |
| @@ -609,22 +628,22 @@ | |
| 609 | void diff_against_disk( |
| 610 | const char *zFrom, /* Version to difference from */ |
| 611 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 612 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 613 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 614 | u64 diffFlags, /* Flags controlling diff output */ |
| 615 | FileDirList *pFileDir, /* Which files to diff */ |
| 616 | Blob *diffBlob /* Blob to output diff instead of stdout */ |
| 617 | ){ |
| 618 | int vid; |
| 619 | Blob sql; |
| 620 | Stmt q; |
| 621 | int asNewFile; /* Treat non-existant files as empty files */ |
| 622 | int isNumStat; /* True for --numstat */ |
| 623 | |
| 624 | asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; |
| 625 | isNumStat = (diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; |
| 626 | vid = db_lget_int("checkout", 0); |
| 627 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 628 | blob_zero(&sql); |
| 629 | db_begin_transaction(); |
| 630 | if( zFrom ){ |
| @@ -706,24 +725,24 @@ | |
| 706 | } |
| 707 | if( showDiff ){ |
| 708 | Blob content; |
| 709 | int isBin; |
| 710 | if( !isLink != !file_islink(zFullName) ){ |
| 711 | diff_print_index(zPathname, diffFlags, 0); |
| 712 | diff_print_filenames(zPathname, zPathname, diffFlags, 0); |
| 713 | fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); |
| 714 | continue; |
| 715 | } |
| 716 | if( srcid>0 ){ |
| 717 | content_get(srcid, &content); |
| 718 | }else{ |
| 719 | blob_zero(&content); |
| 720 | } |
| 721 | isBin = fIncludeBinary ? 0 : looks_like_binary(&content); |
| 722 | diff_print_index(zPathname, diffFlags, diffBlob); |
| 723 | diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, |
| 724 | zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob); |
| 725 | blob_reset(&content); |
| 726 | } |
| 727 | blob_reset(&fname); |
| 728 | } |
| 729 | db_finalize(&q); |
| @@ -742,11 +761,11 @@ | |
| 742 | */ |
| 743 | static void diff_against_undo( |
| 744 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 745 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 746 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 747 | u64 diffFlags, /* Flags controlling diff output */ |
| 748 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 749 | ){ |
| 750 | Stmt q; |
| 751 | Blob content; |
| 752 | db_prepare(&q, "SELECT pathname, content FROM undo"); |
| @@ -756,11 +775,11 @@ | |
| 756 | const char *zFile = (const char*)db_column_text(&q, 0); |
| 757 | if( !file_dir_match(pFileDir, zFile) ) continue; |
| 758 | zFullName = mprintf("%s%s", g.zLocalRoot, zFile); |
| 759 | db_column_blob(&q, 1, &content); |
| 760 | diff_file(&content, 0, zFullName, zFile, |
| 761 | zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0); |
| 762 | fossil_free(zFullName); |
| 763 | blob_reset(&content); |
| 764 | } |
| 765 | db_finalize(&q); |
| 766 | } |
| @@ -780,11 +799,11 @@ | |
| 780 | struct ManifestFile *pFrom, |
| 781 | struct ManifestFile *pTo, |
| 782 | const char *zDiffCmd, |
| 783 | const char *zBinGlob, |
| 784 | int fIncludeBinary, |
| 785 | u64 diffFlags |
| 786 | ){ |
| 787 | Blob f1, f2; |
| 788 | int isBin1, isBin2; |
| 789 | int rid; |
| 790 | const char *zName; |
| @@ -793,12 +812,12 @@ | |
| 793 | }else if( pTo ){ |
| 794 | zName = pTo->zName; |
| 795 | }else{ |
| 796 | zName = DIFF_NO_NAME; |
| 797 | } |
| 798 | if( diffFlags & DIFF_BRIEF ) return; |
| 799 | diff_print_index(zName, diffFlags, 0); |
| 800 | if( pFrom ){ |
| 801 | rid = uuid_to_rid(pFrom->zUuid, 0); |
| 802 | content_get(rid, &f1); |
| 803 | }else{ |
| 804 | blob_zero(&f1); |
| @@ -810,11 +829,11 @@ | |
| 810 | blob_zero(&f2); |
| 811 | } |
| 812 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1); |
| 813 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2); |
| 814 | diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, |
| 815 | zBinGlob, fIncludeBinary, diffFlags); |
| 816 | blob_reset(&f1); |
| 817 | blob_reset(&f2); |
| 818 | } |
| 819 | |
| 820 | /* |
| @@ -831,16 +850,16 @@ | |
| 831 | const char *zFrom, |
| 832 | const char *zTo, |
| 833 | const char *zDiffCmd, |
| 834 | const char *zBinGlob, |
| 835 | int fIncludeBinary, |
| 836 | u64 diffFlags, |
| 837 | FileDirList *pFileDir |
| 838 | ){ |
| 839 | Manifest *pFrom, *pTo; |
| 840 | ManifestFile *pFromFile, *pToFile; |
| 841 | int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; |
| 842 | |
| 843 | pFrom = manifest_get_by_name(zFrom, 0); |
| 844 | manifest_file_rewind(pFrom); |
| 845 | pFromFile = manifest_file_next(pFrom,0); |
| 846 | pTo = manifest_get_by_name(zTo, 0); |
| @@ -856,27 +875,28 @@ | |
| 856 | }else{ |
| 857 | cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); |
| 858 | } |
| 859 | if( cmp<0 ){ |
| 860 | if( file_dir_match(pFileDir, pFromFile->zName) ){ |
| 861 | if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ |
| 862 | fossil_print("DELETED %s\n", pFromFile->zName); |
| 863 | } |
| 864 | if( asNewFlag ){ |
| 865 | diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, |
| 866 | fIncludeBinary, diffFlags); |
| 867 | } |
| 868 | } |
| 869 | pFromFile = manifest_file_next(pFrom,0); |
| 870 | }else if( cmp>0 ){ |
| 871 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 872 | if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ |
| 873 | fossil_print("ADDED %s\n", pToFile->zName); |
| 874 | } |
| 875 | if( asNewFlag ){ |
| 876 | diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, |
| 877 | fIncludeBinary, diffFlags); |
| 878 | } |
| 879 | } |
| 880 | pToFile = manifest_file_next(pTo,0); |
| 881 | }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ |
| 882 | /* No changes */ |
| @@ -883,15 +903,15 @@ | |
| 883 | (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ |
| 884 | pFromFile = manifest_file_next(pFrom,0); |
| 885 | pToFile = manifest_file_next(pTo,0); |
| 886 | }else{ |
| 887 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 888 | if( diffFlags & DIFF_BRIEF ){ |
| 889 | fossil_print("CHANGED %s\n", pFromFile->zName); |
| 890 | }else{ |
| 891 | diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, |
| 892 | fIncludeBinary, diffFlags); |
| 893 | } |
| 894 | } |
| 895 | pFromFile = manifest_file_next(pFrom,0); |
| 896 | pToFile = manifest_file_next(pTo,0); |
| 897 | } |
| @@ -1107,12 +1127,12 @@ | |
| 1107 | const char *zBranch; /* Branch to diff */ |
| 1108 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 1109 | const char *zBinGlob = 0; /* Treat file names matching this as binary */ |
| 1110 | int fIncludeBinary = 0; /* Include binary files for external diff */ |
| 1111 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1112 | u64 diffFlags = 0; /* Flags to control the DIFF */ |
| 1113 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1114 | |
| 1115 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| 1116 | diff_tk("diff", 2); |
| 1117 | return; |
| 1118 | } |
| @@ -1121,16 +1141,16 @@ | |
| 1121 | zFrom = find_option("from", "r", 1); |
| 1122 | zTo = find_option("to", 0, 1); |
| 1123 | zCheckin = find_option("checkin", 0, 1); |
| 1124 | zBranch = find_option("branch", 0, 1); |
| 1125 | againstUndo = find_option("undo",0,0)!=0; |
| 1126 | diffFlags = diff_options(); |
| 1127 | verboseFlag = find_option("verbose","v",0)!=0; |
| 1128 | if( !verboseFlag ){ |
| 1129 | verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ |
| 1130 | } |
| 1131 | if( verboseFlag ) diffFlags |= DIFF_VERBOSE; |
| 1132 | if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
| 1133 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1134 | " or --branch"); |
| 1135 | } |
| 1136 | if( zBranch ){ |
| @@ -1150,11 +1170,11 @@ | |
| 1150 | fossil_fatal("must use --from if --to is present"); |
| 1151 | }else{ |
| 1152 | db_find_and_open_repository(0, 0); |
| 1153 | } |
| 1154 | if( !isInternDiff |
| 1155 | && (diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ |
| 1156 | ){ |
| 1157 | zDiffCmd = find_option("command", 0, 1); |
| 1158 | if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff); |
| 1159 | } |
| 1160 | zBinGlob = diff_get_binary_glob(); |
| @@ -1188,24 +1208,24 @@ | |
| 1188 | ridTo); |
| 1189 | if( zFrom==0 ){ |
| 1190 | fossil_fatal("check-in %s has no parent", zTo); |
| 1191 | } |
| 1192 | } |
| 1193 | diff_begin(diffFlags); |
| 1194 | if( againstUndo ){ |
| 1195 | if( db_lget_int("undo_available",0)==0 ){ |
| 1196 | fossil_print("No undo or redo is available\n"); |
| 1197 | return; |
| 1198 | } |
| 1199 | diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, |
| 1200 | diffFlags, pFileDir); |
| 1201 | }else if( zTo==0 ){ |
| 1202 | diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1203 | diffFlags, pFileDir, 0); |
| 1204 | }else{ |
| 1205 | diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1206 | diffFlags, pFileDir); |
| 1207 | } |
| 1208 | if( pFileDir ){ |
| 1209 | int i; |
| 1210 | for(i=0; pFileDir[i].zName; i++){ |
| 1211 | if( pFileDir[i].nUsed==0 |
| @@ -1216,12 +1236,12 @@ | |
| 1216 | } |
| 1217 | fossil_free(pFileDir[i].zName); |
| 1218 | } |
| 1219 | fossil_free(pFileDir); |
| 1220 | } |
| 1221 | diff_end(diffFlags, 0); |
| 1222 | if ( diffFlags & DIFF_NUMSTAT ){ |
| 1223 | fossil_print("%10d %10d TOTAL over %d changed files\n", |
| 1224 | g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]); |
| 1225 | } |
| 1226 | } |
| 1227 | |
| @@ -1232,12 +1252,14 @@ | |
| 1232 | ** Show a patch that goes from check-in FROM to check-in TO. |
| 1233 | */ |
| 1234 | void vpatch_page(void){ |
| 1235 | const char *zFrom = P("from"); |
| 1236 | const char *zTo = P("to"); |
| 1237 | login_check_credentials(); |
| 1238 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1239 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1240 | |
| 1241 | cgi_set_content_type("text/plain"); |
| 1242 | diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0); |
| 1243 | } |
| 1244 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -113,13 +113,15 @@ | |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** Print the "Index:" message that patches wants to see at the top of a diff. |
| 117 | */ |
| 118 | void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *diffBlob){ |
| 119 | if( (pCfg->diffFlags & |
| 120 | (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| |
| 121 | DIFF_WEBPAGE|DIFF_TCL))==0 |
| 122 | ){ |
| 123 | char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); |
| 124 | if( !diffBlob ){ |
| 125 | fossil_print("%s", z); |
| 126 | }else{ |
| 127 | blob_appendf(diffBlob, "%s", z); |
| @@ -127,20 +129,22 @@ | |
| 129 | fossil_free(z); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Print the +++/--- filename lines or whatever filename information |
| 135 | ** is appropriate for the output format. |
| 136 | */ |
| 137 | void diff_print_filenames( |
| 138 | const char *zLeft, /* Name of the left file */ |
| 139 | const char *zRight, /* Name of the right file */ |
| 140 | DiffConfig *pCfg, /* Diff configuration */ |
| 141 | Blob *diffBlob /* Write to this blob, or stdout of this is NULL */ |
| 142 | ){ |
| 143 | char *z = 0; |
| 144 | u64 diffFlags = pCfg->diffFlags; |
| 145 | if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ |
| 146 | /* no-op */ |
| 147 | }else if( diffFlags & DIFF_DEBUG ){ |
| 148 | fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", |
| 149 | zLeft, zRight); |
| 150 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| @@ -147,31 +151,42 @@ | |
| 151 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 152 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 153 | }else{ |
| 154 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 155 | } |
| 156 | }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){ |
| 157 | Blob *pOut; |
| 158 | Blob x; |
| 159 | if( diffBlob ){ |
| 160 | pOut = diffBlob; |
| 161 | }else{ |
| 162 | blob_init(&x, 0, 0); |
| 163 | pOut = &x; |
| 164 | } |
| 165 | if( diffFlags & DIFF_TCL ){ |
| 166 | blob_append(pOut, "FILE ", 5); |
| 167 | blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); |
| 168 | blob_append_char(pOut, ' '); |
| 169 | blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); |
| 170 | blob_append_char(pOut, '\n'); |
| 171 | }else{ |
| 172 | blob_trim(pOut); |
| 173 | blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1); |
| 174 | pCfg->nFile++; |
| 175 | blob_append(pOut, "\n \"leftname\":", -1); |
| 176 | blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft)); |
| 177 | blob_append(pOut, ",\n \"rightname\":", -1); |
| 178 | blob_append_json_literal(pOut, zRight, (int)strlen(zRight)); |
| 179 | blob_append(pOut, ",\n \"diff\":\n", -1); |
| 180 | } |
| 181 | if( !diffBlob ){ |
| 182 | fossil_print("%s", blob_str(pOut)); |
| 183 | blob_reset(&x); |
| 184 | } |
| 185 | return; |
| 186 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 187 | int w = diff_width(pCfg); |
| 188 | int n1 = strlen(zLeft); |
| 189 | int n2 = strlen(zRight); |
| 190 | int x; |
| 191 | if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ |
| 192 | if( n1>w*2 ) n1 = w*2; |
| @@ -282,11 +297,13 @@ | |
| 297 | @ </body> |
| 298 | @ </html> |
| 299 | ; |
| 300 | |
| 301 | /* |
| 302 | ** State variables used by the --browser option for diff. These must |
| 303 | ** be static variables, not elements of DiffConfig, since they are |
| 304 | ** used by the interrupt handler. |
| 305 | */ |
| 306 | static char *tempDiffFilename; /* File holding the diff HTML */ |
| 307 | static FILE *diffOut; /* Open to write into tempDiffFilename */ |
| 308 | |
| 309 | /* Amount of delay (in milliseconds) between launching the |
| @@ -321,12 +338,12 @@ | |
| 338 | ** hold the result. Make arrangements to delete that temporary |
| 339 | ** file if the diff is interrupted. |
| 340 | ** |
| 341 | ** For --browser and --webpage, output the HTML header. |
| 342 | */ |
| 343 | void diff_begin(DiffConfig *pCfg){ |
| 344 | if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){ |
| 345 | tempDiffFilename = fossil_temp_filename(); |
| 346 | tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename); |
| 347 | diffOut = fossil_freopen(tempDiffFilename,"wb",stdout); |
| 348 | if( diffOut==0 ){ |
| 349 | fossil_fatal("unable to create temporary file \"%s\"", |
| @@ -336,11 +353,11 @@ | |
| 353 | signal(SIGINT, diff_www_interrupt); |
| 354 | #else |
| 355 | SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE); |
| 356 | #endif |
| 357 | } |
| 358 | if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ |
| 359 | fossil_print("%s",zWebpageHdr); |
| 360 | fflush(stdout); |
| 361 | } |
| 362 | } |
| 363 | |
| @@ -352,19 +369,19 @@ | |
| 369 | ** |
| 370 | ** For --browser, close the connection to the temporary file, then |
| 371 | ** launch a web browser to view the file. After a delay |
| 372 | ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file. |
| 373 | */ |
| 374 | void diff_end(DiffConfig *pCfg, int nErr){ |
| 375 | if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ |
| 376 | if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ |
| 377 | const unsigned char *zJs = builtin_file("diff.js", 0); |
| 378 | fossil_print("<script>\n%s</script>\n", zJs); |
| 379 | } |
| 380 | fossil_print("%s", zWebpageEnd); |
| 381 | } |
| 382 | if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ |
| 383 | char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename); |
| 384 | fclose(diffOut); |
| 385 | diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout); |
| 386 | fossil_system(zCmd); |
| 387 | fossil_free(zCmd); |
| @@ -371,10 +388,13 @@ | |
| 388 | diffOut = 0; |
| 389 | sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY); |
| 390 | file_delete(tempDiffFilename); |
| 391 | sqlite3_free(tempDiffFilename); |
| 392 | tempDiffFilename = 0; |
| 393 | } |
| 394 | if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){ |
| 395 | fossil_print("]\n"); |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | /* |
| 400 | ** Show the difference between two files, one in memory and one on disk. |
| @@ -398,11 +418,11 @@ | |
| 418 | const char *zFile2, /* On disk content to compare to */ |
| 419 | const char *zName, /* Display name of the file */ |
| 420 | const char *zDiffCmd, /* Command for comparison */ |
| 421 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 422 | int fIncludeBinary, /* Include binary files for external diff */ |
| 423 | DiffConfig *pCfg, /* Flags to control the diff */ |
| 424 | int fSwapDiff, /* Diff from Zfile2 to Pfile1 */ |
| 425 | Blob *diffBlob /* Blob to store diff output */ |
| 426 | ){ |
| 427 | if( zDiffCmd==0 ){ |
| 428 | Blob out; /* Diff output text */ |
| @@ -417,34 +437,33 @@ | |
| 437 | blob_read_from_file(&file2, zFile2, ExtFILE); |
| 438 | zName2 = zName; |
| 439 | } |
| 440 | |
| 441 | /* Compute and output the differences */ |
| 442 | if( pCfg->diffFlags & DIFF_BRIEF ){ |
| 443 | if( blob_compare(pFile1, &file2) ){ |
| 444 | fossil_print("CHANGED %s\n", zName); |
| 445 | } |
| 446 | }else{ |
| 447 | blob_zero(&out); |
| 448 | if( fSwapDiff ){ |
| 449 | text_diff(&file2, pFile1, &out, pCfg); |
| 450 | }else{ |
| 451 | text_diff(pFile1, &file2, &out, pCfg); |
| 452 | } |
| 453 | if( blob_size(&out) ){ |
| 454 | if( pCfg->diffFlags & DIFF_NUMSTAT ){ |
| 455 | if( !diffBlob ){ |
| 456 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 457 | }else{ |
| 458 | blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName); |
| 459 | } |
| 460 | }else{ |
| 461 | diff_print_filenames(zName, zName2, pCfg, diffBlob); |
| 462 | if( !diffBlob ){ |
| 463 | fossil_print("%s\n", blob_str(&out)); |
| 464 | }else{ |
| 465 | blob_appendf(diffBlob, "%s\n", blob_str(&out)); |
| 466 | } |
| 467 | } |
| 468 | } |
| 469 | blob_reset(&out); |
| @@ -529,22 +548,22 @@ | |
| 548 | int isBin2, /* Does the 'to' content appear to be binary */ |
| 549 | const char *zName, /* Display name of the file */ |
| 550 | const char *zDiffCmd, /* Command for comparison */ |
| 551 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 552 | int fIncludeBinary, /* Include binary files for external diff */ |
| 553 | DiffConfig *pCfg /* Diff flags */ |
| 554 | ){ |
| 555 | if( pCfg->diffFlags & DIFF_BRIEF ) return; |
| 556 | if( zDiffCmd==0 ){ |
| 557 | Blob out; /* Diff output text */ |
| 558 | |
| 559 | blob_zero(&out); |
| 560 | text_diff(pFile1, pFile2, &out, pCfg); |
| 561 | if( pCfg->diffFlags & DIFF_NUMSTAT ){ |
| 562 | fossil_print("%s %s\n", blob_str(&out), zName); |
| 563 | }else{ |
| 564 | diff_print_filenames(zName, zName, pCfg, 0); |
| 565 | fossil_print("%s\n", blob_str(&out)); |
| 566 | } |
| 567 | |
| 568 | /* Release memory resources */ |
| 569 | blob_reset(&out); |
| @@ -609,22 +628,22 @@ | |
| 628 | void diff_against_disk( |
| 629 | const char *zFrom, /* Version to difference from */ |
| 630 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 631 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 632 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 633 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 634 | FileDirList *pFileDir, /* Which files to diff */ |
| 635 | Blob *diffBlob /* Blob to output diff instead of stdout */ |
| 636 | ){ |
| 637 | int vid; |
| 638 | Blob sql; |
| 639 | Stmt q; |
| 640 | int asNewFile; /* Treat non-existant files as empty files */ |
| 641 | int isNumStat; /* True for --numstat */ |
| 642 | |
| 643 | asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; |
| 644 | isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; |
| 645 | vid = db_lget_int("checkout", 0); |
| 646 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 647 | blob_zero(&sql); |
| 648 | db_begin_transaction(); |
| 649 | if( zFrom ){ |
| @@ -706,24 +725,24 @@ | |
| 725 | } |
| 726 | if( showDiff ){ |
| 727 | Blob content; |
| 728 | int isBin; |
| 729 | if( !isLink != !file_islink(zFullName) ){ |
| 730 | diff_print_index(zPathname, pCfg, 0); |
| 731 | diff_print_filenames(zPathname, zPathname, pCfg, 0); |
| 732 | fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); |
| 733 | continue; |
| 734 | } |
| 735 | if( srcid>0 ){ |
| 736 | content_get(srcid, &content); |
| 737 | }else{ |
| 738 | blob_zero(&content); |
| 739 | } |
| 740 | isBin = fIncludeBinary ? 0 : looks_like_binary(&content); |
| 741 | diff_print_index(zPathname, pCfg, diffBlob); |
| 742 | diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, |
| 743 | zBinGlob, fIncludeBinary, pCfg, 0, diffBlob); |
| 744 | blob_reset(&content); |
| 745 | } |
| 746 | blob_reset(&fname); |
| 747 | } |
| 748 | db_finalize(&q); |
| @@ -742,11 +761,11 @@ | |
| 761 | */ |
| 762 | static void diff_against_undo( |
| 763 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 764 | const char *zBinGlob, /* Treat file names matching this as binary */ |
| 765 | int fIncludeBinary, /* Treat file names matching this as binary */ |
| 766 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 767 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 768 | ){ |
| 769 | Stmt q; |
| 770 | Blob content; |
| 771 | db_prepare(&q, "SELECT pathname, content FROM undo"); |
| @@ -756,11 +775,11 @@ | |
| 775 | const char *zFile = (const char*)db_column_text(&q, 0); |
| 776 | if( !file_dir_match(pFileDir, zFile) ) continue; |
| 777 | zFullName = mprintf("%s%s", g.zLocalRoot, zFile); |
| 778 | db_column_blob(&q, 1, &content); |
| 779 | diff_file(&content, 0, zFullName, zFile, |
| 780 | zDiffCmd, zBinGlob, fIncludeBinary, pCfg, 0, 0); |
| 781 | fossil_free(zFullName); |
| 782 | blob_reset(&content); |
| 783 | } |
| 784 | db_finalize(&q); |
| 785 | } |
| @@ -780,11 +799,11 @@ | |
| 799 | struct ManifestFile *pFrom, |
| 800 | struct ManifestFile *pTo, |
| 801 | const char *zDiffCmd, |
| 802 | const char *zBinGlob, |
| 803 | int fIncludeBinary, |
| 804 | DiffConfig *pCfg |
| 805 | ){ |
| 806 | Blob f1, f2; |
| 807 | int isBin1, isBin2; |
| 808 | int rid; |
| 809 | const char *zName; |
| @@ -793,12 +812,12 @@ | |
| 812 | }else if( pTo ){ |
| 813 | zName = pTo->zName; |
| 814 | }else{ |
| 815 | zName = DIFF_NO_NAME; |
| 816 | } |
| 817 | if( pCfg->diffFlags & DIFF_BRIEF ) return; |
| 818 | diff_print_index(zName, pCfg, 0); |
| 819 | if( pFrom ){ |
| 820 | rid = uuid_to_rid(pFrom->zUuid, 0); |
| 821 | content_get(rid, &f1); |
| 822 | }else{ |
| 823 | blob_zero(&f1); |
| @@ -810,11 +829,11 @@ | |
| 829 | blob_zero(&f2); |
| 830 | } |
| 831 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1); |
| 832 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2); |
| 833 | diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, |
| 834 | zBinGlob, fIncludeBinary, pCfg); |
| 835 | blob_reset(&f1); |
| 836 | blob_reset(&f2); |
| 837 | } |
| 838 | |
| 839 | /* |
| @@ -831,16 +850,16 @@ | |
| 850 | const char *zFrom, |
| 851 | const char *zTo, |
| 852 | const char *zDiffCmd, |
| 853 | const char *zBinGlob, |
| 854 | int fIncludeBinary, |
| 855 | DiffConfig *pCfg, |
| 856 | FileDirList *pFileDir |
| 857 | ){ |
| 858 | Manifest *pFrom, *pTo; |
| 859 | ManifestFile *pFromFile, *pToFile; |
| 860 | int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; |
| 861 | |
| 862 | pFrom = manifest_get_by_name(zFrom, 0); |
| 863 | manifest_file_rewind(pFrom); |
| 864 | pFromFile = manifest_file_next(pFrom,0); |
| 865 | pTo = manifest_get_by_name(zTo, 0); |
| @@ -856,27 +875,28 @@ | |
| 875 | }else{ |
| 876 | cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); |
| 877 | } |
| 878 | if( cmp<0 ){ |
| 879 | if( file_dir_match(pFileDir, pFromFile->zName) ){ |
| 880 | if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ |
| 881 | fossil_print("DELETED %s\n", pFromFile->zName); |
| 882 | } |
| 883 | if( asNewFlag ){ |
| 884 | diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, |
| 885 | fIncludeBinary, pCfg); |
| 886 | } |
| 887 | } |
| 888 | pFromFile = manifest_file_next(pFrom,0); |
| 889 | }else if( cmp>0 ){ |
| 890 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 891 | if( (pCfg->diffFlags & |
| 892 | (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ |
| 893 | fossil_print("ADDED %s\n", pToFile->zName); |
| 894 | } |
| 895 | if( asNewFlag ){ |
| 896 | diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, |
| 897 | fIncludeBinary, pCfg); |
| 898 | } |
| 899 | } |
| 900 | pToFile = manifest_file_next(pTo,0); |
| 901 | }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ |
| 902 | /* No changes */ |
| @@ -883,15 +903,15 @@ | |
| 903 | (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ |
| 904 | pFromFile = manifest_file_next(pFrom,0); |
| 905 | pToFile = manifest_file_next(pTo,0); |
| 906 | }else{ |
| 907 | if( file_dir_match(pFileDir, pToFile->zName) ){ |
| 908 | if( pCfg->diffFlags & DIFF_BRIEF ){ |
| 909 | fossil_print("CHANGED %s\n", pFromFile->zName); |
| 910 | }else{ |
| 911 | diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, |
| 912 | fIncludeBinary, pCfg); |
| 913 | } |
| 914 | } |
| 915 | pFromFile = manifest_file_next(pFrom,0); |
| 916 | pToFile = manifest_file_next(pTo,0); |
| 917 | } |
| @@ -1107,12 +1127,12 @@ | |
| 1127 | const char *zBranch; /* Branch to diff */ |
| 1128 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 1129 | const char *zBinGlob = 0; /* Treat file names matching this as binary */ |
| 1130 | int fIncludeBinary = 0; /* Include binary files for external diff */ |
| 1131 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1132 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1133 | DiffConfig DCfg; /* Diff configuration object */ |
| 1134 | |
| 1135 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| 1136 | diff_tk("diff", 2); |
| 1137 | return; |
| 1138 | } |
| @@ -1121,16 +1141,16 @@ | |
| 1141 | zFrom = find_option("from", "r", 1); |
| 1142 | zTo = find_option("to", 0, 1); |
| 1143 | zCheckin = find_option("checkin", 0, 1); |
| 1144 | zBranch = find_option("branch", 0, 1); |
| 1145 | againstUndo = find_option("undo",0,0)!=0; |
| 1146 | diff_options(&DCfg, isGDiff); |
| 1147 | verboseFlag = find_option("verbose","v",0)!=0; |
| 1148 | if( !verboseFlag ){ |
| 1149 | verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ |
| 1150 | } |
| 1151 | if( verboseFlag ) DCfg.diffFlags |= DIFF_VERBOSE; |
| 1152 | if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
| 1153 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1154 | " or --branch"); |
| 1155 | } |
| 1156 | if( zBranch ){ |
| @@ -1150,11 +1170,11 @@ | |
| 1170 | fossil_fatal("must use --from if --to is present"); |
| 1171 | }else{ |
| 1172 | db_find_and_open_repository(0, 0); |
| 1173 | } |
| 1174 | if( !isInternDiff |
| 1175 | && (DCfg.diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ |
| 1176 | ){ |
| 1177 | zDiffCmd = find_option("command", 0, 1); |
| 1178 | if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff); |
| 1179 | } |
| 1180 | zBinGlob = diff_get_binary_glob(); |
| @@ -1188,24 +1208,24 @@ | |
| 1208 | ridTo); |
| 1209 | if( zFrom==0 ){ |
| 1210 | fossil_fatal("check-in %s has no parent", zTo); |
| 1211 | } |
| 1212 | } |
| 1213 | diff_begin(&DCfg); |
| 1214 | if( againstUndo ){ |
| 1215 | if( db_lget_int("undo_available",0)==0 ){ |
| 1216 | fossil_print("No undo or redo is available\n"); |
| 1217 | return; |
| 1218 | } |
| 1219 | diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, |
| 1220 | &DCfg, pFileDir); |
| 1221 | }else if( zTo==0 ){ |
| 1222 | diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1223 | &DCfg, pFileDir, 0); |
| 1224 | }else{ |
| 1225 | diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, |
| 1226 | &DCfg, pFileDir); |
| 1227 | } |
| 1228 | if( pFileDir ){ |
| 1229 | int i; |
| 1230 | for(i=0; pFileDir[i].zName; i++){ |
| 1231 | if( pFileDir[i].nUsed==0 |
| @@ -1216,12 +1236,12 @@ | |
| 1236 | } |
| 1237 | fossil_free(pFileDir[i].zName); |
| 1238 | } |
| 1239 | fossil_free(pFileDir); |
| 1240 | } |
| 1241 | diff_end(&DCfg, 0); |
| 1242 | if ( DCfg.diffFlags & DIFF_NUMSTAT ){ |
| 1243 | fossil_print("%10d %10d TOTAL over %d changed files\n", |
| 1244 | g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]); |
| 1245 | } |
| 1246 | } |
| 1247 | |
| @@ -1232,12 +1252,14 @@ | |
| 1252 | ** Show a patch that goes from check-in FROM to check-in TO. |
| 1253 | */ |
| 1254 | void vpatch_page(void){ |
| 1255 | const char *zFrom = P("from"); |
| 1256 | const char *zTo = P("to"); |
| 1257 | DiffConfig DCfg; |
| 1258 | login_check_credentials(); |
| 1259 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1260 | if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
| 1261 | |
| 1262 | cgi_set_content_type("text/plain"); |
| 1263 | diff_config_init(&DCfg, DIFF_VERBOSE); |
| 1264 | diff_two_versions(zFrom, zTo, 0, 0, 0, &DCfg, 0); |
| 1265 | } |
| 1266 |
+41
-31
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -330,12 +330,11 @@ | ||
| 330 | 330 | ** Append the difference between artifacts to the output |
| 331 | 331 | */ |
| 332 | 332 | static void append_diff( |
| 333 | 333 | const char *zFrom, /* Diff from this artifact */ |
| 334 | 334 | const char *zTo, /* ... to this artifact */ |
| 335 | - u64 diffFlags, /* Diff formatting flags */ | |
| 336 | - ReCompiled *pRe /* Only show change matching this regex */ | |
| 335 | + DiffConfig *pCfg /* The diff configuration */ | |
| 337 | 336 | ){ |
| 338 | 337 | int fromid; |
| 339 | 338 | int toid; |
| 340 | 339 | Blob from, to; |
| 341 | 340 | if( zFrom ){ |
| @@ -348,16 +347,16 @@ | ||
| 348 | 347 | toid = uuid_to_rid(zTo, 0); |
| 349 | 348 | content_get(toid, &to); |
| 350 | 349 | }else{ |
| 351 | 350 | blob_zero(&to); |
| 352 | 351 | } |
| 353 | - if( diffFlags & DIFF_SIDEBYSIDE ){ | |
| 354 | - diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; | |
| 352 | + if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ | |
| 353 | + pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; | |
| 355 | 354 | }else{ |
| 356 | - diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; | |
| 355 | + pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; | |
| 357 | 356 | } |
| 358 | - text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags); | |
| 357 | + text_diff(&from, &to, cgi_output_blob(), pCfg); | |
| 359 | 358 | blob_reset(&from); |
| 360 | 359 | blob_reset(&to); |
| 361 | 360 | } |
| 362 | 361 | |
| 363 | 362 | /* |
| @@ -368,12 +367,11 @@ | ||
| 368 | 367 | const char *zCkin, /* The checkin on which the change occurs */ |
| 369 | 368 | const char *zName, /* Name of the file that has changed */ |
| 370 | 369 | const char *zOld, /* blob.uuid before change. NULL for added files */ |
| 371 | 370 | const char *zNew, /* blob.uuid after change. NULL for deletes */ |
| 372 | 371 | const char *zOldName, /* Prior name. NULL if no name change. */ |
| 373 | - u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */ | |
| 374 | - ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */ | |
| 372 | + DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */ | |
| 375 | 373 | int mperm /* executable or symlink permission for zNew */ |
| 376 | 374 | ){ |
| 377 | 375 | @ <p> |
| 378 | 376 | if( !g.perm.Hyperlink ){ |
| 379 | 377 | if( zNew==0 ){ |
| @@ -391,12 +389,12 @@ | ||
| 391 | 389 | @ %h(zName) became a regular file. |
| 392 | 390 | } |
| 393 | 391 | }else{ |
| 394 | 392 | @ Changes to %h(zName). |
| 395 | 393 | } |
| 396 | - if( diffFlags ){ | |
| 397 | - append_diff(zOld, zNew, diffFlags, pRe); | |
| 394 | + if( pCfg ){ | |
| 395 | + append_diff(zOld, zNew, pCfg); | |
| 398 | 396 | } |
| 399 | 397 | }else{ |
| 400 | 398 | if( zOld && zNew ){ |
| 401 | 399 | if( fossil_strcmp(zOld, zNew)!=0 ){ |
| 402 | 400 | @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| @@ -426,12 +424,12 @@ | ||
| 426 | 424 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>. |
| 427 | 425 | }else{ |
| 428 | 426 | @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| 429 | 427 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. |
| 430 | 428 | } |
| 431 | - if( diffFlags ){ | |
| 432 | - append_diff(zOld, zNew, diffFlags, pRe); | |
| 429 | + if( pCfg ){ | |
| 430 | + append_diff(zOld, zNew, pCfg); | |
| 433 | 431 | }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ |
| 434 | 432 | @ |
| 435 | 433 | @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a> |
| 436 | 434 | } |
| 437 | 435 | } |
| @@ -448,11 +446,11 @@ | ||
| 448 | 446 | |
| 449 | 447 | /* |
| 450 | 448 | ** Construct an appropriate diffFlag for text_diff() based on query |
| 451 | 449 | ** parameters and the to boolean arguments. |
| 452 | 450 | */ |
| 453 | -u64 construct_diff_flags(int diffType){ | |
| 451 | +DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){ | |
| 454 | 452 | u64 diffFlags = 0; /* Zero means do not show any diff */ |
| 455 | 453 | if( diffType>0 ){ |
| 456 | 454 | int x; |
| 457 | 455 | if( diffType==2 ){ |
| 458 | 456 | diffFlags = DIFF_SIDEBYSIDE; |
| @@ -472,12 +470,16 @@ | ||
| 472 | 470 | diffFlags += x; |
| 473 | 471 | |
| 474 | 472 | /* The "noopt" parameter disables diff optimization */ |
| 475 | 473 | if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; |
| 476 | 474 | diffFlags |= DIFF_STRIP_EOLCR; |
| 475 | + diff_config_init(pCfg, diffFlags); | |
| 476 | + return pCfg; | |
| 477 | + }else{ | |
| 478 | + diff_config_init(pCfg, 0); | |
| 479 | + return 0; | |
| 477 | 480 | } |
| 478 | - return diffFlags; | |
| 479 | 481 | } |
| 480 | 482 | |
| 481 | 483 | /* |
| 482 | 484 | ** WEBPAGE: ci_tags |
| 483 | 485 | ** URL: /ci_tags?name=ARTIFACTID |
| @@ -614,20 +616,20 @@ | ||
| 614 | 616 | void ci_page(void){ |
| 615 | 617 | Stmt q1, q2, q3; |
| 616 | 618 | int rid; |
| 617 | 619 | int isLeaf; |
| 618 | 620 | int diffType; /* 0: no diff, 1: unified, 2: side-by-side */ |
| 619 | - u64 diffFlags; /* Flag parameter for text_diff() */ | |
| 620 | 621 | const char *zName; /* Name of the check-in to be displayed */ |
| 621 | 622 | const char *zUuid; /* Hash of zName, found via blob.uuid */ |
| 622 | 623 | const char *zParent; /* Hash of the parent check-in (if any) */ |
| 623 | 624 | const char *zRe; /* regex parameter */ |
| 624 | 625 | ReCompiled *pRe = 0; /* regex */ |
| 625 | - const char *zW; /* URL param for ignoring whitespace */ | |
| 626 | + const char *zW; /* URL param for ignoring whitespace */ | |
| 626 | 627 | const char *zPage = "vinfo"; /* Page that shows diffs */ |
| 627 | 628 | const char *zPageHide = "ci"; /* Page that hides diffs */ |
| 628 | - const char *zBrName; /* Branch name */ | |
| 629 | + const char *zBrName; /* Branch name */ | |
| 630 | + DiffConfig DCfg,*pCfg; /* Type of diff */ | |
| 629 | 631 | |
| 630 | 632 | login_check_credentials(); |
| 631 | 633 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 632 | 634 | style_set_current_feature("vinfo"); |
| 633 | 635 | zName = P("name"); |
| @@ -878,12 +880,13 @@ | ||
| 878 | 880 | render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n"); |
| 879 | 881 | @ <div class="section">Context</div> |
| 880 | 882 | render_checkin_context(rid, 0, 0, 0); |
| 881 | 883 | @ <div class="section">Changes</div> |
| 882 | 884 | @ <div class="sectionmenu"> |
| 883 | - diffFlags = construct_diff_flags(diffType); | |
| 884 | - zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; | |
| 885 | + pCfg = construct_diff_flags(diffType, &DCfg); | |
| 886 | + DCfg.pRe = pRe; | |
| 887 | + zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; | |
| 885 | 888 | if( diffType!=0 ){ |
| 886 | 889 | @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\ |
| 887 | 890 | @ Hide Diffs</a> |
| 888 | 891 | } |
| 889 | 892 | if( diffType!=1 ){ |
| @@ -933,14 +936,14 @@ | ||
| 933 | 936 | int mperm = db_column_int(&q3, 1); |
| 934 | 937 | const char *zOld = db_column_text(&q3,2); |
| 935 | 938 | const char *zNew = db_column_text(&q3,3); |
| 936 | 939 | const char *zOldName = db_column_text(&q3, 4); |
| 937 | 940 | append_file_change_line(zUuid, zName, zOld, zNew, zOldName, |
| 938 | - diffFlags,pRe,mperm); | |
| 941 | + pCfg,mperm); | |
| 939 | 942 | } |
| 940 | 943 | db_finalize(&q3); |
| 941 | - append_diff_javascript(diffType==2); | |
| 944 | + append_diff_javascript(diffType); | |
| 942 | 945 | builtin_fossil_js_bundle_or("info-diff",NULL); |
| 943 | 946 | style_finish_page(); |
| 944 | 947 | } |
| 945 | 948 | |
| 946 | 949 | /* |
| @@ -1167,20 +1170,20 @@ | ||
| 1167 | 1170 | ** Show all differences between two check-ins. |
| 1168 | 1171 | */ |
| 1169 | 1172 | void vdiff_page(void){ |
| 1170 | 1173 | int ridFrom, ridTo; |
| 1171 | 1174 | int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */ |
| 1172 | - u64 diffFlags = 0; | |
| 1173 | 1175 | Manifest *pFrom, *pTo; |
| 1174 | 1176 | ManifestFile *pFileFrom, *pFileTo; |
| 1175 | 1177 | const char *zBranch; |
| 1176 | 1178 | const char *zFrom; |
| 1177 | 1179 | const char *zTo; |
| 1178 | 1180 | const char *zRe; |
| 1179 | 1181 | const char *zGlob; |
| 1180 | 1182 | char *zMergeOrigin = 0; |
| 1181 | 1183 | ReCompiled *pRe = 0; |
| 1184 | + DiffConfig DCfg, *pCfg = 0; | |
| 1182 | 1185 | int graphFlags = 0; |
| 1183 | 1186 | Blob qp; |
| 1184 | 1187 | int bInvert = PB("inv"); |
| 1185 | 1188 | |
| 1186 | 1189 | login_check_credentials(); |
| @@ -1229,12 +1232,12 @@ | ||
| 1229 | 1232 | } |
| 1230 | 1233 | if( PB("nc") ){ |
| 1231 | 1234 | graphFlags |= TIMELINE_NOCOLOR; |
| 1232 | 1235 | blob_appendf(&qp, "&nc"); |
| 1233 | 1236 | } |
| 1234 | - diffFlags = construct_diff_flags(diffType); | |
| 1235 | - if( diffFlags & DIFF_IGNORE_ALLWS ){ | |
| 1237 | + pCfg = construct_diff_flags(diffType, &DCfg); | |
| 1238 | + if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){ | |
| 1236 | 1239 | blob_appendf(&qp, "&w"); |
| 1237 | 1240 | } |
| 1238 | 1241 | style_set_current_feature("vdiff"); |
| 1239 | 1242 | if( zBranch==0 ){ |
| 1240 | 1243 | style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo); |
| @@ -1253,11 +1256,11 @@ | ||
| 1253 | 1256 | } |
| 1254 | 1257 | if( zGlob ){ |
| 1255 | 1258 | style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp); |
| 1256 | 1259 | }else{ |
| 1257 | 1260 | style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, |
| 1258 | - (diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); | |
| 1261 | + (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); | |
| 1259 | 1262 | } |
| 1260 | 1263 | if( diffType!=0 ){ |
| 1261 | 1264 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1262 | 1265 | } |
| 1263 | 1266 | if( zBranch ){ |
| @@ -1301,10 +1304,11 @@ | ||
| 1301 | 1304 | |
| 1302 | 1305 | manifest_file_rewind(pFrom); |
| 1303 | 1306 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1304 | 1307 | manifest_file_rewind(pTo); |
| 1305 | 1308 | pFileTo = manifest_file_next(pTo, 0); |
| 1309 | + DCfg.pRe = pRe; | |
| 1306 | 1310 | while( pFileFrom || pFileTo ){ |
| 1307 | 1311 | int cmp; |
| 1308 | 1312 | if( pFileFrom==0 ){ |
| 1309 | 1313 | cmp = +1; |
| 1310 | 1314 | }else if( pFileTo==0 ){ |
| @@ -1313,17 +1317,17 @@ | ||
| 1313 | 1317 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 1314 | 1318 | } |
| 1315 | 1319 | if( cmp<0 ){ |
| 1316 | 1320 | if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){ |
| 1317 | 1321 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1318 | - pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0); | |
| 1322 | + pFileFrom->zUuid, 0, 0, pCfg, 0); | |
| 1319 | 1323 | } |
| 1320 | 1324 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1321 | 1325 | }else if( cmp>0 ){ |
| 1322 | 1326 | if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){ |
| 1323 | 1327 | append_file_change_line(zTo, pFileTo->zName, |
| 1324 | - 0, pFileTo->zUuid, 0, diffFlags, pRe, | |
| 1328 | + 0, pFileTo->zUuid, 0, pCfg, | |
| 1325 | 1329 | manifest_file_mperm(pFileTo)); |
| 1326 | 1330 | } |
| 1327 | 1331 | pFileTo = manifest_file_next(pTo, 0); |
| 1328 | 1332 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 1329 | 1333 | pFileFrom = manifest_file_next(pFrom, 0); |
| @@ -1331,11 +1335,11 @@ | ||
| 1331 | 1335 | }else{ |
| 1332 | 1336 | if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0 |
| 1333 | 1337 | || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){ |
| 1334 | 1338 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1335 | 1339 | pFileFrom->zUuid, |
| 1336 | - pFileTo->zUuid, 0, diffFlags, pRe, | |
| 1340 | + pFileTo->zUuid, 0, pCfg, | |
| 1337 | 1341 | manifest_file_mperm(pFileTo)); |
| 1338 | 1342 | } |
| 1339 | 1343 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1340 | 1344 | pFileTo = manifest_file_next(pTo, 0); |
| 1341 | 1345 | } |
| @@ -1722,10 +1726,11 @@ | ||
| 1722 | 1726 | const char *zRe; |
| 1723 | 1727 | ReCompiled *pRe = 0; |
| 1724 | 1728 | u64 diffFlags; |
| 1725 | 1729 | u32 objdescFlags = 0; |
| 1726 | 1730 | int verbose = PB("verbose"); |
| 1731 | + DiffConfig DCfg; | |
| 1727 | 1732 | |
| 1728 | 1733 | login_check_credentials(); |
| 1729 | 1734 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1730 | 1735 | diffType = preferred_diff_type(); |
| 1731 | 1736 | if( P("from") && P("to") ){ |
| @@ -1768,24 +1773,28 @@ | ||
| 1768 | 1773 | zRe = P("regex"); |
| 1769 | 1774 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 1770 | 1775 | if( verbose ) objdescFlags |= OBJDESC_DETAIL; |
| 1771 | 1776 | if( isPatch ){ |
| 1772 | 1777 | Blob c1, c2, *pOut; |
| 1778 | + DiffConfig DCfg; | |
| 1773 | 1779 | pOut = cgi_output_blob(); |
| 1774 | 1780 | cgi_set_content_type("text/plain"); |
| 1775 | 1781 | diffFlags = 4; |
| 1776 | 1782 | content_get(v1, &c1); |
| 1777 | 1783 | content_get(v2, &c2); |
| 1778 | - text_diff(&c1, &c2, pOut, pRe, diffFlags); | |
| 1784 | + diff_config_init(&DCfg, diffFlags); | |
| 1785 | + DCfg.pRe = pRe; | |
| 1786 | + text_diff(&c1, &c2, pOut, &DCfg); | |
| 1779 | 1787 | blob_reset(&c1); |
| 1780 | 1788 | blob_reset(&c2); |
| 1781 | 1789 | return; |
| 1782 | 1790 | } |
| 1783 | 1791 | |
| 1784 | 1792 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 1785 | 1793 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 1786 | - diffFlags = construct_diff_flags(diffType) | DIFF_HTML; | |
| 1794 | + construct_diff_flags(diffType, &DCfg); | |
| 1795 | + DCfg.diffFlags |= DIFF_HTML; | |
| 1787 | 1796 | |
| 1788 | 1797 | style_set_current_feature("fdiff"); |
| 1789 | 1798 | style_header("Diff"); |
| 1790 | 1799 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1791 | 1800 | if( diffType==2 ){ |
| @@ -1811,13 +1820,14 @@ | ||
| 1811 | 1820 | object_description(v2, objdescFlags,0, 0); |
| 1812 | 1821 | } |
| 1813 | 1822 | if( pRe ){ |
| 1814 | 1823 | @ <b>Only differences that match regular expression "%h(zRe)" |
| 1815 | 1824 | @ are shown.</b> |
| 1825 | + DCfg.pRe = pRe; | |
| 1816 | 1826 | } |
| 1817 | 1827 | @ <hr /> |
| 1818 | - append_diff(zV1, zV2, diffFlags, pRe); | |
| 1828 | + append_diff(zV1, zV2, &DCfg); | |
| 1819 | 1829 | append_diff_javascript(diffType); |
| 1820 | 1830 | style_finish_page(); |
| 1821 | 1831 | } |
| 1822 | 1832 | |
| 1823 | 1833 | /* |
| 1824 | 1834 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -330,12 +330,11 @@ | |
| 330 | ** Append the difference between artifacts to the output |
| 331 | */ |
| 332 | static void append_diff( |
| 333 | const char *zFrom, /* Diff from this artifact */ |
| 334 | const char *zTo, /* ... to this artifact */ |
| 335 | u64 diffFlags, /* Diff formatting flags */ |
| 336 | ReCompiled *pRe /* Only show change matching this regex */ |
| 337 | ){ |
| 338 | int fromid; |
| 339 | int toid; |
| 340 | Blob from, to; |
| 341 | if( zFrom ){ |
| @@ -348,16 +347,16 @@ | |
| 348 | toid = uuid_to_rid(zTo, 0); |
| 349 | content_get(toid, &to); |
| 350 | }else{ |
| 351 | blob_zero(&to); |
| 352 | } |
| 353 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 354 | diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; |
| 355 | }else{ |
| 356 | diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; |
| 357 | } |
| 358 | text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags); |
| 359 | blob_reset(&from); |
| 360 | blob_reset(&to); |
| 361 | } |
| 362 | |
| 363 | /* |
| @@ -368,12 +367,11 @@ | |
| 368 | const char *zCkin, /* The checkin on which the change occurs */ |
| 369 | const char *zName, /* Name of the file that has changed */ |
| 370 | const char *zOld, /* blob.uuid before change. NULL for added files */ |
| 371 | const char *zNew, /* blob.uuid after change. NULL for deletes */ |
| 372 | const char *zOldName, /* Prior name. NULL if no name change. */ |
| 373 | u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */ |
| 374 | ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */ |
| 375 | int mperm /* executable or symlink permission for zNew */ |
| 376 | ){ |
| 377 | @ <p> |
| 378 | if( !g.perm.Hyperlink ){ |
| 379 | if( zNew==0 ){ |
| @@ -391,12 +389,12 @@ | |
| 391 | @ %h(zName) became a regular file. |
| 392 | } |
| 393 | }else{ |
| 394 | @ Changes to %h(zName). |
| 395 | } |
| 396 | if( diffFlags ){ |
| 397 | append_diff(zOld, zNew, diffFlags, pRe); |
| 398 | } |
| 399 | }else{ |
| 400 | if( zOld && zNew ){ |
| 401 | if( fossil_strcmp(zOld, zNew)!=0 ){ |
| 402 | @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| @@ -426,12 +424,12 @@ | |
| 426 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>. |
| 427 | }else{ |
| 428 | @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| 429 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. |
| 430 | } |
| 431 | if( diffFlags ){ |
| 432 | append_diff(zOld, zNew, diffFlags, pRe); |
| 433 | }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ |
| 434 | @ |
| 435 | @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a> |
| 436 | } |
| 437 | } |
| @@ -448,11 +446,11 @@ | |
| 448 | |
| 449 | /* |
| 450 | ** Construct an appropriate diffFlag for text_diff() based on query |
| 451 | ** parameters and the to boolean arguments. |
| 452 | */ |
| 453 | u64 construct_diff_flags(int diffType){ |
| 454 | u64 diffFlags = 0; /* Zero means do not show any diff */ |
| 455 | if( diffType>0 ){ |
| 456 | int x; |
| 457 | if( diffType==2 ){ |
| 458 | diffFlags = DIFF_SIDEBYSIDE; |
| @@ -472,12 +470,16 @@ | |
| 472 | diffFlags += x; |
| 473 | |
| 474 | /* The "noopt" parameter disables diff optimization */ |
| 475 | if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; |
| 476 | diffFlags |= DIFF_STRIP_EOLCR; |
| 477 | } |
| 478 | return diffFlags; |
| 479 | } |
| 480 | |
| 481 | /* |
| 482 | ** WEBPAGE: ci_tags |
| 483 | ** URL: /ci_tags?name=ARTIFACTID |
| @@ -614,20 +616,20 @@ | |
| 614 | void ci_page(void){ |
| 615 | Stmt q1, q2, q3; |
| 616 | int rid; |
| 617 | int isLeaf; |
| 618 | int diffType; /* 0: no diff, 1: unified, 2: side-by-side */ |
| 619 | u64 diffFlags; /* Flag parameter for text_diff() */ |
| 620 | const char *zName; /* Name of the check-in to be displayed */ |
| 621 | const char *zUuid; /* Hash of zName, found via blob.uuid */ |
| 622 | const char *zParent; /* Hash of the parent check-in (if any) */ |
| 623 | const char *zRe; /* regex parameter */ |
| 624 | ReCompiled *pRe = 0; /* regex */ |
| 625 | const char *zW; /* URL param for ignoring whitespace */ |
| 626 | const char *zPage = "vinfo"; /* Page that shows diffs */ |
| 627 | const char *zPageHide = "ci"; /* Page that hides diffs */ |
| 628 | const char *zBrName; /* Branch name */ |
| 629 | |
| 630 | login_check_credentials(); |
| 631 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 632 | style_set_current_feature("vinfo"); |
| 633 | zName = P("name"); |
| @@ -878,12 +880,13 @@ | |
| 878 | render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n"); |
| 879 | @ <div class="section">Context</div> |
| 880 | render_checkin_context(rid, 0, 0, 0); |
| 881 | @ <div class="section">Changes</div> |
| 882 | @ <div class="sectionmenu"> |
| 883 | diffFlags = construct_diff_flags(diffType); |
| 884 | zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; |
| 885 | if( diffType!=0 ){ |
| 886 | @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\ |
| 887 | @ Hide Diffs</a> |
| 888 | } |
| 889 | if( diffType!=1 ){ |
| @@ -933,14 +936,14 @@ | |
| 933 | int mperm = db_column_int(&q3, 1); |
| 934 | const char *zOld = db_column_text(&q3,2); |
| 935 | const char *zNew = db_column_text(&q3,3); |
| 936 | const char *zOldName = db_column_text(&q3, 4); |
| 937 | append_file_change_line(zUuid, zName, zOld, zNew, zOldName, |
| 938 | diffFlags,pRe,mperm); |
| 939 | } |
| 940 | db_finalize(&q3); |
| 941 | append_diff_javascript(diffType==2); |
| 942 | builtin_fossil_js_bundle_or("info-diff",NULL); |
| 943 | style_finish_page(); |
| 944 | } |
| 945 | |
| 946 | /* |
| @@ -1167,20 +1170,20 @@ | |
| 1167 | ** Show all differences between two check-ins. |
| 1168 | */ |
| 1169 | void vdiff_page(void){ |
| 1170 | int ridFrom, ridTo; |
| 1171 | int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */ |
| 1172 | u64 diffFlags = 0; |
| 1173 | Manifest *pFrom, *pTo; |
| 1174 | ManifestFile *pFileFrom, *pFileTo; |
| 1175 | const char *zBranch; |
| 1176 | const char *zFrom; |
| 1177 | const char *zTo; |
| 1178 | const char *zRe; |
| 1179 | const char *zGlob; |
| 1180 | char *zMergeOrigin = 0; |
| 1181 | ReCompiled *pRe = 0; |
| 1182 | int graphFlags = 0; |
| 1183 | Blob qp; |
| 1184 | int bInvert = PB("inv"); |
| 1185 | |
| 1186 | login_check_credentials(); |
| @@ -1229,12 +1232,12 @@ | |
| 1229 | } |
| 1230 | if( PB("nc") ){ |
| 1231 | graphFlags |= TIMELINE_NOCOLOR; |
| 1232 | blob_appendf(&qp, "&nc"); |
| 1233 | } |
| 1234 | diffFlags = construct_diff_flags(diffType); |
| 1235 | if( diffFlags & DIFF_IGNORE_ALLWS ){ |
| 1236 | blob_appendf(&qp, "&w"); |
| 1237 | } |
| 1238 | style_set_current_feature("vdiff"); |
| 1239 | if( zBranch==0 ){ |
| 1240 | style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo); |
| @@ -1253,11 +1256,11 @@ | |
| 1253 | } |
| 1254 | if( zGlob ){ |
| 1255 | style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp); |
| 1256 | }else{ |
| 1257 | style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, |
| 1258 | (diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); |
| 1259 | } |
| 1260 | if( diffType!=0 ){ |
| 1261 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1262 | } |
| 1263 | if( zBranch ){ |
| @@ -1301,10 +1304,11 @@ | |
| 1301 | |
| 1302 | manifest_file_rewind(pFrom); |
| 1303 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1304 | manifest_file_rewind(pTo); |
| 1305 | pFileTo = manifest_file_next(pTo, 0); |
| 1306 | while( pFileFrom || pFileTo ){ |
| 1307 | int cmp; |
| 1308 | if( pFileFrom==0 ){ |
| 1309 | cmp = +1; |
| 1310 | }else if( pFileTo==0 ){ |
| @@ -1313,17 +1317,17 @@ | |
| 1313 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 1314 | } |
| 1315 | if( cmp<0 ){ |
| 1316 | if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){ |
| 1317 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1318 | pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0); |
| 1319 | } |
| 1320 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1321 | }else if( cmp>0 ){ |
| 1322 | if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){ |
| 1323 | append_file_change_line(zTo, pFileTo->zName, |
| 1324 | 0, pFileTo->zUuid, 0, diffFlags, pRe, |
| 1325 | manifest_file_mperm(pFileTo)); |
| 1326 | } |
| 1327 | pFileTo = manifest_file_next(pTo, 0); |
| 1328 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 1329 | pFileFrom = manifest_file_next(pFrom, 0); |
| @@ -1331,11 +1335,11 @@ | |
| 1331 | }else{ |
| 1332 | if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0 |
| 1333 | || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){ |
| 1334 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1335 | pFileFrom->zUuid, |
| 1336 | pFileTo->zUuid, 0, diffFlags, pRe, |
| 1337 | manifest_file_mperm(pFileTo)); |
| 1338 | } |
| 1339 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1340 | pFileTo = manifest_file_next(pTo, 0); |
| 1341 | } |
| @@ -1722,10 +1726,11 @@ | |
| 1722 | const char *zRe; |
| 1723 | ReCompiled *pRe = 0; |
| 1724 | u64 diffFlags; |
| 1725 | u32 objdescFlags = 0; |
| 1726 | int verbose = PB("verbose"); |
| 1727 | |
| 1728 | login_check_credentials(); |
| 1729 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1730 | diffType = preferred_diff_type(); |
| 1731 | if( P("from") && P("to") ){ |
| @@ -1768,24 +1773,28 @@ | |
| 1768 | zRe = P("regex"); |
| 1769 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 1770 | if( verbose ) objdescFlags |= OBJDESC_DETAIL; |
| 1771 | if( isPatch ){ |
| 1772 | Blob c1, c2, *pOut; |
| 1773 | pOut = cgi_output_blob(); |
| 1774 | cgi_set_content_type("text/plain"); |
| 1775 | diffFlags = 4; |
| 1776 | content_get(v1, &c1); |
| 1777 | content_get(v2, &c2); |
| 1778 | text_diff(&c1, &c2, pOut, pRe, diffFlags); |
| 1779 | blob_reset(&c1); |
| 1780 | blob_reset(&c2); |
| 1781 | return; |
| 1782 | } |
| 1783 | |
| 1784 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 1785 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 1786 | diffFlags = construct_diff_flags(diffType) | DIFF_HTML; |
| 1787 | |
| 1788 | style_set_current_feature("fdiff"); |
| 1789 | style_header("Diff"); |
| 1790 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1791 | if( diffType==2 ){ |
| @@ -1811,13 +1820,14 @@ | |
| 1811 | object_description(v2, objdescFlags,0, 0); |
| 1812 | } |
| 1813 | if( pRe ){ |
| 1814 | @ <b>Only differences that match regular expression "%h(zRe)" |
| 1815 | @ are shown.</b> |
| 1816 | } |
| 1817 | @ <hr /> |
| 1818 | append_diff(zV1, zV2, diffFlags, pRe); |
| 1819 | append_diff_javascript(diffType); |
| 1820 | style_finish_page(); |
| 1821 | } |
| 1822 | |
| 1823 | /* |
| 1824 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -330,12 +330,11 @@ | |
| 330 | ** Append the difference between artifacts to the output |
| 331 | */ |
| 332 | static void append_diff( |
| 333 | const char *zFrom, /* Diff from this artifact */ |
| 334 | const char *zTo, /* ... to this artifact */ |
| 335 | DiffConfig *pCfg /* The diff configuration */ |
| 336 | ){ |
| 337 | int fromid; |
| 338 | int toid; |
| 339 | Blob from, to; |
| 340 | if( zFrom ){ |
| @@ -348,16 +347,16 @@ | |
| 347 | toid = uuid_to_rid(zTo, 0); |
| 348 | content_get(toid, &to); |
| 349 | }else{ |
| 350 | blob_zero(&to); |
| 351 | } |
| 352 | if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ |
| 353 | pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; |
| 354 | }else{ |
| 355 | pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; |
| 356 | } |
| 357 | text_diff(&from, &to, cgi_output_blob(), pCfg); |
| 358 | blob_reset(&from); |
| 359 | blob_reset(&to); |
| 360 | } |
| 361 | |
| 362 | /* |
| @@ -368,12 +367,11 @@ | |
| 367 | const char *zCkin, /* The checkin on which the change occurs */ |
| 368 | const char *zName, /* Name of the file that has changed */ |
| 369 | const char *zOld, /* blob.uuid before change. NULL for added files */ |
| 370 | const char *zNew, /* blob.uuid after change. NULL for deletes */ |
| 371 | const char *zOldName, /* Prior name. NULL if no name change. */ |
| 372 | DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */ |
| 373 | int mperm /* executable or symlink permission for zNew */ |
| 374 | ){ |
| 375 | @ <p> |
| 376 | if( !g.perm.Hyperlink ){ |
| 377 | if( zNew==0 ){ |
| @@ -391,12 +389,12 @@ | |
| 389 | @ %h(zName) became a regular file. |
| 390 | } |
| 391 | }else{ |
| 392 | @ Changes to %h(zName). |
| 393 | } |
| 394 | if( pCfg ){ |
| 395 | append_diff(zOld, zNew, pCfg); |
| 396 | } |
| 397 | }else{ |
| 398 | if( zOld && zNew ){ |
| 399 | if( fossil_strcmp(zOld, zNew)!=0 ){ |
| 400 | @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| @@ -426,12 +424,12 @@ | |
| 424 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>. |
| 425 | }else{ |
| 426 | @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ |
| 427 | @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>. |
| 428 | } |
| 429 | if( pCfg ){ |
| 430 | append_diff(zOld, zNew, pCfg); |
| 431 | }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ |
| 432 | @ |
| 433 | @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a> |
| 434 | } |
| 435 | } |
| @@ -448,11 +446,11 @@ | |
| 446 | |
| 447 | /* |
| 448 | ** Construct an appropriate diffFlag for text_diff() based on query |
| 449 | ** parameters and the to boolean arguments. |
| 450 | */ |
| 451 | DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){ |
| 452 | u64 diffFlags = 0; /* Zero means do not show any diff */ |
| 453 | if( diffType>0 ){ |
| 454 | int x; |
| 455 | if( diffType==2 ){ |
| 456 | diffFlags = DIFF_SIDEBYSIDE; |
| @@ -472,12 +470,16 @@ | |
| 470 | diffFlags += x; |
| 471 | |
| 472 | /* The "noopt" parameter disables diff optimization */ |
| 473 | if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; |
| 474 | diffFlags |= DIFF_STRIP_EOLCR; |
| 475 | diff_config_init(pCfg, diffFlags); |
| 476 | return pCfg; |
| 477 | }else{ |
| 478 | diff_config_init(pCfg, 0); |
| 479 | return 0; |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | ** WEBPAGE: ci_tags |
| 485 | ** URL: /ci_tags?name=ARTIFACTID |
| @@ -614,20 +616,20 @@ | |
| 616 | void ci_page(void){ |
| 617 | Stmt q1, q2, q3; |
| 618 | int rid; |
| 619 | int isLeaf; |
| 620 | int diffType; /* 0: no diff, 1: unified, 2: side-by-side */ |
| 621 | const char *zName; /* Name of the check-in to be displayed */ |
| 622 | const char *zUuid; /* Hash of zName, found via blob.uuid */ |
| 623 | const char *zParent; /* Hash of the parent check-in (if any) */ |
| 624 | const char *zRe; /* regex parameter */ |
| 625 | ReCompiled *pRe = 0; /* regex */ |
| 626 | const char *zW; /* URL param for ignoring whitespace */ |
| 627 | const char *zPage = "vinfo"; /* Page that shows diffs */ |
| 628 | const char *zPageHide = "ci"; /* Page that hides diffs */ |
| 629 | const char *zBrName; /* Branch name */ |
| 630 | DiffConfig DCfg,*pCfg; /* Type of diff */ |
| 631 | |
| 632 | login_check_credentials(); |
| 633 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 634 | style_set_current_feature("vinfo"); |
| 635 | zName = P("name"); |
| @@ -878,12 +880,13 @@ | |
| 880 | render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n"); |
| 881 | @ <div class="section">Context</div> |
| 882 | render_checkin_context(rid, 0, 0, 0); |
| 883 | @ <div class="section">Changes</div> |
| 884 | @ <div class="sectionmenu"> |
| 885 | pCfg = construct_diff_flags(diffType, &DCfg); |
| 886 | DCfg.pRe = pRe; |
| 887 | zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; |
| 888 | if( diffType!=0 ){ |
| 889 | @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\ |
| 890 | @ Hide Diffs</a> |
| 891 | } |
| 892 | if( diffType!=1 ){ |
| @@ -933,14 +936,14 @@ | |
| 936 | int mperm = db_column_int(&q3, 1); |
| 937 | const char *zOld = db_column_text(&q3,2); |
| 938 | const char *zNew = db_column_text(&q3,3); |
| 939 | const char *zOldName = db_column_text(&q3, 4); |
| 940 | append_file_change_line(zUuid, zName, zOld, zNew, zOldName, |
| 941 | pCfg,mperm); |
| 942 | } |
| 943 | db_finalize(&q3); |
| 944 | append_diff_javascript(diffType); |
| 945 | builtin_fossil_js_bundle_or("info-diff",NULL); |
| 946 | style_finish_page(); |
| 947 | } |
| 948 | |
| 949 | /* |
| @@ -1167,20 +1170,20 @@ | |
| 1170 | ** Show all differences between two check-ins. |
| 1171 | */ |
| 1172 | void vdiff_page(void){ |
| 1173 | int ridFrom, ridTo; |
| 1174 | int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */ |
| 1175 | Manifest *pFrom, *pTo; |
| 1176 | ManifestFile *pFileFrom, *pFileTo; |
| 1177 | const char *zBranch; |
| 1178 | const char *zFrom; |
| 1179 | const char *zTo; |
| 1180 | const char *zRe; |
| 1181 | const char *zGlob; |
| 1182 | char *zMergeOrigin = 0; |
| 1183 | ReCompiled *pRe = 0; |
| 1184 | DiffConfig DCfg, *pCfg = 0; |
| 1185 | int graphFlags = 0; |
| 1186 | Blob qp; |
| 1187 | int bInvert = PB("inv"); |
| 1188 | |
| 1189 | login_check_credentials(); |
| @@ -1229,12 +1232,12 @@ | |
| 1232 | } |
| 1233 | if( PB("nc") ){ |
| 1234 | graphFlags |= TIMELINE_NOCOLOR; |
| 1235 | blob_appendf(&qp, "&nc"); |
| 1236 | } |
| 1237 | pCfg = construct_diff_flags(diffType, &DCfg); |
| 1238 | if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){ |
| 1239 | blob_appendf(&qp, "&w"); |
| 1240 | } |
| 1241 | style_set_current_feature("vdiff"); |
| 1242 | if( zBranch==0 ){ |
| 1243 | style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo); |
| @@ -1253,11 +1256,11 @@ | |
| 1256 | } |
| 1257 | if( zGlob ){ |
| 1258 | style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp); |
| 1259 | }else{ |
| 1260 | style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, |
| 1261 | (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); |
| 1262 | } |
| 1263 | if( diffType!=0 ){ |
| 1264 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1265 | } |
| 1266 | if( zBranch ){ |
| @@ -1301,10 +1304,11 @@ | |
| 1304 | |
| 1305 | manifest_file_rewind(pFrom); |
| 1306 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1307 | manifest_file_rewind(pTo); |
| 1308 | pFileTo = manifest_file_next(pTo, 0); |
| 1309 | DCfg.pRe = pRe; |
| 1310 | while( pFileFrom || pFileTo ){ |
| 1311 | int cmp; |
| 1312 | if( pFileFrom==0 ){ |
| 1313 | cmp = +1; |
| 1314 | }else if( pFileTo==0 ){ |
| @@ -1313,17 +1317,17 @@ | |
| 1317 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 1318 | } |
| 1319 | if( cmp<0 ){ |
| 1320 | if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){ |
| 1321 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1322 | pFileFrom->zUuid, 0, 0, pCfg, 0); |
| 1323 | } |
| 1324 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1325 | }else if( cmp>0 ){ |
| 1326 | if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){ |
| 1327 | append_file_change_line(zTo, pFileTo->zName, |
| 1328 | 0, pFileTo->zUuid, 0, pCfg, |
| 1329 | manifest_file_mperm(pFileTo)); |
| 1330 | } |
| 1331 | pFileTo = manifest_file_next(pTo, 0); |
| 1332 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 1333 | pFileFrom = manifest_file_next(pFrom, 0); |
| @@ -1331,11 +1335,11 @@ | |
| 1335 | }else{ |
| 1336 | if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0 |
| 1337 | || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){ |
| 1338 | append_file_change_line(zFrom, pFileFrom->zName, |
| 1339 | pFileFrom->zUuid, |
| 1340 | pFileTo->zUuid, 0, pCfg, |
| 1341 | manifest_file_mperm(pFileTo)); |
| 1342 | } |
| 1343 | pFileFrom = manifest_file_next(pFrom, 0); |
| 1344 | pFileTo = manifest_file_next(pTo, 0); |
| 1345 | } |
| @@ -1722,10 +1726,11 @@ | |
| 1726 | const char *zRe; |
| 1727 | ReCompiled *pRe = 0; |
| 1728 | u64 diffFlags; |
| 1729 | u32 objdescFlags = 0; |
| 1730 | int verbose = PB("verbose"); |
| 1731 | DiffConfig DCfg; |
| 1732 | |
| 1733 | login_check_credentials(); |
| 1734 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1735 | diffType = preferred_diff_type(); |
| 1736 | if( P("from") && P("to") ){ |
| @@ -1768,24 +1773,28 @@ | |
| 1773 | zRe = P("regex"); |
| 1774 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 1775 | if( verbose ) objdescFlags |= OBJDESC_DETAIL; |
| 1776 | if( isPatch ){ |
| 1777 | Blob c1, c2, *pOut; |
| 1778 | DiffConfig DCfg; |
| 1779 | pOut = cgi_output_blob(); |
| 1780 | cgi_set_content_type("text/plain"); |
| 1781 | diffFlags = 4; |
| 1782 | content_get(v1, &c1); |
| 1783 | content_get(v2, &c2); |
| 1784 | diff_config_init(&DCfg, diffFlags); |
| 1785 | DCfg.pRe = pRe; |
| 1786 | text_diff(&c1, &c2, pOut, &DCfg); |
| 1787 | blob_reset(&c1); |
| 1788 | blob_reset(&c2); |
| 1789 | return; |
| 1790 | } |
| 1791 | |
| 1792 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 1793 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 1794 | construct_diff_flags(diffType, &DCfg); |
| 1795 | DCfg.diffFlags |= DIFF_HTML; |
| 1796 | |
| 1797 | style_set_current_feature("fdiff"); |
| 1798 | style_header("Diff"); |
| 1799 | style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); |
| 1800 | if( diffType==2 ){ |
| @@ -1811,13 +1820,14 @@ | |
| 1820 | object_description(v2, objdescFlags,0, 0); |
| 1821 | } |
| 1822 | if( pRe ){ |
| 1823 | @ <b>Only differences that match regular expression "%h(zRe)" |
| 1824 | @ are shown.</b> |
| 1825 | DCfg.pRe = pRe; |
| 1826 | } |
| 1827 | @ <hr /> |
| 1828 | append_diff(zV1, zV2, &DCfg); |
| 1829 | append_diff_javascript(diffType); |
| 1830 | style_finish_page(); |
| 1831 | } |
| 1832 | |
| 1833 | /* |
| 1834 |
+3
-1
| --- src/json_diff.c | ||
| +++ src/json_diff.c | ||
| @@ -38,10 +38,11 @@ | ||
| 38 | 38 | int nContext, char fSbs, |
| 39 | 39 | char fHtml){ |
| 40 | 40 | int fromid; |
| 41 | 41 | int toid; |
| 42 | 42 | int outLen; |
| 43 | + DiffConfig DCfg; | |
| 43 | 44 | Blob from = empty_blob, to = empty_blob, out = empty_blob; |
| 44 | 45 | cson_value * rc = NULL; |
| 45 | 46 | int flags = (DIFF_CONTEXT_MASK & nContext) |
| 46 | 47 | | (fSbs ? DIFF_SIDEBYSIDE : 0) |
| 47 | 48 | | (fHtml ? DIFF_HTML : 0); |
| @@ -58,11 +59,12 @@ | ||
| 58 | 59 | return NULL; |
| 59 | 60 | } |
| 60 | 61 | content_get(fromid, &from); |
| 61 | 62 | content_get(toid, &to); |
| 62 | 63 | blob_zero(&out); |
| 63 | - text_diff(&from, &to, &out, 0, flags); | |
| 64 | + diff_config_init(&DCfg, flags); | |
| 65 | + text_diff(&from, &to, &out, &DCfg); | |
| 64 | 66 | blob_reset(&from); |
| 65 | 67 | blob_reset(&to); |
| 66 | 68 | outLen = blob_size(&out); |
| 67 | 69 | if(outLen>=0){ |
| 68 | 70 | rc = cson_value_new_string(blob_buffer(&out), |
| 69 | 71 |
| --- src/json_diff.c | |
| +++ src/json_diff.c | |
| @@ -38,10 +38,11 @@ | |
| 38 | int nContext, char fSbs, |
| 39 | char fHtml){ |
| 40 | int fromid; |
| 41 | int toid; |
| 42 | int outLen; |
| 43 | Blob from = empty_blob, to = empty_blob, out = empty_blob; |
| 44 | cson_value * rc = NULL; |
| 45 | int flags = (DIFF_CONTEXT_MASK & nContext) |
| 46 | | (fSbs ? DIFF_SIDEBYSIDE : 0) |
| 47 | | (fHtml ? DIFF_HTML : 0); |
| @@ -58,11 +59,12 @@ | |
| 58 | return NULL; |
| 59 | } |
| 60 | content_get(fromid, &from); |
| 61 | content_get(toid, &to); |
| 62 | blob_zero(&out); |
| 63 | text_diff(&from, &to, &out, 0, flags); |
| 64 | blob_reset(&from); |
| 65 | blob_reset(&to); |
| 66 | outLen = blob_size(&out); |
| 67 | if(outLen>=0){ |
| 68 | rc = cson_value_new_string(blob_buffer(&out), |
| 69 |
| --- src/json_diff.c | |
| +++ src/json_diff.c | |
| @@ -38,10 +38,11 @@ | |
| 38 | int nContext, char fSbs, |
| 39 | char fHtml){ |
| 40 | int fromid; |
| 41 | int toid; |
| 42 | int outLen; |
| 43 | DiffConfig DCfg; |
| 44 | Blob from = empty_blob, to = empty_blob, out = empty_blob; |
| 45 | cson_value * rc = NULL; |
| 46 | int flags = (DIFF_CONTEXT_MASK & nContext) |
| 47 | | (fSbs ? DIFF_SIDEBYSIDE : 0) |
| 48 | | (fHtml ? DIFF_HTML : 0); |
| @@ -58,11 +59,12 @@ | |
| 59 | return NULL; |
| 60 | } |
| 61 | content_get(fromid, &from); |
| 62 | content_get(toid, &to); |
| 63 | blob_zero(&out); |
| 64 | diff_config_init(&DCfg, flags); |
| 65 | text_diff(&from, &to, &out, &DCfg); |
| 66 | blob_reset(&from); |
| 67 | blob_reset(&to); |
| 68 | outLen = blob_size(&out); |
| 69 | if(outLen>=0){ |
| 70 | rc = cson_value_new_string(blob_buffer(&out), |
| 71 |
+3
-3
| --- src/json_wiki.c | ||
| +++ src/json_wiki.c | ||
| @@ -519,11 +519,11 @@ | ||
| 519 | 519 | int argPos = g.json.dispatchDepth; |
| 520 | 520 | int r1 = 0, r2 = 0; |
| 521 | 521 | Manifest * pW1 = NULL, *pW2 = NULL; |
| 522 | 522 | Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; |
| 523 | 523 | char const * zErrTag = NULL; |
| 524 | - u64 diffFlags; | |
| 524 | + DiffConfig DCfg; | |
| 525 | 525 | char * zUuid = NULL; |
| 526 | 526 | if( !g.perm.Hyperlink ){ |
| 527 | 527 | json_set_err(FSL_JSON_E_DENIED, |
| 528 | 528 | "Requires 'h' permissions."); |
| 529 | 529 | return NULL; |
| @@ -567,12 +567,12 @@ | ||
| 567 | 567 | |
| 568 | 568 | blob_init(&w1, pW1->zWiki, -1); |
| 569 | 569 | blob_zero(&w2); |
| 570 | 570 | blob_init(&w2, pW2->zWiki, -1); |
| 571 | 571 | blob_zero(&d); |
| 572 | - diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR; | |
| 573 | - text_diff(&w1, &w2, &d, 0, diffFlags); | |
| 572 | + diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR); | |
| 573 | + text_diff(&w1, &w2, &d, &DCfg); | |
| 574 | 574 | blob_reset(&w1); |
| 575 | 575 | blob_reset(&w2); |
| 576 | 576 | |
| 577 | 577 | pay = cson_new_object(); |
| 578 | 578 | |
| 579 | 579 |
| --- src/json_wiki.c | |
| +++ src/json_wiki.c | |
| @@ -519,11 +519,11 @@ | |
| 519 | int argPos = g.json.dispatchDepth; |
| 520 | int r1 = 0, r2 = 0; |
| 521 | Manifest * pW1 = NULL, *pW2 = NULL; |
| 522 | Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; |
| 523 | char const * zErrTag = NULL; |
| 524 | u64 diffFlags; |
| 525 | char * zUuid = NULL; |
| 526 | if( !g.perm.Hyperlink ){ |
| 527 | json_set_err(FSL_JSON_E_DENIED, |
| 528 | "Requires 'h' permissions."); |
| 529 | return NULL; |
| @@ -567,12 +567,12 @@ | |
| 567 | |
| 568 | blob_init(&w1, pW1->zWiki, -1); |
| 569 | blob_zero(&w2); |
| 570 | blob_init(&w2, pW2->zWiki, -1); |
| 571 | blob_zero(&d); |
| 572 | diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR; |
| 573 | text_diff(&w1, &w2, &d, 0, diffFlags); |
| 574 | blob_reset(&w1); |
| 575 | blob_reset(&w2); |
| 576 | |
| 577 | pay = cson_new_object(); |
| 578 | |
| 579 |
| --- src/json_wiki.c | |
| +++ src/json_wiki.c | |
| @@ -519,11 +519,11 @@ | |
| 519 | int argPos = g.json.dispatchDepth; |
| 520 | int r1 = 0, r2 = 0; |
| 521 | Manifest * pW1 = NULL, *pW2 = NULL; |
| 522 | Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; |
| 523 | char const * zErrTag = NULL; |
| 524 | DiffConfig DCfg; |
| 525 | char * zUuid = NULL; |
| 526 | if( !g.perm.Hyperlink ){ |
| 527 | json_set_err(FSL_JSON_E_DENIED, |
| 528 | "Requires 'h' permissions."); |
| 529 | return NULL; |
| @@ -567,12 +567,12 @@ | |
| 567 | |
| 568 | blob_init(&w1, pW1->zWiki, -1); |
| 569 | blob_zero(&w2); |
| 570 | blob_init(&w2, pW2->zWiki, -1); |
| 571 | blob_zero(&d); |
| 572 | diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR); |
| 573 | text_diff(&w1, &w2, &d, &DCfg); |
| 574 | blob_reset(&w1); |
| 575 | blob_reset(&w2); |
| 576 | |
| 577 | pay = cson_new_object(); |
| 578 | |
| 579 |
+4
-2
| --- src/merge3.c | ||
| +++ src/merge3.c | ||
| @@ -196,10 +196,11 @@ | ||
| 196 | 196 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 197 | 197 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 198 | 198 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 199 | 199 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 200 | 200 | int useCrLf = 0; |
| 201 | + DiffConfig DCfg; | |
| 201 | 202 | |
| 202 | 203 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 203 | 204 | |
| 204 | 205 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| 205 | 206 | ** keep it in the output. This should be secure enough not to cause |
| @@ -224,12 +225,13 @@ | ||
| 224 | 225 | ** is the number of lines of text to copy directly from the pivot, |
| 225 | 226 | ** the second integer is the number of lines of text to omit from the |
| 226 | 227 | ** pivot, and the third integer is the number of lines of text that are |
| 227 | 228 | ** inserted. The edit array ends with a triple of 0,0,0. |
| 228 | 229 | */ |
| 229 | - aC1 = text_diff(pPivot, pV1, 0, 0, 0); | |
| 230 | - aC2 = text_diff(pPivot, pV2, 0, 0, 0); | |
| 230 | + diff_config_init(&DCfg, 0); | |
| 231 | + aC1 = text_diff(pPivot, pV1, 0, &DCfg); | |
| 232 | + aC2 = text_diff(pPivot, pV2, 0, &DCfg); | |
| 231 | 233 | if( aC1==0 || aC2==0 ){ |
| 232 | 234 | free(aC1); |
| 233 | 235 | free(aC2); |
| 234 | 236 | return -1; |
| 235 | 237 | } |
| 236 | 238 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -196,10 +196,11 @@ | |
| 196 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 197 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 198 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 199 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 200 | int useCrLf = 0; |
| 201 | |
| 202 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 203 | |
| 204 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| 205 | ** keep it in the output. This should be secure enough not to cause |
| @@ -224,12 +225,13 @@ | |
| 224 | ** is the number of lines of text to copy directly from the pivot, |
| 225 | ** the second integer is the number of lines of text to omit from the |
| 226 | ** pivot, and the third integer is the number of lines of text that are |
| 227 | ** inserted. The edit array ends with a triple of 0,0,0. |
| 228 | */ |
| 229 | aC1 = text_diff(pPivot, pV1, 0, 0, 0); |
| 230 | aC2 = text_diff(pPivot, pV2, 0, 0, 0); |
| 231 | if( aC1==0 || aC2==0 ){ |
| 232 | free(aC1); |
| 233 | free(aC2); |
| 234 | return -1; |
| 235 | } |
| 236 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -196,10 +196,11 @@ | |
| 196 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 197 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 198 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 199 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 200 | int useCrLf = 0; |
| 201 | DiffConfig DCfg; |
| 202 | |
| 203 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 204 | |
| 205 | /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), |
| 206 | ** keep it in the output. This should be secure enough not to cause |
| @@ -224,12 +225,13 @@ | |
| 225 | ** is the number of lines of text to copy directly from the pivot, |
| 226 | ** the second integer is the number of lines of text to omit from the |
| 227 | ** pivot, and the third integer is the number of lines of text that are |
| 228 | ** inserted. The edit array ends with a triple of 0,0,0. |
| 229 | */ |
| 230 | diff_config_init(&DCfg, 0); |
| 231 | aC1 = text_diff(pPivot, pV1, 0, &DCfg); |
| 232 | aC2 = text_diff(pPivot, pV2, 0, &DCfg); |
| 233 | if( aC1==0 || aC2==0 ){ |
| 234 | free(aC1); |
| 235 | free(aC2); |
| 236 | return -1; |
| 237 | } |
| 238 |
+14
-14
| --- src/patch.c | ||
| +++ src/patch.c | ||
| @@ -720,15 +720,15 @@ | ||
| 720 | 720 | static void patch_diff( |
| 721 | 721 | unsigned mFlags, /* Patch flags. only -f is allowed */ |
| 722 | 722 | const char *zDiffCmd, /* Command used for diffing */ |
| 723 | 723 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 724 | 724 | int fIncludeBinary, /* Do diffs against binary files */ |
| 725 | - u64 diffFlags /* Other diff flags */ | |
| 725 | + DiffConfig *pCfg /* Diff options */ | |
| 726 | 726 | ){ |
| 727 | 727 | int nErr = 0; |
| 728 | 728 | Stmt q; |
| 729 | - int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; | |
| 729 | + int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; | |
| 730 | 730 | Blob empty; |
| 731 | 731 | blob_zero(&empty); |
| 732 | 732 | |
| 733 | 733 | if( (mFlags & PATCH_FORCE)==0 ){ |
| 734 | 734 | /* Check to ensure that the patch is against the repository that |
| @@ -764,11 +764,11 @@ | ||
| 764 | 764 | "in the %s repository", zBaseline, g.zRepositoryName); |
| 765 | 765 | } |
| 766 | 766 | } |
| 767 | 767 | } |
| 768 | 768 | |
| 769 | - diff_begin(diffFlags); | |
| 769 | + diff_begin(pCfg); | |
| 770 | 770 | db_prepare(&q, |
| 771 | 771 | "SELECT" |
| 772 | 772 | " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash)," |
| 773 | 773 | " pathname," /* 1: new pathname */ |
| 774 | 774 | " origname," /* 2: original pathname. Null if not renamed */ |
| @@ -804,25 +804,25 @@ | ||
| 804 | 804 | zName = db_column_text(&q, 1); |
| 805 | 805 | rid = db_column_int(&q, 0); |
| 806 | 806 | |
| 807 | 807 | if( db_column_type(&q,3)==SQLITE_NULL ){ |
| 808 | 808 | if( !bWebpage ) fossil_print("DELETE %s\n", zName); |
| 809 | - diff_print_index(zName, diffFlags, 0); | |
| 809 | + diff_print_index(zName, pCfg, 0); | |
| 810 | 810 | isBin2 = 0; |
| 811 | 811 | content_get(rid, &a); |
| 812 | 812 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 813 | 813 | diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd, |
| 814 | - zBinGlob, fIncludeBinary, diffFlags); | |
| 814 | + zBinGlob, fIncludeBinary, pCfg); | |
| 815 | 815 | }else if( rid==0 ){ |
| 816 | 816 | db_ephemeral_blob(&q, 3, &a); |
| 817 | 817 | blob_uncompress(&a, &a); |
| 818 | 818 | if( !bWebpage ) fossil_print("ADDED %s\n", zName); |
| 819 | - diff_print_index(zName, diffFlags, 0); | |
| 819 | + diff_print_index(zName, pCfg, 0); | |
| 820 | 820 | isBin1 = 0; |
| 821 | 821 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 822 | 822 | diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd, |
| 823 | - zBinGlob, fIncludeBinary, diffFlags); | |
| 823 | + zBinGlob, fIncludeBinary, pCfg); | |
| 824 | 824 | blob_reset(&a); |
| 825 | 825 | }else if( db_column_bytes(&q, 3)>0 ){ |
| 826 | 826 | Blob delta; |
| 827 | 827 | db_ephemeral_blob(&q, 3, &delta); |
| 828 | 828 | blob_uncompress(&delta, &delta); |
| @@ -829,18 +829,18 @@ | ||
| 829 | 829 | content_get(rid, &a); |
| 830 | 830 | blob_delta_apply(&a, &delta, &b); |
| 831 | 831 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 832 | 832 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 833 | 833 | diff_file_mem(&a, &b, isBin1, isBin2, zName, |
| 834 | - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); | |
| 834 | + zDiffCmd, zBinGlob, fIncludeBinary, pCfg); | |
| 835 | 835 | blob_reset(&a); |
| 836 | 836 | blob_reset(&b); |
| 837 | 837 | blob_reset(&delta); |
| 838 | 838 | } |
| 839 | 839 | } |
| 840 | 840 | db_finalize(&q); |
| 841 | - diff_end(diffFlags, nErr); | |
| 841 | + diff_end(pCfg, nErr); | |
| 842 | 842 | if( nErr ) fossil_fatal("abort due to prior errors"); |
| 843 | 843 | } |
| 844 | 844 | |
| 845 | 845 | |
| 846 | 846 | /* |
| @@ -949,36 +949,36 @@ | ||
| 949 | 949 | }else |
| 950 | 950 | if( strncmp(zCmd, "diff", n)==0 ){ |
| 951 | 951 | const char *zDiffCmd = 0; |
| 952 | 952 | const char *zBinGlob = 0; |
| 953 | 953 | int fIncludeBinary = 0; |
| 954 | - u64 diffFlags; | |
| 955 | 954 | char *zIn; |
| 956 | 955 | unsigned flags = 0; |
| 956 | + DiffConfig DCfg; | |
| 957 | 957 | |
| 958 | 958 | if( find_option("tk",0,0)!=0 ){ |
| 959 | 959 | db_close(0); |
| 960 | 960 | diff_tk("patch diff", 3); |
| 961 | 961 | return; |
| 962 | 962 | } |
| 963 | - diffFlags = diff_options(); | |
| 963 | + diff_options(&DCfg, zCmd[0]=='g'); | |
| 964 | 964 | if( find_option("internal","i",0)==0 |
| 965 | - && (diffFlags & DIFF_HTML)==0 | |
| 965 | + && (DCfg.diffFlags & DIFF_HTML)==0 | |
| 966 | 966 | ){ |
| 967 | 967 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 968 | 968 | } |
| 969 | - if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; | |
| 969 | + if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; | |
| 970 | 970 | if( zDiffCmd ){ |
| 971 | 971 | zBinGlob = diff_get_binary_glob(); |
| 972 | 972 | fIncludeBinary = diff_include_binary_files(); |
| 973 | 973 | } |
| 974 | 974 | db_find_and_open_repository(0, 0); |
| 975 | 975 | if( find_option("force","f",0) ) flags |= PATCH_FORCE; |
| 976 | 976 | verify_all_options(); |
| 977 | 977 | zIn = patch_find_patch_filename("apply"); |
| 978 | 978 | patch_attach(zIn, stdin); |
| 979 | - patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); | |
| 979 | + patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, &DCfg); | |
| 980 | 980 | fossil_free(zIn); |
| 981 | 981 | }else |
| 982 | 982 | if( strncmp(zCmd, "pull", n)==0 ){ |
| 983 | 983 | FILE *pIn = 0; |
| 984 | 984 | unsigned flags = 0; |
| 985 | 985 |
| --- src/patch.c | |
| +++ src/patch.c | |
| @@ -720,15 +720,15 @@ | |
| 720 | static void patch_diff( |
| 721 | unsigned mFlags, /* Patch flags. only -f is allowed */ |
| 722 | const char *zDiffCmd, /* Command used for diffing */ |
| 723 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 724 | int fIncludeBinary, /* Do diffs against binary files */ |
| 725 | u64 diffFlags /* Other diff flags */ |
| 726 | ){ |
| 727 | int nErr = 0; |
| 728 | Stmt q; |
| 729 | int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; |
| 730 | Blob empty; |
| 731 | blob_zero(&empty); |
| 732 | |
| 733 | if( (mFlags & PATCH_FORCE)==0 ){ |
| 734 | /* Check to ensure that the patch is against the repository that |
| @@ -764,11 +764,11 @@ | |
| 764 | "in the %s repository", zBaseline, g.zRepositoryName); |
| 765 | } |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | diff_begin(diffFlags); |
| 770 | db_prepare(&q, |
| 771 | "SELECT" |
| 772 | " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash)," |
| 773 | " pathname," /* 1: new pathname */ |
| 774 | " origname," /* 2: original pathname. Null if not renamed */ |
| @@ -804,25 +804,25 @@ | |
| 804 | zName = db_column_text(&q, 1); |
| 805 | rid = db_column_int(&q, 0); |
| 806 | |
| 807 | if( db_column_type(&q,3)==SQLITE_NULL ){ |
| 808 | if( !bWebpage ) fossil_print("DELETE %s\n", zName); |
| 809 | diff_print_index(zName, diffFlags, 0); |
| 810 | isBin2 = 0; |
| 811 | content_get(rid, &a); |
| 812 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 813 | diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd, |
| 814 | zBinGlob, fIncludeBinary, diffFlags); |
| 815 | }else if( rid==0 ){ |
| 816 | db_ephemeral_blob(&q, 3, &a); |
| 817 | blob_uncompress(&a, &a); |
| 818 | if( !bWebpage ) fossil_print("ADDED %s\n", zName); |
| 819 | diff_print_index(zName, diffFlags, 0); |
| 820 | isBin1 = 0; |
| 821 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 822 | diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd, |
| 823 | zBinGlob, fIncludeBinary, diffFlags); |
| 824 | blob_reset(&a); |
| 825 | }else if( db_column_bytes(&q, 3)>0 ){ |
| 826 | Blob delta; |
| 827 | db_ephemeral_blob(&q, 3, &delta); |
| 828 | blob_uncompress(&delta, &delta); |
| @@ -829,18 +829,18 @@ | |
| 829 | content_get(rid, &a); |
| 830 | blob_delta_apply(&a, &delta, &b); |
| 831 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 832 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 833 | diff_file_mem(&a, &b, isBin1, isBin2, zName, |
| 834 | zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); |
| 835 | blob_reset(&a); |
| 836 | blob_reset(&b); |
| 837 | blob_reset(&delta); |
| 838 | } |
| 839 | } |
| 840 | db_finalize(&q); |
| 841 | diff_end(diffFlags, nErr); |
| 842 | if( nErr ) fossil_fatal("abort due to prior errors"); |
| 843 | } |
| 844 | |
| 845 | |
| 846 | /* |
| @@ -949,36 +949,36 @@ | |
| 949 | }else |
| 950 | if( strncmp(zCmd, "diff", n)==0 ){ |
| 951 | const char *zDiffCmd = 0; |
| 952 | const char *zBinGlob = 0; |
| 953 | int fIncludeBinary = 0; |
| 954 | u64 diffFlags; |
| 955 | char *zIn; |
| 956 | unsigned flags = 0; |
| 957 | |
| 958 | if( find_option("tk",0,0)!=0 ){ |
| 959 | db_close(0); |
| 960 | diff_tk("patch diff", 3); |
| 961 | return; |
| 962 | } |
| 963 | diffFlags = diff_options(); |
| 964 | if( find_option("internal","i",0)==0 |
| 965 | && (diffFlags & DIFF_HTML)==0 |
| 966 | ){ |
| 967 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 968 | } |
| 969 | if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; |
| 970 | if( zDiffCmd ){ |
| 971 | zBinGlob = diff_get_binary_glob(); |
| 972 | fIncludeBinary = diff_include_binary_files(); |
| 973 | } |
| 974 | db_find_and_open_repository(0, 0); |
| 975 | if( find_option("force","f",0) ) flags |= PATCH_FORCE; |
| 976 | verify_all_options(); |
| 977 | zIn = patch_find_patch_filename("apply"); |
| 978 | patch_attach(zIn, stdin); |
| 979 | patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); |
| 980 | fossil_free(zIn); |
| 981 | }else |
| 982 | if( strncmp(zCmd, "pull", n)==0 ){ |
| 983 | FILE *pIn = 0; |
| 984 | unsigned flags = 0; |
| 985 |
| --- src/patch.c | |
| +++ src/patch.c | |
| @@ -720,15 +720,15 @@ | |
| 720 | static void patch_diff( |
| 721 | unsigned mFlags, /* Patch flags. only -f is allowed */ |
| 722 | const char *zDiffCmd, /* Command used for diffing */ |
| 723 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 724 | int fIncludeBinary, /* Do diffs against binary files */ |
| 725 | DiffConfig *pCfg /* Diff options */ |
| 726 | ){ |
| 727 | int nErr = 0; |
| 728 | Stmt q; |
| 729 | int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; |
| 730 | Blob empty; |
| 731 | blob_zero(&empty); |
| 732 | |
| 733 | if( (mFlags & PATCH_FORCE)==0 ){ |
| 734 | /* Check to ensure that the patch is against the repository that |
| @@ -764,11 +764,11 @@ | |
| 764 | "in the %s repository", zBaseline, g.zRepositoryName); |
| 765 | } |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | diff_begin(pCfg); |
| 770 | db_prepare(&q, |
| 771 | "SELECT" |
| 772 | " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash)," |
| 773 | " pathname," /* 1: new pathname */ |
| 774 | " origname," /* 2: original pathname. Null if not renamed */ |
| @@ -804,25 +804,25 @@ | |
| 804 | zName = db_column_text(&q, 1); |
| 805 | rid = db_column_int(&q, 0); |
| 806 | |
| 807 | if( db_column_type(&q,3)==SQLITE_NULL ){ |
| 808 | if( !bWebpage ) fossil_print("DELETE %s\n", zName); |
| 809 | diff_print_index(zName, pCfg, 0); |
| 810 | isBin2 = 0; |
| 811 | content_get(rid, &a); |
| 812 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 813 | diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd, |
| 814 | zBinGlob, fIncludeBinary, pCfg); |
| 815 | }else if( rid==0 ){ |
| 816 | db_ephemeral_blob(&q, 3, &a); |
| 817 | blob_uncompress(&a, &a); |
| 818 | if( !bWebpage ) fossil_print("ADDED %s\n", zName); |
| 819 | diff_print_index(zName, pCfg, 0); |
| 820 | isBin1 = 0; |
| 821 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 822 | diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd, |
| 823 | zBinGlob, fIncludeBinary, pCfg); |
| 824 | blob_reset(&a); |
| 825 | }else if( db_column_bytes(&q, 3)>0 ){ |
| 826 | Blob delta; |
| 827 | db_ephemeral_blob(&q, 3, &delta); |
| 828 | blob_uncompress(&delta, &delta); |
| @@ -829,18 +829,18 @@ | |
| 829 | content_get(rid, &a); |
| 830 | blob_delta_apply(&a, &delta, &b); |
| 831 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 832 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 833 | diff_file_mem(&a, &b, isBin1, isBin2, zName, |
| 834 | zDiffCmd, zBinGlob, fIncludeBinary, pCfg); |
| 835 | blob_reset(&a); |
| 836 | blob_reset(&b); |
| 837 | blob_reset(&delta); |
| 838 | } |
| 839 | } |
| 840 | db_finalize(&q); |
| 841 | diff_end(pCfg, nErr); |
| 842 | if( nErr ) fossil_fatal("abort due to prior errors"); |
| 843 | } |
| 844 | |
| 845 | |
| 846 | /* |
| @@ -949,36 +949,36 @@ | |
| 949 | }else |
| 950 | if( strncmp(zCmd, "diff", n)==0 ){ |
| 951 | const char *zDiffCmd = 0; |
| 952 | const char *zBinGlob = 0; |
| 953 | int fIncludeBinary = 0; |
| 954 | char *zIn; |
| 955 | unsigned flags = 0; |
| 956 | DiffConfig DCfg; |
| 957 | |
| 958 | if( find_option("tk",0,0)!=0 ){ |
| 959 | db_close(0); |
| 960 | diff_tk("patch diff", 3); |
| 961 | return; |
| 962 | } |
| 963 | diff_options(&DCfg, zCmd[0]=='g'); |
| 964 | if( find_option("internal","i",0)==0 |
| 965 | && (DCfg.diffFlags & DIFF_HTML)==0 |
| 966 | ){ |
| 967 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 968 | } |
| 969 | if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; |
| 970 | if( zDiffCmd ){ |
| 971 | zBinGlob = diff_get_binary_glob(); |
| 972 | fIncludeBinary = diff_include_binary_files(); |
| 973 | } |
| 974 | db_find_and_open_repository(0, 0); |
| 975 | if( find_option("force","f",0) ) flags |= PATCH_FORCE; |
| 976 | verify_all_options(); |
| 977 | zIn = patch_find_patch_filename("apply"); |
| 978 | patch_attach(zIn, stdin); |
| 979 | patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, &DCfg); |
| 980 | fossil_free(zIn); |
| 981 | }else |
| 982 | if( strncmp(zCmd, "pull", n)==0 ){ |
| 983 | FILE *pIn = 0; |
| 984 | unsigned flags = 0; |
| 985 |
+9
-6
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -867,22 +867,25 @@ | ||
| 867 | 867 | @ Baseline: \ |
| 868 | 868 | skin_emit_skin_selector("basis", zBasis, zDraft); |
| 869 | 869 | @ <input type="submit" name="diff" value="Unified Diff" /> |
| 870 | 870 | @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" /> |
| 871 | 871 | if( P("diff")!=0 || P("sbsdiff")!=0 ){ |
| 872 | - u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR; | |
| 873 | 872 | Blob from, to, out; |
| 874 | - if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE; | |
| 873 | + DiffConfig DCfg; | |
| 874 | + construct_diff_flags(1, &DCfg); | |
| 875 | + DCfg.diffFlags |= DIFF_STRIP_EOLCR; | |
| 876 | + if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE; | |
| 875 | 877 | blob_init(&to, zContent, -1); |
| 876 | 878 | blob_init(&from, skin_file_content(zBasis, zFile), -1); |
| 877 | 879 | blob_zero(&out); |
| 878 | - if( diffFlags & DIFF_SIDEBYSIDE ){ | |
| 879 | - text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG); | |
| 880 | + DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; | |
| 881 | + if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){ | |
| 882 | + text_diff(&from, &to, &out, &DCfg); | |
| 880 | 883 | @ %s(blob_str(&out)) |
| 881 | 884 | }else{ |
| 882 | - text_diff(&from, &to, &out, 0, | |
| 883 | - diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG); | |
| 885 | + DCfg.diffFlags |= DIFF_LINENO; | |
| 886 | + text_diff(&from, &to, &out, &DCfg); | |
| 884 | 887 | @ <pre class="udiff"> |
| 885 | 888 | @ %s(blob_str(&out)) |
| 886 | 889 | @ </pre> |
| 887 | 890 | } |
| 888 | 891 | blob_reset(&from); |
| 889 | 892 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -867,22 +867,25 @@ | |
| 867 | @ Baseline: \ |
| 868 | skin_emit_skin_selector("basis", zBasis, zDraft); |
| 869 | @ <input type="submit" name="diff" value="Unified Diff" /> |
| 870 | @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" /> |
| 871 | if( P("diff")!=0 || P("sbsdiff")!=0 ){ |
| 872 | u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR; |
| 873 | Blob from, to, out; |
| 874 | if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE; |
| 875 | blob_init(&to, zContent, -1); |
| 876 | blob_init(&from, skin_file_content(zBasis, zFile), -1); |
| 877 | blob_zero(&out); |
| 878 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 879 | text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG); |
| 880 | @ %s(blob_str(&out)) |
| 881 | }else{ |
| 882 | text_diff(&from, &to, &out, 0, |
| 883 | diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG); |
| 884 | @ <pre class="udiff"> |
| 885 | @ %s(blob_str(&out)) |
| 886 | @ </pre> |
| 887 | } |
| 888 | blob_reset(&from); |
| 889 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -867,22 +867,25 @@ | |
| 867 | @ Baseline: \ |
| 868 | skin_emit_skin_selector("basis", zBasis, zDraft); |
| 869 | @ <input type="submit" name="diff" value="Unified Diff" /> |
| 870 | @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" /> |
| 871 | if( P("diff")!=0 || P("sbsdiff")!=0 ){ |
| 872 | Blob from, to, out; |
| 873 | DiffConfig DCfg; |
| 874 | construct_diff_flags(1, &DCfg); |
| 875 | DCfg.diffFlags |= DIFF_STRIP_EOLCR; |
| 876 | if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE; |
| 877 | blob_init(&to, zContent, -1); |
| 878 | blob_init(&from, skin_file_content(zBasis, zFile), -1); |
| 879 | blob_zero(&out); |
| 880 | DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; |
| 881 | if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){ |
| 882 | text_diff(&from, &to, &out, &DCfg); |
| 883 | @ %s(blob_str(&out)) |
| 884 | }else{ |
| 885 | DCfg.diffFlags |= DIFF_LINENO; |
| 886 | text_diff(&from, &to, &out, &DCfg); |
| 887 | @ <pre class="udiff"> |
| 888 | @ %s(blob_str(&out)) |
| 889 | @ </pre> |
| 890 | } |
| 891 | blob_reset(&from); |
| 892 |
+17
-18
| --- src/stash.c | ||
| +++ src/stash.c | ||
| @@ -406,17 +406,17 @@ | ||
| 406 | 406 | int stashid, /* The stash entry to diff */ |
| 407 | 407 | const char *zDiffCmd, /* Command used for diffing */ |
| 408 | 408 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 409 | 409 | int fBaseline, /* Diff against original baseline check-in if true */ |
| 410 | 410 | int fIncludeBinary, /* Do diffs against binary files */ |
| 411 | - u64 diffFlags /* Other diff flags */ | |
| 411 | + DiffConfig *pCfg /* Diff formatting options */ | |
| 412 | 412 | ){ |
| 413 | 413 | Stmt q; |
| 414 | 414 | Blob empty; |
| 415 | - int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; | |
| 415 | + int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; | |
| 416 | 416 | blob_zero(&empty); |
| 417 | - diff_begin(diffFlags); | |
| 417 | + diff_begin(pCfg); | |
| 418 | 418 | db_prepare(&q, |
| 419 | 419 | "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta" |
| 420 | 420 | " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash", |
| 421 | 421 | stashid |
| 422 | 422 | ); |
| @@ -430,56 +430,56 @@ | ||
| 430 | 430 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 431 | 431 | Blob a, b; |
| 432 | 432 | if( rid==0 ){ |
| 433 | 433 | db_ephemeral_blob(&q, 6, &a); |
| 434 | 434 | if( !bWebpage ) fossil_print("ADDED %s\n", zNew); |
| 435 | - diff_print_index(zNew, diffFlags, 0); | |
| 435 | + diff_print_index(zNew, pCfg, 0); | |
| 436 | 436 | isBin1 = 0; |
| 437 | 437 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 438 | 438 | diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd, |
| 439 | - zBinGlob, fIncludeBinary, diffFlags); | |
| 439 | + zBinGlob, fIncludeBinary, pCfg); | |
| 440 | 440 | }else if( isRemoved ){ |
| 441 | 441 | if( !bWebpage) fossil_print("DELETE %s\n", zOrig); |
| 442 | - diff_print_index(zNew, diffFlags, 0); | |
| 442 | + diff_print_index(zNew, pCfg, 0); | |
| 443 | 443 | isBin2 = 0; |
| 444 | 444 | if( fBaseline ){ |
| 445 | 445 | content_get(rid, &a); |
| 446 | 446 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 447 | 447 | diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd, |
| 448 | - zBinGlob, fIncludeBinary, diffFlags); | |
| 448 | + zBinGlob, fIncludeBinary, pCfg); | |
| 449 | 449 | } |
| 450 | 450 | }else{ |
| 451 | 451 | Blob delta; |
| 452 | 452 | int isOrigLink = file_islink(zOPath); |
| 453 | 453 | db_ephemeral_blob(&q, 6, &delta); |
| 454 | 454 | if( !bWebpage ) fossil_print("CHANGED %s\n", zNew); |
| 455 | 455 | if( !isOrigLink != !isLink ){ |
| 456 | - diff_print_index(zNew, diffFlags, 0); | |
| 457 | - diff_print_filenames(zOrig, zNew, diffFlags, 0); | |
| 456 | + diff_print_index(zNew, pCfg, 0); | |
| 457 | + diff_print_filenames(zOrig, zNew, pCfg, 0); | |
| 458 | 458 | printf(DIFF_CANNOT_COMPUTE_SYMLINK); |
| 459 | 459 | }else{ |
| 460 | 460 | content_get(rid, &a); |
| 461 | 461 | blob_delta_apply(&a, &delta, &b); |
| 462 | 462 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 463 | 463 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 464 | 464 | if( fBaseline ){ |
| 465 | 465 | diff_file_mem(&a, &b, isBin1, isBin2, zNew, |
| 466 | - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); | |
| 466 | + zDiffCmd, zBinGlob, fIncludeBinary, pCfg); | |
| 467 | 467 | }else{ |
| 468 | 468 | /*Diff with file on disk using fSwapDiff=1 to show the diff in the |
| 469 | 469 | same direction as if fBaseline=1.*/ |
| 470 | 470 | diff_file(&b, isBin2, zOPath, zNew, zDiffCmd, |
| 471 | - zBinGlob, fIncludeBinary, diffFlags, 1, 0); | |
| 471 | + zBinGlob, fIncludeBinary, pCfg, 1, 0); | |
| 472 | 472 | } |
| 473 | 473 | blob_reset(&a); |
| 474 | 474 | blob_reset(&b); |
| 475 | 475 | } |
| 476 | 476 | blob_reset(&delta); |
| 477 | 477 | } |
| 478 | 478 | } |
| 479 | 479 | db_finalize(&q); |
| 480 | - diff_end(diffFlags, 0); | |
| 480 | + diff_end(pCfg, 0); | |
| 481 | 481 | } |
| 482 | 482 | |
| 483 | 483 | /* |
| 484 | 484 | ** Drop the indicated stash |
| 485 | 485 | */ |
| @@ -744,35 +744,34 @@ | ||
| 744 | 744 | ){ |
| 745 | 745 | const char *zDiffCmd = 0; |
| 746 | 746 | const char *zBinGlob = 0; |
| 747 | 747 | int fIncludeBinary = 0; |
| 748 | 748 | int fBaseline = 0; |
| 749 | - u64 diffFlags; | |
| 749 | + DiffConfig DCfg; | |
| 750 | 750 | |
| 751 | 751 | if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ |
| 752 | 752 | fBaseline = 1; |
| 753 | 753 | } |
| 754 | 754 | if( find_option("tk",0,0)!=0 ){ |
| 755 | 755 | db_close(0); |
| 756 | 756 | diff_tk(fBaseline ? "stash show" : "stash diff", 3); |
| 757 | 757 | return; |
| 758 | 758 | } |
| 759 | - diffFlags = diff_options(); | |
| 759 | + diff_options(&DCfg, zCmd[0]=='g'); | |
| 760 | 760 | if( find_option("internal","i",0)==0 |
| 761 | - && (diffFlags & DIFF_HTML)==0 | |
| 761 | + && (DCfg.diffFlags & DIFF_HTML)==0 | |
| 762 | 762 | ){ |
| 763 | 763 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 764 | 764 | } |
| 765 | - if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; | |
| 765 | + if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; | |
| 766 | 766 | if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd)); |
| 767 | 767 | if( zDiffCmd ){ |
| 768 | 768 | zBinGlob = diff_get_binary_glob(); |
| 769 | 769 | fIncludeBinary = diff_include_binary_files(); |
| 770 | 770 | } |
| 771 | 771 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 772 | - stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, | |
| 773 | - diffFlags); | |
| 772 | + stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, &DCfg); | |
| 774 | 773 | }else |
| 775 | 774 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 776 | 775 | g.argv[1] = "help"; |
| 777 | 776 | g.argv[2] = "stash"; |
| 778 | 777 | g.argc = 3; |
| 779 | 778 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -406,17 +406,17 @@ | |
| 406 | int stashid, /* The stash entry to diff */ |
| 407 | const char *zDiffCmd, /* Command used for diffing */ |
| 408 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 409 | int fBaseline, /* Diff against original baseline check-in if true */ |
| 410 | int fIncludeBinary, /* Do diffs against binary files */ |
| 411 | u64 diffFlags /* Other diff flags */ |
| 412 | ){ |
| 413 | Stmt q; |
| 414 | Blob empty; |
| 415 | int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; |
| 416 | blob_zero(&empty); |
| 417 | diff_begin(diffFlags); |
| 418 | db_prepare(&q, |
| 419 | "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta" |
| 420 | " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash", |
| 421 | stashid |
| 422 | ); |
| @@ -430,56 +430,56 @@ | |
| 430 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 431 | Blob a, b; |
| 432 | if( rid==0 ){ |
| 433 | db_ephemeral_blob(&q, 6, &a); |
| 434 | if( !bWebpage ) fossil_print("ADDED %s\n", zNew); |
| 435 | diff_print_index(zNew, diffFlags, 0); |
| 436 | isBin1 = 0; |
| 437 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 438 | diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd, |
| 439 | zBinGlob, fIncludeBinary, diffFlags); |
| 440 | }else if( isRemoved ){ |
| 441 | if( !bWebpage) fossil_print("DELETE %s\n", zOrig); |
| 442 | diff_print_index(zNew, diffFlags, 0); |
| 443 | isBin2 = 0; |
| 444 | if( fBaseline ){ |
| 445 | content_get(rid, &a); |
| 446 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 447 | diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd, |
| 448 | zBinGlob, fIncludeBinary, diffFlags); |
| 449 | } |
| 450 | }else{ |
| 451 | Blob delta; |
| 452 | int isOrigLink = file_islink(zOPath); |
| 453 | db_ephemeral_blob(&q, 6, &delta); |
| 454 | if( !bWebpage ) fossil_print("CHANGED %s\n", zNew); |
| 455 | if( !isOrigLink != !isLink ){ |
| 456 | diff_print_index(zNew, diffFlags, 0); |
| 457 | diff_print_filenames(zOrig, zNew, diffFlags, 0); |
| 458 | printf(DIFF_CANNOT_COMPUTE_SYMLINK); |
| 459 | }else{ |
| 460 | content_get(rid, &a); |
| 461 | blob_delta_apply(&a, &delta, &b); |
| 462 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 463 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 464 | if( fBaseline ){ |
| 465 | diff_file_mem(&a, &b, isBin1, isBin2, zNew, |
| 466 | zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); |
| 467 | }else{ |
| 468 | /*Diff with file on disk using fSwapDiff=1 to show the diff in the |
| 469 | same direction as if fBaseline=1.*/ |
| 470 | diff_file(&b, isBin2, zOPath, zNew, zDiffCmd, |
| 471 | zBinGlob, fIncludeBinary, diffFlags, 1, 0); |
| 472 | } |
| 473 | blob_reset(&a); |
| 474 | blob_reset(&b); |
| 475 | } |
| 476 | blob_reset(&delta); |
| 477 | } |
| 478 | } |
| 479 | db_finalize(&q); |
| 480 | diff_end(diffFlags, 0); |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | ** Drop the indicated stash |
| 485 | */ |
| @@ -744,35 +744,34 @@ | |
| 744 | ){ |
| 745 | const char *zDiffCmd = 0; |
| 746 | const char *zBinGlob = 0; |
| 747 | int fIncludeBinary = 0; |
| 748 | int fBaseline = 0; |
| 749 | u64 diffFlags; |
| 750 | |
| 751 | if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ |
| 752 | fBaseline = 1; |
| 753 | } |
| 754 | if( find_option("tk",0,0)!=0 ){ |
| 755 | db_close(0); |
| 756 | diff_tk(fBaseline ? "stash show" : "stash diff", 3); |
| 757 | return; |
| 758 | } |
| 759 | diffFlags = diff_options(); |
| 760 | if( find_option("internal","i",0)==0 |
| 761 | && (diffFlags & DIFF_HTML)==0 |
| 762 | ){ |
| 763 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 764 | } |
| 765 | if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; |
| 766 | if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd)); |
| 767 | if( zDiffCmd ){ |
| 768 | zBinGlob = diff_get_binary_glob(); |
| 769 | fIncludeBinary = diff_include_binary_files(); |
| 770 | } |
| 771 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 772 | stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, |
| 773 | diffFlags); |
| 774 | }else |
| 775 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 776 | g.argv[1] = "help"; |
| 777 | g.argv[2] = "stash"; |
| 778 | g.argc = 3; |
| 779 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -406,17 +406,17 @@ | |
| 406 | int stashid, /* The stash entry to diff */ |
| 407 | const char *zDiffCmd, /* Command used for diffing */ |
| 408 | const char *zBinGlob, /* GLOB pattern to determine binary files */ |
| 409 | int fBaseline, /* Diff against original baseline check-in if true */ |
| 410 | int fIncludeBinary, /* Do diffs against binary files */ |
| 411 | DiffConfig *pCfg /* Diff formatting options */ |
| 412 | ){ |
| 413 | Stmt q; |
| 414 | Blob empty; |
| 415 | int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; |
| 416 | blob_zero(&empty); |
| 417 | diff_begin(pCfg); |
| 418 | db_prepare(&q, |
| 419 | "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta" |
| 420 | " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash", |
| 421 | stashid |
| 422 | ); |
| @@ -430,56 +430,56 @@ | |
| 430 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 431 | Blob a, b; |
| 432 | if( rid==0 ){ |
| 433 | db_ephemeral_blob(&q, 6, &a); |
| 434 | if( !bWebpage ) fossil_print("ADDED %s\n", zNew); |
| 435 | diff_print_index(zNew, pCfg, 0); |
| 436 | isBin1 = 0; |
| 437 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 438 | diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd, |
| 439 | zBinGlob, fIncludeBinary, pCfg); |
| 440 | }else if( isRemoved ){ |
| 441 | if( !bWebpage) fossil_print("DELETE %s\n", zOrig); |
| 442 | diff_print_index(zNew, pCfg, 0); |
| 443 | isBin2 = 0; |
| 444 | if( fBaseline ){ |
| 445 | content_get(rid, &a); |
| 446 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 447 | diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd, |
| 448 | zBinGlob, fIncludeBinary, pCfg); |
| 449 | } |
| 450 | }else{ |
| 451 | Blob delta; |
| 452 | int isOrigLink = file_islink(zOPath); |
| 453 | db_ephemeral_blob(&q, 6, &delta); |
| 454 | if( !bWebpage ) fossil_print("CHANGED %s\n", zNew); |
| 455 | if( !isOrigLink != !isLink ){ |
| 456 | diff_print_index(zNew, pCfg, 0); |
| 457 | diff_print_filenames(zOrig, zNew, pCfg, 0); |
| 458 | printf(DIFF_CANNOT_COMPUTE_SYMLINK); |
| 459 | }else{ |
| 460 | content_get(rid, &a); |
| 461 | blob_delta_apply(&a, &delta, &b); |
| 462 | isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); |
| 463 | isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); |
| 464 | if( fBaseline ){ |
| 465 | diff_file_mem(&a, &b, isBin1, isBin2, zNew, |
| 466 | zDiffCmd, zBinGlob, fIncludeBinary, pCfg); |
| 467 | }else{ |
| 468 | /*Diff with file on disk using fSwapDiff=1 to show the diff in the |
| 469 | same direction as if fBaseline=1.*/ |
| 470 | diff_file(&b, isBin2, zOPath, zNew, zDiffCmd, |
| 471 | zBinGlob, fIncludeBinary, pCfg, 1, 0); |
| 472 | } |
| 473 | blob_reset(&a); |
| 474 | blob_reset(&b); |
| 475 | } |
| 476 | blob_reset(&delta); |
| 477 | } |
| 478 | } |
| 479 | db_finalize(&q); |
| 480 | diff_end(pCfg, 0); |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | ** Drop the indicated stash |
| 485 | */ |
| @@ -744,35 +744,34 @@ | |
| 744 | ){ |
| 745 | const char *zDiffCmd = 0; |
| 746 | const char *zBinGlob = 0; |
| 747 | int fIncludeBinary = 0; |
| 748 | int fBaseline = 0; |
| 749 | DiffConfig DCfg; |
| 750 | |
| 751 | if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ |
| 752 | fBaseline = 1; |
| 753 | } |
| 754 | if( find_option("tk",0,0)!=0 ){ |
| 755 | db_close(0); |
| 756 | diff_tk(fBaseline ? "stash show" : "stash diff", 3); |
| 757 | return; |
| 758 | } |
| 759 | diff_options(&DCfg, zCmd[0]=='g'); |
| 760 | if( find_option("internal","i",0)==0 |
| 761 | && (DCfg.diffFlags & DIFF_HTML)==0 |
| 762 | ){ |
| 763 | zDiffCmd = diff_command_external(zCmd[0]=='g'); |
| 764 | } |
| 765 | if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; |
| 766 | if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd)); |
| 767 | if( zDiffCmd ){ |
| 768 | zBinGlob = diff_get_binary_glob(); |
| 769 | fIncludeBinary = diff_include_binary_files(); |
| 770 | } |
| 771 | stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); |
| 772 | stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, &DCfg); |
| 773 | }else |
| 774 | if( memcmp(zCmd, "help", nCmd)==0 ){ |
| 775 | g.argv[1] = "help"; |
| 776 | g.argv[2] = "stash"; |
| 777 | g.argc = 3; |
| 778 |
+4
-3
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1815,11 +1815,11 @@ | ||
| 1815 | 1815 | const char *zId; |
| 1816 | 1816 | const char *zPid; |
| 1817 | 1817 | Manifest *pW1, *pW2 = 0; |
| 1818 | 1818 | int rid1, rid2, nextRid; |
| 1819 | 1819 | Blob w1, w2, d; |
| 1820 | - u64 diffFlags; | |
| 1820 | + DiffConfig DCfg; | |
| 1821 | 1821 | |
| 1822 | 1822 | login_check_credentials(); |
| 1823 | 1823 | if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } |
| 1824 | 1824 | zId = P("id"); |
| 1825 | 1825 | if( zId==0 ){ |
| @@ -1858,12 +1858,13 @@ | ||
| 1858 | 1858 | style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid); |
| 1859 | 1859 | } |
| 1860 | 1860 | style_set_current_feature("wiki"); |
| 1861 | 1861 | style_header("Changes To %s", pW1->zWikiTitle); |
| 1862 | 1862 | blob_zero(&d); |
| 1863 | - diffFlags = construct_diff_flags(1); | |
| 1864 | - text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO); | |
| 1863 | + construct_diff_flags(1, &DCfg); | |
| 1864 | + DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO; | |
| 1865 | + text_diff(&w2, &w1, &d, &DCfg); | |
| 1865 | 1866 | @ <pre class="udiff"> |
| 1866 | 1867 | @ %s(blob_str(&d)) |
| 1867 | 1868 | @ <pre> |
| 1868 | 1869 | manifest_destroy(pW1); |
| 1869 | 1870 | manifest_destroy(pW2); |
| 1870 | 1871 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1815,11 +1815,11 @@ | |
| 1815 | const char *zId; |
| 1816 | const char *zPid; |
| 1817 | Manifest *pW1, *pW2 = 0; |
| 1818 | int rid1, rid2, nextRid; |
| 1819 | Blob w1, w2, d; |
| 1820 | u64 diffFlags; |
| 1821 | |
| 1822 | login_check_credentials(); |
| 1823 | if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } |
| 1824 | zId = P("id"); |
| 1825 | if( zId==0 ){ |
| @@ -1858,12 +1858,13 @@ | |
| 1858 | style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid); |
| 1859 | } |
| 1860 | style_set_current_feature("wiki"); |
| 1861 | style_header("Changes To %s", pW1->zWikiTitle); |
| 1862 | blob_zero(&d); |
| 1863 | diffFlags = construct_diff_flags(1); |
| 1864 | text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO); |
| 1865 | @ <pre class="udiff"> |
| 1866 | @ %s(blob_str(&d)) |
| 1867 | @ <pre> |
| 1868 | manifest_destroy(pW1); |
| 1869 | manifest_destroy(pW2); |
| 1870 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1815,11 +1815,11 @@ | |
| 1815 | const char *zId; |
| 1816 | const char *zPid; |
| 1817 | Manifest *pW1, *pW2 = 0; |
| 1818 | int rid1, rid2, nextRid; |
| 1819 | Blob w1, w2, d; |
| 1820 | DiffConfig DCfg; |
| 1821 | |
| 1822 | login_check_credentials(); |
| 1823 | if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } |
| 1824 | zId = P("id"); |
| 1825 | if( zId==0 ){ |
| @@ -1858,12 +1858,13 @@ | |
| 1858 | style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid); |
| 1859 | } |
| 1860 | style_set_current_feature("wiki"); |
| 1861 | style_header("Changes To %s", pW1->zWikiTitle); |
| 1862 | blob_zero(&d); |
| 1863 | construct_diff_flags(1, &DCfg); |
| 1864 | DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO; |
| 1865 | text_diff(&w2, &w1, &d, &DCfg); |
| 1866 | @ <pre class="udiff"> |
| 1867 | @ %s(blob_str(&d)) |
| 1868 | @ <pre> |
| 1869 | manifest_destroy(pW1); |
| 1870 | manifest_destroy(pW2); |
| 1871 |