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 ea2598e447 to af4d780446

2013-04-05
07:44
Branches "use-blob_strip_bom" and "improve_commit_warning" go together in a single new (experimental) branch check-in: a7e77a66b0 user: jan.nijtmans tags: ui-no-utf8
2013-03-19
14:12
take over new testcases from bomRefactor branch. check-in: f58bc2dfc7 user: jan.nijtmans tags: trunk
10:06
merge trunk (still experimental) Closed-Leaf check-in: af4d780446 user: jan.nijtmans tags: use-blob_strip_bom
08:59
Merge "cr-warning" branch to trunk: Fossil now warns before committing files with CR line-endings and offers to convert them to LF line-endings; fossil's diff cannot handle those. In checkin.c, use LOOK_BINARY in stead of LOOK_NUL, in case more flags are added to the BINARY detection. Rename LOOK_LENGTH to LOOK_LONG. check-in: ea2598e447 user: jan.nijtmans tags: trunk
2013-03-18
12:37
Adapt test-case 112 such that it contains a reversed CR/LF, a case not covered before. Fix detection of reversed CR/LF and lone CR in reversed UTF-16 case, broken by [e3f9a42b58]. check-in: a4cdc7235a user: jan.nijtmans tags: trunk
2013-03-15
12:53
(expirimental) First implementation of "CR line endings" warning. Closed-Leaf check-in: 5a886cfd9b user: jan.nijtmans tags: cr-warning
2013-02-27
11:30
comment fix check-in: f78a487f43 user: jan.nijtmans tags: use-blob_strip_bom

Changes to src/blob.c.

1090
1091
1092
1093
1094
1095
1096

1097
1098
1099
1100
1101

1102
1103
1104
1105
1106
1107
1108
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110







+





+







}

/*
** Strip a possible byte-order-mark (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.
** If useMbcs is 2, any BOM is replaced by the UTF-8 BOM
*/
void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
  char *zUtf8;
  int bomSize = 0;
  int bomReverse = 0;

  if( starts_with_utf8_bom(pBlob, &bomSize) ){
    struct Blob temp;
    zUtf8 = blob_str(pBlob) + bomSize;
    blob_zero(&temp);
    blob_append(&temp, zUtf8, -1);
    blob_swap(pBlob, &temp);
    blob_reset(&temp);
1120
1121
1122
1123
1124
1125
1126




1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144







+
+
+
+












      }
    }
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + bomSize;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    if( useMbcs>1 ){
      const unsigned char *bom = get_utf8_bom(&bomSize);
      blob_append(pBlob, (char*)bom, bomSize);
    }
    blob_append(pBlob, zUtf8, -1);
    fossil_unicode_free(zUtf8);
#endif /* _WIN32 ||  __CYGWIN__ */
#if defined(_WIN32)
  }else if( useMbcs ){
    zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
    blob_reset(pBlob);
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
#endif /* _WIN32 */
  }
}

Changes to src/checkin.c.

917
918
919
920
921
922
923
924

925
926
927
928
929
930
931

932
933
934
935

936
937

938
939
940
941
942
943
944
917
918
919
920
921
922
923

924
925
926
927
928
929
930

931
932
933
934

935
936

937
938
939
940
941
942
943
944







-
+






-
+



-
+

