Index: src/ajax.c ================================================================== --- src/ajax.c +++ src/ajax.c @@ -152,12 +152,14 @@ ** and pContent is the locally-edited (v2) content. diffFlags is any ** set of flags suitable for passing to text_diff(). */ void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){ Blob out = empty_blob; + DiffConfig DCfg; - text_diff(pOrig, pContent, &out, 0, diffFlags); + diff_config_init(&DCfg, diffFlags); + text_diff(pOrig, pContent, &out, &DCfg); if(blob_size(&out)==0){ /* nothing to do */ }else if(DIFF_SIDEBYSIDE & diffFlags){ CX("%b",&out); }else{ Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -1338,15 +1338,17 @@ "# All merged-in branches will be closed due to the --integrate flag\n" "#\n", -1 ); } if( p->verboseFlag ){ + DiffConfig DCfg; blob_appendf(&prompt, "#\n%.78c\n" "# The following diff is excluded from the commit message:\n#\n", '#' ); + diff_config_init(&DCfg, DIFF_VERBOSE); if( g.aCommitFile ){ FileDirList *diffFiles; int i; diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles)); for( i=0; g.aCommitFile[i]!=0; ++i ){ @@ -1360,19 +1362,19 @@ diffFiles[i].nName = strlen(diffFiles[i].zName); diffFiles[i].nUsed = 0; } diff_against_disk(0, 0, diff_get_binary_glob(), db_get_boolean("diff-binary", 1), - DIFF_VERBOSE, diffFiles, &prompt); + &DCfg, diffFiles, &prompt); for( i=0; diffFiles[i].zName; ++i ){ fossil_free(diffFiles[i].zName); } fossil_free(diffFiles); }else{ diff_against_disk(0, 0, diff_get_binary_glob(), db_get_boolean("diff-binary", 1), - DIFF_VERBOSE, 0, &prompt); + &DCfg, 0, &prompt); } } prompt_for_user_comment(pComment, &prompt); blob_reset(&prompt); } Index: src/diff.c ================================================================== --- src/diff.c +++ src/diff.c @@ -70,12 +70,47 @@ /* ** Maximum length of a line in a text file, in bytes. (2**15 = 32768 bytes) */ #define LENGTH_MASK_SZ 15 #define LENGTH_MASK ((1<diffFlags = diffFlags; + return pCfg; +} /* ** Information about each line of a file being diffed. ** ** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length @@ -332,11 +367,11 @@ ** Output a patch-style text diff. */ static void contextDiff( DContext *p, /* The difference */ Blob *pOut, /* Output a context diff to here */ - u64 diffFlags /* Flags controlling the diff format */ + DiffConfig *pCfg /* Configuration options */ ){ DLine *A; /* Left side of the diff */ DLine *B; /* Right side of the diff */ int a = 0; /* Index of next line in A[] */ int b = 0; /* Index of next line in B[] */ @@ -351,12 +386,12 @@ static int nChunk = 0; /* Number of diff chunks seen so far */ int nContext; /* Number of lines of context */ int showLn; /* Show line numbers */ int showDivider = 0; /* True to show the divider between diff blocks */ - nContext = diff_context_lines(diffFlags); - showLn = (diffFlags & DIFF_LINENO)!=0; + nContext = diff_context_lines(pCfg); + showLn = (pCfg->diffFlags & DIFF_LINENO)!=0; A = p->aFrom; B = p->aTo; R = p->aEdit; mxr = p->nEdit; while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } @@ -1119,11 +1154,11 @@ blob_append_char(p->pOut, ','); blob_append_json_literal(p->pOut, pX->z + x, pX->n - x); blob_append(p->pOut, "],\n",3); } static void dfjsonEnd(DiffBuilder *p){ - blob_append(p->pOut, "0]", 2); + blob_append(p->pOut, "0]}", 3); fossil_free(p); } static DiffBuilder *dfjsonNew(Blob *pOut){ DiffBuilder *p = fossil_malloc(sizeof(*p)); p->xSkip = dfjsonSkip; @@ -1631,21 +1666,21 @@ blob_append_char(p->pOut, '\n'); } static void dfsbsEnd(DiffBuilder *p){ fossil_free(p); } -static DiffBuilder *dfsbsNew(Blob *pOut, u64 diffFlags){ +static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){ DiffBuilder *p = fossil_malloc(sizeof(*p)); p->xSkip = dfsbsSkip; p->xCommon = dfsbsCommon; p->xInsert = dfsbsInsert; p->xDelete = dfsbsDelete; p->xReplace = dfsbsEdit; p->xEdit = dfsbsEdit; p->xEnd = dfsbsEnd; p->lnLeft = p->lnRight = 0; - p->width = diff_width(diffFlags); + p->width = diff_width(pCfg); p->pOut = pOut; return p; } /****************************************************************************/ /* @@ -1767,11 +1802,11 @@ ** mismatch. */ static unsigned char *diffBlockAlignment( const DLine *aLeft, int nLeft, /* Text on the left */ const DLine *aRight, int nRight, /* Text on the right */ - u64 diffFlags, /* Flags passed into the original diff */ + DiffConfig *pCfg, /* Configuration options */ int *pNResult /* OUTPUT: Bytes of result */ ){ int i, j, k; /* Loop counters */ int *a; /* One row of the Wagner matrix */ int *pToFree; /* Space that needs to be freed */ @@ -1795,11 +1830,11 @@ /* For large alignments, use a divide and conquer algorithm that is ** O(NlogN). The result is not as precise, but this whole thing is an ** approximation anyhow, and the faster response time is an acceptable ** trade-off for reduced precision. */ - if( nLeft*nRight>DIFF_ALIGN_MX && (diffFlags & DIFF_SLOW_SBS)==0 ){ + if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){ const DLine *aSmall; /* The smaller of aLeft and aRight */ const DLine *aBig; /* The larger of aLeft and aRight */ int nSmall, nBig; /* Size of aSmall and aBig. nSmall<=nBig */ int iDivSmall, iDivBig; /* Divider point for aSmall and aBig */ int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */ @@ -1832,14 +1867,14 @@ iDivLeft = iDivBig; }else{ iDivRight = iDivBig; iDivLeft = iDivSmall; } - a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,diffFlags,&n1); + a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1); a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft, aRight+iDivRight, nRight-iDivRight, - diffFlags, &n2); + pCfg, &n2); a1 = fossil_realloc(a1, n1+n2 ); memcpy(a1+n1,a2,n2); fossil_free(a2); *pNResult = n1+n2; return a1; @@ -1938,12 +1973,11 @@ /* ** Format a diff using a DiffBuilder object */ static void formatDiff( DContext *p, /* The computed diff */ - ReCompiled *pRe, /* Only show changes that match this regex */ - u64 diffFlags, /* Flags controlling the diff */ + DiffConfig *pCfg, /* Configuration options */ DiffBuilder *pBuilder /* The formatter object */ ){ const DLine *A; /* Left side of the diff */ const DLine *B; /* Right side of the diff */ unsigned int a = 0; /* Index of next line in A[] */ @@ -1956,11 +1990,11 @@ unsigned int i, j; /* Loop counters */ unsigned int m, ma, mb;/* Number of lines to output */ signed int skip = 0; /* Number of lines to skip */ unsigned int nContext; /* Lines of context above and below each change */ - nContext = diff_context_lines(diffFlags); + nContext = diff_context_lines(pCfg); A = p->aFrom; B = p->aTo; R = p->aEdit; mxr = p->nEdit; while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } @@ -1972,19 +2006,19 @@ /* If there is a regex, skip this block (generate no diff output) ** if the regex matches or does not match both insert and delete. ** Only display the block if one side matches but the other side does ** not. */ - if( pRe ){ + if( pCfg->pRe ){ int hideBlock = 1; int xa = a, xb = b; for(i=0; hideBlock && ipRe, &A[xa], R[r+i*3+1]); + c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]); hideBlock = c1==c2; xa += R[r+i*3+1]; xb += R[r+i*3+2]; } if( hideBlock ){ @@ -2050,11 +2084,11 @@ ma += R[r+i*3+1] + m; mb += R[r+i*3+2] + m; } /* Try to find an alignment for the lines within this one block */ - alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, diffFlags, &nAlign); + alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign); for(j=0; ma+mb>0; j++){ assert( jdiffFlags & DIFF_CONTEXT_MASK; + if( n==0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5; return n; } /* ** Extract the width of columns for side-by-side diff. Supply an @@ -2527,12 +2561,12 @@ ** term-width = 2*diff-col + diff-marker + 1 ** diff-col = lineno + lmargin + text-width + rmargin ** ** text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin */ -int diff_width(u64 diffFlags){ - int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); +int diff_width(DiffConfig *pCfg){ + int w = (pCfg->diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); if( w==0 ){ static struct { unsigned int lineno, lmargin, text, rmargin, marker; } sbsW = { 5, 2, 0, 0, 3 }; const unsigned int wMin = 24, wMax = 132; @@ -2589,41 +2623,40 @@ */ int *text_diff( Blob *pA_Blob, /* FROM file */ Blob *pB_Blob, /* TO file */ Blob *pOut, /* Write diff here if not NULL */ - ReCompiled *pRe, /* Only output changes where this Regexp matches */ - u64 diffFlags /* DIFF_* flags defined above */ + DiffConfig *pCfg /* Configuration options */ ){ int ignoreWs; /* Ignore whitespace */ DContext c; - if( diffFlags & DIFF_INVERT ){ + if( pCfg->diffFlags & DIFF_INVERT ){ Blob *pTemp = pA_Blob; pA_Blob = pB_Blob; pB_Blob = pTemp; } - ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0; + ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0; blob_to_utf8_no_bom(pA_Blob, 0); blob_to_utf8_no_bom(pB_Blob, 0); /* Prepare the input files */ memset(&c, 0, sizeof(c)); - if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ + if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){ c.xDiffer = compare_dline_ignore_allws; }else{ c.xDiffer = compare_dline; } c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), - &c.nFrom, diffFlags); + &c.nFrom, pCfg->diffFlags); c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), - &c.nTo, diffFlags); + &c.nTo, pCfg->diffFlags); if( c.aFrom==0 || c.aTo==0 ){ fossil_free(c.aFrom); fossil_free(c.aTo); if( pOut ){ - diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags); + diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags); } return 0; } /* Compute the difference */ @@ -2630,32 +2663,32 @@ diff_all(&c); if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){ fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); - if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags); + if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags); return 0; } - if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){ + if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){ int i, m, n; int *a = c.aEdit; int mx = c.nEdit; for(i=m=n=0; i10000 ){ fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); - if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags); + if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags); return 0; } } - if( (diffFlags & DIFF_NOOPT)==0 ){ + if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){ diff_optimize(&c); } if( pOut ){ - if( diffFlags & DIFF_NUMSTAT ){ + if( pCfg->diffFlags & DIFF_NUMSTAT ){ int nDel = 0, nIns = 0, i; for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){ nDel += c.aEdit[i+1]; nIns += c.aEdit[i+2]; } @@ -2663,40 +2696,40 @@ g.diffCnt[2] += nDel; if( nIns+nDel ){ g.diffCnt[0]++; blob_appendf(pOut, "%10d %10d", nIns, nDel); } - }else if( diffFlags & DIFF_RAW ){ + }else if( pCfg->diffFlags & DIFF_RAW ){ const int *R = c.aEdit; unsigned int r; for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ blob_appendf(pOut, " copy %6d delete %6d insert %6d\n", R[r], R[r+1], R[r+2]); } - }else if( diffFlags & DIFF_JSON ){ + }else if( pCfg->diffFlags & DIFF_JSON ){ DiffBuilder *pBuilder = dfjsonNew(pOut); - formatDiff(&c, pRe, diffFlags, pBuilder); + formatDiff(&c, pCfg, pBuilder); blob_append_char(pOut, '\n'); - }else if( diffFlags & DIFF_TCL ){ + }else if( pCfg->diffFlags & DIFF_TCL ){ DiffBuilder *pBuilder = dftclNew(pOut); - formatDiff(&c, pRe, diffFlags, pBuilder); - }else if( diffFlags & DIFF_SIDEBYSIDE ){ + formatDiff(&c, pCfg, pBuilder); + }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ DiffBuilder *pBuilder; - if( diffFlags & DIFF_HTML ){ + if( pCfg->diffFlags & DIFF_HTML ){ pBuilder = dfsplitNew(pOut); }else{ - pBuilder = dfsbsNew(pOut, diffFlags); + pBuilder = dfsbsNew(pOut, pCfg); } - formatDiff(&c, pRe, diffFlags, pBuilder); - }else if( diffFlags & DIFF_DEBUG ){ + formatDiff(&c, pCfg, pBuilder); + }else if( pCfg->diffFlags & DIFF_DEBUG ){ DiffBuilder *pBuilder = dfdebugNew(pOut); - formatDiff(&c, pRe, diffFlags, pBuilder); - }else if( diffFlags & DIFF_HTML ){ + formatDiff(&c, pCfg, pBuilder); + }else if( pCfg->diffFlags & DIFF_HTML ){ DiffBuilder *pBuilder = dfunifiedNew(pOut); - formatDiff(&c, pRe, diffFlags, pBuilder); + formatDiff(&c, pCfg, pBuilder); }else{ - contextDiff(&c, pOut, diffFlags); + contextDiff(&c, pOut, pCfg); } fossil_free(c.aFrom); fossil_free(c.aTo); fossil_free(c.aEdit); return 0; @@ -2709,31 +2742,35 @@ return c.aEdit; } } /* +** Initialize the DiffConfig object using command-line options. +** ** Process diff-related command-line options and return an appropriate ** "diffFlags" integer. ** -** --brief Show filenames only DIFF_BRIEF -** -c|--context N N lines of context. DIFF_CONTEXT_MASK -** --html Format for HTML DIFF_HTML -** --invert Invert the diff DIFF_INVERT -** -n|--linenum Show line numbers DIFF_LINENO -** --noopt Disable optimization DIFF_NOOPT -** --numstat Show change counts DIFF_NUMSTAT -** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR -** --unified Unified diff. ~DIFF_SIDEBYSIDE -** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS -** -W|--width N N character lines. DIFF_WIDTH_MASK -** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE -** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS +** --brief Show filenames only DIFF_BRIEF +** -c|--context N N lines of context. DIFF_CONTEXT_MASK +** --html Format for HTML DIFF_HTML +** --invert Invert the diff DIFF_INVERT +** -n|--linenum Show line numbers DIFF_LINENO +** --noopt Disable optimization DIFF_NOOPT +** --numstat Show change counts DIFF_NUMSTAT +** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR +** --unified Unified diff. ~DIFF_SIDEBYSIDE +** -w|--ignore-all-space Ignore all whitespaces DIFF_IGNORE_ALLWS +** -W|--width N N character lines. DIFF_WIDTH_MASK +** -y|--side-by-side Side-by-side diff. DIFF_SIDEBYSIDE +** -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS */ -u64 diff_options(void){ +void diff_options(DiffConfig *pCfg, int isGDiff){ u64 diffFlags = 0; const char *z; int f; + + memset(pCfg, 0, sizeof(*pCfg)); if( find_option("ignore-trailing-space","Z",0)!=0 ){ diffFlags = DIFF_IGNORE_EOLWS; } if( find_option("ignore-all-space","w",0)!=0 ){ diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */ @@ -2780,11 +2817,11 @@ /* Undocumented and unsupported flags used for development ** debugging and analysis: */ if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG; if( find_option("raw",0,0)!=0 ) diffFlags |= DIFF_RAW; - return diffFlags; + pCfg->diffFlags = diffFlags; } /* ** COMMAND: test-diff ** COMMAND: xdiff @@ -2802,39 +2839,38 @@ ** See the "diff" command for a full list of command-line options. ** ** This command used to be called "test-diff". The older "test-diff" spelling ** still works, for compatibility. */ -void test_diff_cmd(void){ +void xdiff_cmd(void){ Blob a, b, out; - u64 diffFlag; const char *zRe; /* Regex filter for diff output */ - ReCompiled *pRe = 0; /* Regex filter for diff output */ + DiffConfig DCfg; if( find_option("tk",0,0)!=0 ){ - diff_tk("test-diff", 2); + diff_tk("xdiff", 2); return; } find_option("i",0,0); find_option("v",0,0); + diff_options(&DCfg, 0); zRe = find_option("regexp","e",1); if( zRe ){ - const char *zErr = re_compile(&pRe, zRe, 0); + const char *zErr = re_compile(&DCfg.pRe, zRe, 0); if( zErr ) fossil_fatal("regex error: %s", zErr); } - diffFlag = diff_options(); verify_all_options(); if( g.argc!=4 ) usage("FILE1 FILE2"); blob_zero(&out); - diff_begin(diffFlag); - diff_print_filenames(g.argv[2], g.argv[3], diffFlag, &out); + diff_begin(&DCfg); + diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out); blob_read_from_file(&a, g.argv[2], ExtFILE); blob_read_from_file(&b, g.argv[3], ExtFILE); - text_diff(&a, &b, &out, pRe, diffFlag); + text_diff(&a, &b, &out, &DCfg); blob_write_to_file(&out, "-"); - diff_end(diffFlag, 0); - re_free(pRe); + diff_end(&DCfg, 0); + re_free(DCfg.pRe); } /************************************************************************** ** The basic difference engine is above. What follows is the annotation ** engine. Both are in the same file since they share many components. Index: src/diffcmd.c ================================================================== --- src/diffcmd.c +++ src/diffcmd.c @@ -113,13 +113,15 @@ } /* ** Print the "Index:" message that patches wants to see at the top of a diff. */ -void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){ - if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| - DIFF_WEBPAGE|DIFF_TCL))==0 ){ +void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *diffBlob){ + if( (pCfg->diffFlags & + (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| + DIFF_WEBPAGE|DIFF_TCL))==0 + ){ char *z = mprintf("Index: %s\n%.66c\n", zFile, '='); if( !diffBlob ){ fossil_print("%s", z); }else{ blob_appendf(diffBlob, "%s", z); @@ -127,20 +129,22 @@ fossil_free(z); } } /* -** Print the +++/--- filename lines for a diff operation. +** Print the +++/--- filename lines or whatever filename information +** is appropriate for the output format. */ void diff_print_filenames( - const char *zLeft, - const char *zRight, - u64 diffFlags, - Blob *diffBlob + const char *zLeft, /* Name of the left file */ + const char *zRight, /* Name of the right file */ + DiffConfig *pCfg, /* Diff configuration */ + Blob *diffBlob /* Write to this blob, or stdout of this is NULL */ ){ char *z = 0; - if( diffFlags & (DIFF_BRIEF|DIFF_RAW|DIFF_JSON) ){ + u64 diffFlags = pCfg->diffFlags; + if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ /* no-op */ }else if( diffFlags & DIFF_DEBUG ){ fossil_print("FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight); }else if( diffFlags & DIFF_WEBPAGE ){ @@ -147,31 +151,42 @@ if( fossil_strcmp(zLeft,zRight)==0 ){ z = mprintf("

