Changes On Branch use-blob_strip_bom
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch use-blob_strip_bom Excluding Merge-Ins

This is equivalent to a diff from db0c512767 to b0e05a90b6

2012-11-05
21:10
Do not run the graphical merging tool nor leave merge-droppings after a dry-run merge. Also improve the merge summary message at the end of a merge. check-in: cd2c0e4cb5 user: drh tags: trunk
13:56
merge trunk Leaf check-in: b0e05a90b6 user: jan.nijtmans tags: use-blob_strip_bom
13:10
If the committed file has CR/NL or UTF-16 (or both), give the user the possibility to convert it to resp NL or UTF-8 (or both) without committing check-in: c6223a8e2a user: jan.nijtmans tags: convert_before_commit
2012-11-04
18:03
merge trunk check-in: e86aa2a1e8 user: jan.nijtmans tags: improve_commit_warning
17:41
Merge the "spelling" branch into trunk, fixing a huge number of typos, mostly in comments, but occasionally in error messages or help screens. check-in: db0c512767 user: drh tags: trunk
12:59
Fix typos. Closed-Leaf check-in: 45065c5c28 user: dmitry tags: spelling
11:58
Improvements to the fix for [0ff64b0a5fc88e7e]: (1) Better error message and (2) allow the partial commit of the renamed file as long as its destination files is also part of the partial commit. check-in: c0fe455c78 user: drh tags: trunk
2012-11-01
14:02
bug-fix: Before preparing a diff, BOM's should not be removed. It might result in a BOM in the middle of UTF-8, which is invalid, but that's how diff works. check-in: cd06b7d8af user: jan.nijtmans tags: use-blob_strip_bom

Changes to src/blob.c.

1089
1090
1091
1092
1093
1094
1095
1096
1097

1098
1099
1100
1101
1102
1103
1104
1105
1106

1107
1108
1109
1110
1111
1112
1113

1114
1115
1116
1117
1118
1119
1120
1121



1122
1123
1124
1125
1126
1127
1128
....
1132
1133
1134
1135
1136
1137
1138



1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  *pRight = swap;
}

/*
** Strip a possible BOM from the blob. On Windows, if there
** is either no BOM at all or an (le/be) UTF-16 BOM, a conversion
** to UTF-8 is done.
** If useMbcs is false and there is no BOM, the input string
** is assumed to be UTF-8 already, so no conversion is done.

*/
void blob_strip_bom(Blob *pBlob, int useMbcs){
  static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
#ifdef _WIN32
  static const unsigned short ubom = 0xfeff;
  static const unsigned short urbom = 0xfffe;
#endif /* _WIN32 */
  char *zUtf8;
  if( blob_size(pBlob)>2 && memcmp(blob_buffer(pBlob), bom, 3)==0 ) {

	struct Blob temp;
    zUtf8 = blob_str(pBlob) + 3;
    blob_zero(&temp);
    blob_append(&temp, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
    blob_swap(pBlob, &temp);
    blob_reset(&temp);

#ifdef _WIN32
  }else if( blob_size(pBlob)>1 && (blob_size(pBlob)&1)==0
      && memcmp(blob_buffer(pBlob), &ubom, 2)==0 ) {
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + 2;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);



    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
  }else if( blob_size(pBlob)>1 && (blob_size(pBlob)&1)==0
      && memcmp(blob_buffer(pBlob), &urbom, 2)==0 ) {
    unsigned int i = blob_size(pBlob);
    zUtf8 = blob_buffer(pBlob);
    while( i > 0 ){
................................................................................
        zUtf8[--i] = temp;
    }
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + 2;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);



    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
  }else if (useMbcs) {
    zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
    blob_zero(pBlob);
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
#endif /* _WIN32 */
  }
}






|

>









>
|
|
|
|
|
|
|
>








>
>
>







 







>
>
>


|







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
....
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  *pRight = swap;
}