-
+







  if( allOk ) return 0;
  fUnicode = could_be_utf16(p, &bReverse);
  if( fUnicode ){
    lookFlags = looks_like_utf16(p, bReverse);
  }else{
    lookFlags = looks_like_utf8(p);
  }
  if( lookFlags&(LOOK_BINARY|LOOK_LONG|LOOK_LONE_CR|LOOK_CRLF) || fUnicode ){
  if( !lookFlags || lookFlags&(LOOK_LONG|LOOK_LONE_CR|LOOK_CRLF|LOOK_UNICODE) ){
    const char *zWarning;
    const char *zDisable;
    const char *zConvert = "c=convert/";
    Blob ans;
    char cReply;

    if( lookFlags&(LOOK_BINARY|LOOK_LONG) ){
    if( !lookFlags || (lookFlags&LOOK_LONG) ){
      if( binOk ){
        return 0; /* We don't want binary warnings for this file. */
      }
      if( (lookFlags&LOOK_LONE_CR) && !(lookFlags&LOOK_NUL) ){
      if( lookFlags&LOOK_LONE_CR ){
        zWarning = "CR line endings (would be handled as binary)";
      }else if( (lookFlags&LOOK_LONG) && !(lookFlags&LOOK_NUL) ){
      }else if( lookFlags&LOOK_LONG ){
        zWarning = "long lines";
        zConvert = ""; /* We cannot convert binary files. */
      }else{
        zWarning = "binary data";
        zConvert = ""; /* We cannot convert binary files. */
      }
      zDisable = "\"binary-glob\" setting";

Changes to src/diff.c.

46
47
48
49
50
51
52



53
54
55
56
57
58
59
60
61
62
63
64


65






66




67
68
69
70
71
72
73
74
75
76
77
78
79
80









81
82
83
84
85
86
87
88
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
71
72
73
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







+
+
+










-
-
+
+

+
+
+
+
+
+
-
+
+
+
+






-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-







/*
** 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 DIFF_TOO_MANY_CHANGES_TXT \
    "more than 10,000 changes\n"

#define DIFF_TOO_MANY_CHANGES_HTML \
    "<p class='generalError'>More than 10,000 changes</p>\n"

/*
** This macro is designed to return non-zero if the specified blob contains
** data that MAY be binary in nature; otherwise, zero will be returned.
** This macro is designed to return zero if the specified blob is binary
** in nature (contains NUL bytes).
*/
#define looks_like_text(lookFlags, blob) \
  do { \
    int result = 0; \
    if (could_be_utf16(blob, &result)) { \
      result = looks_like_utf16(blob, result); \
    }else{ \
#define looks_like_binary(blob) ((looks_like_utf8(blob)&LOOK_BINARY)!=LOOK_NONE)
      result = looks_like_utf8(blob); \
    } \
    (lookFlags) = result&(LOOK_TEXT|LOOK_LONG); \
  }while(0)

/*
** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
** to convey status information about the blob content.
*/
#define LOOK_NONE    ((int)0x00000000) /* Nothing special was found. */
#define LOOK_NUL     ((int)0x00000001) /* One or more NUL chars were found. */
#define LOOK_CR      ((int)0x00000002) /* One or more CR chars were found. */
#define LOOK_LONE_CR ((int)0x00000004) /* An unpaired CR char was found. */
#define LOOK_LF      ((int)0x00000008) /* One or more LF chars were found. */
#define LOOK_LONE_LF ((int)0x00000010) /* An unpaired CR char was found. */
#define LOOK_CRLF    ((int)0x00000020) /* One or more CR/LF pairs were found. */
#define LOOK_LONG    ((int)0x00000040) /* An over length line was found. */
#define LOOK_ODD     ((int)0x00000080) /* An odd number of bytes was found. */
#define LOOK_UNICODE ((int)0x00000002) /* Might contain valid Unicode. */
#define LOOK_TEXT    ((int)0x00000003) /* 0=binary,1=text, 2=UTF16, 3=reversed-UTF16 */
#define LOOK_CR      ((int)0x00000004) /* One or more CR chars were found. */
#define LOOK_LONE_CR ((int)0x00000008) /* An unpaired CR char was found. */
#define LOOK_LF      ((int)0x00000010) /* One or more LF chars were found. */
#define LOOK_LONE_LF ((int)0x00000020) /* An unpaired CR char was found. */
#define LOOK_CRLF    ((int)0x00000040) /* One or more CR/LF pairs were found. */
#define LOOK_LONG    ((int)0x00000080) /* An over length line was found. */
#define LOOK_ODD     ((int)0x00000100) /* An odd number of bytes was found. */
#define LOOK_BINARY  (LOOK_NUL | LOOK_LONG) /* Binary. */
#endif /* INTERFACE */

/*
** Maximum length of a line in a text file, in bytes.  (2**13 = 8192 bytes)
*/
#define LENGTH_MASK_SZ  13
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)
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
245
246
247
248
249
250
251

252
253
254
255
256

257
258
259
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277







-
+




-
+












-
+







** officially unspecified.
**
************************************ WARNING **********************************
*/
int looks_like_utf8(const Blob *pContent){
  const char *z = blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  int j, c, flags = LOOK_NONE;  /* Assume UTF-8 text, prove otherwise */
  int j, c, flags = 1;  /* Assume UTF-8 text, prove otherwise */

  if( n==0 ) return flags;  /* Empty file -> text */
  c = *z;
  if( c==0 ){
    flags |= LOOK_NUL;  /* NUL character in a file -> binary */
    return 0;  /* NUL character in a file -> binary */
  }else if( c=='\r' ){
    flags |= LOOK_CR;
    if( n<=1 || z[1]!='\n' ){
      flags |= LOOK_LONE_CR;  /* More chars, next char is not LF */
    }
  }
  j = (c!='\n');
  if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF);  /* Found LF as first char */
  while( --n>0 ){
    int c2 = c;
    c = *++z; ++j;
    if( c==0 ){
      flags |= LOOK_NUL;  /* NUL character in a file -> binary */
      return 0;  /* NUL character in a file -> binary */
    }else if( c=='\n' ){
      flags |= LOOK_LF;
      if( c2=='\r' ){
        flags |= LOOK_CRLF;  /* Found LF preceded by CR */
      }else{
        flags |= LOOK_LONE_LF;
      }
288
289
290
291
292
293
294
295
296
297




298
299
300

301
302
303
304
305
306
307
300
301
302
303
304
305
306



307
308
309
310
311


312
313
314
315
316
317
318
319







-
-
-
+
+
+
+

-
-
+







#    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.
** 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_SZ  (LENGTH_MASK_SZ-(sizeof(WCHAR_T)-sizeof(char)))
#define UTF16_LENGTH_MASK     ((1<<UTF16_LENGTH_MASK_SZ)-1)
#define UTF16_LENGTH_MASK     (LENGTH_MASK/3)

/*
** This macro is used to swap the byte order of a UTF-16 character in the
** looks_like_utf16() function.
*/
#define UTF16_SWAP(ch)        (((ch) << 8) & 0xFF00) | (((ch) >> 8) & 0xFF)

336
337
338
339
340
341
342
343

344
345
346
347
348
349
350
351
352
353



354
355
356
357
358
359
360
361
362
363
364
365
366



367
368
369
370
371
372
373
348
349
350
351
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
377
378
379
380
381
382
383
384
385







-
+







-
-
-
+
+
+










-
-
-
+
+
+







** officially unspecified.
**
************************************ WARNING **********************************
*/
int looks_like_utf16(const Blob *pContent, int bReverse){
  const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  int j, c, flags = LOOK_NONE;  /* Assume UTF-16 text, prove otherwise */
  int j, c, flags = 2|(bReverse!=0);  /* Assume UTF-16 text, prove otherwise */

  if( n==0 ) return flags;  /* Empty file -> text */
  if( n%sizeof(WCHAR_T) ){
    flags |= LOOK_ODD;  /* Odd number of bytes -> binary (UTF-8?) */
    if( n<sizeof(WCHAR_T) ) return flags;  /* One byte -> binary (UTF-8?) */
  }
  c = *z;
  if( c==0 ){
    flags |= LOOK_NUL;  /* NUL character in a file -> binary */
  }else if( bReverse ){
  if( c==0 )
    return 0;  /* NUL character in a file -> binary */
  if( bReverse ){
    c = UTF16_SWAP(c);
  }
  j = (c!='\n');
  if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF);  /* Found LF as first char */
  while( 1 ){
    int c2 = c;
    n -= sizeof(WCHAR_T);
    if( n<sizeof(WCHAR_T) ) break;
    c = *++z;
    ++j;
    if( c==0 ){
      flags |= LOOK_NUL;  /* NUL character in a file -> binary */
    }else if( bReverse ){
    if( c==0 )
      return 0;  /* NUL character in a file -> binary */
    if( bReverse ){
      c = UTF16_SWAP(c);
    }
    if( c=='\n' ){
      if( c2=='\r' ){
        flags |= (LOOK_CRLF | LOOK_CR | LOOK_LF);
      }else{
        flags |= (LOOK_LONE_LF | LOOK_LF);
2534
2535
2536
2537
2538
2539
2540
2541
2542


2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2546
2547
2548
2549
2550
2551
2552


2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565







-
-
+
+











  lookFlags = fUnicode ? looks_like_utf16(&blob, bReverse) :
                       looks_like_utf8(&blob);
  fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
  fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
  fossil_print("Starts with UTF-16 BOM: %s\n",
               fUtf16?(bReverse?"reversed":"yes"):"no");
  fossil_print("Looks like UTF-%s: %s\n",fUnicode?"16":"8",
               (lookFlags&LOOK_BINARY)?"no":"yes");
  fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
               ((lookFlags==0) || (lookFlags&LOOK_LONG))?"no":"yes");
  fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags==0)?"yes":"no");
  fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
  fossil_print("Has flag LOOK_LONE_CR: %s\n",
               (lookFlags&LOOK_LONE_CR)?"yes":"no");
  fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
  fossil_print("Has flag LOOK_LONE_LF: %s\n",
               (lookFlags&LOOK_LONE_LF)?"yes":"no");
  fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
  fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
  fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
  blob_reset(&blob);
}

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
120
121
122
123
124
125
126
127
128
129
130

131

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159
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
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
167
168







-
+











+













+
+
-
+





+
+

+
+


















+
-
+




















-
+
+







**
** 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 */
  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 ){
      looks_like_text(eType2, &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_to_utf8_no_bom(pFile1, 2);
      blob_to_utf8_no_bom(&file2, 2);
      blob_zero(&out);
      text_diff(pFile1, &file2, &out, 0, diffFlags);
      if( blob_size(&out) ){
        diff_print_filenames(zName, zName2, diffFlags);
        fossil_print("%s\n", blob_str(&out));
      }
      blob_reset(&out);
    }

    /* Release memory resources */
    blob_reset(&file2);
  }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( isBin1 ){
      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);
          glob_free(pBinary);
          return;
        }
        glob_free(pBinary);
      }
      blob_zero(&file2);
      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) ){
      looks_like_text(eType2, &file2);
      if( (eType2&3)!=1 ){
        fossil_print(DIFF_CANNOT_COMPUTE_BINARY);
        blob_reset(&file2);
        return;
      }
      blob_reset(&file2);
    }

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
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







-
+
-











+
+












-
+







** 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 eType,                /* Does the content appear to be text */
  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);
    blob_to_utf8_no_bom(pFile1, 2);
    blob_to_utf8_no_bom(pFile2, 2);
    text_diff(pFile1, pFile2, &out, 0, 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 ){
      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);
280
281
282
283
284
285
286
287

288
289
290

291
292
293
294

295
296
297
298
299
300
301
290
291
292
293
294
295
296

297
298
299

300
301
302
303

304
305
306
307
308
309
310
311







-
+


-
+



-
+







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

/*
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
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







-
+











-
+
+
+

-
+







    }else if( isChnged==3 ){
      fossil_print("ADDED_BY_MERGE %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      int isBin;
      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);
      }
      isBin = fIncludeBinary ? 0 : looks_like_binary(&content);
      if( !fIncludeBinary ){
        looks_like_text(eType, &content);
      }
      diff_print_index(zPathname, diffFlags);
      diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
      diff_file(&content, eType, zFullName, zPathname, zDiffCmd,
                zBinGlob, fIncludeBinary, diffFlags);
      blob_reset(&content);
    }
    free(zToFree);
  }
  db_finalize(&q);
  db_end_transaction(1);  /* ROLLBACK */
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
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







-
+




-
+

-
+



+
+
+

-
+







  u64 diffFlags,
  const char *zFileTreeName
){
  char *zName;
  Blob fname;
  Blob v1, v2;
  int isLink1, isLink2;
  int isBin1, isBin2;
  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 : &isBin1, 0);
                             fIncludeBinary ? 0 : &eType, 0);
  historical_version_of_file(zTo, zName, &v2, &isLink2, 0,
                             fIncludeBinary ? 0 : &isBin2, 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, isBin1, isBin2, zName, zDiffCmd,
    diff_file_mem(&v1, &v2, eType, zName, zDiffCmd,
                  zBinGlob, fIncludeBinary, diffFlags);
  }
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&fname);
}

