Fossil

Check-in [bd7b8a48]
Login

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

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | improve_commit_warning
Files: files | file ages | folders
SHA1: bd7b8a485f969da0126db57f82305c679f412109
User & Date: jan.nijtmans 2012-11-04 10:50:47
Context
2012-11-04
18:00
merge trunk

Factor out main part of UTF-8 check to macro

check-in: ce7c5222 user: jan.nijtmans tags: improve_commit_warning
10:50
merge trunk check-in: bd7b8a48 user: jan.nijtmans tags: improve_commit_warning
10:48
merge trunk, some improvements in messages (not yet ready yet) check-in: 517a6f7a user: jan.nijtmans tags: improve_commit_warning
00:46
Disallow the sequence: "fossil mv A B; fossil add A; fossil commit A;" since doing so requires both the old A and the new A to be in the same check-in. Ticket [0ff64b0a5fc8]. check-in: 27298fff user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/blob.c.

1119
1120
1121
1122
1123
1124
1125
1126
1127

1128
1129
1130
1131
1132
1133
1134
    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 ) {
    zUtf8 = blob_buffer(pBlob);
    unsigned int i = blob_size(pBlob);

    while( i > 0 ){
        /* swap bytes of unicode representation */
        char temp = zUtf8[--i];
        zUtf8[i] = zUtf8[i-1];
        zUtf8[--i] = temp;
    }
    /* Make sure the blob contains two terminating 0-bytes */







<

>







1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1133
1134
    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 ){
        /* swap bytes of unicode representation */
        char temp = zUtf8[--i];
        zUtf8[i] = zUtf8[i-1];
        zUtf8[--i] = temp;
    }
    /* Make sure the blob contains two terminating 0-bytes */

Changes to src/checkin.c.

