Fossil SCM
Corrections to line counting in the formatDiff procedure that drives the DiffBuilder object. Remove the test-rawdiff command and substitute and undocumented --raw option on the various diff commands.
Commit
5e70c3ff96d97d392886d2dad0529e0085a612efc97cfa508a3640396de33716
Parent
6e8d87b398f52d7…
2 files changed
+54
-59
+4
-1
+54
-59
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -42,13 +42,14 @@ | ||
| 42 | 42 | #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ |
| 43 | 43 | #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ |
| 44 | 44 | #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ |
| 45 | 45 | #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */ |
| 46 | 46 | #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */ |
| 47 | -#define DIFF_WEBPAGE (((u64)0x40)<<32) /* Complete webpage */ | |
| 48 | -#define DIFF_BROWSER (((u64)0x80)<<32) /* The --browser option */ | |
| 49 | -#define DIFF_DEBUG1 (((u64)0x100000)<<32) /* Debugging diff output */ | |
| 47 | +#define DIFF_WEBPAGE (((u64)0x00040)<<32) /* Complete webpage */ | |
| 48 | +#define DIFF_BROWSER (((u64)0x00080)<<32) /* The --browser option */ | |
| 49 | +#define DIFF_DEBUG (((u64)0x00100)<<32) /* Debugging diff output */ | |
| 50 | +#define DIFF_RAW (((u64)0x00200)<<32) /* Raw triples - for debugging */ | |
| 50 | 51 | |
| 51 | 52 | /* |
| 52 | 53 | ** These error messages are shared in multiple locations. They are defined |
| 53 | 54 | ** here for consistency. |
| 54 | 55 | */ |
| @@ -1532,51 +1533,52 @@ | ||
| 1532 | 1533 | /* Subclass add additional fields */ |
| 1533 | 1534 | }; |
| 1534 | 1535 | |
| 1535 | 1536 | /************************* DiffBuilderDebug ********************************/ |
| 1536 | 1537 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1537 | - fossil_print("SKIP %d (%d..%d left and %d..%d right)\n", | |
| 1538 | + blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)\n", | |
| 1538 | 1539 | n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n); |
| 1539 | 1540 | p->lnLeft += n; |
| 1540 | 1541 | p->lnRight += n; |
| 1541 | 1542 | } |
| 1542 | 1543 | static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){ |
| 1543 | 1544 | p->lnLeft++; |
| 1544 | 1545 | p->lnRight++; |
| 1545 | - fossil_print("COMMON %8u %8u %.*s\n", | |
| 1546 | + blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n", | |
| 1546 | 1547 | p->lnLeft, p->lnRight, (int)pLine->n, pLine->z); |
| 1547 | 1548 | } |
| 1548 | 1549 | static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){ |
| 1549 | 1550 | p->lnRight++; |
| 1550 | - fossil_print("RIGHT %8d %.*s\n", | |
| 1551 | + blob_appendf(p->pOut, "RIGHT %8d %.*s\n", | |
| 1551 | 1552 | p->lnRight, (int)pLine->n, pLine->z); |
| 1552 | 1553 | } |
| 1553 | 1554 | static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){ |
| 1554 | 1555 | p->lnLeft++; |
| 1555 | - fossil_print("LEFT %8u %.*s\n", | |
| 1556 | + blob_appendf(p->pOut, "LEFT %8u %.*s\n", | |
| 1556 | 1557 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1557 | 1558 | } |
| 1558 | 1559 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1559 | 1560 | p->lnLeft++; |
| 1560 | 1561 | p->lnRight++; |
| 1561 | - fossil_print("EDIT %8u %.*s\n %8u %.*s\n", | |
| 1562 | + blob_appendf(p->pOut, "EDIT %8u %.*s\n %8u %.*s\n", | |
| 1562 | 1563 | p->lnLeft, (int)pX->n, pX->z, p->lnRight, (int)pY->n, pY->z); |
| 1563 | 1564 | } |
| 1564 | 1565 | static void dfdebugEnd(DiffBuilder *p){ |
| 1565 | - fossil_print("END with %u lines left and %u lines right\n", | |
| 1566 | + blob_appendf(p->pOut, "END with %u lines left and %u lines right\n", | |
| 1566 | 1567 | p->lnLeft, p->lnRight); |
| 1567 | 1568 | fossil_free(p); |
| 1568 | 1569 | } |
| 1569 | -static DiffBuilder *dfdebugNew(void){ | |
| 1570 | +static DiffBuilder *dfdebugNew(Blob *pOut){ | |
| 1570 | 1571 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1571 | 1572 | p->xSkip = dfdebugSkip; |
| 1572 | 1573 | p->xCommon = dfdebugCommon; |
| 1573 | 1574 | p->xInsert = dfdebugInsert; |
| 1574 | 1575 | p->xDelete = dfdebugDelete; |
| 1575 | 1576 | p->xEdit = dfdebugEdit; |
| 1576 | 1577 | p->xEnd = dfdebugEnd; |
| 1577 | 1578 | p->lnLeft = p->lnRight = 0; |
| 1579 | + p->pOut = pOut; | |
| 1578 | 1580 | return p; |
| 1579 | 1581 | } |
| 1580 | 1582 | /****************************************************************************/ |
| 1581 | 1583 | |
| 1582 | 1584 | /* |
| @@ -1597,11 +1599,11 @@ | ||
| 1597 | 1599 | unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| 1598 | 1600 | unsigned int mxr; /* Maximum value for r */ |
| 1599 | 1601 | unsigned int na, nb; /* Number of lines shown from A and B */ |
| 1600 | 1602 | unsigned int i, j; /* Loop counters */ |
| 1601 | 1603 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1602 | - unsigned int skip; /* Number of lines to skip */ | |
| 1604 | + signed int skip = 0; /* Number of lines to skip */ | |
| 1603 | 1605 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1604 | 1606 | |
| 1605 | 1607 | nContext = diff_context_lines(diffFlags); |
| 1606 | 1608 | A = p->aFrom; |
| 1607 | 1609 | B = p->aTo; |
| @@ -1636,12 +1638,12 @@ | ||
| 1636 | 1638 | b = xb; |
| 1637 | 1639 | continue; |
| 1638 | 1640 | } |
| 1639 | 1641 | } |
| 1640 | 1642 | |
| 1641 | - /* For the current block comprising nr triples, figure out | |
| 1642 | - ** how many lines of A and B are to be displayed | |
| 1643 | + /* Figure out how many lines of A and B are to be displayed | |
| 1644 | + ** for this change block. | |
| 1643 | 1645 | */ |
| 1644 | 1646 | if( R[r]>nContext ){ |
| 1645 | 1647 | na = nb = nContext; |
| 1646 | 1648 | skip = R[r] - nContext; |
| 1647 | 1649 | }else{ |
| @@ -1662,18 +1664,18 @@ | ||
| 1662 | 1664 | for(i=1; i<nr; i++){ |
| 1663 | 1665 | na += R[r+i*3]; |
| 1664 | 1666 | nb += R[r+i*3]; |
| 1665 | 1667 | } |
| 1666 | 1668 | |
| 1667 | - if( skip>0 ){ | |
| 1668 | - pBuilder->xSkip(pBuilder, skip); | |
| 1669 | - } | |
| 1670 | - | |
| 1671 | 1669 | /* Show the initial common area */ |
| 1672 | 1670 | a += skip; |
| 1673 | 1671 | b += skip; |
| 1674 | 1672 | m = R[r] - skip; |
| 1673 | + if( r ) skip -= nContext; | |
| 1674 | + if( skip>0 ){ | |
| 1675 | + pBuilder->xSkip(pBuilder, skip); | |
| 1676 | + } | |
| 1675 | 1677 | for(j=0; j<m; j++){ |
| 1676 | 1678 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1677 | 1679 | } |
| 1678 | 1680 | a += m; |
| 1679 | 1681 | b += m; |
| @@ -1720,14 +1722,17 @@ | ||
| 1720 | 1722 | |
| 1721 | 1723 | /* Show the final common area */ |
| 1722 | 1724 | assert( nr==i ); |
| 1723 | 1725 | m = R[r+nr*3]; |
| 1724 | 1726 | if( m>nContext ) m = nContext; |
| 1725 | - for(j=0; j<m; j++){ | |
| 1727 | + for(j=0; j<m && j<nContext; j++){ | |
| 1726 | 1728 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1727 | 1729 | } |
| 1728 | 1730 | } |
| 1731 | + if( R[r]>nContext ){ | |
| 1732 | + pBuilder->xSkip(pBuilder, R[r] - nContext); | |
| 1733 | + } | |
| 1729 | 1734 | pBuilder->xEnd(pBuilder); |
| 1730 | 1735 | } |
| 1731 | 1736 | |
| 1732 | 1737 | |
| 1733 | 1738 | /* |
| @@ -2170,18 +2175,26 @@ | ||
| 2170 | 2175 | blob_append(pOut, msg, -1); |
| 2171 | 2176 | } |
| 2172 | 2177 | } |
| 2173 | 2178 | |
| 2174 | 2179 | /* |
| 2175 | -** Generate a report of the differences between files pA and pB. | |
| 2176 | -** If pOut is not NULL then a unified diff is appended there. It | |
| 2177 | -** is assumed that pOut has already been initialized. If pOut is | |
| 2178 | -** NULL, then a pointer to an array of integers is returned. | |
| 2179 | -** The integers come in triples. For each triple, | |
| 2180 | -** the elements are the number of lines copied, the number of | |
| 2181 | -** lines deleted, and the number of lines inserted. The vector | |
| 2182 | -** is terminated by a triple of all zeros. | |
| 2180 | +** Generate a report of the differences between files pA_Blob and pB_Blob. | |
| 2181 | +** | |
| 2182 | +** If pOut!=NULL then append text to pOut that will be the difference, | |
| 2183 | +** formatted according to flags in diffFlags. The pOut Blob must have | |
| 2184 | +** already been initialized. | |
| 2185 | +** | |
| 2186 | +** If pOut==NULL then no formatting occurs. Instead, this routine | |
| 2187 | +** returns a pointer to an array of integers. The integers come in | |
| 2188 | +** triples. The elements of each triple are: | |
| 2189 | +** | |
| 2190 | +** 1. The number of lines to copy | |
| 2191 | +** 2. The number of lines to delete | |
| 2192 | +** 3. The number of lines to insert | |
| 2193 | +** | |
| 2194 | +** The return vector is terminated bin a triple of all zeros. The caller | |
| 2195 | +** should free the returned vector using fossil_free(). | |
| 2183 | 2196 | ** |
| 2184 | 2197 | ** This diff utility does not work on binary files. If a binary |
| 2185 | 2198 | ** file is encountered, 0 is returned and pOut is written with |
| 2186 | 2199 | ** text "cannot compute difference between binary files". |
| 2187 | 2200 | */ |
| @@ -2261,14 +2274,21 @@ | ||
| 2261 | 2274 | g.diffCnt[2] += nDel; |
| 2262 | 2275 | if( nIns+nDel ){ |
| 2263 | 2276 | g.diffCnt[0]++; |
| 2264 | 2277 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2265 | 2278 | } |
| 2279 | + }else if( diffFlags & DIFF_RAW ){ | |
| 2280 | + const int *R = c.aEdit; | |
| 2281 | + unsigned int r; | |
| 2282 | + for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ | |
| 2283 | + blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", | |
| 2284 | + R[r], R[r+1], R[r+2]); | |
| 2285 | + } | |
| 2266 | 2286 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 2267 | 2287 | sbsDiff(&c, pOut, pRe, diffFlags); |
| 2268 | - }else if( diffFlags & DIFF_DEBUG1 ){ | |
| 2269 | - DiffBuilder *pBuilder = dfdebugNew(); | |
| 2288 | + }else if( diffFlags & DIFF_DEBUG ){ | |
| 2289 | + DiffBuilder *pBuilder = dfdebugNew(pOut); | |
| 2270 | 2290 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2271 | 2291 | }else{ |
| 2272 | 2292 | contextDiff(&c, pOut, pRe, diffFlags); |
| 2273 | 2293 | } |
| 2274 | 2294 | fossil_free(c.aFrom); |
| @@ -2344,40 +2364,16 @@ | ||
| 2344 | 2364 | } |
| 2345 | 2365 | if( find_option("by",0,0)!=0 ){ |
| 2346 | 2366 | diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER |
| 2347 | 2367 | |DIFF_SIDEBYSIDE; |
| 2348 | 2368 | } |
| 2349 | - return diffFlags; | |
| 2350 | -} | |
| 2351 | - | |
| 2352 | -/* | |
| 2353 | -** COMMAND: test-rawdiff | |
| 2354 | -** | |
| 2355 | -** Usage: %fossil test-rawdiff FILE1 FILE2 | |
| 2356 | -** | |
| 2357 | -** Show a minimal sequence of Copy/Delete/Insert operations needed to convert | |
| 2358 | -** FILE1 into FILE2. This command is intended for use in testing and debugging | |
| 2359 | -** the built-in difference engine of Fossil. | |
| 2360 | -*/ | |
| 2361 | -void test_rawdiff_cmd(void){ | |
| 2362 | - Blob a, b; | |
| 2363 | - int r; | |
| 2364 | - int i; | |
| 2365 | - int *R; | |
| 2366 | - u64 diffFlags = diff_options(); | |
| 2367 | - if( g.argc<4 ) usage("FILE1 FILE2 ..."); | |
| 2368 | - blob_read_from_file(&a, g.argv[2], ExtFILE); | |
| 2369 | - for(i=3; i<g.argc; i++){ | |
| 2370 | - if( i>3 ) fossil_print("-------------------------------\n"); | |
| 2371 | - blob_read_from_file(&b, g.argv[i], ExtFILE); | |
| 2372 | - R = text_diff(&a, &b, 0, 0, diffFlags); | |
| 2373 | - for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ | |
| 2374 | - fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); | |
| 2375 | - } | |
| 2376 | - /* free(R); */ | |
| 2377 | - blob_reset(&b); | |
| 2378 | - } | |
| 2369 | + | |
| 2370 | + /* Undocumented and unsupported flags used for development | |
| 2371 | + ** debugging and analysis: */ | |
| 2372 | + if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; | |
| 2373 | + if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; | |
| 2374 | + return diffFlags; | |
| 2379 | 2375 | } |
| 2380 | 2376 | |
| 2381 | 2377 | /* |
| 2382 | 2378 | ** COMMAND: test-diff |
| 2383 | 2379 | ** |
| @@ -2401,11 +2397,10 @@ | ||
| 2401 | 2397 | if( zRe ){ |
| 2402 | 2398 | const char *zErr = re_compile(&pRe, zRe, 0); |
| 2403 | 2399 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2404 | 2400 | } |
| 2405 | 2401 | diffFlag = diff_options(); |
| 2406 | - if( find_option("debug",0,0)!=0 ) diffFlag |= DIFF_DEBUG1; | |
| 2407 | 2402 | verify_all_options(); |
| 2408 | 2403 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2409 | 2404 | blob_zero(&out); |
| 2410 | 2405 | diff_begin(diffFlag); |
| 2411 | 2406 | diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); |
| 2412 | 2407 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -42,13 +42,14 @@ | |
| 42 | #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ |
| 43 | #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ |
| 44 | #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ |
| 45 | #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */ |
| 46 | #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */ |
| 47 | #define DIFF_WEBPAGE (((u64)0x40)<<32) /* Complete webpage */ |
| 48 | #define DIFF_BROWSER (((u64)0x80)<<32) /* The --browser option */ |
| 49 | #define DIFF_DEBUG1 (((u64)0x100000)<<32) /* Debugging diff output */ |
| 50 | |
| 51 | /* |
| 52 | ** These error messages are shared in multiple locations. They are defined |
| 53 | ** here for consistency. |
| 54 | */ |
| @@ -1532,51 +1533,52 @@ | |
| 1532 | /* Subclass add additional fields */ |
| 1533 | }; |
| 1534 | |
| 1535 | /************************* DiffBuilderDebug ********************************/ |
| 1536 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1537 | fossil_print("SKIP %d (%d..%d left and %d..%d right)\n", |
| 1538 | n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n); |
| 1539 | p->lnLeft += n; |
| 1540 | p->lnRight += n; |
| 1541 | } |
| 1542 | static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){ |
| 1543 | p->lnLeft++; |
| 1544 | p->lnRight++; |
| 1545 | fossil_print("COMMON %8u %8u %.*s\n", |
| 1546 | p->lnLeft, p->lnRight, (int)pLine->n, pLine->z); |
| 1547 | } |
| 1548 | static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){ |
| 1549 | p->lnRight++; |
| 1550 | fossil_print("RIGHT %8d %.*s\n", |
| 1551 | p->lnRight, (int)pLine->n, pLine->z); |
| 1552 | } |
| 1553 | static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){ |
| 1554 | p->lnLeft++; |
| 1555 | fossil_print("LEFT %8u %.*s\n", |
| 1556 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1557 | } |
| 1558 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1559 | p->lnLeft++; |
| 1560 | p->lnRight++; |
| 1561 | fossil_print("EDIT %8u %.*s\n %8u %.*s\n", |
| 1562 | p->lnLeft, (int)pX->n, pX->z, p->lnRight, (int)pY->n, pY->z); |
| 1563 | } |
| 1564 | static void dfdebugEnd(DiffBuilder *p){ |
| 1565 | fossil_print("END with %u lines left and %u lines right\n", |
| 1566 | p->lnLeft, p->lnRight); |
| 1567 | fossil_free(p); |
| 1568 | } |
| 1569 | static DiffBuilder *dfdebugNew(void){ |
| 1570 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1571 | p->xSkip = dfdebugSkip; |
| 1572 | p->xCommon = dfdebugCommon; |
| 1573 | p->xInsert = dfdebugInsert; |
| 1574 | p->xDelete = dfdebugDelete; |
| 1575 | p->xEdit = dfdebugEdit; |
| 1576 | p->xEnd = dfdebugEnd; |
| 1577 | p->lnLeft = p->lnRight = 0; |
| 1578 | return p; |
| 1579 | } |
| 1580 | /****************************************************************************/ |
| 1581 | |
| 1582 | /* |
| @@ -1597,11 +1599,11 @@ | |
| 1597 | unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| 1598 | unsigned int mxr; /* Maximum value for r */ |
| 1599 | unsigned int na, nb; /* Number of lines shown from A and B */ |
| 1600 | unsigned int i, j; /* Loop counters */ |
| 1601 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1602 | unsigned int skip; /* Number of lines to skip */ |
| 1603 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1604 | |
| 1605 | nContext = diff_context_lines(diffFlags); |
| 1606 | A = p->aFrom; |
| 1607 | B = p->aTo; |
| @@ -1636,12 +1638,12 @@ | |
| 1636 | b = xb; |
| 1637 | continue; |
| 1638 | } |
| 1639 | } |
| 1640 | |
| 1641 | /* For the current block comprising nr triples, figure out |
| 1642 | ** how many lines of A and B are to be displayed |
| 1643 | */ |
| 1644 | if( R[r]>nContext ){ |
| 1645 | na = nb = nContext; |
| 1646 | skip = R[r] - nContext; |
| 1647 | }else{ |
| @@ -1662,18 +1664,18 @@ | |
| 1662 | for(i=1; i<nr; i++){ |
| 1663 | na += R[r+i*3]; |
| 1664 | nb += R[r+i*3]; |
| 1665 | } |
| 1666 | |
| 1667 | if( skip>0 ){ |
| 1668 | pBuilder->xSkip(pBuilder, skip); |
| 1669 | } |
| 1670 | |
| 1671 | /* Show the initial common area */ |
| 1672 | a += skip; |
| 1673 | b += skip; |
| 1674 | m = R[r] - skip; |
| 1675 | for(j=0; j<m; j++){ |
| 1676 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1677 | } |
| 1678 | a += m; |
| 1679 | b += m; |
| @@ -1720,14 +1722,17 @@ | |
| 1720 | |
| 1721 | /* Show the final common area */ |
| 1722 | assert( nr==i ); |
| 1723 | m = R[r+nr*3]; |
| 1724 | if( m>nContext ) m = nContext; |
| 1725 | for(j=0; j<m; j++){ |
| 1726 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1727 | } |
| 1728 | } |
| 1729 | pBuilder->xEnd(pBuilder); |
| 1730 | } |
| 1731 | |
| 1732 | |
| 1733 | /* |
| @@ -2170,18 +2175,26 @@ | |
| 2170 | blob_append(pOut, msg, -1); |
| 2171 | } |
| 2172 | } |
| 2173 | |
| 2174 | /* |
| 2175 | ** Generate a report of the differences between files pA and pB. |
| 2176 | ** If pOut is not NULL then a unified diff is appended there. It |
| 2177 | ** is assumed that pOut has already been initialized. If pOut is |
| 2178 | ** NULL, then a pointer to an array of integers is returned. |
| 2179 | ** The integers come in triples. For each triple, |
| 2180 | ** the elements are the number of lines copied, the number of |
| 2181 | ** lines deleted, and the number of lines inserted. The vector |
| 2182 | ** is terminated by a triple of all zeros. |
| 2183 | ** |
| 2184 | ** This diff utility does not work on binary files. If a binary |
| 2185 | ** file is encountered, 0 is returned and pOut is written with |
| 2186 | ** text "cannot compute difference between binary files". |
| 2187 | */ |
| @@ -2261,14 +2274,21 @@ | |
| 2261 | g.diffCnt[2] += nDel; |
| 2262 | if( nIns+nDel ){ |
| 2263 | g.diffCnt[0]++; |
| 2264 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2265 | } |
| 2266 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 2267 | sbsDiff(&c, pOut, pRe, diffFlags); |
| 2268 | }else if( diffFlags & DIFF_DEBUG1 ){ |
| 2269 | DiffBuilder *pBuilder = dfdebugNew(); |
| 2270 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2271 | }else{ |
| 2272 | contextDiff(&c, pOut, pRe, diffFlags); |
| 2273 | } |
| 2274 | fossil_free(c.aFrom); |
| @@ -2344,40 +2364,16 @@ | |
| 2344 | } |
| 2345 | if( find_option("by",0,0)!=0 ){ |
| 2346 | diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER |
| 2347 | |DIFF_SIDEBYSIDE; |
| 2348 | } |
| 2349 | return diffFlags; |
| 2350 | } |
| 2351 | |
| 2352 | /* |
| 2353 | ** COMMAND: test-rawdiff |
| 2354 | ** |
| 2355 | ** Usage: %fossil test-rawdiff FILE1 FILE2 |
| 2356 | ** |
| 2357 | ** Show a minimal sequence of Copy/Delete/Insert operations needed to convert |
| 2358 | ** FILE1 into FILE2. This command is intended for use in testing and debugging |
| 2359 | ** the built-in difference engine of Fossil. |
| 2360 | */ |
| 2361 | void test_rawdiff_cmd(void){ |
| 2362 | Blob a, b; |
| 2363 | int r; |
| 2364 | int i; |
| 2365 | int *R; |
| 2366 | u64 diffFlags = diff_options(); |
| 2367 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 2368 | blob_read_from_file(&a, g.argv[2], ExtFILE); |
| 2369 | for(i=3; i<g.argc; i++){ |
| 2370 | if( i>3 ) fossil_print("-------------------------------\n"); |
| 2371 | blob_read_from_file(&b, g.argv[i], ExtFILE); |
| 2372 | R = text_diff(&a, &b, 0, 0, diffFlags); |
| 2373 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 2374 | fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); |
| 2375 | } |
| 2376 | /* free(R); */ |
| 2377 | blob_reset(&b); |
| 2378 | } |
| 2379 | } |
| 2380 | |
| 2381 | /* |
| 2382 | ** COMMAND: test-diff |
| 2383 | ** |
| @@ -2401,11 +2397,10 @@ | |
| 2401 | if( zRe ){ |
| 2402 | const char *zErr = re_compile(&pRe, zRe, 0); |
| 2403 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2404 | } |
| 2405 | diffFlag = diff_options(); |
| 2406 | if( find_option("debug",0,0)!=0 ) diffFlag |= DIFF_DEBUG1; |
| 2407 | verify_all_options(); |
| 2408 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2409 | blob_zero(&out); |
| 2410 | diff_begin(diffFlag); |
| 2411 | diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); |
| 2412 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -42,13 +42,14 @@ | |
| 42 | #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */ |
| 43 | #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */ |
| 44 | #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */ |
| 45 | #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */ |
| 46 | #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */ |
| 47 | #define DIFF_WEBPAGE (((u64)0x00040)<<32) /* Complete webpage */ |
| 48 | #define DIFF_BROWSER (((u64)0x00080)<<32) /* The --browser option */ |
| 49 | #define DIFF_DEBUG (((u64)0x00100)<<32) /* Debugging diff output */ |
| 50 | #define DIFF_RAW (((u64)0x00200)<<32) /* Raw triples - for debugging */ |
| 51 | |
| 52 | /* |
| 53 | ** These error messages are shared in multiple locations. They are defined |
| 54 | ** here for consistency. |
| 55 | */ |
| @@ -1532,51 +1533,52 @@ | |
| 1533 | /* Subclass add additional fields */ |
| 1534 | }; |
| 1535 | |
| 1536 | /************************* DiffBuilderDebug ********************************/ |
| 1537 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1538 | blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)\n", |
| 1539 | n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n); |
| 1540 | p->lnLeft += n; |
| 1541 | p->lnRight += n; |
| 1542 | } |
| 1543 | static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){ |
| 1544 | p->lnLeft++; |
| 1545 | p->lnRight++; |
| 1546 | blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n", |
| 1547 | p->lnLeft, p->lnRight, (int)pLine->n, pLine->z); |
| 1548 | } |
| 1549 | static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){ |
| 1550 | p->lnRight++; |
| 1551 | blob_appendf(p->pOut, "RIGHT %8d %.*s\n", |
| 1552 | p->lnRight, (int)pLine->n, pLine->z); |
| 1553 | } |
| 1554 | static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){ |
| 1555 | p->lnLeft++; |
| 1556 | blob_appendf(p->pOut, "LEFT %8u %.*s\n", |
| 1557 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1558 | } |
| 1559 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1560 | p->lnLeft++; |
| 1561 | p->lnRight++; |
| 1562 | blob_appendf(p->pOut, "EDIT %8u %.*s\n %8u %.*s\n", |
| 1563 | p->lnLeft, (int)pX->n, pX->z, p->lnRight, (int)pY->n, pY->z); |
| 1564 | } |
| 1565 | static void dfdebugEnd(DiffBuilder *p){ |
| 1566 | blob_appendf(p->pOut, "END with %u lines left and %u lines right\n", |
| 1567 | p->lnLeft, p->lnRight); |
| 1568 | fossil_free(p); |
| 1569 | } |
| 1570 | static DiffBuilder *dfdebugNew(Blob *pOut){ |
| 1571 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1572 | p->xSkip = dfdebugSkip; |
| 1573 | p->xCommon = dfdebugCommon; |
| 1574 | p->xInsert = dfdebugInsert; |
| 1575 | p->xDelete = dfdebugDelete; |
| 1576 | p->xEdit = dfdebugEdit; |
| 1577 | p->xEnd = dfdebugEnd; |
| 1578 | p->lnLeft = p->lnRight = 0; |
| 1579 | p->pOut = pOut; |
| 1580 | return p; |
| 1581 | } |
| 1582 | /****************************************************************************/ |
| 1583 | |
| 1584 | /* |
| @@ -1597,11 +1599,11 @@ | |
| 1599 | unsigned int nr; /* Number of COPY/DELETE/INSERT triples to process */ |
| 1600 | unsigned int mxr; /* Maximum value for r */ |
| 1601 | unsigned int na, nb; /* Number of lines shown from A and B */ |
| 1602 | unsigned int i, j; /* Loop counters */ |
| 1603 | unsigned int m, ma, mb;/* Number of lines to output */ |
| 1604 | signed int skip = 0; /* Number of lines to skip */ |
| 1605 | unsigned int nContext; /* Lines of context above and below each change */ |
| 1606 | |
| 1607 | nContext = diff_context_lines(diffFlags); |
| 1608 | A = p->aFrom; |
| 1609 | B = p->aTo; |
| @@ -1636,12 +1638,12 @@ | |
| 1638 | b = xb; |
| 1639 | continue; |
| 1640 | } |
| 1641 | } |
| 1642 | |
| 1643 | /* Figure out how many lines of A and B are to be displayed |
| 1644 | ** for this change block. |
| 1645 | */ |
| 1646 | if( R[r]>nContext ){ |
| 1647 | na = nb = nContext; |
| 1648 | skip = R[r] - nContext; |
| 1649 | }else{ |
| @@ -1662,18 +1664,18 @@ | |
| 1664 | for(i=1; i<nr; i++){ |
| 1665 | na += R[r+i*3]; |
| 1666 | nb += R[r+i*3]; |
| 1667 | } |
| 1668 | |
| 1669 | /* Show the initial common area */ |
| 1670 | a += skip; |
| 1671 | b += skip; |
| 1672 | m = R[r] - skip; |
| 1673 | if( r ) skip -= nContext; |
| 1674 | if( skip>0 ){ |
| 1675 | pBuilder->xSkip(pBuilder, skip); |
| 1676 | } |
| 1677 | for(j=0; j<m; j++){ |
| 1678 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1679 | } |
| 1680 | a += m; |
| 1681 | b += m; |
| @@ -1720,14 +1722,17 @@ | |
| 1722 | |
| 1723 | /* Show the final common area */ |
| 1724 | assert( nr==i ); |
| 1725 | m = R[r+nr*3]; |
| 1726 | if( m>nContext ) m = nContext; |
| 1727 | for(j=0; j<m && j<nContext; j++){ |
| 1728 | pBuilder->xCommon(pBuilder, &A[a+j]); |
| 1729 | } |
| 1730 | } |
| 1731 | if( R[r]>nContext ){ |
| 1732 | pBuilder->xSkip(pBuilder, R[r] - nContext); |
| 1733 | } |
| 1734 | pBuilder->xEnd(pBuilder); |
| 1735 | } |
| 1736 | |
| 1737 | |
| 1738 | /* |
| @@ -2170,18 +2175,26 @@ | |
| 2175 | blob_append(pOut, msg, -1); |
| 2176 | } |
| 2177 | } |
| 2178 | |
| 2179 | /* |
| 2180 | ** Generate a report of the differences between files pA_Blob and pB_Blob. |
| 2181 | ** |
| 2182 | ** If pOut!=NULL then append text to pOut that will be the difference, |
| 2183 | ** formatted according to flags in diffFlags. The pOut Blob must have |
| 2184 | ** already been initialized. |
| 2185 | ** |
| 2186 | ** If pOut==NULL then no formatting occurs. Instead, this routine |
| 2187 | ** returns a pointer to an array of integers. The integers come in |
| 2188 | ** triples. The elements of each triple are: |
| 2189 | ** |
| 2190 | ** 1. The number of lines to copy |
| 2191 | ** 2. The number of lines to delete |
| 2192 | ** 3. The number of lines to insert |
| 2193 | ** |
| 2194 | ** The return vector is terminated bin a triple of all zeros. The caller |
| 2195 | ** should free the returned vector using fossil_free(). |
| 2196 | ** |
| 2197 | ** This diff utility does not work on binary files. If a binary |
| 2198 | ** file is encountered, 0 is returned and pOut is written with |
| 2199 | ** text "cannot compute difference between binary files". |
| 2200 | */ |
| @@ -2261,14 +2274,21 @@ | |
| 2274 | g.diffCnt[2] += nDel; |
| 2275 | if( nIns+nDel ){ |
| 2276 | g.diffCnt[0]++; |
| 2277 | blob_appendf(pOut, "%10d %10d", nIns, nDel); |
| 2278 | } |
| 2279 | }else if( diffFlags & DIFF_RAW ){ |
| 2280 | const int *R = c.aEdit; |
| 2281 | unsigned int r; |
| 2282 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 2283 | blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", |
| 2284 | R[r], R[r+1], R[r+2]); |
| 2285 | } |
| 2286 | }else if( diffFlags & DIFF_SIDEBYSIDE ){ |
| 2287 | sbsDiff(&c, pOut, pRe, diffFlags); |
| 2288 | }else if( diffFlags & DIFF_DEBUG ){ |
| 2289 | DiffBuilder *pBuilder = dfdebugNew(pOut); |
| 2290 | formatDiff(&c, pRe, diffFlags, pBuilder); |
| 2291 | }else{ |
| 2292 | contextDiff(&c, pOut, pRe, diffFlags); |
| 2293 | } |
| 2294 | fossil_free(c.aFrom); |
| @@ -2344,40 +2364,16 @@ | |
| 2364 | } |
| 2365 | if( find_option("by",0,0)!=0 ){ |
| 2366 | diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER |
| 2367 | |DIFF_SIDEBYSIDE; |
| 2368 | } |
| 2369 | |
| 2370 | /* Undocumented and unsupported flags used for development |
| 2371 | ** debugging and analysis: */ |
| 2372 | if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; |
| 2373 | if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; |
| 2374 | return diffFlags; |
| 2375 | } |
| 2376 | |
| 2377 | /* |
| 2378 | ** COMMAND: test-diff |
| 2379 | ** |
| @@ -2401,11 +2397,10 @@ | |
| 2397 | if( zRe ){ |
| 2398 | const char *zErr = re_compile(&pRe, zRe, 0); |
| 2399 | if( zErr ) fossil_fatal("regex error: %s", zErr); |
| 2400 | } |
| 2401 | diffFlag = diff_options(); |
| 2402 | verify_all_options(); |
| 2403 | if( g.argc!=4 ) usage("FILE1 FILE2"); |
| 2404 | blob_zero(&out); |
| 2405 | diff_begin(diffFlag); |
| 2406 | diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); |
| 2407 |
+4
-1
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -135,12 +135,15 @@ | ||
| 135 | 135 | const char *zRight, |
| 136 | 136 | u64 diffFlags, |
| 137 | 137 | Blob *diffBlob |
| 138 | 138 | ){ |
| 139 | 139 | char *z = 0; |
| 140 | - if( diffFlags & (DIFF_BRIEF|DIFF_DEBUG1) ){ | |
| 140 | + if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ | |
| 141 | 141 | /* no-op */ |
| 142 | + }else if( diffFlags & DIFF_DEBUG ){ | |
| 143 | + fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", | |
| 144 | + zLeft, zRight); | |
| 142 | 145 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| 143 | 146 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 144 | 147 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 145 | 148 | }else{ |
| 146 | 149 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 147 | 150 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -135,12 +135,15 @@ | |
| 135 | const char *zRight, |
| 136 | u64 diffFlags, |
| 137 | Blob *diffBlob |
| 138 | ){ |
| 139 | char *z = 0; |
| 140 | if( diffFlags & (DIFF_BRIEF|DIFF_DEBUG1) ){ |
| 141 | /* no-op */ |
| 142 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| 143 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 144 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 145 | }else{ |
| 146 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 147 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -135,12 +135,15 @@ | |
| 135 | const char *zRight, |
| 136 | u64 diffFlags, |
| 137 | Blob *diffBlob |
| 138 | ){ |
| 139 | char *z = 0; |
| 140 | if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ |
| 141 | /* no-op */ |
| 142 | }else if( diffFlags & DIFF_DEBUG ){ |
| 143 | fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", |
| 144 | zLeft, zRight); |
| 145 | }else if( diffFlags & DIFF_WEBPAGE ){ |
| 146 | if( fossil_strcmp(zLeft,zRight)==0 ){ |
| 147 | z = mprintf("<h1>%h</h1>\n", zLeft); |
| 148 | }else{ |
| 149 | z = mprintf("<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
| 150 |