475
476
477
478
479
480
481
482

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502











503
504
505
506
507
508
509
490
491
492
493
494
495
496

497
498
499
500
501
502
503
504
505
506
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







-
+
















-
-
-
-
+
+
+
+
+
+
+
+
+
+
+







  struct ManifestFile *pTo,
  const char *zDiffCmd,
  const char *zBinGlob,
  int fIncludeBinary,
  u64 diffFlags
){
  Blob f1, f2;
  int isBin1, isBin2;
  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);
  }else{
    blob_zero(&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);
  if ( !fIncludeBinary ){
    looks_like_text(eType, &f1);
    looks_like_text(eType2, &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.

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
348
349
350
351
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
377
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
348
349
350
351
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
377
378
379

380
381
382
383
384
385
386
387







-
+








-
-
-
+
+
+
+













-
-
-
+
+
+
+




















+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+






-
+







     "  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;
    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);
      isBin1 = 0;
      isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
      diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
      if( !fIncludeBinary ){
        looks_like_text(eType, &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);
      isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
      isBin2 = 0;
      diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
      if( !fIncludeBinary){
        looks_like_text(eType, &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);
        }else{
          blob_read_from_file(&disk, zOPath);
        }
      }
      fossil_print("CHANGED %s\n", zNew);
      if( !isOrigLink != !isLink ){
        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;
        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);
        if( !fIncludeBinary ){
          looks_like_text(eType, pBase);
          looks_like_text(eType2, &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.

611
612
613
614
615
616
617
618

619
620
621
622
623
624
625
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625







-
+







*/
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 *pEType,             /* Set to file type, looks_like_text() */
  int errCode              /* Error code if file not found.  Panic if 0. */
){
  Manifest *pManifest;
  ManifestFile *pFile;
  int rid=0;
  
  if( revision ){
638
639
640
641
642
643
644
645
646


647
648
649
650
651
652
653
638
639
640
641
642
643
644


645
646
647
648
649
650
651
652
653







-
-
+
+







    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);
      if( rc && pEType ){
        looks_like_text(*pEType, content);
      }
      return rc;
    }
    manifest_destroy(pManifest);
    if( errCode<=0 ){
      fossil_fatal("file %s does not exist in checkin: %s", file, revision);
    }

Changes to win/Makefile.mingw.

11
12
13
14
15
16
17
18

19
20
21

22
23
24
25
26
27
28
11
12
13
14
15
16
17

18
19
20

21
22
23
24
25
26
27
28







-
+


-
+







# This is a makefile for use on Cygwin/Darwin/FreeBSD/Linux/Windows using
# MinGW or MinGW-w64.
#

#### Select one of MinGW, MinGW-w64 (32-bit) or MinGW-w64 (64-bit) compilers.
#    By default, this is an empty string (i.e. use the native compiler).
#
PREFIX =
# PREFIX =
# PREFIX = mingw32-
# PREFIX = i686-pc-mingw32-
# PREFIX = i686-w64-mingw32-
PREFIX = i686-w64-mingw32-
# PREFIX = x86_64-w64-mingw32-

#### The toplevel directory of the source tree.  Fossil can be built
#    in a directory that is separate from the source tree.  Just change
#    the following to point from the build directory to the src/ folder.
#
SRCDIR = src