| | @@ -19,16 +19,10 @@ |
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "diffcmd.h" |
| 22 | 22 | #include <assert.h> |
| 23 | 23 | |
| 24 | | -/* |
| 25 | | -** Diff option flags |
| 26 | | -*/ |
| 27 | | -#define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */ |
| 28 | | -#define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */ |
| 29 | | - |
| 30 | 24 | /* |
| 31 | 25 | ** Output the results of a diff. Output goes to stdout for command-line |
| 32 | 26 | ** or to the CGI/HTTP result buffer for web pages. |
| 33 | 27 | */ |
| 34 | 28 | static void diff_printf(const char *zFormat, ...){ |
| | @@ -62,11 +56,11 @@ |
| 62 | 56 | void diff_file( |
| 63 | 57 | Blob *pFile1, /* In memory content to compare from */ |
| 64 | 58 | const char *zFile2, /* On disk content to compare to */ |
| 65 | 59 | const char *zName, /* Display name of the file */ |
| 66 | 60 | const char *zDiffCmd, /* Command for comparison */ |
| 67 | | - int ignoreEolWs /* Ignore whitespace at end of line */ |
| 61 | + int diffFlags /* Flags to control the diff */ |
| 68 | 62 | ){ |
| 69 | 63 | if( zDiffCmd==0 ){ |
| 70 | 64 | Blob out; /* Diff output text */ |
| 71 | 65 | Blob file2; /* Content of zFile2 */ |
| 72 | 66 | const char *zName2; /* Name of zFile2 for display */ |
| | @@ -84,11 +78,11 @@ |
| 84 | 78 | zName2 = zName; |
| 85 | 79 | } |
| 86 | 80 | |
| 87 | 81 | /* Compute and output the differences */ |
| 88 | 82 | blob_zero(&out); |
| 89 | | - text_diff(pFile1, &file2, &out, 5, ignoreEolWs); |
| 83 | + text_diff(pFile1, &file2, &out, diffFlags); |
| 90 | 84 | if( blob_size(&out) ){ |
| 91 | 85 | diff_printf("--- %s\n+++ %s\n", zName, zName2); |
| 92 | 86 | diff_printf("%s\n", blob_str(&out)); |
| 93 | 87 | } |
| 94 | 88 | |
| | @@ -138,17 +132,17 @@ |
| 138 | 132 | void diff_file_mem( |
| 139 | 133 | Blob *pFile1, /* In memory content to compare from */ |
| 140 | 134 | Blob *pFile2, /* In memory content to compare to */ |
| 141 | 135 | const char *zName, /* Display name of the file */ |
| 142 | 136 | const char *zDiffCmd, /* Command for comparison */ |
| 143 | | - int ignoreEolWs /* Ignore whitespace at end of lines */ |
| 137 | + int diffFlags /* Diff flags */ |
| 144 | 138 | ){ |
| 145 | 139 | if( zDiffCmd==0 ){ |
| 146 | 140 | Blob out; /* Diff output text */ |
| 147 | 141 | |
| 148 | 142 | blob_zero(&out); |
| 149 | | - text_diff(pFile1, pFile2, &out, 5, ignoreEolWs); |
| 143 | + text_diff(pFile1, pFile2, &out, diffFlags); |
| 150 | 144 | diff_printf("--- %s\n+++ %s\n", zName, zName); |
| 151 | 145 | diff_printf("%s\n", blob_str(&out)); |
| 152 | 146 | |
| 153 | 147 | /* Release memory resources */ |
| 154 | 148 | blob_reset(&out); |
| | @@ -185,11 +179,11 @@ |
| 185 | 179 | ** against the same file on disk. |
| 186 | 180 | */ |
| 187 | 181 | static void diff_one_against_disk( |
| 188 | 182 | const char *zFrom, /* Name of file */ |
| 189 | 183 | const char *zDiffCmd, /* Use this "diff" command */ |
| 190 | | - int ignoreEolWs, /* Ignore whitespace changes at end of lines */ |
| 184 | + int diffFlags, /* Diff control flags */ |
| 191 | 185 | const char *zFileTreeName |
| 192 | 186 | ){ |
| 193 | 187 | Blob fname; |
| 194 | 188 | Blob content; |
| 195 | 189 | int isLink; |
| | @@ -196,11 +190,11 @@ |
| 196 | 190 | file_tree_name(zFileTreeName, &fname, 1); |
| 197 | 191 | historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0); |
| 198 | 192 | if( !isLink != !file_wd_islink(zFrom) ){ |
| 199 | 193 | diff_printf("cannot compute difference between symlink and regular file\n"); |
| 200 | 194 | }else{ |
| 201 | | - diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs); |
| 195 | + diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags); |
| 202 | 196 | } |
| 203 | 197 | blob_reset(&content); |
| 204 | 198 | blob_reset(&fname); |
| 205 | 199 | } |
| 206 | 200 | |
| | @@ -215,14 +209,12 @@ |
| 215 | 209 | int diffFlags /* Flags controlling diff output */ |
| 216 | 210 | ){ |
| 217 | 211 | int vid; |
| 218 | 212 | Blob sql; |
| 219 | 213 | Stmt q; |
| 220 | | - int ignoreEolWs; /* Ignore end-of-line whitespace */ |
| 221 | 214 | int asNewFile; /* Treat non-existant files as empty files */ |
| 222 | 215 | |
| 223 | | - ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0; |
| 224 | 216 | asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 225 | 217 | vid = db_lget_int("checkout", 0); |
| 226 | 218 | vfile_check_signature(vid, 1, 0); |
| 227 | 219 | blob_zero(&sql); |
| 228 | 220 | db_begin_transaction(); |
| | @@ -300,11 +292,11 @@ |
| 300 | 292 | content_get(srcid, &content); |
| 301 | 293 | }else{ |
| 302 | 294 | blob_zero(&content); |
| 303 | 295 | } |
| 304 | 296 | diff_print_index(zPathname); |
| 305 | | - diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs); |
| 297 | + diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags); |
| 306 | 298 | blob_reset(&content); |
| 307 | 299 | } |
| 308 | 300 | free(zToFree); |
| 309 | 301 | } |
| 310 | 302 | db_finalize(&q); |
| | @@ -317,11 +309,11 @@ |
| 317 | 309 | */ |
| 318 | 310 | static void diff_one_two_versions( |
| 319 | 311 | const char *zFrom, |
| 320 | 312 | const char *zTo, |
| 321 | 313 | const char *zDiffCmd, |
| 322 | | - int ignoreEolWs, |
| 314 | + int diffFlags, |
| 323 | 315 | const char *zFileTreeName |
| 324 | 316 | ){ |
| 325 | 317 | char *zName; |
| 326 | 318 | Blob fname; |
| 327 | 319 | Blob v1, v2; |
| | @@ -332,11 +324,11 @@ |
| 332 | 324 | historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0); |
| 333 | 325 | if( isLink1 != isLink2 ){ |
| 334 | 326 | diff_printf("--- %s\n+++ %s\n", zName, zName); |
| 335 | 327 | diff_printf("cannot compute difference between symlink and regular file\n"); |
| 336 | 328 | }else{ |
| 337 | | - diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs); |
| 329 | + diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags); |
| 338 | 330 | } |
| 339 | 331 | blob_reset(&v1); |
| 340 | 332 | blob_reset(&v2); |
| 341 | 333 | blob_reset(&fname); |
| 342 | 334 | } |
| | @@ -347,11 +339,11 @@ |
| 347 | 339 | */ |
| 348 | 340 | static void diff_manifest_entry( |
| 349 | 341 | struct ManifestFile *pFrom, |
| 350 | 342 | struct ManifestFile *pTo, |
| 351 | 343 | const char *zDiffCmd, |
| 352 | | - int ignoreEolWs |
| 344 | + int diffFlags |
| 353 | 345 | ){ |
| 354 | 346 | Blob f1, f2; |
| 355 | 347 | int rid; |
| 356 | 348 | const char *zName = pFrom ? pFrom->zName : pTo->zName; |
| 357 | 349 | diff_print_index(zName); |
| | @@ -365,11 +357,11 @@ |
| 365 | 357 | rid = uuid_to_rid(pTo->zUuid, 0); |
| 366 | 358 | content_get(rid, &f2); |
| 367 | 359 | }else{ |
| 368 | 360 | blob_zero(&f2); |
| 369 | 361 | } |
| 370 | | - diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs); |
| 362 | + diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags); |
| 371 | 363 | blob_reset(&f1); |
| 372 | 364 | blob_reset(&f2); |
| 373 | 365 | } |
| 374 | 366 | |
| 375 | 367 | /* |
| | @@ -381,11 +373,10 @@ |
| 381 | 373 | const char *zDiffCmd, |
| 382 | 374 | int diffFlags |
| 383 | 375 | ){ |
| 384 | 376 | Manifest *pFrom, *pTo; |
| 385 | 377 | ManifestFile *pFromFile, *pToFile; |
| 386 | | - int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0; |
| 387 | 378 | int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0; |
| 388 | 379 | |
| 389 | 380 | pFrom = manifest_get_by_name(zFrom, 0); |
| 390 | 381 | manifest_file_rewind(pFrom); |
| 391 | 382 | pFromFile = manifest_file_next(pFrom,0); |
| | @@ -403,26 +394,26 @@ |
| 403 | 394 | cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); |
| 404 | 395 | } |
| 405 | 396 | if( cmp<0 ){ |
| 406 | 397 | diff_printf("DELETED %s\n", pFromFile->zName); |
| 407 | 398 | if( asNewFlag ){ |
| 408 | | - diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs); |
| 399 | + diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags); |
| 409 | 400 | } |
| 410 | 401 | pFromFile = manifest_file_next(pFrom,0); |
| 411 | 402 | }else if( cmp>0 ){ |
| 412 | 403 | diff_printf("ADDED %s\n", pToFile->zName); |
| 413 | 404 | if( asNewFlag ){ |
| 414 | | - diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs); |
| 405 | + diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags); |
| 415 | 406 | } |
| 416 | 407 | pToFile = manifest_file_next(pTo,0); |
| 417 | 408 | }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ |
| 418 | 409 | /* No changes */ |
| 419 | 410 | pFromFile = manifest_file_next(pFrom,0); |
| 420 | 411 | pToFile = manifest_file_next(pTo,0); |
| 421 | 412 | }else{ |
| 422 | 413 | /* diff_printf("CHANGED %s\n", pFromFile->zName); */ |
| 423 | | - diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs); |
| 414 | + diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags); |
| 424 | 415 | pFromFile = manifest_file_next(pFrom,0); |
| 425 | 416 | pToFile = manifest_file_next(pTo,0); |
| 426 | 417 | } |
| 427 | 418 | } |
| 428 | 419 | manifest_destroy(pFrom); |
| | @@ -460,26 +451,34 @@ |
| 460 | 451 | ** Options: |
| 461 | 452 | ** --from|-r VERSION select VERSION as source for the diff |
| 462 | 453 | ** --new-file|-N output complete text of added or deleted files |
| 463 | 454 | ** -i use internal diff logic |
| 464 | 455 | ** --to VERSION select VERSION as target for the diff |
| 456 | +** --sbs side-by-side diff |
| 457 | +** --context|-c N Use N lines of context |
| 465 | 458 | */ |
| 466 | 459 | void diff_cmd(void){ |
| 467 | 460 | int isGDiff; /* True for gdiff. False for normal diff */ |
| 468 | 461 | int isInternDiff; /* True for internal diff */ |
| 469 | 462 | int hasNFlag; /* True if -N or --new-file flag is used */ |
| 470 | 463 | const char *zFrom; /* Source version number */ |
| 471 | 464 | const char *zTo; /* Target version number */ |
| 472 | 465 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 473 | 466 | int diffFlags = 0; /* Flags to control the DIFF */ |
| 467 | + const char *z; |
| 474 | 468 | int f; |
| 475 | 469 | |
| 476 | 470 | isGDiff = g.argv[1][0]=='g'; |
| 477 | 471 | isInternDiff = find_option("internal","i",0)!=0; |
| 478 | 472 | zFrom = find_option("from", "r", 1); |
| 479 | 473 | zTo = find_option("to", 0, 1); |
| 480 | 474 | hasNFlag = find_option("new-file","N",0)!=0; |
| 475 | + if( find_option("sbs",0,0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE; |
| 476 | + if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){ |
| 477 | + if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK; |
| 478 | + diffFlags |= f; |
| 479 | + } |
| 481 | 480 | |
| 482 | 481 | |
| 483 | 482 | if( hasNFlag ) diffFlags |= DIFF_NEWFILE; |
| 484 | 483 | if( zTo==0 ){ |
| 485 | 484 | db_must_be_within_tree(); |
| 486 | 485 | |