Fossil

Check-in [d29dd544]
Login

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

Overview
Comment:Modularize byte-order-mark and blob UTF-8 conversion handling.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | convert_before_commit_v2
Files: files | file ages | folders
SHA1:d29dd5449c8b4b3f7a8b8e97d501bf7d56b9634d
User & Date: mistachkin 2012-11-19 04:39:51
Context
2012-11-19
20:39
Allow the get_utf8_bom function to return the size as well. check-in: d857d20b user: mistachkin tags: convert_before_commit_v2
04:39
Modularize byte-order-mark and blob UTF-8 conversion handling. check-in: d29dd544 user: mistachkin tags: convert_before_commit_v2
2012-11-17
20:19
merge trunk Closed-Leaf check-in: 7e7dcdd2 user: jan.nijtmans tags: convert_before_commit
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/attach.c.

511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  @ <div class="section">Content Appended</div>
  @ <blockquote>
  blob_zero(&attach);
  if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
    const char *z;
    const char *zLn = P("ln");
    content_get(ridSrc, &attach);
    blob_strip_bom(&attach, 0);
    z = blob_str(&attach);
    if( zLn ){
      output_text_with_line_numbers(z, zLn);
    }else{
      @ <pre>
      @ %h(z)
      @ </pre>







|







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  @ <div class="section">Content Appended</div>
  @ <blockquote>
  blob_zero(&attach);
  if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
    const char *z;
    const char *zLn = P("ln");
    content_get(ridSrc, &attach);
    blob_to_utf8_no_bom(&attach, 0);
    z = blob_str(&attach);
    if( zLn ){
      output_text_with_line_numbers(z, zLn);
    }else{
      @ <pre>
      @ %h(z)
      @ </pre>

Changes to src/blob.c.

1086
1087
1088
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
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
void blob_swap( Blob *pLeft, Blob *pRight ){
  Blob swap = *pLeft;
  *pLeft = *pRight;
  *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 ){
        /* 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 */
    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 */
  }
}







|
|
<
|
|

|
<
<
<
<
<

<
>
|



<



|
<







|
<



|
|
|
|








|

|





1086
1087
1088
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
1135
1136
1137
1138
1139
void blob_swap( Blob *pLeft, Blob *pRight ){
  Blob swap = *pLeft;
  *pLeft = *pRight;
  *pRight = swap;
}

/*
** 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.
*/
void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){





  char *zUtf8;

  if( starts_with_utf8_bom(pBlob) ){
    struct Blob temp;
    zUtf8 = blob_str(pBlob) + 3;
    blob_zero(&temp);
    blob_append(&temp, zUtf8, -1);

    blob_swap(pBlob, &temp);
    blob_reset(&temp);
#ifdef _WIN32
  }else if( starts_with_utf16be_bom(pBlob) ){

    /* 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( starts_with_utf16le_bom(pBlob) ){

    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 */
    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_reset(pBlob);
    blob_append(pBlob, zUtf8, -1);
    fossil_mbcs_free(zUtf8);
#endif /* _WIN32 */
  }
}

Changes to src/checkin.c.