/*
** Strip a possible BOM from the blob. On Windows, if there
** is either no BOM at all or an (le/be) UTF-16 BOM, a conversion
** to UTF-8 is done.
** If useMbcs is 0 and there is no BOM, the input string
** is assumed to be UTF-8 already, so no conversion is done.
** If useMbcs is 2, any BOM is replaced by the UTF-8 BOM
*/
void blob_strip_bom(Blob *pBlob, int useMbcs){
  static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
#ifdef _WIN32
  static const unsigned short ubom = 0xfeff;
  static const unsigned short urbom = 0xfffe;
#endif /* _WIN32 */
  char *zUtf8;
  if( blob_size(pBlob)>2 && memcmp(blob_buffer(pBlob), bom, 3)==0 ) {
    if( useMbcs<2 ){
      struct Blob temp;
      zUtf8 = blob_str(pBlob) + 3;
      blob_zero(&temp);
      blob_append(&temp, zUtf8, -1);
      fossil_mbcs_free(zUtf8);
      blob_swap(pBlob, &temp);
      blob_reset(&temp);
    }
#ifdef _WIN32
  }else if( blob_size(pBlob)>1 && (blob_size(pBlob)&1)==0
      && memcmp(blob_buffer(pBlob), &ubom, 2)==0 ) {
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + 2;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    if( useMbcs>1 ){
      blob_append(pBlob, (char*)bom, 3);
    }
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
  }else if( blob_size(pBlob)>1 && (blob_size(pBlob)&1)==0
      && memcmp(blob_buffer(pBlob), &urbom, 2)==0 ) {
    unsigned int i = blob_size(pBlob);
    zUtf8 = blob_buffer(pBlob);
    while( i > 0 ){
................................................................................
        zUtf8[--i] = temp;
    }
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + 2;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    if( useMbcs>1 ){
      blob_append(pBlob, (char*)bom, 3);
    }
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
  }else if (useMbcs==1) {
    zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
    blob_zero(pBlob);
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
#endif /* _WIN32 */
  }
}

Changes to src/diff.c.

43
44
45
46
47
48
49



50
51
52
53
54
55
56
57
58
59
60
...
181
182
183
184
185
186
187


188
189
190
191
192
193
194
195
...
209
210
211
212
213
214
215








































216
217
218
219
220
221
222
...
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
259
260
/*
** These error messages are shared in multiple locations.  They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
    "cannot compute difference between binary files\n"




#define DIFF_CANNOT_COMPUTE_SYMLINK \
    "cannot compute difference between symlink and regular file\n"

#define looks_like_binary(blob) (looks_like_utf8((blob)) == 0)
#endif /* INTERFACE */

/*
** Maximum length of a line in a text file, in bytes.  (8192)
*/
#define LENGTH_MASK_SZ  13
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)
................................................................................
**         not be UTF-8.
**
**  (0) -- The content appears to be binary because it contains embedded
**         NUL characters or an extremely long line.  Since this function
**         does not understand UTF-16, it may falsely consider UTF-16 text
**         to be binary.
**