911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  if( eType<3){
    Blob ans;
    char cReply;

    blob_zero(&ans);
    file_relative_name(zFilename, &fname, 0);
    zMsg = mprintf(
         "%s appears to be text, but not UTF-8 or ASCII.  commit anyhow (a=all/y/N)? ",
         blob_str(&fname));
    prompt_user(zMsg, &ans);
    fossil_free(zMsg);
    cReply = blob_str(&ans)[0];
    if( cReply!='y' && cReply!='Y' ){
      fossil_fatal("Abandoning commit due to non-UTF-8 in %s",
                   blob_str(&fname));







|







911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  if( eType<3){
    Blob ans;
    char cReply;

    blob_zero(&ans);
    file_relative_name(zFilename, &fname, 0);
    zMsg = mprintf(
         "%s appears to be text, but not UTF-8 or ASCII.  commit anyhow (y/N)? ",
         blob_str(&fname));
    prompt_user(zMsg, &ans);
    fossil_free(zMsg);
    cReply = blob_str(&ans)[0];
    if( cReply!='y' && cReply!='Y' ){
      fossil_fatal("Abandoning commit due to non-UTF-8 in %s",
                   blob_str(&fname));

Changes to src/db.c.

2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
....
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
struct stControlSettings const ctrlSettings[] = {
  { "access-log",    0,                0, 0, "off"                 },
  { "allow-symlinks",0,                0, 1, "off"                 },
  { "auto-captcha",  "autocaptcha",    0, 0, "on"                  },
  { "auto-hyperlink",0,                0, 0, "on",                 },
  { "auto-shun",     0,                0, 0, "on"                  },
  { "autosync",      0,                0, 0, "on"                  },
  { "binary-glob",   0,               32, 1, ""                    },
  { "clearsign",     0,                0, 0, "off"                 },
  { "case-sensitive",0,                0, 0, "on"                  },
  { "crnl-glob",     0,               16, 1, ""                    },
  { "default-perms", 0,               16, 0, "u"                   },
  { "diff-binary",   0,                0, 0, "on"                  },
  { "diff-command",  0,               16, 0, ""                    },
  { "dont-push",     0,                0, 0, "off"                 },
  { "editor",        0,               16, 0, ""                    },
  { "gdiff-command", 0,               16, 0, "gdiff"               },
  { "gmerge-command",0,               40, 0, ""                    },
  { "https-login",   0,                0, 0, "off"                 },
  { "ignore-glob",   0,               40, 1, ""                    },
  { "empty-dirs",    0,               40, 1, ""                    },
  { "http-port",     0,               16, 0, "8080"                },
  { "localauth",     0,                0, 0, "off"                 },
  { "main-branch",   0,               40, 0, "trunk"               },
  { "manifest",      0,                0, 1, "off"                 },
  { "max-upload",    0,               25, 0, "250000"              },
  { "mtime-changes", 0,                0, 0, "on"                  },
  { "pgp-command",   0,               32, 0, "gpg --clearsign -o " },
  { "proxy",         0,               32, 0, "off"                 },
  { "relative-paths",0,                0, 0, "on"                  },
  { "repo-cksum",    0,                0, 0, "on"                  },
  { "self-register", 0,                0, 0, "off"                 },
  { "ssl-ca-location",0,              40, 0, ""                    },
  { "ssl-identity",  0,               40, 0, ""                    },
  { "ssh-command",   0,               32, 0, ""                    },
#ifdef FOSSIL_ENABLE_TCL
  { "tcl",           0,                0, 0, "off"                 },
  { "tcl-setup",     0,               40, 0, ""                    },
#endif
  { "web-browser",   0,               32, 0, ""                    },
  { "white-foreground", 0,             0, 0, "off"                 },
  { 0,0,0,0,0 }
................................................................................
**                     or update and automatically push after commit or
**                     tag or branch creation.  If the value is "pullonly"
**                     then only pull operations occur automatically.
**                     Default: on
**
**    binary-glob      The VALUE is a comma or newline-separated list of
**     (versionable)   GLOB patterns that should be treated as binary files
**                     for merging purposes.  Example:   *.xml
**
**    case-sensitive   If TRUE, the files whose names differ only in case
**                     care considered distinct.  If FALSE files whose names
**                     differ only in case are the same file.  Defaults to
**                     TRUE for unix and FALSE for windows and mac.
**
**    clearsign        When enabled, fossil will attempt to sign all commits







|


|


|

|
|










|






|







 







|







2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
....
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
struct stControlSettings const ctrlSettings[] = {
  { "access-log",    0,                0, 0, "off"                 },
  { "allow-symlinks",0,                0, 1, "off"                 },
  { "auto-captcha",  "autocaptcha",    0, 0, "on"                  },
  { "auto-hyperlink",0,                0, 0, "on",                 },
  { "auto-shun",     0,                0, 0, "on"                  },
  { "autosync",      0,                0, 0, "on"                  },
  { "binary-glob",   0,               40, 1, ""                    },
  { "clearsign",     0,                0, 0, "off"                 },
  { "case-sensitive",0,                0, 0, "on"                  },
  { "crnl-glob",     0,               40, 1, ""                    },
  { "default-perms", 0,               16, 0, "u"                   },
  { "diff-binary",   0,                0, 0, "on"                  },
  { "diff-command",  0,               40, 0, ""                    },
  { "dont-push",     0,                0, 0, "off"                 },
  { "editor",        0,               32, 0, ""                    },
  { "gdiff-command", 0,               40, 0, "gdiff"               },
  { "gmerge-command",0,               40, 0, ""                    },
  { "https-login",   0,                0, 0, "off"                 },
  { "ignore-glob",   0,               40, 1, ""                    },
  { "empty-dirs",    0,               40, 1, ""                    },
  { "http-port",     0,               16, 0, "8080"                },
  { "localauth",     0,                0, 0, "off"                 },
  { "main-branch",   0,               40, 0, "trunk"               },
  { "manifest",      0,                0, 1, "off"                 },
  { "max-upload",    0,               25, 0, "250000"              },
  { "mtime-changes", 0,                0, 0, "on"                  },
  { "pgp-command",   0,               40, 0, "gpg --clearsign -o " },
  { "proxy",         0,               32, 0, "off"                 },
  { "relative-paths",0,                0, 0, "on"                  },
  { "repo-cksum",    0,                0, 0, "on"                  },
  { "self-register", 0,                0, 0, "off"                 },
  { "ssl-ca-location",0,              40, 0, ""                    },
  { "ssl-identity",  0,               40, 0, ""                    },
  { "ssh-command",   0,               40, 0, ""                    },
#ifdef FOSSIL_ENABLE_TCL
  { "tcl",           0,                0, 0, "off"                 },
  { "tcl-setup",     0,               40, 0, ""                    },
#endif
  { "web-browser",   0,               32, 0, ""                    },
  { "white-foreground", 0,             0, 0, "off"                 },
  { 0,0,0,0,0 }
................................................................................
**                     or update and automatically push after commit or
**                     tag or branch creation.  If the value is "pullonly"
**                     then only pull operations occur automatically.
**                     Default: on
**
**    binary-glob      The VALUE is a comma or newline-separated list of
**     (versionable)   GLOB patterns that should be treated as binary files
**                     for committing and merging purposes.  Example: *.jpg
**
**    case-sensitive   If TRUE, the files whose names differ only in case
**                     care considered distinct.  If FALSE files whose names
**                     differ only in case are the same file.  Defaults to
**                     TRUE for unix and FALSE for windows and mac.
**
**    clearsign        When enabled, fossil will attempt to sign all commits

Changes to src/diff.c.

191
192
193
194
195
196
197











198
199
200
201
202
203
204
...
271
272
273
274
275
276
277











278
279
280
281
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
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
**         delimited by line-feed characters; however, the encoding is
**         not UTF-8 or ASCII.
**
** (-5) -- The content appears to consist entirely of text, with lines
**         delimited by carriage-return, line-feed pairs; however, the
**         encoding is not UTF-8 or ASCII.
**











*/

int looks_like_utf8(const Blob *pContent){
  unsigned char *z = (unsigned char *) blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  unsigned int j;
  unsigned char c;
................................................................................
  if( j>LENGTH_MASK ){
    return 0;  /* Very long line -> binary */
  }
  return 1-result;  /* No problems seen -> not binary */
}

/*











** Maximum length of a line in a text file, in UTF-16 characters.  (2731)
** The number of bytes represented by this value after conversion to
** UTF-8 (which can increase the size by 50%) cannot exceed LENGTH_MASK
** bytes, because that is the line buffer size 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')
#define UTF16LE_CR  (((wchar_t)'\r')<<(sizeof(wchar_t)<<2))
#define UTF16LE_LF  (((wchar_t)'\n')<<(sizeof(wchar_t)<<2))
#define UTF16_FFFF  ((wchar_t)-1)

/*
** This function attempts to scan each logical line within the blob to
** determine the type of content it appears to contain.  Possible return
** values are:
**
**  (1) -- The content appears to consist entirely of text, with lines
................................................................................
**         does not understand UTF-8, it may falsely consider UTF-8 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-16.
**











*/
int looks_like_utf16(const Blob *pContent){
  const wchar_t *z = (wchar_t *)blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  int j, c;
  int result = 1;  /* Assume UTF-16 text with no CR/NL */

  /* Check individual lines.
  */
  if( n==0 ) return result;  /* Empty file -> text */
  if( n%2 ) return 0;  /* Odd number of bytes -> binary (or UTF-8) */
  c = *z;
  if( c==0 ) return 0;  /* NUL character in a file -> binary */
  j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
  while( (n-=2)>0 ){
    c = *++z; ++j;
    if( c==0 || c==UTF16_FFFF ) return 0;  /* NUL/FFFF character in a file -> binary */
    if( c==UTF16BE_LF || c==UTF16LE_LF ){
      int c2 = z[-1];
      if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
        result = -1;  /* Contains CR/NL, continue */
      }
      if( j>UTF16_LENGTH_MASK ){
        return 0;  /* Very long line -> binary */







>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
|
|
<


>
|





|
|
|
|
<







 







>
>
>
>
>
>
>
>
>
>
>


|













|







191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301

302
303
304
305
306
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
...
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
**         delimited by line-feed characters; however, the encoding is
**         not UTF-8 or ASCII.
**
** (-5) -- The content appears to consist entirely of text, with lines
**         delimited by carriage-return, line-feed pairs; however, the
**         encoding is not UTF-8 or ASCII.
**
************************************ 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
** validate any code points.  It makes no attempt to detect if any [invalid]
** switches between UTF-8 and other encodings occur.
**
** The only code points that this function cares about are the NUL character,
** carriage-return, and line-feed.
**
************************************ WARNING **********************************
*/

int looks_like_utf8(const Blob *pContent){
  unsigned char *z = (unsigned char *) blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  unsigned int j;
  unsigned char c;
................................................................................
  if( j>LENGTH_MASK ){
    return 0;  /* Very long line -> binary */
  }
  return 1-result;  /* No problems seen -> not binary */
}

/*
** Define the type needed to represent a Unicode (UTF-16) character.
*/
#ifndef WCHAR_T
#  ifdef _WIN32
#    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')
#define UTF16LE_CR  (((WCHAR_T)'\r')<<(sizeof(char)<<3))
#define UTF16LE_LF  (((WCHAR_T)'\n')<<(sizeof(char)<<3))


/*
** This function attempts to scan each logical line within the blob to
** determine the type of content it appears to contain.  Possible return
** values are:
**
**  (1) -- The content appears to consist entirely of text, with lines
................................................................................
**         does not understand UTF-8, it may falsely consider UTF-8 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-16.
**
************************************ WARNING **********************************
**
** This function does not validate that the blob content is properly formed
** UTF-16.  It assumes that all code points are the same size.  It does not
** validate any code points.  It makes no attempt to detect if any [invalid]
** switches between the UTF-16be and UTF-16le encodings occur.
**
** The only code points that this function cares about are the NUL character,
** carriage-return, and line-feed.
**
************************************ WARNING **********************************
*/
int looks_like_utf16(const Blob *pContent){
  const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
  unsigned int n = blob_size(pContent);
  int j, c;
  int result = 1;  /* Assume UTF-16 text with no CR/NL */

  /* Check individual lines.
  */
  if( n==0 ) return result;  /* Empty file -> text */
  if( n%2 ) return 0;  /* Odd number of bytes -> binary (or UTF-8) */
  c = *z;
  if( c==0 ) return 0;  /* NUL character in a file -> binary */
  j = ((c!=UTF16BE_LF) && (c!=UTF16LE_LF));
  while( (n-=2)>0 ){
    c = *++z; ++j;
    if( c==0 ) return 0;  /* NUL character in a file -> binary */
    if( c==UTF16BE_LF || c==UTF16LE_LF ){
      int c2 = z[-1];
      if( c2==UTF16BE_CR || c2==UTF16LE_CR ){
        result = -1;  /* Contains CR/NL, continue */
      }
      if( j>UTF16_LENGTH_MASK ){
        return 0;  /* Very long line -> binary */

Changes to src/main.c.

339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#endif
  free(g.zErrMsg);
  if(g.db){
    db_close(0);
  }
}

#if defined(_WIN32)
/*
** Parse the command-line arguments passed to windows.  We do this
** ourselves to work around bugs in the command-line parsing of MinGW.
** It is possible (in theory) to only use this routine when compiling
** with MinGW and to use built-in command-line parsing for MSVC and
** MinGW-64.  However, the code is here, it is efficient, and works, and
** by using it in all cases we do a better job of testing it.  If you suspect
................................................................................
    *arg = '\0';
    argSpace = arg + 1;
  }
  argv[argc] = NULL;
  *argcPtr = argc;
  *((WCHAR ***)argvPtr) = argv;
}
#endif /* defined(_WIN32) */


/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
................................................................................
  unsigned int nLine;       /* Number of lines in the file*/
  unsigned int i, j, k;     /* Loop counters */
  int n;                    /* Number of bytes in one line */
  char *z;                  /* General use string pointer */
  char **newArgv;           /* New expanded g.argv under construction */
  char const * zFileName;   /* input file name */
  FILE * zInFile;           /* input FILE */
#ifdef _WIN32
  WCHAR buf[MAX_PATH];
#endif

  g.argc = argc;
  g.argv = argv;
#ifdef _WIN32
  parse_windows_command_line(&g.argc, &g.argv);
  GetModuleFileNameW(NULL, buf, MAX_PATH);
  g.nameOfExe = fossil_unicode_to_utf8(buf);
  for(i=0; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]);
#else
  g.nameOfExe = g.argv[0];
#endif







|







 







|







 







|





|







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#endif
  free(g.zErrMsg);
  if(g.db){
    db_close(0);
  }
}

#if defined(_WIN32) && !defined(__MINGW32__)
/*
** Parse the command-line arguments passed to windows.  We do this
** ourselves to work around bugs in the command-line parsing of MinGW.
** It is possible (in theory) to only use this routine when compiling
** with MinGW and to use built-in command-line parsing for MSVC and
** MinGW-64.  However, the code is here, it is efficient, and works, and
** by using it in all cases we do a better job of testing it.  If you suspect
................................................................................
    *arg = '\0';
    argSpace = arg + 1;
  }
  argv[argc] = NULL;
  *argcPtr = argc;
  *((WCHAR ***)argvPtr) = argv;
}
#endif /* defined(_WIN32) && !defined(__MINGW32__) */


/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
................................................................................
  unsigned int nLine;       /* Number of lines in the file*/
  unsigned int i, j, k;     /* Loop counters */
  int n;                    /* Number of bytes in one line */
  char *z;                  /* General use string pointer */
  char **newArgv;           /* New expanded g.argv under construction */
  char const * zFileName;   /* input file name */
  FILE * zInFile;           /* input FILE */
#if defined(_WIN32) && !defined(__MINGW32__)
  WCHAR buf[MAX_PATH];
#endif

  g.argc = argc;
  g.argv = argv;
#if defined(_WIN32) && !defined(__MINGW32__)
  parse_windows_command_line(&g.argc, &g.argv);
  GetModuleFileNameW(NULL, buf, MAX_PATH);
  g.nameOfExe = fossil_unicode_to_utf8(buf);
  for(i=0; i<g.argc; i++) g.argv[i] = fossil_unicode_to_utf8(g.argv[i]);
#else
  g.nameOfExe = g.argv[0];
#endif

Changes to src/md5.c.

431
432
433
434
435
436
437

438
439
440
441
442
443
444
445
446
447
*/
void md5sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  
  for(i=2; i<g.argc; i++){

    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      md5sum_blob(&in, &cksum);
    }else{
      md5sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}







>










431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
*/
void md5sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  
  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "********** not found ***********", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      md5sum_blob(&in, &cksum);
    }else{
      md5sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}

Changes to src/timeline.c.

200
201
202
203
204
205
206

207
208
209
210
211
212
213
...
251
252
253
254
255
256
257
258
259
260
261




262
263
264
265
266
267
268
...
459
460
461
462
463
464
465
466
467
468
469
470
471
472



473
474
475
476
477
478
479
...
939
940
941
942
943
944
945

946
947
948
949
950
951
952
...
955
956
957
958
959
960
961

962

963



964


965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
  int suppressCnt = 0;
  char zPrevDate[20];
  GraphContext *pGraph = 0;
  int prevWasDivider = 0;     /* True if previous output row was <hr> */
  int fchngQueryInit = 0;     /* True if fchngQuery is initialized */
  Stmt fchngQuery;            /* Query for file changes on check-ins */
  static Stmt qbranch;


  zPrevDate[0] = 0;
  mxWikiLen = db_get_int("timeline-max-comment", 0);
  if( db_get_boolean("timeline-block-markup", 0) ){
    wikiFlags = WIKI_INLINE;
  }else{
    wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
................................................................................
        }else{
          commentColumn = 10;
        }
      }
    }
    prevTagid = tagid;
    if( suppressCnt ){
      @ <tr><td /><td /><td>
      @ <span class="timelineDisabled">... %d(suppressCnt) similar
      @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
      suppressCnt = 0;




    }
    if( fossil_strcmp(zType,"div")==0 ){
      if( !prevWasDivider ){
        @ <tr><td colspan="3"><hr /></td></tr>
      }
      prevWasDivider = 1;
      continue;
................................................................................
        }
      }
      db_reset(&fchngQuery);
      if( inUl ){
        @ </ul>
      }
    }
    @ </td></tr>
  }
  if( suppressCnt ){
    @ <tr><td /><td /><td>
    @ <span class="timelineDisabled">... %d(suppressCnt) similar
    @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
    suppressCnt = 0;



  }
  if( pGraph ){
    graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
    if( pGraph->nErr ){
      graph_free(pGraph);
      pGraph = 0;
    }else{
................................................................................
    p_rid = d_rid = pd_rid;
  }
  login_check_credentials();
  if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){
    login_needed();
    return;
  }

  if( zTagName && g.perm.Read ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
    zThisTag = zTagName;
  }else if( zBrName && g.perm.Read ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
    zThisTag = zBrName;
  }else{
................................................................................
  if( zType[0]=='a' ){
    tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
  }else{
    tmFlags = TIMELINE_GRAPH;
  }
  if( P("ng")!=0 || zSearch!=0 ){
    tmFlags &= ~TIMELINE_GRAPH;

  }

  if( P("brbg")!=0 ) tmFlags |= TIMELINE_BRCOLOR;



  if( P("ubg")!=0 ) tmFlags |= TIMELINE_UCOLOR;



  style_header("Timeline");
  login_anonymous_available();
  timeline_temp_table();
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);
  url_initialize(&url, "timeline");
  if( P("fc")!=0 || P("detail")!=0 ){
    tmFlags |= TIMELINE_FCHANGES;
    url_add_parameter(&url, "fc", 0);
  }
  if( !useDividers ) url_add_parameter(&url, "nd", 0);
  if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
    /* If from= and to= are present, display all nodes on a path connecting







>







 







<



>
>
>
>







 







|


<



>
>
>







 







>







 







>

>
|
>
>
>
|
>
>








<







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
269
270
271
272
...
463
464
465
466
467
468
469
470
471
472

473
474
475
476
477
478
479
480
481
482
483
484
485
...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
...
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986

987
988
989
990
991
992
993
  int suppressCnt = 0;
  char zPrevDate[20];
  GraphContext *pGraph = 0;
  int prevWasDivider = 0;     /* True if previous output row was <hr> */
  int fchngQueryInit = 0;     /* True if fchngQuery is initialized */
  Stmt fchngQuery;            /* Query for file changes on check-ins */
  static Stmt qbranch;
  int pendingEndTr = 0;       /* True if a </td></tr> is needed */

  zPrevDate[0] = 0;
  mxWikiLen = db_get_int("timeline-max-comment", 0);
  if( db_get_boolean("timeline-block-markup", 0) ){
    wikiFlags = WIKI_INLINE;
  }else{
    wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
................................................................................
        }else{
          commentColumn = 10;
        }
      }
    }
    prevTagid = tagid;
    if( suppressCnt ){

      @ <span class="timelineDisabled">... %d(suppressCnt) similar
      @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
      suppressCnt = 0;
    }
    if( pendingEndTr ){
      @ </td></tr>
      pendingEndTr = 0;
    }
    if( fossil_strcmp(zType,"div")==0 ){
      if( !prevWasDivider ){
        @ <tr><td colspan="3"><hr /></td></tr>
      }
      prevWasDivider = 1;
      continue;
................................................................................
        }
      }
      db_reset(&fchngQuery);
      if( inUl ){
        @ </ul>
      }
    }
    pendingEndTr = 1;
  }
  if( suppressCnt ){

    @ <span class="timelineDisabled">... %d(suppressCnt) similar
    @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
    suppressCnt = 0;
  }
  if( pendingEndTr ){
    @ </td></tr>
  }
  if( pGraph ){
    graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
    if( pGraph->nErr ){
      graph_free(pGraph);
      pGraph = 0;
    }else{
................................................................................
    p_rid = d_rid = pd_rid;
  }
  login_check_credentials();
  if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){
    login_needed();
    return;
  }
  url_initialize(&url, "timeline");
  if( zTagName && g.perm.Read ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
    zThisTag = zTagName;
  }else if( zBrName && g.perm.Read ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
    zThisTag = zBrName;
  }else{
................................................................................
  if( zType[0]=='a' ){
    tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
  }else{
    tmFlags = TIMELINE_GRAPH;
  }
  if( P("ng")!=0 || zSearch!=0 ){
    tmFlags &= ~TIMELINE_GRAPH;
    url_add_parameter(&url, "ng", 0);
  }
  if( P("brbg")!=0 ){
    tmFlags |= TIMELINE_BRCOLOR;
    url_add_parameter(&url, "brbg", 0);
  }
  if( P("ubg")!=0 ){
    tmFlags |= TIMELINE_UCOLOR;
    url_add_parameter(&url, "ubg", 0);
  }

  style_header("Timeline");
  login_anonymous_available();
  timeline_temp_table();
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);

  if( P("fc")!=0 || P("detail")!=0 ){
    tmFlags |= TIMELINE_FCHANGES;
    url_add_parameter(&url, "fc", 0);
  }
  if( !useDividers ) url_add_parameter(&url, "nd", 0);
  if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
    /* If from= and to= are present, display all nodes on a path connecting