%h

\n", zLeft); }else{ z = mprintf("

%h ⇆ %h

\n", zLeft, zRight); } - }else if( diffFlags & DIFF_TCL ){ + }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){ Blob *pOut; Blob x; if( diffBlob ){ pOut = diffBlob; }else{ blob_init(&x, 0, 0); pOut = &x; } - blob_append(pOut, "FILE ", 5); - blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); - blob_append_char(pOut, ' '); - blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); - blob_append_char(pOut, '\n'); + if( diffFlags & DIFF_TCL ){ + blob_append(pOut, "FILE ", 5); + blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); + blob_append_char(pOut, ' '); + blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); + blob_append_char(pOut, '\n'); + }else{ + blob_trim(pOut); + blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1); + pCfg->nFile++; + blob_append(pOut, "\n \"leftname\":", -1); + blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft)); + blob_append(pOut, ",\n \"rightname\":", -1); + blob_append_json_literal(pOut, zRight, (int)strlen(zRight)); + blob_append(pOut, ",\n \"diff\":\n", -1); + } if( !diffBlob ){ fossil_print("%s", blob_str(pOut)); blob_reset(&x); } return; }else if( diffFlags & DIFF_SIDEBYSIDE ){ - int w = diff_width(diffFlags); + int w = diff_width(pCfg); int n1 = strlen(zLeft); int n2 = strlen(zRight); int x; if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ if( n1>w*2 ) n1 = w*2; @@ -282,11 +297,13 @@ @ @ ; /* -** State variables used by the --browser option for diff +** State variables used by the --browser option for diff. These must +** be static variables, not elements of DiffConfig, since they are +** used by the interrupt handler. */ static char *tempDiffFilename; /* File holding the diff HTML */ static FILE *diffOut; /* Open to write into tempDiffFilename */ /* Amount of delay (in milliseconds) between launching the @@ -321,12 +338,12 @@ ** hold the result. Make arrangements to delete that temporary ** file if the diff is interrupted. ** ** For --browser and --webpage, output the HTML header. */ -void diff_begin(u64 diffFlags){ - if( (diffFlags & DIFF_BROWSER)!=0 ){ +void diff_begin(DiffConfig *pCfg){ + if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){ tempDiffFilename = fossil_temp_filename(); tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename); diffOut = fossil_freopen(tempDiffFilename,"wb",stdout); if( diffOut==0 ){ fossil_fatal("unable to create temporary file \"%s\"", @@ -336,11 +353,11 @@ signal(SIGINT, diff_www_interrupt); #else SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE); #endif } - if( (diffFlags & DIFF_WEBPAGE)!=0 ){ + if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ fossil_print("%s",zWebpageHdr); fflush(stdout); } } @@ -352,19 +369,19 @@ ** ** For --browser, close the connection to the temporary file, then ** launch a web browser to view the file. After a delay ** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file. */ -void diff_end(u64 diffFlags, int nErr){ - if( (diffFlags & DIFF_WEBPAGE)!=0 ){ - if( diffFlags & DIFF_SIDEBYSIDE ){ +void diff_end(DiffConfig *pCfg, int nErr){ + if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ + if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ const unsigned char *zJs = builtin_file("diff.js", 0); fossil_print("\n", zJs); } fossil_print("%s", zWebpageEnd); } - if( (diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ + if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename); fclose(diffOut); diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout); fossil_system(zCmd); fossil_free(zCmd); @@ -371,10 +388,13 @@ diffOut = 0; sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY); file_delete(tempDiffFilename); sqlite3_free(tempDiffFilename); tempDiffFilename = 0; + } + if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){ + fossil_print("]\n"); } } /* ** Show the difference between two files, one in memory and one on disk. @@ -398,11 +418,11 @@ const char *zFile2, /* On disk content to compare to */ const char *zName, /* Display name of the file */ const char *zDiffCmd, /* Command for comparison */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Include binary files for external diff */ - u64 diffFlags, /* Flags to control the diff */ + DiffConfig *pCfg, /* Flags to control the diff */ int fSwapDiff, /* Diff from Zfile2 to Pfile1 */ Blob *diffBlob /* Blob to store diff output */ ){ if( zDiffCmd==0 ){ Blob out; /* Diff output text */ @@ -417,34 +437,33 @@ blob_read_from_file(&file2, zFile2, ExtFILE); zName2 = zName; } /* Compute and output the differences */ - if( diffFlags & DIFF_BRIEF ){ + if( pCfg->diffFlags & DIFF_BRIEF ){ if( blob_compare(pFile1, &file2) ){ fossil_print("CHANGED %s\n", zName); } }else{ blob_zero(&out); if( fSwapDiff ){ - text_diff(&file2, pFile1, &out, 0, diffFlags); + text_diff(&file2, pFile1, &out, pCfg); }else{ - text_diff(pFile1, &file2, &out, 0, diffFlags); + text_diff(pFile1, &file2, &out, pCfg); } if( blob_size(&out) ){ - if( diffFlags & DIFF_NUMSTAT ){ + if( pCfg->diffFlags & DIFF_NUMSTAT ){ if( !diffBlob ){ fossil_print("%s %s\n", blob_str(&out), zName); }else{ blob_appendf(diffBlob, "%s %s\n", blob_str(&out), zName); } }else{ + diff_print_filenames(zName, zName2, pCfg, diffBlob); if( !diffBlob ){ - diff_print_filenames(zName, zName2, diffFlags, 0); fossil_print("%s\n", blob_str(&out)); }else{ - diff_print_filenames(zName, zName2, diffFlags, diffBlob); blob_appendf(diffBlob, "%s\n", blob_str(&out)); } } } blob_reset(&out); @@ -529,22 +548,22 @@ int isBin2, /* Does the 'to' content appear to be binary */ const char *zName, /* Display name of the file */ const char *zDiffCmd, /* Command for comparison */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Include binary files for external diff */ - u64 diffFlags /* Diff flags */ + DiffConfig *pCfg /* Diff flags */ ){ - if( diffFlags & DIFF_BRIEF ) return; + if( pCfg->diffFlags & DIFF_BRIEF ) return; if( zDiffCmd==0 ){ Blob out; /* Diff output text */ blob_zero(&out); - text_diff(pFile1, pFile2, &out, 0, diffFlags); - if( diffFlags & DIFF_NUMSTAT ){ + text_diff(pFile1, pFile2, &out, pCfg); + if( pCfg->diffFlags & DIFF_NUMSTAT ){ fossil_print("%s %s\n", blob_str(&out), zName); }else{ - diff_print_filenames(zName, zName, diffFlags, 0); + diff_print_filenames(zName, zName, pCfg, 0); fossil_print("%s\n", blob_str(&out)); } /* Release memory resources */ blob_reset(&out); @@ -609,22 +628,22 @@ void diff_against_disk( const char *zFrom, /* Version to difference from */ const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ - u64 diffFlags, /* Flags controlling diff output */ + DiffConfig *pCfg, /* Flags controlling diff output */ FileDirList *pFileDir, /* Which files to diff */ Blob *diffBlob /* Blob to output diff instead of stdout */ ){ int vid; Blob sql; Stmt q; int asNewFile; /* Treat non-existant files as empty files */ int isNumStat; /* True for --numstat */ - asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; - isNumStat = (diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; + asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; + isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; vid = db_lget_int("checkout", 0); vfile_check_signature(vid, CKSIG_ENOTFILE); blob_zero(&sql); db_begin_transaction(); if( zFrom ){ @@ -706,24 +725,24 @@ } if( showDiff ){ Blob content; int isBin; if( !isLink != !file_islink(zFullName) ){ - diff_print_index(zPathname, diffFlags, 0); - diff_print_filenames(zPathname, zPathname, diffFlags, 0); + diff_print_index(zPathname, pCfg, 0); + diff_print_filenames(zPathname, zPathname, pCfg, 0); fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); continue; } if( srcid>0 ){ content_get(srcid, &content); }else{ blob_zero(&content); } isBin = fIncludeBinary ? 0 : looks_like_binary(&content); - diff_print_index(zPathname, diffFlags, diffBlob); + diff_print_index(zPathname, pCfg, diffBlob); diff_file(&content, isBin, zFullName, zPathname, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob); + zBinGlob, fIncludeBinary, pCfg, 0, diffBlob); blob_reset(&content); } blob_reset(&fname); } db_finalize(&q); @@ -742,11 +761,11 @@ */ static void diff_against_undo( const char *zDiffCmd, /* Use this diff command. NULL for built-in */ const char *zBinGlob, /* Treat file names matching this as binary */ int fIncludeBinary, /* Treat file names matching this as binary */ - u64 diffFlags, /* Flags controlling diff output */ + DiffConfig *pCfg, /* Flags controlling diff output */ FileDirList *pFileDir /* List of files and directories to diff */ ){ Stmt q; Blob content; db_prepare(&q, "SELECT pathname, content FROM undo"); @@ -756,11 +775,11 @@ const char *zFile = (const char*)db_column_text(&q, 0); if( !file_dir_match(pFileDir, zFile) ) continue; zFullName = mprintf("%s%s", g.zLocalRoot, zFile); db_column_blob(&q, 1, &content); diff_file(&content, 0, zFullName, zFile, - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0); + zDiffCmd, zBinGlob, fIncludeBinary, pCfg, 0, 0); fossil_free(zFullName); blob_reset(&content); } db_finalize(&q); } @@ -780,11 +799,11 @@ struct ManifestFile *pFrom, struct ManifestFile *pTo, const char *zDiffCmd, const char *zBinGlob, int fIncludeBinary, - u64 diffFlags + DiffConfig *pCfg ){ Blob f1, f2; int isBin1, isBin2; int rid; const char *zName; @@ -793,12 +812,12 @@ }else if( pTo ){ zName = pTo->zName; }else{ zName = DIFF_NO_NAME; } - if( diffFlags & DIFF_BRIEF ) return; - diff_print_index(zName, diffFlags, 0); + if( pCfg->diffFlags & DIFF_BRIEF ) return; + diff_print_index(zName, pCfg, 0); if( pFrom ){ rid = uuid_to_rid(pFrom->zUuid, 0); content_get(rid, &f1); }else{ blob_zero(&f1); @@ -810,11 +829,11 @@ blob_zero(&f2); } isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1); isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2); diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags); + zBinGlob, fIncludeBinary, pCfg); blob_reset(&f1); blob_reset(&f2); } /* @@ -831,16 +850,16 @@ const char *zFrom, const char *zTo, const char *zDiffCmd, const char *zBinGlob, int fIncludeBinary, - u64 diffFlags, + DiffConfig *pCfg, FileDirList *pFileDir ){ Manifest *pFrom, *pTo; ManifestFile *pFromFile, *pToFile; - int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; + int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; pFrom = manifest_get_by_name(zFrom, 0); manifest_file_rewind(pFrom); pFromFile = manifest_file_next(pFrom,0); pTo = manifest_get_by_name(zTo, 0); @@ -856,27 +875,28 @@ }else{ cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); } if( cmp<0 ){ if( file_dir_match(pFileDir, pFromFile->zName) ){ - if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ + if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ fossil_print("DELETED %s\n", pFromFile->zName); } if( asNewFlag ){ diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob, - fIncludeBinary, diffFlags); + fIncludeBinary, pCfg); } } pFromFile = manifest_file_next(pFrom,0); }else if( cmp>0 ){ if( file_dir_match(pFileDir, pToFile->zName) ){ - if( (diffFlags & (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ + if( (pCfg->diffFlags & + (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ fossil_print("ADDED %s\n", pToFile->zName); } if( asNewFlag ){ diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob, - fIncludeBinary, diffFlags); + fIncludeBinary, pCfg); } } pToFile = manifest_file_next(pTo,0); }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ /* No changes */ @@ -883,15 +903,15 @@ (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); }else{ if( file_dir_match(pFileDir, pToFile->zName) ){ - if( diffFlags & DIFF_BRIEF ){ + if( pCfg->diffFlags & DIFF_BRIEF ){ fossil_print("CHANGED %s\n", pFromFile->zName); }else{ diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob, - fIncludeBinary, diffFlags); + fIncludeBinary, pCfg); } } pFromFile = manifest_file_next(pFrom,0); pToFile = manifest_file_next(pTo,0); } @@ -1107,12 +1127,12 @@ const char *zBranch; /* Branch to diff */ const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ const char *zBinGlob = 0; /* Treat file names matching this as binary */ int fIncludeBinary = 0; /* Include binary files for external diff */ int againstUndo = 0; /* Diff against files in the undo buffer */ - u64 diffFlags = 0; /* Flags to control the DIFF */ FileDirList *pFileDir = 0; /* Restrict the diff to these files */ + DiffConfig DCfg; /* Diff configuration object */ if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ diff_tk("diff", 2); return; } @@ -1121,16 +1141,16 @@ zFrom = find_option("from", "r", 1); zTo = find_option("to", 0, 1); zCheckin = find_option("checkin", 0, 1); zBranch = find_option("branch", 0, 1); againstUndo = find_option("undo",0,0)!=0; - diffFlags = diff_options(); + diff_options(&DCfg, isGDiff); verboseFlag = find_option("verbose","v",0)!=0; if( !verboseFlag ){ verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */ } - if( verboseFlag ) diffFlags |= DIFF_VERBOSE; + if( verboseFlag ) DCfg.diffFlags |= DIFF_VERBOSE; if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ fossil_fatal("cannot use --undo together with --from, --to, --checkin," " or --branch"); } if( zBranch ){ @@ -1150,11 +1170,11 @@ fossil_fatal("must use --from if --to is present"); }else{ db_find_and_open_repository(0, 0); } if( !isInternDiff - && (diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ + && (DCfg.diffFlags & DIFF_HTML)==0 /* External diff can't generate HTML */ ){ zDiffCmd = find_option("command", 0, 1); if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff); } zBinGlob = diff_get_binary_glob(); @@ -1188,24 +1208,24 @@ ridTo); if( zFrom==0 ){ fossil_fatal("check-in %s has no parent", zTo); } } - diff_begin(diffFlags); + diff_begin(&DCfg); if( againstUndo ){ if( db_lget_int("undo_available",0)==0 ){ fossil_print("No undo or redo is available\n"); return; } diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary, - diffFlags, pFileDir); + &DCfg, pFileDir); }else if( zTo==0 ){ diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary, - diffFlags, pFileDir, 0); + &DCfg, pFileDir, 0); }else{ diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary, - diffFlags, pFileDir); + &DCfg, pFileDir); } if( pFileDir ){ int i; for(i=0; pFileDir[i].zName; i++){ if( pFileDir[i].nUsed==0 @@ -1216,12 +1236,12 @@ } fossil_free(pFileDir[i].zName); } fossil_free(pFileDir); } - diff_end(diffFlags, 0); - if ( diffFlags & DIFF_NUMSTAT ){ + diff_end(&DCfg, 0); + if ( DCfg.diffFlags & DIFF_NUMSTAT ){ fossil_print("%10d %10d TOTAL over %d changed files\n", g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]); } } @@ -1232,12 +1252,14 @@ ** Show a patch that goes from check-in FROM to check-in TO. */ void vpatch_page(void){ const char *zFrom = P("from"); const char *zTo = P("to"); + DiffConfig DCfg; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } if( zFrom==0 || zTo==0 ) fossil_redirect_home(); cgi_set_content_type("text/plain"); - diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0); + diff_config_init(&DCfg, DIFF_VERBOSE); + diff_two_versions(zFrom, zTo, 0, 0, 0, &DCfg, 0); } Index: src/info.c ================================================================== --- src/info.c +++ src/info.c @@ -330,12 +330,11 @@ ** Append the difference between artifacts to the output */ static void append_diff( const char *zFrom, /* Diff from this artifact */ const char *zTo, /* ... to this artifact */ - u64 diffFlags, /* Diff formatting flags */ - ReCompiled *pRe /* Only show change matching this regex */ + DiffConfig *pCfg /* The diff configuration */ ){ int fromid; int toid; Blob from, to; if( zFrom ){ @@ -348,16 +347,16 @@ toid = uuid_to_rid(zTo, 0); content_get(toid, &to); }else{ blob_zero(&to); } - if( diffFlags & DIFF_SIDEBYSIDE ){ - diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; + if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ + pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; }else{ - diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; + pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG; } - text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags); + text_diff(&from, &to, cgi_output_blob(), pCfg); blob_reset(&from); blob_reset(&to); } /* @@ -368,12 +367,11 @@ const char *zCkin, /* The checkin on which the change occurs */ const char *zName, /* Name of the file that has changed */ const char *zOld, /* blob.uuid before change. NULL for added files */ const char *zNew, /* blob.uuid after change. NULL for deletes */ const char *zOldName, /* Prior name. NULL if no name change. */ - u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */ - ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */ + DiffConfig *pCfg, /* Flags for text_diff() or NULL to omit all */ int mperm /* executable or symlink permission for zNew */ ){ @

if( !g.perm.Hyperlink ){ if( zNew==0 ){ @@ -391,12 +389,12 @@ @ %h(zName) became a regular file. } }else{ @ Changes to %h(zName). } - if( diffFlags ){ - append_diff(zOld, zNew, diffFlags, pRe); + if( pCfg ){ + append_diff(zOld, zNew, pCfg); } }else{ if( zOld && zNew ){ if( fossil_strcmp(zOld, zNew)!=0 ){ @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ @@ -426,12 +424,12 @@ @ %h(zName) version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]. }else{ @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\ @ %h(zName) version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]. } - if( diffFlags ){ - append_diff(zOld, zNew, diffFlags, pRe); + if( pCfg ){ + append_diff(zOld, zNew, pCfg); }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ @    @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff] } } @@ -448,11 +446,11 @@ /* ** Construct an appropriate diffFlag for text_diff() based on query ** parameters and the to boolean arguments. */ -u64 construct_diff_flags(int diffType){ +DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){ u64 diffFlags = 0; /* Zero means do not show any diff */ if( diffType>0 ){ int x; if( diffType==2 ){ diffFlags = DIFF_SIDEBYSIDE; @@ -472,12 +470,16 @@ diffFlags += x; /* The "noopt" parameter disables diff optimization */ if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; diffFlags |= DIFF_STRIP_EOLCR; + diff_config_init(pCfg, diffFlags); + return pCfg; + }else{ + diff_config_init(pCfg, 0); + return 0; } - return diffFlags; } /* ** WEBPAGE: ci_tags ** URL: /ci_tags?name=ARTIFACTID @@ -614,20 +616,20 @@ void ci_page(void){ Stmt q1, q2, q3; int rid; int isLeaf; int diffType; /* 0: no diff, 1: unified, 2: side-by-side */ - u64 diffFlags; /* Flag parameter for text_diff() */ const char *zName; /* Name of the check-in to be displayed */ const char *zUuid; /* Hash of zName, found via blob.uuid */ const char *zParent; /* Hash of the parent check-in (if any) */ const char *zRe; /* regex parameter */ ReCompiled *pRe = 0; /* regex */ - const char *zW; /* URL param for ignoring whitespace */ + const char *zW; /* URL param for ignoring whitespace */ const char *zPage = "vinfo"; /* Page that shows diffs */ const char *zPageHide = "ci"; /* Page that hides diffs */ - const char *zBrName; /* Branch name */ + const char *zBrName; /* Branch name */ + DiffConfig DCfg,*pCfg; /* Type of diff */ login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } style_set_current_feature("vinfo"); zName = P("name"); @@ -878,12 +880,13 @@ render_backlink_graph(zUuid, "

References
\n"); @
Context
render_checkin_context(rid, 0, 0, 0); @
Changes
@
- diffFlags = construct_diff_flags(diffType); - zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; + pCfg = construct_diff_flags(diffType, &DCfg); + DCfg.pRe = pRe; + zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":""; if( diffType!=0 ){ @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\ @ Hide Diffs } if( diffType!=1 ){ @@ -933,14 +936,14 @@ int mperm = db_column_int(&q3, 1); const char *zOld = db_column_text(&q3,2); const char *zNew = db_column_text(&q3,3); const char *zOldName = db_column_text(&q3, 4); append_file_change_line(zUuid, zName, zOld, zNew, zOldName, - diffFlags,pRe,mperm); + pCfg,mperm); } db_finalize(&q3); - append_diff_javascript(diffType==2); + append_diff_javascript(diffType); builtin_fossil_js_bundle_or("info-diff",NULL); style_finish_page(); } /* @@ -1167,20 +1170,20 @@ ** Show all differences between two check-ins. */ void vdiff_page(void){ int ridFrom, ridTo; int diffType = 0; /* 0: none, 1: unified, 2: side-by-side */ - u64 diffFlags = 0; Manifest *pFrom, *pTo; ManifestFile *pFileFrom, *pFileTo; const char *zBranch; const char *zFrom; const char *zTo; const char *zRe; const char *zGlob; char *zMergeOrigin = 0; ReCompiled *pRe = 0; + DiffConfig DCfg, *pCfg = 0; int graphFlags = 0; Blob qp; int bInvert = PB("inv"); login_check_credentials(); @@ -1229,12 +1232,12 @@ } if( PB("nc") ){ graphFlags |= TIMELINE_NOCOLOR; blob_appendf(&qp, "&nc"); } - diffFlags = construct_diff_flags(diffType); - if( diffFlags & DIFF_IGNORE_ALLWS ){ + pCfg = construct_diff_flags(diffType, &DCfg); + if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){ blob_appendf(&qp, "&w"); } style_set_current_feature("vdiff"); if( zBranch==0 ){ style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo); @@ -1253,11 +1256,11 @@ } if( zGlob ){ style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp); }else{ style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo, - (diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); + (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":""); } if( diffType!=0 ){ style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); } if( zBranch ){ @@ -1301,10 +1304,11 @@ manifest_file_rewind(pFrom); pFileFrom = manifest_file_next(pFrom, 0); manifest_file_rewind(pTo); pFileTo = manifest_file_next(pTo, 0); + DCfg.pRe = pRe; while( pFileFrom || pFileTo ){ int cmp; if( pFileFrom==0 ){ cmp = +1; }else if( pFileTo==0 ){ @@ -1313,17 +1317,17 @@ cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); } if( cmp<0 ){ if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){ append_file_change_line(zFrom, pFileFrom->zName, - pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0); + pFileFrom->zUuid, 0, 0, pCfg, 0); } pFileFrom = manifest_file_next(pFrom, 0); }else if( cmp>0 ){ if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){ append_file_change_line(zTo, pFileTo->zName, - 0, pFileTo->zUuid, 0, diffFlags, pRe, + 0, pFileTo->zUuid, 0, pCfg, manifest_file_mperm(pFileTo)); } pFileTo = manifest_file_next(pTo, 0); }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ pFileFrom = manifest_file_next(pFrom, 0); @@ -1331,11 +1335,11 @@ }else{ if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0 || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){ append_file_change_line(zFrom, pFileFrom->zName, pFileFrom->zUuid, - pFileTo->zUuid, 0, diffFlags, pRe, + pFileTo->zUuid, 0, pCfg, manifest_file_mperm(pFileTo)); } pFileFrom = manifest_file_next(pFrom, 0); pFileTo = manifest_file_next(pTo, 0); } @@ -1722,10 +1726,11 @@ const char *zRe; ReCompiled *pRe = 0; u64 diffFlags; u32 objdescFlags = 0; int verbose = PB("verbose"); + DiffConfig DCfg; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } diffType = preferred_diff_type(); if( P("from") && P("to") ){ @@ -1768,24 +1773,28 @@ zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); if( verbose ) objdescFlags |= OBJDESC_DETAIL; if( isPatch ){ Blob c1, c2, *pOut; + DiffConfig DCfg; pOut = cgi_output_blob(); cgi_set_content_type("text/plain"); diffFlags = 4; content_get(v1, &c1); content_get(v2, &c2); - text_diff(&c1, &c2, pOut, pRe, diffFlags); + diff_config_init(&DCfg, diffFlags); + DCfg.pRe = pRe; + text_diff(&c1, &c2, pOut, &DCfg); blob_reset(&c1); blob_reset(&c2); return; } zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); - diffFlags = construct_diff_flags(diffType) | DIFF_HTML; + construct_diff_flags(diffType, &DCfg); + DCfg.diffFlags |= DIFF_HTML; style_set_current_feature("fdiff"); style_header("Diff"); style_submenu_checkbox("w", "Ignore Whitespace", 0, 0); if( diffType==2 ){ @@ -1811,13 +1820,14 @@ object_description(v2, objdescFlags,0, 0); } if( pRe ){ @ Only differences that match regular expression "%h(zRe)" @ are shown. + DCfg.pRe = pRe; } @
- append_diff(zV1, zV2, diffFlags, pRe); + append_diff(zV1, zV2, &DCfg); append_diff_javascript(diffType); style_finish_page(); } /* Index: src/json_diff.c ================================================================== --- src/json_diff.c +++ src/json_diff.c @@ -38,10 +38,11 @@ int nContext, char fSbs, char fHtml){ int fromid; int toid; int outLen; + DiffConfig DCfg; Blob from = empty_blob, to = empty_blob, out = empty_blob; cson_value * rc = NULL; int flags = (DIFF_CONTEXT_MASK & nContext) | (fSbs ? DIFF_SIDEBYSIDE : 0) | (fHtml ? DIFF_HTML : 0); @@ -58,11 +59,12 @@ return NULL; } content_get(fromid, &from); content_get(toid, &to); blob_zero(&out); - text_diff(&from, &to, &out, 0, flags); + diff_config_init(&DCfg, flags); + text_diff(&from, &to, &out, &DCfg); blob_reset(&from); blob_reset(&to); outLen = blob_size(&out); if(outLen>=0){ rc = cson_value_new_string(blob_buffer(&out), Index: src/json_wiki.c ================================================================== --- src/json_wiki.c +++ src/json_wiki.c @@ -519,11 +519,11 @@ int argPos = g.json.dispatchDepth; int r1 = 0, r2 = 0; Manifest * pW1 = NULL, *pW2 = NULL; Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; char const * zErrTag = NULL; - u64 diffFlags; + DiffConfig DCfg; char * zUuid = NULL; if( !g.perm.Hyperlink ){ json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions."); return NULL; @@ -567,12 +567,12 @@ blob_init(&w1, pW1->zWiki, -1); blob_zero(&w2); blob_init(&w2, pW2->zWiki, -1); blob_zero(&d); - diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR; - text_diff(&w1, &w2, &d, 0, diffFlags); + diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR); + text_diff(&w1, &w2, &d, &DCfg); blob_reset(&w1); blob_reset(&w2); pay = cson_new_object(); Index: src/merge3.c ================================================================== --- src/merge3.c +++ src/merge3.c @@ -196,10 +196,11 @@ int i1, i2; /* Index into aC1[] and aC2[] */ int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ int limit1, limit2; /* Sizes of aC1[] and aC2[] */ int nConflict = 0; /* Number of merge conflicts seen so far */ int useCrLf = 0; + DiffConfig DCfg; blob_zero(pOut); /* Merge results stored in pOut */ /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM), ** keep it in the output. This should be secure enough not to cause @@ -224,12 +225,13 @@ ** is the number of lines of text to copy directly from the pivot, ** the second integer is the number of lines of text to omit from the ** pivot, and the third integer is the number of lines of text that are ** inserted. The edit array ends with a triple of 0,0,0. */ - aC1 = text_diff(pPivot, pV1, 0, 0, 0); - aC2 = text_diff(pPivot, pV2, 0, 0, 0); + diff_config_init(&DCfg, 0); + aC1 = text_diff(pPivot, pV1, 0, &DCfg); + aC2 = text_diff(pPivot, pV2, 0, &DCfg); if( aC1==0 || aC2==0 ){ free(aC1); free(aC2); return -1; } Index: src/patch.c ================================================================== --- src/patch.c +++ src/patch.c @@ -720,15 +720,15 @@ static void patch_diff( unsigned mFlags, /* Patch flags. only -f is allowed */ const char *zDiffCmd, /* Command used for diffing */ const char *zBinGlob, /* GLOB pattern to determine binary files */ int fIncludeBinary, /* Do diffs against binary files */ - u64 diffFlags /* Other diff flags */ + DiffConfig *pCfg /* Diff options */ ){ int nErr = 0; Stmt q; - int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; + int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; Blob empty; blob_zero(&empty); if( (mFlags & PATCH_FORCE)==0 ){ /* Check to ensure that the patch is against the repository that @@ -764,11 +764,11 @@ "in the %s repository", zBaseline, g.zRepositoryName); } } } - diff_begin(diffFlags); + diff_begin(pCfg); db_prepare(&q, "SELECT" " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash)," " pathname," /* 1: new pathname */ " origname," /* 2: original pathname. Null if not renamed */ @@ -804,25 +804,25 @@ zName = db_column_text(&q, 1); rid = db_column_int(&q, 0); if( db_column_type(&q,3)==SQLITE_NULL ){ if( !bWebpage ) fossil_print("DELETE %s\n", zName); - diff_print_index(zName, diffFlags, 0); + diff_print_index(zName, pCfg, 0); isBin2 = 0; content_get(rid, &a); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags); + zBinGlob, fIncludeBinary, pCfg); }else if( rid==0 ){ db_ephemeral_blob(&q, 3, &a); blob_uncompress(&a, &a); if( !bWebpage ) fossil_print("ADDED %s\n", zName); - diff_print_index(zName, diffFlags, 0); + diff_print_index(zName, pCfg, 0); isBin1 = 0; isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags); + zBinGlob, fIncludeBinary, pCfg); blob_reset(&a); }else if( db_column_bytes(&q, 3)>0 ){ Blob delta; db_ephemeral_blob(&q, 3, &delta); blob_uncompress(&delta, &delta); @@ -829,18 +829,18 @@ content_get(rid, &a); blob_delta_apply(&a, &delta, &b); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); diff_file_mem(&a, &b, isBin1, isBin2, zName, - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); + zDiffCmd, zBinGlob, fIncludeBinary, pCfg); blob_reset(&a); blob_reset(&b); blob_reset(&delta); } } db_finalize(&q); - diff_end(diffFlags, nErr); + diff_end(pCfg, nErr); if( nErr ) fossil_fatal("abort due to prior errors"); } /* @@ -949,36 +949,36 @@ }else if( strncmp(zCmd, "diff", n)==0 ){ const char *zDiffCmd = 0; const char *zBinGlob = 0; int fIncludeBinary = 0; - u64 diffFlags; char *zIn; unsigned flags = 0; + DiffConfig DCfg; if( find_option("tk",0,0)!=0 ){ db_close(0); diff_tk("patch diff", 3); return; } - diffFlags = diff_options(); + diff_options(&DCfg, zCmd[0]=='g'); if( find_option("internal","i",0)==0 - && (diffFlags & DIFF_HTML)==0 + && (DCfg.diffFlags & DIFF_HTML)==0 ){ zDiffCmd = diff_command_external(zCmd[0]=='g'); } - if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; + if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; if( zDiffCmd ){ zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); } db_find_and_open_repository(0, 0); if( find_option("force","f",0) ) flags |= PATCH_FORCE; verify_all_options(); zIn = patch_find_patch_filename("apply"); patch_attach(zIn, stdin); - patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); + patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, &DCfg); fossil_free(zIn); }else if( strncmp(zCmd, "pull", n)==0 ){ FILE *pIn = 0; unsigned flags = 0; Index: src/skins.c ================================================================== --- src/skins.c +++ src/skins.c @@ -867,22 +867,25 @@ @ Baseline: \ skin_emit_skin_selector("basis", zBasis, zDraft); @ @ if( P("diff")!=0 || P("sbsdiff")!=0 ){ - u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR; Blob from, to, out; - if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE; + DiffConfig DCfg; + construct_diff_flags(1, &DCfg); + DCfg.diffFlags |= DIFF_STRIP_EOLCR; + if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE; blob_init(&to, zContent, -1); blob_init(&from, skin_file_content(zBasis, zFile), -1); blob_zero(&out); - if( diffFlags & DIFF_SIDEBYSIDE ){ - text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG); + DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; + if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){ + text_diff(&from, &to, &out, &DCfg); @ %s(blob_str(&out)) }else{ - text_diff(&from, &to, &out, 0, - diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG); + DCfg.diffFlags |= DIFF_LINENO; + text_diff(&from, &to, &out, &DCfg); @
       @ %s(blob_str(&out))
       @ 
} blob_reset(&from); Index: src/stash.c ================================================================== --- src/stash.c +++ src/stash.c @@ -406,17 +406,17 @@ int stashid, /* The stash entry to diff */ const char *zDiffCmd, /* Command used for diffing */ const char *zBinGlob, /* GLOB pattern to determine binary files */ int fBaseline, /* Diff against original baseline check-in if true */ int fIncludeBinary, /* Do diffs against binary files */ - u64 diffFlags /* Other diff flags */ + DiffConfig *pCfg /* Diff formatting options */ ){ Stmt q; Blob empty; - int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0; + int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0; blob_zero(&empty); - diff_begin(diffFlags); + diff_begin(pCfg); db_prepare(&q, "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta" " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash", stashid ); @@ -430,56 +430,56 @@ char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); Blob a, b; if( rid==0 ){ db_ephemeral_blob(&q, 6, &a); if( !bWebpage ) fossil_print("ADDED %s\n", zNew); - diff_print_index(zNew, diffFlags, 0); + diff_print_index(zNew, pCfg, 0); isBin1 = 0; isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags); + zBinGlob, fIncludeBinary, pCfg); }else if( isRemoved ){ if( !bWebpage) fossil_print("DELETE %s\n", zOrig); - diff_print_index(zNew, diffFlags, 0); + diff_print_index(zNew, pCfg, 0); isBin2 = 0; if( fBaseline ){ content_get(rid, &a); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags); + zBinGlob, fIncludeBinary, pCfg); } }else{ Blob delta; int isOrigLink = file_islink(zOPath); db_ephemeral_blob(&q, 6, &delta); if( !bWebpage ) fossil_print("CHANGED %s\n", zNew); if( !isOrigLink != !isLink ){ - diff_print_index(zNew, diffFlags, 0); - diff_print_filenames(zOrig, zNew, diffFlags, 0); + diff_print_index(zNew, pCfg, 0); + diff_print_filenames(zOrig, zNew, pCfg, 0); printf(DIFF_CANNOT_COMPUTE_SYMLINK); }else{ content_get(rid, &a); blob_delta_apply(&a, &delta, &b); isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a); isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b); if( fBaseline ){ diff_file_mem(&a, &b, isBin1, isBin2, zNew, - zDiffCmd, zBinGlob, fIncludeBinary, diffFlags); + zDiffCmd, zBinGlob, fIncludeBinary, pCfg); }else{ /*Diff with file on disk using fSwapDiff=1 to show the diff in the same direction as if fBaseline=1.*/ diff_file(&b, isBin2, zOPath, zNew, zDiffCmd, - zBinGlob, fIncludeBinary, diffFlags, 1, 0); + zBinGlob, fIncludeBinary, pCfg, 1, 0); } blob_reset(&a); blob_reset(&b); } blob_reset(&delta); } } db_finalize(&q); - diff_end(diffFlags, 0); + diff_end(pCfg, 0); } /* ** Drop the indicated stash */ @@ -744,35 +744,34 @@ ){ const char *zDiffCmd = 0; const char *zBinGlob = 0; int fIncludeBinary = 0; int fBaseline = 0; - u64 diffFlags; + DiffConfig DCfg; if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ fBaseline = 1; } if( find_option("tk",0,0)!=0 ){ db_close(0); diff_tk(fBaseline ? "stash show" : "stash diff", 3); return; } - diffFlags = diff_options(); + diff_options(&DCfg, zCmd[0]=='g'); if( find_option("internal","i",0)==0 - && (diffFlags & DIFF_HTML)==0 + && (DCfg.diffFlags & DIFF_HTML)==0 ){ zDiffCmd = diff_command_external(zCmd[0]=='g'); } - if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE; + if( find_option("verbose","v",0)!=0 ) DCfg.diffFlags |= DIFF_VERBOSE; if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd)); if( zDiffCmd ){ zBinGlob = diff_get_binary_glob(); fIncludeBinary = diff_include_binary_files(); } stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); - stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, - diffFlags); + stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary, &DCfg); }else if( memcmp(zCmd, "help", nCmd)==0 ){ g.argv[1] = "help"; g.argv[2] = "stash"; g.argc = 3; Index: src/wiki.c ================================================================== --- src/wiki.c +++ src/wiki.c @@ -1815,11 +1815,11 @@ const char *zId; const char *zPid; Manifest *pW1, *pW2 = 0; int rid1, rid2, nextRid; Blob w1, w2, d; - u64 diffFlags; + DiffConfig DCfg; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } zId = P("id"); if( zId==0 ){ @@ -1858,12 +1858,13 @@ style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid); } style_set_current_feature("wiki"); style_header("Changes To %s", pW1->zWikiTitle); blob_zero(&d); - diffFlags = construct_diff_flags(1); - text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO); + construct_diff_flags(1, &DCfg); + DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO; + text_diff(&w2, &w1, &d, &DCfg); @
   @ %s(blob_str(&d))
   @ 
   manifest_destroy(pW1);
   manifest_destroy(pW2);