| | @@ -19,10 +19,16 @@ |
| 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 | + |
| 24 | 30 | /* |
| 25 | 31 | ** This function implements a cross-platform "system()" interface. |
| 26 | 32 | */ |
| 27 | 33 | int portable_system(const char *zOrigCmd){ |
| 28 | 34 | int rc; |
| | @@ -53,24 +59,30 @@ |
| 53 | 59 | static void diff_file( |
| 54 | 60 | Blob *pFile1, /* In memory content to compare from */ |
| 55 | 61 | const char *zFile2, /* On disk content to compare to */ |
| 56 | 62 | const char *zName, /* Display name of the file */ |
| 57 | 63 | const char *zDiffCmd, /* Command for comparison */ |
| 58 | | - int ignoreEolWs /* Ignore whitespace at end of lines */ |
| 64 | + int ignoreEolWs /* Ignore whitespace at end of line */ |
| 59 | 65 | ){ |
| 60 | 66 | if( zDiffCmd==0 ){ |
| 61 | | - Blob out; /* Diff output text */ |
| 62 | | - Blob file2; /* Content of zFile2 */ |
| 67 | + Blob out; /* Diff output text */ |
| 68 | + Blob file2; /* Content of zFile2 */ |
| 69 | + const char *zName2; /* Name of zFile2 for display */ |
| 63 | 70 | |
| 64 | 71 | /* Read content of zFile2 into memory */ |
| 65 | 72 | blob_zero(&file2); |
| 66 | | - blob_read_from_file(&file2, zFile2); |
| 73 | + if( file_size(zFile2)<0 ){ |
| 74 | + zName2 = "/dev/null"; |
| 75 | + }else{ |
| 76 | + blob_read_from_file(&file2, zFile2); |
| 77 | + zName2 = zName; |
| 78 | + } |
| 67 | 79 | |
| 68 | 80 | /* Compute and output the differences */ |
| 69 | 81 | blob_zero(&out); |
| 70 | 82 | text_diff(pFile1, &file2, &out, 5, ignoreEolWs); |
| 71 | | - printf("--- %s\n+++ %s\n", zName, zName); |
| 83 | + printf("--- %s\n+++ %s\n", zName, zName2); |
| 72 | 84 | printf("%s\n", blob_str(&out)); |
| 73 | 85 | |
| 74 | 86 | /* Release memory resources */ |
| 75 | 87 | blob_reset(&file2); |
| 76 | 88 | blob_reset(&out); |
| | @@ -183,16 +195,20 @@ |
| 183 | 195 | ** files on disk and the check-out on which they are based. |
| 184 | 196 | */ |
| 185 | 197 | static void diff_all_against_disk( |
| 186 | 198 | const char *zFrom, /* Version to difference from */ |
| 187 | 199 | const char *zDiffCmd, /* Use this diff command. NULL for built-in */ |
| 188 | | - int ignoreEolWs /* Ignore end-of-line whitespace */ |
| 200 | + int diffFlags /* Flags controlling diff output */ |
| 189 | 201 | ){ |
| 190 | 202 | int vid; |
| 191 | 203 | Blob sql; |
| 192 | 204 | Stmt q; |
| 205 | + int ignoreEolWs; /* Ignore end-of-line whitespace */ |
| 206 | + int asNewFile; /* Treat non-existant files as empty files */ |
| 193 | 207 | |
| 208 | + ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0; |
| 209 | + asNewFile = (diffFlags & DIFF_NEWFILE)!=0; |
| 194 | 210 | vid = db_lget_int("checkout", 0); |
| 195 | 211 | vfile_check_signature(vid, 1); |
| 196 | 212 | blob_zero(&sql); |
| 197 | 213 | db_begin_transaction(); |
| 198 | 214 | if( zFrom ){ |
| | @@ -235,23 +251,35 @@ |
| 235 | 251 | while( db_step(&q)==SQLITE_ROW ){ |
| 236 | 252 | const char *zPathname = db_column_text(&q,0); |
| 237 | 253 | int isDeleted = db_column_int(&q, 1); |
| 238 | 254 | int isChnged = db_column_int(&q,2); |
| 239 | 255 | int isNew = db_column_int(&q,3); |
| 256 | + int srcid = db_column_int(&q, 4); |
| 240 | 257 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 258 | + int showDiff = 1; |
| 241 | 259 | if( isDeleted ){ |
| 242 | 260 | printf("DELETED %s\n", zPathname); |
| 261 | + if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; } |
| 243 | 262 | }else if( access(zFullName, 0) ){ |
| 244 | 263 | printf("MISSING %s\n", zPathname); |
| 264 | + if( !asNewFile ){ showDiff = 0; } |
| 245 | 265 | }else if( isNew ){ |
| 246 | 266 | printf("ADDED %s\n", zPathname); |
| 267 | + srcid = 0; |
| 268 | + if( !asNewFile ){ showDiff = 0; } |
| 247 | 269 | }else if( isChnged==3 ){ |
| 248 | 270 | printf("ADDED_BY_MERGE %s\n", zPathname); |
| 249 | | - }else{ |
| 250 | | - int srcid = db_column_int(&q, 4); |
| 271 | + srcid = 0; |
| 272 | + if( !asNewFile ){ showDiff = 0; } |
| 273 | + } |
| 274 | + if( showDiff ){ |
| 251 | 275 | Blob content; |
| 252 | | - content_get(srcid, &content); |
| 276 | + if( srcid>0 ){ |
| 277 | + content_get(srcid, &content); |
| 278 | + }else{ |
| 279 | + blob_zero(&content); |
| 280 | + } |
| 253 | 281 | printf("Index: %s\n=======================================" |
| 254 | 282 | "============================\n", |
| 255 | 283 | zPathname |
| 256 | 284 | ); |
| 257 | 285 | diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs); |
| | @@ -292,14 +320,16 @@ |
| 292 | 320 | */ |
| 293 | 321 | static void diff_all_two_versions( |
| 294 | 322 | const char *zFrom, |
| 295 | 323 | const char *zTo, |
| 296 | 324 | const char *zDiffCmd, |
| 297 | | - int ignoreEolWs |
| 325 | + int diffFlags |
| 298 | 326 | ){ |
| 299 | 327 | Manifest mFrom, mTo; |
| 300 | 328 | int iFrom, iTo; |
| 329 | + int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0; |
| 330 | + /* int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0; */ |
| 301 | 331 | |
| 302 | 332 | manifest_from_name(zFrom, &mFrom); |
| 303 | 333 | manifest_from_name(zTo, &mTo); |
| 304 | 334 | iFrom = iTo = 0; |
| 305 | 335 | while( iFrom<mFrom.nFile && iTo<mTo.nFile ){ |
| | @@ -370,29 +400,34 @@ |
| 370 | 400 | ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff". |
| 371 | 401 | */ |
| 372 | 402 | void diff_cmd(void){ |
| 373 | 403 | int isGDiff; /* True for gdiff. False for normal diff */ |
| 374 | 404 | int isInternDiff; /* True for internal diff */ |
| 405 | + int hasNFlag; /* True if -N or --new-file flag is used */ |
| 375 | 406 | const char *zFrom; /* Source version number */ |
| 376 | 407 | const char *zTo; /* Target version number */ |
| 377 | 408 | const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ |
| 409 | + int diffFlags = 0; /* Flags to control the DIFF */ |
| 378 | 410 | |
| 379 | 411 | isGDiff = g.argv[1][0]=='g'; |
| 380 | 412 | isInternDiff = find_option("internal","i",0)!=0; |
| 381 | 413 | zFrom = find_option("from", "r", 1); |
| 382 | 414 | zTo = find_option("to", 0, 1); |
| 415 | + hasNFlag = find_option("new-file","N",0)!=0; |
| 416 | + |
| 383 | 417 | |
| 418 | + if( hasNFlag ) diffFlags |= DIFF_NEWFILE; |
| 384 | 419 | if( zTo==0 ){ |
| 385 | 420 | db_must_be_within_tree(); |
| 386 | 421 | verify_all_options(); |
| 387 | 422 | if( !isInternDiff ){ |
| 388 | 423 | zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); |
| 389 | 424 | } |
| 390 | 425 | if( g.argc==3 ){ |
| 391 | 426 | diff_one_against_disk(zFrom, zDiffCmd, 0); |
| 392 | 427 | }else{ |
| 393 | | - diff_all_against_disk(zFrom, zDiffCmd, 0); |
| 428 | + diff_all_against_disk(zFrom, zDiffCmd, diffFlags); |
| 394 | 429 | } |
| 395 | 430 | }else if( zFrom==0 ){ |
| 396 | 431 | fossil_fatal("must use --from if --to is present"); |
| 397 | 432 | }else{ |
| 398 | 433 | db_find_and_open_repository(1); |
| | @@ -401,9 +436,9 @@ |
| 401 | 436 | zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0); |
| 402 | 437 | } |
| 403 | 438 | if( g.argc==3 ){ |
| 404 | 439 | diff_one_two_versions(zFrom, zTo, zDiffCmd, 0); |
| 405 | 440 | }else{ |
| 406 | | - diff_all_two_versions(zFrom, zTo, zDiffCmd, 0); |
| 441 | + diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags); |
| 407 | 442 | } |
| 408 | 443 | } |
| 409 | 444 | } |
| 410 | 445 | |