** (-1) -- The content appears to consist entirely of text, with lines
**         delimited by carriage-return, line-feed pairs; however, the
**         encoding may not be UTF-8.
**
************************************ WARNING **********************************
**
** This function does not validate that the blob content is properly formed
** UTF-8.  It assumes that all code points are the same size.  It does not
................................................................................

  /* Check individual lines.
  */
  if( n==0 ) return result;  /* Empty file -> text */
  c = *z;
  if( c==0 ) return 0;  /* Zero byte in a file -> binary */
  j = (c!='\n');








































  while( --n>0 ){
    c = *++z; ++j;
    if( c==0 ) return 0;  /* Zero byte in a file -> binary */
    if( c=='\n' ){
      int c2 = z[-1];
      if( c2=='\r' ){
        result = -1;  /* Contains CR/NL, continue */
................................................................................
#    define WCHAR_T wchar_t
#  else
#    define WCHAR_T unsigned short
#  endif
#endif

/*
** Maximum length of a line in a text file, in UTF-16 characters.  (4096)
** The number of bytes represented by this value cannot exceed LENGTH_MASK
** bytes, because that is the line buffer size used by the diff engine.

*/
#define UTF16_LENGTH_MASK_SZ  (LENGTH_MASK_SZ-(sizeof(WCHAR_T)-sizeof(char)))
#define UTF16_LENGTH_MASK     ((1<<UTF16_LENGTH_MASK_SZ)-1)

/*
** The carriage-return / line-feed characters in the UTF-16be and UTF-16le
** encodings.
*/
#define UTF16BE_CR  ((WCHAR_T)'\r')
#define UTF16BE_LF  ((WCHAR_T)'\n')






>
>
>



|







 







>
>
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|
>

<
|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
305
/*
** These error messages are shared in multiple locations.  They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
    "cannot compute difference between binary files\n"

#define DIFF_CANNOT_COMPUTE_ENCODING \
    "cannot compute difference between files with different encodings\n"

#define DIFF_CANNOT_COMPUTE_SYMLINK \
    "cannot compute difference between symlink and regular file\n"

#define looks_like_text(blob) (looks_like_utf8(blob)&3)
#endif /* INTERFACE */

/*
** Maximum length of a line in a text file, in bytes.  (8192)
*/
#define LENGTH_MASK_SZ  13
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)
................................................................................
**         not be UTF-8.
**
**  (0) -- The content appears to be binary because it contains embedded
**         NUL characters or an extremely long line.  Since this function
**         does not understand UTF-16, it may falsely consider UTF-16 text
**         to be binary.
**
** (-1,-2) UTF-16 (le/be)
**
** (-3) -- The content appears to consist entirely of text, with lines
**         delimited by carriage-return, line-feed pairs; however, the
**         encoding may not be UTF-8.
**
************************************ WARNING **********************************
**
** This function does not validate that the blob content is properly formed
** UTF-8.  It assumes that all code points are the same size.  It does not
................................................................................

  /* Check individual lines.
  */
  if( n==0 ) return result;  /* Empty file -> text */
  c = *z;
  if( c==0 ) return 0;  /* Zero byte in a file -> binary */
  j = (c!='\n');
  if ( (n&1)==0 ){ /* UTF-16 must have an even blob length */
    if ( (c==0xff) && (z[1]==0xfe) ){ /* UTF-16 LE BOM */
      result = -1;
      while( (n-=2)>0 ){
        c = *(z+=2); ++j;
        if( z[1]==0 ){ /* High-byte must be 0 for further checks */
          if( c==0 ) return 0;  /* Zero char in a file -> binary */
          if( c=='\n' ){
            if( j>LENGTH_MASK ){
              return 0;  /* Very long line -> binary */
            }
            j = 0;
          }
        }
        if( j>LENGTH_MASK ){
          return 0;  /* Very long line -> binary */
        }
      }
      return result;
    } else if ( (c==0xfe) && (z[1]==0xff) ){ /* UTF-16 BE BOM */
      result = -2;
      ++z;
      while( (n-=2)>0 ){
        c = *(z+=2); ++j;
        if ( z[-1]==0 ){ /* High-byte must be 0 for further checks */
          if( c==0 ) return 0;  /* Zero char in a file -> binary */
          if( c=='\n' ){
            if( j>LENGTH_MASK ){
              return 0;  /* Very long line -> binary */
            }
            j = 0;
          }
        }
        if( j>LENGTH_MASK ){
          return 0;  /* Very long line -> binary */
        }
      }
      return result;
    }
  }
  while( --n>0 ){
    c = *++z; ++j;
    if( c==0 ) return 0;  /* Zero byte in a file -> binary */
    if( c=='\n' ){
      int c2 = z[-1];
      if( c2=='\r' ){
        result = -1;  /* Contains CR/NL, continue */
................................................................................
#    define WCHAR_T wchar_t
#  else
#    define WCHAR_T unsigned short
#  endif
#endif

/*
** Maximum length of a line in a text file, in UTF-16 characters.  (2731)
** The number of characters represented by this value cannot exceed
** LENGTH_UTF16_LENGTH_MASK characters, because when converting UTF-16
** to UTF-8 it could overflow the line buffer used by the diff engine.
*/

#define UTF16_LENGTH_MASK     (LENGTH_MASK/3)

/*
** The carriage-return / line-feed characters in the UTF-16be and UTF-16le
** encodings.
*/
#define UTF16BE_CR  ((WCHAR_T)'\r')
#define UTF16BE_LF  ((WCHAR_T)'\n')

Changes to src/diffcmd.c.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
100
101
102
103
104
105


106
107
108
109
110
111


112


113
114
115
116
117
118
119
...
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
...
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406


407
408
409
410
411
412
413
414
415
...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452



453
454
455
456
457
458
459
460
461
...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
492
493
494
495
496
497
498
499
500






501
502

503
504
505
506
507
508
509
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file(
  Blob *pFile1,             /* In memory content to compare from */
  int isBin1,               /* Does the 'from' content appear to be binary */
  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 */
){
  if( zDiffCmd==0 ){
    Blob out;                 /* Diff output text */
    Blob file2;               /* Content of zFile2 */
    const char *zName2;       /* Name of zFile2 for display */


    /* Read content of zFile2 into memory */
    blob_zero(&file2);
    if( file_wd_size(zFile2)<0 ){
      zName2 = NULL_DEVICE;
    }else{
      if( file_wd_islink(zFile2) ){
        blob_read_link(&file2, zFile2);
      }else{
        blob_read_from_file(&file2, zFile2);
      }
      zName2 = zName;
    }



    /* Compute and output the differences */
    if( diffFlags & DIFF_BRIEF ){
      if( blob_compare(pFile1, &file2) ){
        fossil_print("CHANGED  %s\n", zName);
      }


    }else{


      blob_zero(&out);
      text_diff(pFile1, &file2, &out, diffFlags);
      if( blob_size(&out) ){
        diff_print_filenames(zName, zName2, diffFlags);
        fossil_print("%s\n", blob_str(&out));
      }
      blob_reset(&out);
................................................................................
  }else{
    int cnt = 0;
    Blob nameFile1;    /* Name of temporary file to old pFile1 content */
    Blob cmd;          /* Text of command to run */

    if( !fIncludeBinary ){
      Blob file2;
      if( isBin1 ){

        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
................................................................................
      if( file_wd_size(zFile2)>=0 ){
        if( file_wd_islink(zFile2) ){
          blob_read_link(&file2, zFile2);
        }else{
          blob_read_from_file(&file2, zFile2);
        }
      }
      if( looks_like_binary(&file2) ){

        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        blob_reset(&file2);
        return;
      }
      blob_reset(&file2);
    }

................................................................................
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */
  int isBin1,               /* Does the 'from' content appear to be binary */
  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 */
){
  if( diffFlags & DIFF_BRIEF ) return;
  if( zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);


    text_diff(pFile1, pFile2, &out, diffFlags);
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print("%s\n", blob_str(&out));

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    char zTemp1[300];
    char zTemp2[300];

    if( !fIncludeBinary ){
      if( isBin1 || isBin2 ){
        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
................................................................................
  int fIncludeBinary,       /* Include binary files for external diff */
  u64 diffFlags,            /* Diff control flags */
  const char *zFileTreeName
){
  Blob fname;
  Blob content;
  int isLink;
  int isBin;
  file_tree_name(zFileTreeName, &fname, 1);
  historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0,
                             fIncludeBinary ? 0 : &isBin, 0);
  if( !isLink != !file_wd_islink(zFrom) ){
    fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK);
  }else{
    diff_file(&content, isBin, zFileTreeName, zFileTreeName,
              zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&content);
  blob_reset(&fname);
}

/*
................................................................................
    }else if( isChnged==3 ){
      fossil_print("ADDED_BY_MERGE %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      int isBin;
      if( !isLink != !file_wd_islink(zFullName) ){
        diff_print_index(zPathname, diffFlags);
        diff_print_filenames(zPathname, zPathname, diffFlags);
        fossil_print(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);
      diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
                zBinGlob, fIncludeBinary, diffFlags);
      blob_reset(&content);
    }
    free(zToFree);
  }
  db_finalize(&q);
  db_end_transaction(1);  /* ROLLBACK */
................................................................................
  u64 diffFlags,
  const char *zFileTreeName
){
  char *zName;
  Blob fname;
  Blob v1, v2;
  int isLink1, isLink2;
  int isBin1, isBin2;
  if( diffFlags & DIFF_BRIEF ) return;
  file_tree_name(zFileTreeName, &fname, 1);
  zName = blob_str(&fname);
  historical_version_of_file(zFrom, zName, &v1, &isLink1, 0,
                             fIncludeBinary ? 0 : &isBin1, 0);
  historical_version_of_file(zTo, zName, &v2, &isLink2, 0,
                             fIncludeBinary ? 0 : &isBin2, 0);
  if( isLink1 != isLink2 ){
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK);



  }else{
    diff_file_mem(&v1, &v2, isBin1, isBin2, zName, zDiffCmd,
                  zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&fname);
}

................................................................................
  struct ManifestFile *pTo,
  const char *zDiffCmd,
  const char *zBinGlob,
  int fIncludeBinary,
  u64 diffFlags
){
  Blob f1, f2;
  int isBin1, isBin2;
  int rid;
  const char *zName =  pFrom ? pFrom->zName : pTo->zName;
  if( diffFlags & DIFF_BRIEF ) return;
  diff_print_index(zName, diffFlags);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
................................................................................
  }
  if( pTo ){
    rid = uuid_to_rid(pTo->zUuid, 0);
    content_get(rid, &f2);
  }else{
    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);

  blob_reset(&f1);
  blob_reset(&f2);
}

/*
** Output the differences between two check-ins.
**






|











>













>
>
|





>
>

>
>







 







|
>







 







|
>







 







|
<











>
>












|







 







|


|



|







 







|











|
>
>

|







 







|




|

|



>
>
>

|







 







|







 







|
|
>
>
>
>
>
>
|
|
>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
...
204
205
206
207
208
209
210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
...
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file(
  Blob *pFile1,             /* In memory content to compare from */
  int eType1,               /* Does the 'from' content appear to be text */
  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 */
){
  if( zDiffCmd==0 ){
    Blob out;                 /* Diff output text */
    Blob file2;               /* Content of zFile2 */
    const char *zName2;       /* Name of zFile2 for display */
    int eType2 = 0;

    /* Read content of zFile2 into memory */
    blob_zero(&file2);
    if( file_wd_size(zFile2)<0 ){
      zName2 = NULL_DEVICE;
    }else{
      if( file_wd_islink(zFile2) ){
        blob_read_link(&file2, zFile2);
      }else{
        blob_read_from_file(&file2, zFile2);
      }
      zName2 = zName;
    }
    if( !fIncludeBinary ){
      eType2 = looks_like_text(&file2);
    }
    /* Compute and output the differences */
    if( diffFlags & DIFF_BRIEF ){
      if( blob_compare(pFile1, &file2) ){
        fossil_print("CHANGED  %s\n", zName);
      }
    }else if( eType1!=eType2 ){
      fossil_print(DIFF_CANNOT_COMPUTE_ENCODING);
    }else{
      blob_strip_bom(pFile1, 2);
      blob_strip_bom(&file2, 2);
      blob_zero(&out);
      text_diff(pFile1, &file2, &out, diffFlags);
      if( blob_size(&out) ){
        diff_print_filenames(zName, zName2, diffFlags);
        fossil_print("%s\n", blob_str(&out));
      }
      blob_reset(&out);
................................................................................
  }else{
    int cnt = 0;
    Blob nameFile1;    /* Name of temporary file to old pFile1 content */
    Blob cmd;          /* Text of command to run */

    if( !fIncludeBinary ){
      Blob file2;
      int eType2;
      if( eType1!=1 ){
        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
................................................................................
      if( file_wd_size(zFile2)>=0 ){
        if( file_wd_islink(zFile2) ){
          blob_read_link(&file2, zFile2);
        }else{
          blob_read_from_file(&file2, zFile2);
        }
      }
      eType2 = looks_like_text(&file2);
      if( eType2!=1 ){
        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        blob_reset(&file2);
        return;
      }
      blob_reset(&file2);
    }

................................................................................
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */
  int eType,                /* Does the content appear to be text */

  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 */
){
  if( diffFlags & DIFF_BRIEF ) return;
  if( zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);
    blob_strip_bom(pFile1, 2);
    blob_strip_bom(pFile2, 2);
    text_diff(pFile1, pFile2, &out, diffFlags);
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print("%s\n", blob_str(&out));

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    char zTemp1[300];
    char zTemp2[300];

    if( !fIncludeBinary ){
      if( eType==0 ){
        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
................................................................................
  int fIncludeBinary,       /* Include binary files for external diff */
  u64 diffFlags,            /* Diff control flags */
  const char *zFileTreeName
){
  Blob fname;
  Blob content;
  int isLink;
  int eType = 0;
  file_tree_name(zFileTreeName, &fname, 1);
  historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0,
                             fIncludeBinary ? 0 : &eType, 0);
  if( !isLink != !file_wd_islink(zFrom) ){
    fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK);
  }else{
    diff_file(&content, eType, zFileTreeName, zFileTreeName,
              zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&content);
  blob_reset(&fname);
}

/*
................................................................................
    }else if( isChnged==3 ){
      fossil_print("ADDED_BY_MERGE %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      int eType = 0;
      if( !isLink != !file_wd_islink(zFullName) ){
        diff_print_index(zPathname, diffFlags);
        diff_print_filenames(zPathname, zPathname, diffFlags);
        fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK);
        continue;
      }
      if( srcid>0 ){
        content_get(srcid, &content);
      }else{
        blob_zero(&content);
      }
      if( !fIncludeBinary ){
        eType = looks_like_text(&content);
      }
      diff_print_index(zPathname, diffFlags);
      diff_file(&content, eType, zFullName, zPathname, zDiffCmd,
                zBinGlob, fIncludeBinary, diffFlags);
      blob_reset(&content);
    }
    free(zToFree);
  }
  db_finalize(&q);
  db_end_transaction(1);  /* ROLLBACK */
................................................................................
  u64 diffFlags,
  const char *zFileTreeName
){
  char *zName;
  Blob fname;
  Blob v1, v2;
  int isLink1, isLink2;
  int eType = 0, eType2 = 0;
  if( diffFlags & DIFF_BRIEF ) return;
  file_tree_name(zFileTreeName, &fname, 1);
  zName = blob_str(&fname);
  historical_version_of_file(zFrom, zName, &v1, &isLink1, 0,
                             fIncludeBinary ? 0 : &eType, 0);
  historical_version_of_file(zTo, zName, &v2, &isLink2, 0,
                             fIncludeBinary ? 0 : &eType2, 0);
  if( isLink1 != isLink2 ){
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print(DIFF_CANNOT_COMPUTE_SYMLINK);
  }else if( eType!=eType2 ){
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print(DIFF_CANNOT_COMPUTE_ENCODING);
  }else{
    diff_file_mem(&v1, &v2, eType, zName, zDiffCmd,
                  zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&fname);
}

................................................................................
  struct ManifestFile *pTo,
  const char *zDiffCmd,
  const char *zBinGlob,
  int fIncludeBinary,
  u64 diffFlags
){
  Blob f1, f2;
  int eType = 0, eType2 = 0;
  int rid;
  const char *zName =  pFrom ? pFrom->zName : pTo->zName;
  if( diffFlags & DIFF_BRIEF ) return;
  diff_print_index(zName, diffFlags);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
................................................................................
  }
  if( pTo ){
    rid = uuid_to_rid(pTo->zUuid, 0);
    content_get(rid, &f2);
  }else{
    blob_zero(&f2);
  }
  if ( !fIncludeBinary ){
    eType = looks_like_text(&f1);
    eType2 = looks_like_text(&f2);
  }
  if( eType!=eType2 ){
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print(DIFF_CANNOT_COMPUTE_ENCODING);
  }else{
    diff_file_mem(&f1, &f2, eType, zName, zDiffCmd,
                  zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&f1);
  blob_reset(&f2);
}

/*
** Output the differences between two check-ins.
**

Changes to src/stash.c.

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

338
339
340
341
342
343
344
345
...
352
353
354
355
356
357
358
359
360
361







362

363
364
365
366
367
368
369
370
371
372
373
374
375
376
     "  FROM stashfile WHERE stashid=%d",
     stashid
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    int isRemoved = db_column_int(&q, 1);
    int isLink = db_column_int(&q, 3);
    int isBin1, isBin2;
    const char *zOrig = db_column_text(&q, 4);
    const char *zNew = db_column_text(&q, 5);
    char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
    Blob delta, a, b, disk;
    if( rid==0 ){
      db_ephemeral_blob(&q, 6, &a);
      fossil_print("ADDED %s\n", zNew);
      diff_print_index(zNew, diffFlags);
      isBin1 = 0;
      isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);

      diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else if( isRemoved ){
      fossil_print("DELETE %s\n", zOrig);
      if( fBaseline==0 ){
        if( file_wd_islink(zOPath) ){
          blob_read_link(&a, zOPath);
        }else{
          blob_read_from_file(&a, zOPath);
        }
      }else{
        content_get(rid, &a);
      }
      diff_print_index(zNew, diffFlags);
      isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
      isBin2 = 0;

      diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else{
      int isOrigLink = file_wd_islink(zOPath);
      db_ephemeral_blob(&q, 6, &delta);
      if( fBaseline==0 ){
        if( isOrigLink ){
          blob_read_link(&disk, zOPath);
................................................................................
        diff_print_index(zNew, diffFlags);
        diff_print_filenames(zOrig, zNew, diffFlags);
        printf(DIFF_CANNOT_COMPUTE_SYMLINK);
      }else{
        Blob *pBase = fBaseline ? &a : &disk;
        content_get(rid, &a);
        blob_delta_apply(&a, &delta, &b);
        isBin1 = fIncludeBinary ? 0 : looks_like_binary(pBase);
        isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
        diff_file_mem(fBaseline? &a : &disk, &b, isBin1, isBin2, zNew,







                      zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);

        blob_reset(&a);
        blob_reset(&b);
      }
      if( !fBaseline ) blob_reset(&disk);
    }
    blob_reset(&delta);
 }
  db_finalize(&q);
}

/*
** Drop the indicated stash
*/
static void stash_drop(int stashid){






|








|
|
>
|













|
|
>
|







 







|
|
|
>
>
>
>
>
>
>
|
>






|







304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
     "  FROM stashfile WHERE stashid=%d",
     stashid
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    int isRemoved = db_column_int(&q, 1);
    int isLink = db_column_int(&q, 3);
    int eType = 0;
    const char *zOrig = db_column_text(&q, 4);
    const char *zNew = db_column_text(&q, 5);
    char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
    Blob delta, a, b, disk;
    if( rid==0 ){
      db_ephemeral_blob(&q, 6, &a);
      fossil_print("ADDED %s\n", zNew);
      diff_print_index(zNew, diffFlags);
      if( !fIncludeBinary ){
        eType = looks_like_text(&a);
      }
      diff_file_mem(&empty, &a, eType, zNew, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else if( isRemoved ){
      fossil_print("DELETE %s\n", zOrig);
      if( fBaseline==0 ){
        if( file_wd_islink(zOPath) ){
          blob_read_link(&a, zOPath);
        }else{
          blob_read_from_file(&a, zOPath);
        }
      }else{
        content_get(rid, &a);
      }
      diff_print_index(zNew, diffFlags);
      if( !fIncludeBinary){
        eType = looks_like_text(&a);
      }
      diff_file_mem(&a, &empty, eType, zOrig, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else{
      int isOrigLink = file_wd_islink(zOPath);
      db_ephemeral_blob(&q, 6, &delta);
      if( fBaseline==0 ){
        if( isOrigLink ){
          blob_read_link(&disk, zOPath);
................................................................................
        diff_print_index(zNew, diffFlags);
        diff_print_filenames(zOrig, zNew, diffFlags);
        printf(DIFF_CANNOT_COMPUTE_SYMLINK);
      }else{
        Blob *pBase = fBaseline ? &a : &disk;
        content_get(rid, &a);
        blob_delta_apply(&a, &delta, &b);
        int eType2 = 0;
        if( !fIncludeBinary ){
          eType = looks_like_text(pBase);
          eType2 = looks_like_text(&b);
        }
        if( eType!=eType2 ){
          diff_print_filenames(zOrig, zNew, diffFlags);
          printf(DIFF_CANNOT_COMPUTE_ENCODING);
        }else{
          diff_file_mem(pBase, &b, eType, zNew, zDiffCmd,
                        zBinGlob, fIncludeBinary, diffFlags);
        }
        blob_reset(&a);
        blob_reset(&b);
      }
      if( !fBaseline ) blob_reset(&disk);
    }
    blob_reset(&delta);
  }
  db_finalize(&q);
}

/*
** Drop the indicated stash
*/
static void stash_drop(int stashid){

Changes to src/update.c.

598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
*/
int historical_version_of_file(
  const char *revision,    /* The checkin containing the file */
  const char *file,        /* Full treename of the file */
  Blob *content,           /* Put the content here */
  int *pIsLink,            /* Set to true if file is link. */
  int *pIsExe,             /* Set to true if file is executable */
  int *pIsBin,             /* Set to true if file is binary */
  int errCode              /* Error code if file not found.  Panic if 0. */
){
  Manifest *pManifest;
  ManifestFile *pFile;
  int rid=0;
  
  if( revision ){
................................................................................
    if( pFile ){
      int rc;
      rid = uuid_to_rid(pFile->zUuid, 0);
      if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE );
      if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK );
      manifest_destroy(pManifest);
      rc = content_get(rid, content);
      if( rc && pIsBin ){
        *pIsBin = looks_like_binary(content);
      }
      return rc;
    }
    manifest_destroy(pManifest);
    if( errCode<=0 ){
      fossil_fatal("file %s does not exist in checkin: %s", file, revision);
    }






|







 







|
|







598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
*/
int historical_version_of_file(
  const char *revision,    /* The checkin containing the file */
  const char *file,        /* Full treename of the file */
  Blob *content,           /* Put the content here */
  int *pIsLink,            /* Set to true if file is link. */
  int *pIsExe,             /* Set to true if file is executable */
  int *pEType,             /* Set to file type, look_like_text()&3 */
  int errCode              /* Error code if file not found.  Panic if 0. */
){
  Manifest *pManifest;
  ManifestFile *pFile;
  int rid=0;
  
  if( revision ){
................................................................................
    if( pFile ){
      int rc;
      rid = uuid_to_rid(pFile->zUuid, 0);
      if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE );
      if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK );
      manifest_destroy(pManifest);
      rc = content_get(rid, content);
      if( rc && pEType ){
        *pEType = looks_like_text(content);
      }
      return rc;
    }
    manifest_destroy(pManifest);
    if( errCode<=0 ){
      fossil_fatal("file %s does not exist in checkin: %s", file, revision);
    }