519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
...
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
....
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
    while( fgets(zIn, sizeof(zIn), stdin)!=0 ){
      if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ){
        break;
      }
      blob_append(&reply, zIn, -1);
    }
  }
  blob_strip_bom(&reply, 1);
  blob_remove_cr(&reply);
  file_delete(zFile);
  free(zFile);
  blob_zero(pComment);
  while( blob_line(&reply, &line) ){
    int i, n;
    char *z;
................................................................................
  char *zInit,
  const char *zBranch,
  int parent_rid,
  const char *zUserOvrd
){
  Blob prompt;
#ifdef _WIN32
  static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
  blob_init(&prompt, (const char *) bom, 3);
  if( zInit && zInit[0]) {
    blob_append(&prompt, zInit, -1);
  }
#else
  blob_init(&prompt, zInit, -1);
#endif
................................................................................
  static int allOk = 0;   /* Set to true to disable this routine */

  if( allOk ) return 0;
  fUnicode = starts_with_utf16_bom(p);
  eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
  if( eType==0 || eType==-1 || fUnicode ){
    const char *zWarning;
    const char *c = "c=convert/";
    Blob ans;
    char cReply;

    if( eType==-1 && fUnicode ){
      zWarning = "Unicode and CR/NL line endings";
    }else if( eType==-1 ){
      if( crnlOk ){
................................................................................
      }
      zWarning = "CR/NL line endings";
    }else if( eType==0 ){
      if( binOk ){
        return 0; /* We don't want binary warnings for this file. */
      }
      zWarning = "binary data";
      c = ""; /* We cannot automatically convert binary files */
    }else{
      zWarning = "Unicode";
#ifndef _WIN32
      c = ""; /* On UNIX, we cannot automatically convert unicode files */
#endif
    }
    file_relative_name(zFilename, &fname, 0);
    blob_zero(&ans);
    zMsg = mprintf(
         "%s contains %s.  commit anyhow (a=all/%sy/N)? ",
         blob_str(&fname), zWarning, c);
    prompt_user(zMsg, &ans);
    fossil_free(zMsg);
    cReply = blob_str(&ans)[0];
    if( cReply=='a' || cReply=='A' ){
      allOk = 1;
    }else if( (c[0] != 0) && (cReply=='c' || cReply=='C') ){
      char *zOrig = file_newname(zFilename, "original", 1);
      FILE *f;
      blob_write_to_file(p, zOrig);
      fossil_free(zOrig);
      f = fossil_fopen(zFilename, "wb");
      if( fUnicode ) {
        static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
        fwrite(bom, 1, 3, f);
        blob_strip_bom(p, 0);
      }
      blob_remove_cr(p);
      fwrite(blob_buffer(p), 1, blob_size(p), f);
      fclose(f);
      return 1;
    }else if( cReply!='y' && cReply!='Y' ){
      fossil_fatal("Abandoning commit due to %s in %s",
................................................................................
  if( useCksum ) vfile_aggregate_checksum_disk(vid, &cksum1);
  if( zComment ){
    blob_zero(&comment);
    blob_append(&comment, zComment, -1);
  }else if( zComFile ){
    blob_zero(&comment);
    blob_read_from_file(&comment, zComFile);
    blob_strip_bom(&comment, 1);
  }else{
    char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
    prepare_commit_comment(&comment, zInit, zBranch, vid, zUserOvrd);
    if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
      blob_zero(&ans);
      prompt_user("unchanged check-in comment.  continue (y/N)? ", &ans);
      cReply = blob_str(&ans)[0];







|







 







|







 







|







 







|



|






|





|






|

|







 







|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
...
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
...
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
....
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
    while( fgets(zIn, sizeof(zIn), stdin)!=0 ){
      if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ){
        break;
      }
      blob_append(&reply, zIn, -1);
    }
  }
  blob_to_utf8_no_bom(&reply, 1);
  blob_remove_cr(&reply);
  file_delete(zFile);
  free(zFile);
  blob_zero(pComment);
  while( blob_line(&reply, &line) ){
    int i, n;
    char *z;
................................................................................
  char *zInit,
  const char *zBranch,
  int parent_rid,
  const char *zUserOvrd
){
  Blob prompt;
#ifdef _WIN32
  const unsigned char *bom = get_utf8_bom();
  blob_init(&prompt, (const char *) bom, 3);
  if( zInit && zInit[0]) {
    blob_append(&prompt, zInit, -1);
  }
#else
  blob_init(&prompt, zInit, -1);
#endif
................................................................................
  static int allOk = 0;   /* Set to true to disable this routine */

  if( allOk ) return 0;
  fUnicode = starts_with_utf16_bom(p);
  eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
  if( eType==0 || eType==-1 || fUnicode ){
    const char *zWarning;
    const char *zConvert = "c=convert/";
    Blob ans;
    char cReply;

    if( eType==-1 && fUnicode ){
      zWarning = "Unicode and CR/NL line endings";
    }else if( eType==-1 ){
      if( crnlOk ){
................................................................................
      }
      zWarning = "CR/NL line endings";
    }else if( eType==0 ){
      if( binOk ){
        return 0; /* We don't want binary warnings for this file. */
      }
      zWarning = "binary data";
      zConvert = ""; /* We cannot convert binary files. */
    }else{
      zWarning = "Unicode";
#ifndef _WIN32
      zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
#endif
    }
    file_relative_name(zFilename, &fname, 0);
    blob_zero(&ans);
    zMsg = mprintf(
         "%s contains %s.  commit anyhow (a=all/%sy/N)? ",
         blob_str(&fname), zWarning, zConvert);
    prompt_user(zMsg, &ans);
    fossil_free(zMsg);
    cReply = blob_str(&ans)[0];
    if( cReply=='a' || cReply=='A' ){
      allOk = 1;
    }else if( *zConvert && (cReply=='c' || cReply=='C') ){
      char *zOrig = file_newname(zFilename, "original", 1);
      FILE *f;
      blob_write_to_file(p, zOrig);
      fossil_free(zOrig);
      f = fossil_fopen(zFilename, "wb");
      if( fUnicode ) {
        const unsigned char *bom = get_utf8_bom();
        fwrite(bom, 1, 3, f);
        blob_to_utf8_no_bom(p, 0);
      }
      blob_remove_cr(p);
      fwrite(blob_buffer(p), 1, blob_size(p), f);
      fclose(f);
      return 1;
    }else if( cReply!='y' && cReply!='Y' ){
      fossil_fatal("Abandoning commit due to %s in %s",
................................................................................
  if( useCksum ) vfile_aggregate_checksum_disk(vid, &cksum1);
  if( zComment ){
    blob_zero(&comment);
    blob_append(&comment, zComment, -1);
  }else if( zComFile ){
    blob_zero(&comment);
    blob_read_from_file(&comment, zComFile);
    blob_to_utf8_no_bom(&comment, 1);
  }else{
    char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
    prepare_commit_comment(&comment, zInit, zBranch, vid, zUserOvrd);
    if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
      blob_zero(&ans);
      prompt_user("unchanged check-in comment.  continue (y/N)? ", &ans);
      cReply = blob_str(&ans)[0];

Changes to src/diff.c.

319
320
321
322
323
324
325





















326
327
328
329
330
331
332
...
337
338
339
340
341
342
343
































344
345
346
347
348
349
350
    }
  }
  if( j>UTF16_LENGTH_MASK ){
    return 0;  /* Very long line -> binary */
  }
  return result;  /* No problems seen -> not binary */
}






















/*
** This function returns non-zero if the blob starts with a UTF-16le or
** UTF-16be byte-order-mark (BOM).
*/
int starts_with_utf16_bom(const Blob *pContent){
  const char *z = blob_buffer(pContent);
................................................................................
  if( (c1==(char)0xff) && (c2==(char)0xfe) ){
    return 1;
  }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
    return 1;
  }
  return 0;
}

































/*
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
  return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}







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







 







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







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
...
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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    }
  }
  if( j>UTF16_LENGTH_MASK ){
    return 0;  /* Very long line -> binary */
  }
  return result;  /* No problems seen -> not binary */
}

/*
** This function returns an array of bytes representing the byte-order-mark
** for UTF-8.
*/
const unsigned char *get_utf8_bom(){
  static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
  return bom;
}

/*
** This function returns non-zero if the blob starts with a UTF-8
** byte-order-mark (BOM).
*/
int starts_with_utf8_bom(const Blob *pContent){
  const char *z = blob_buffer(pContent);
  const unsigned char *bom = get_utf8_bom();

  if( blob_size(pContent)<3 ) return 0;
  return memcmp(z, bom, 3)==0;
}

/*
** This function returns non-zero if the blob starts with a UTF-16le or
** UTF-16be byte-order-mark (BOM).
*/
int starts_with_utf16_bom(const Blob *pContent){
  const char *z = blob_buffer(pContent);
................................................................................
  if( (c1==(char)0xff) && (c2==(char)0xfe) ){
    return 1;
  }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
    return 1;
  }
  return 0;
}

/*
** This function returns non-zero if the blob starts with a UTF-16le
** byte-order-mark (BOM).
*/
int starts_with_utf16le_bom(const Blob *pContent){
  const char *z = blob_buffer(pContent);
  int c1, c2;

  if( blob_size(pContent)<2 ) return 0;
  c1 = z[0]; c2 = z[1];
  if( (c1==(char)0xff) && (c2==(char)0xfe) ){
    return 1;
  }
  return 0;
}

/*
** This function returns non-zero if the blob starts with a UTF-16be
** byte-order-mark (BOM).
*/
int starts_with_utf16be_bom(const Blob *pContent){
  const char *z = blob_buffer(pContent);
  int c1, c2;

  if( blob_size(pContent)<2 ) return 0;
  c1 = z[0]; c2 = z[1];
  if( (c1==(char)0xfe) && (c2==(char)0xff) ){
    return 1;
  }
  return 0;
}

/*
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
  return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}

Changes to src/info.c.

1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
  }
  @ <hr />
  content_get(rid, &content);
  if( renderAsWiki ){
    wiki_convert(&content, 0, 0);
  }else if( renderAsHtml ){
    @ <div>
    blob_strip_bom(&content, 0);
    cgi_append_content(blob_buffer(&content), blob_size(&content));
    @ </div>
  }else{
    style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid);
    zMime = mimetype_from_content(&content);
    @ <blockquote>
    if( zMime==0 ){
      const char *zLn = P("ln");
      const char *z;
      blob_strip_bom(&content, 0);
      z = blob_str(&content);
      if( zLn ){
        output_text_with_line_numbers(z, zLn);
      }else{
        @ <pre>
        @ %h(z)
        @ </pre>







|









|







1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
  }
  @ <hr />
  content_get(rid, &content);
  if( renderAsWiki ){
    wiki_convert(&content, 0, 0);
  }else if( renderAsHtml ){
    @ <div>
    blob_to_utf8_no_bom(&content, 0);
    cgi_append_content(blob_buffer(&content), blob_size(&content));
    @ </div>
  }else{
    style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid);
    zMime = mimetype_from_content(&content);
    @ <blockquote>
    if( zMime==0 ){
      const char *zLn = P("ln");
      const char *z;
      blob_to_utf8_no_bom(&content, 0);
      z = blob_str(&content);
      if( zLn ){
        output_text_with_line_numbers(z, zLn);
      }else{
        @ <pre>
        @ %h(z)
        @ </pre>

Changes to src/main.c.

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
  }else{
    blob_read_from_channel(&file, zInFile, -1);
    if(stdin != zInFile){
      fclose(zInFile);
    }
    zInFile = NULL;
  }
  blob_strip_bom(&file, 1);
  z = blob_str(&file);
  for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++;
  newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) );
  for(j=0; j<i; j++) newArgv[j] = g.argv[j];

  blob_rewind(&file);
  while( (n = blob_line(&file, &line))>0 ){







|







514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
  }else{
    blob_read_from_channel(&file, zInFile, -1);
    if(stdin != zInFile){
      fclose(zInFile);
    }
    zInFile = NULL;
  }
  blob_to_utf8_no_bom(&file, 1);
  z = blob_str(&file);
  for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++;
  newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) );
  for(j=0; j<i; j++) newArgv[j] = g.argv[j];

  blob_rewind(&file);
  while( (n = blob_line(&file, &line))>0 ){

Changes to src/stash.c.

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

  zComment = find_option("comment", "m", 1);
  verify_all_options();
  if( zComment==0 ){
    Blob prompt;                       /* Prompt for stash comment */
    Blob comment;                      /* User comment reply */
#ifdef _WIN32
    static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
    blob_init(&prompt, (const char *) bom, 3);
#else
    blob_zero(&prompt);
#endif
    blob_append(&prompt,
       "\n"
       "# Enter a description of what is being stashed.  Lines beginning\n"







|







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

  zComment = find_option("comment", "m", 1);
  verify_all_options();
  if( zComment==0 ){
    Blob prompt;                       /* Prompt for stash comment */
    Blob comment;                      /* User comment reply */
#ifdef _WIN32
    const unsigned char *bom = get_utf8_bom();
    blob_init(&prompt, (const char *) bom, 3);
#else
    blob_zero(&prompt);
#endif
    blob_append(&prompt,
       "\n"
       "# Enter a description of what is being stashed.  Lines beginning\n"

Changes to src/wikiformat.c.

1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
....
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
  }
  if( pOut ){
    renderer.pOut = pOut;
  }else{
    renderer.pOut = cgi_output_blob();
  }

  blob_strip_bom(pIn, 0);
  wiki_render(&renderer, blob_str(pIn));
  endAutoParagraph(&renderer);
  while( renderer.nStack ){
    popStack(&renderer);
  }
  blob_append(renderer.pOut, "\n", 1);
  free(renderer.aStack);
................................................................................
** of the title and initialize pTail to be the text that follows the
** title.
*/
int wiki_find_title(Blob *pIn, Blob *pTitle, Blob *pTail){
  char *z;
  int i;
  int iStart;
  blob_strip_bom(pIn, 0);
  z = blob_str(pIn);
  for(i=0; fossil_isspace(z[i]); i++){}
  if( z[i]!='<' ) return 0;
  i++;
  if( strncmp(&z[i],"title>", 6)!=0 ) return 0;
  iStart = i+6;
  for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}







|







 







|







1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
....
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
  }
  if( pOut ){
    renderer.pOut = pOut;
  }else{
    renderer.pOut = cgi_output_blob();
  }

  blob_to_utf8_no_bom(pIn, 0);
  wiki_render(&renderer, blob_str(pIn));
  endAutoParagraph(&renderer);
  while( renderer.nStack ){
    popStack(&renderer);
  }
  blob_append(renderer.pOut, "\n", 1);
  free(renderer.aStack);
................................................................................
** of the title and initialize pTail to be the text that follows the
** title.
*/
int wiki_find_title(Blob *pIn, Blob *pTitle, Blob *pTail){
  char *z;
  int i;
  int iStart;
  blob_to_utf8_no_bom(pIn, 0);
  z = blob_str(pIn);
  for(i=0; fossil_isspace(z[i]); i++){}
  if( z[i]!='<' ) return 0;
  i++;
  if( strncmp(&z[i],"title>", 6)!=0 ) return 0;
  iStart = i+6;
  for(i=iStart; z[i] && (z[i]!='<' || strncmp(&z[i],"</title>",8)!=0); i++){}