Fossil

Check-in [517a6f7a]
Login

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

Overview
Comment:merge trunk, some improvements in messages (not yet ready yet)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | improve_commit_warning
Files: files | file ages | folders
SHA1: 517a6f7a53b6e04821aafd6ad90f37abdbadbee9
User & Date: jan.nijtmans 2012-11-04 10:48:08
Context
2012-11-04
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
2012-11-02
14:22
don't forget to compensate for the line-length check check-in: 9011fe12 user: jan.nijtmans tags: improve_commit_warning
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/checkin.c.

410
411
412
413
414
415
416

417
418
419
420
421

422
423
424
425
426

427
428
429
430
431
432
433
...
434
435
436
437
438
439
440

441


442
443
444
445
446
447
448
449
...
883
884
885
886
887
888
889
890





891
892
893
894
895
896
897
898
899
900



















901
902
903
904
905
906
907
908
909
910
911
912



913
914
915
916
917
918
919
920
....
1130
1131
1132
1133
1134
1135
1136






















1137
1138
1139
1140
1141
1142
1143
....
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223

1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235

1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
  int allFlag;
  unsigned scanFlags = 0;
  const char *zIgnoreFlag;
  Blob path, repo;
  Stmt q;
  int n;
  Glob *pIgnore;


  allFlag = find_option("force","f",0)!=0;
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  zIgnoreFlag = find_option("ignore",0,1);

  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");

  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q,
      "SELECT %Q || x FROM sfile"
................................................................................
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      g.zLocalRoot, fossil_all_reserved_names()
  );
  if( file_tree_name(g.zRepositoryName, &repo, 0) ){
    db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
  }

  while( db_step(&q)==SQLITE_ROW ){


    if( allFlag ){
      file_delete(db_column_text(&q, 0));
    }else{
      Blob ans;
      char cReply;
      char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
                              db_column_text(&q, 0));
      blob_zero(&ans);
................................................................................
}

/*
** Issue a warning and give the user an opportunity to abandon out
** if a Unicode (UTF-16) byte-order-mark (BOM) or a \r\n line ending
** is seen in a text file.
*/
static void commit_warning(const Blob *p, int crnlOk, const char *zFilename){





  int eType;              /* return value of looks_like_utf8/utf16() */
  int fUnicode;           /* return value of starts_with_utf16_bom() */
  char *zMsg;             /* Warning message */
  Blob fname;             /* Relative pathname of the file */
  static int allOk = 0;   /* Set to true to disable this routine */

  if( allOk ) return;
  fUnicode = starts_with_utf16_bom(p);
  eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
  if( eType<0 || fUnicode ){



















    const char *zWarning;
    Blob ans;
    char cReply;

    if( eType==-1 && fUnicode ){
      zWarning = "Unicode and CR/NL line endings";
    }else if( eType==-1 ){
      if( crnlOk ){
        return; /* We don't want CR/NL warnings for this file. */
      }
      zWarning = "CR/NL line endings";
    }else if( eType==-2 ){



      zWarning = "invalid UTF-8 or ASCII";
    }else{
      zWarning = "Unicode";
    }
    file_relative_name(zFilename, &fname, 0);
    blob_zero(&ans);
    zMsg = mprintf(
         "%s contains %s.  commit anyhow (a=all/y/N)? ",
................................................................................
  ** should be committed.
  */
  select_commit_files();
  isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
  if( g.aCommitFile && isAMerge ){
    fossil_fatal("cannot do a partial commit of a merge");
  }























  user_select();
  /*
  ** Check that the user exists.
  */
  if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
    fossil_fatal("no such user: %s", g.zLogin);
................................................................................
  }

  /* Step 1: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified fils are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, chnged FROM vfile "
    "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
    g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob",""))

  );
  while( db_step(&q)==SQLITE_ROW ){
    int id, rid;
    const char *zFullname;
    Blob content;
    int crnlOk, chnged;

    id = db_column_int(&q, 0);
    zFullname = db_column_text(&q, 1);
    rid = db_column_int(&q, 2);
    crnlOk = db_column_int(&q, 3);
    chnged = db_column_int(&q, 4);


    blob_zero(&content);
    if( file_wd_islink(zFullname) ){
      /* Instead of file content, put link destination path */
      blob_read_link(&content, zFullname);
    }else{
      blob_read_from_file(&content, zFullname);
    }
    commit_warning(&content, crnlOk, zFullname);
    if( chnged==1 && contains_merge_marker(&content) ){
      Blob fname; /* Relative pathname of the file */

      nConflict++;
      file_relative_name(zFullname, &fname, 0);
      fossil_print("possible unresolved merge conflict in %s\n",
                   blob_str(&fname));







>





>




|
>







 







>

>
>
|







 







|
>
>
>
>
>









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











|
>
>
>
|







 







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







 







|

|
>





|






>








|







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
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
945
946
947
948
949
950
951
952
953
....
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
....
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
  int allFlag;
  unsigned scanFlags = 0;
  const char *zIgnoreFlag;
  Blob path, repo;
  Stmt q;
  int n;
  Glob *pIgnore;
  int testFlag = 0;

  allFlag = find_option("force","f",0)!=0;
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  zIgnoreFlag = find_option("ignore",0,1);
  testFlag = find_option("test",0,0)!=0;
  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
                filename_collation());
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q,
      "SELECT %Q || x FROM sfile"
................................................................................
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      g.zLocalRoot, fossil_all_reserved_names()
  );
  if( file_tree_name(g.zRepositoryName, &repo, 0) ){
    db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
  }
  db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
  while( db_step(&q)==SQLITE_ROW ){
    if( testFlag ){
      fossil_print("%s\n", db_column_text(&q,0));
    }else if( allFlag ){
      file_delete(db_column_text(&q, 0));
    }else{
      Blob ans;
      char cReply;
      char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ",
                              db_column_text(&q, 0));
      blob_zero(&ans);
................................................................................
}

/*
** Issue a warning and give the user an opportunity to abandon out
** if a Unicode (UTF-16) byte-order-mark (BOM) or a \r\n line ending
** is seen in a text file.
*/
static void commit_warning(
  const Blob *p,        /* The content of the file being committed. */
  int crnlOk,           /* Non-zero if CR/NL warnings should be disabled. */
  int binOk,            /* Non-zero if binary warnings should be disabled. */
  const char *zFilename /* The full name of the file being committed. */
){
  int eType;              /* return value of looks_like_utf8/utf16() */
  int fUnicode;           /* return value of starts_with_utf16_bom() */
  char *zMsg;             /* Warning message */
  Blob fname;             /* Relative pathname of the file */
  static int allOk = 0;   /* Set to true to disable this routine */

  if( allOk ) return;
  fUnicode = starts_with_utf16_bom(p);
  eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
  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));
    }
    blob_reset(&ans);
    eType +=4 ;
  }
  if( eType==0 || eType==-1 || fUnicode ){
    const char *zWarning;
    Blob ans;
    char cReply;

    if( eType==-1 && fUnicode ){
      zWarning = "Unicode and CR/NL line endings";
    }else if( eType==-1 ){
      if( crnlOk ){
        return; /* We don't want CR/NL warnings for this file. */
      }
      zWarning = "CR/NL line endings";
    }else if( eType==0 ){
      if( binOk ){
        return; /* We don't want binary warnings for this file. */
      }
      zWarning = "binary data";
    }else{
      zWarning = "Unicode";
    }
    file_relative_name(zFilename, &fname, 0);
    blob_zero(&ans);
    zMsg = mprintf(
         "%s contains %s.  commit anyhow (a=all/y/N)? ",
................................................................................
  ** should be committed.
  */
  select_commit_files();
  isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
  if( g.aCommitFile && isAMerge ){
    fossil_fatal("cannot do a partial commit of a merge");
  }

  /* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA"
  ** will generate a manifest that has two fileA entries, which is illegal.
  ** When you think about it, the sequence above makes no sense.  So detect
  ** it and disallow it.  Ticket [0ff64b0a5fc8].
  */
  if( g.aCommitFile ){
    Stmt qRename;
    db_prepare(&qRename,
       "SELECT v1.pathname, v2.pathname"
       "  FROM vfile AS v2 CROSS JOIN vfile AS v1"
       " WHERE is_selected(v1.id)"
       "   AND v2.origname IS NOT NULL"
       "   AND v2.origname=v1.pathname");
    if( db_step(&qRename)==SQLITE_ROW ){
      const char *zFrom = db_column_text(&qRename, 0);
      const char *zTo = db_column_text(&qRename, 1);
      fossil_fatal("cannot do a partial commit of '%s' because "
                   "'%s' was renamed to '%s'", zFrom, zFrom, zTo);
    }
    db_finalize(&qRename);
  }

  user_select();
  /*
  ** Check that the user exists.
  */
  if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
    fossil_fatal("no such user: %s", g.zLogin);
................................................................................
  }

  /* Step 1: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified fils are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
    "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
    g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
    glob_expr("pathname", db_get("binary-glob",""))
  );
  while( db_step(&q)==SQLITE_ROW ){
    int id, rid;
    const char *zFullname;
    Blob content;
    int crnlOk, binOk, chnged;

    id = db_column_int(&q, 0);
    zFullname = db_column_text(&q, 1);
    rid = db_column_int(&q, 2);
    crnlOk = db_column_int(&q, 3);
    chnged = db_column_int(&q, 4);
    binOk = db_column_int(&q, 5);

    blob_zero(&content);
    if( file_wd_islink(zFullname) ){
      /* Instead of file content, put link destination path */
      blob_read_link(&content, zFullname);
    }else{
      blob_read_from_file(&content, zFullname);
    }
    commit_warning(&content, crnlOk, binOk, zFullname);
    if( chnged==1 && contains_merge_marker(&content) ){
      Blob fname; /* Relative pathname of the file */

      nConflict++;
      file_relative_name(zFullname, &fname, 0);
      fossil_print("possible unresolved merge conflict in %s\n",
                   blob_str(&fname));

Changes to src/diff.c.

183
184
185
186
187
188
189
190
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
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
268
269
270
271
272
273
274
275
276
277
278
**         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.
**
** (-2) -- The content appears to consist entirely of text, with lines
**         delimited by line-feed characters or 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;
  int result = 1;  /* Assume UTF-8 text with no CR/NL */

  /* Check individual lines.
  */
  if( n==0 ) return result;  /* Empty file -> text */
  c = *z;
  j = (c!='\n');
  if( c<0x80 ){
    if( c==0 ) return 0;  /* Zero byte in a file -> binary */
  }else if( c<0xC0 ){
    result = -2;  /* Invalid UTF-8, continue */
  }else if( c<0xE0 ){
    if( n<2 || ((z[1]&0xC0)!=0x80) ){
      result = -2; /* Invalid 2-byte UTF-8, continue */
    }else{
      --n; ++j; ++z;
    }
  }else if( c<0xF0 ){
    if( n<3 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) ){
      result = -2; /* Invalid 3-byte UTF-8, continue */
    }else{
      n-=2; j+=2; z+=2;
    }
  }else if( c<0xF8 ){
    if( n<4 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) || ((z[3]&0xC0)!=0x80) ){
      result = -2; /* Invalid 4-byte UTF-8, continue */
    }else{
      n-=3; j+=3; z+=3;
    }
  }else{
    result = -2;  /* Invalid multi-byte UTF-8, continue */
  }
  while( --n>0 ){
    c = *++z; ++j;
    if( c<0x80 ){
      if( c==0 ) return 0;  /* Zero byte in a file -> binary */
      if( c=='\n' ){
        unsigned char c2 = z[-1];
        if( c2=='\r' && result>0 ){
          result = -1;  /* Contains CR/NL, continue */
        }
        if( j>LENGTH_MASK ){
          return 0;  /* Very long line -> binary */
        }
        j = 0;
      }
    }else if( c<0xC0 ){
      result = -2;  /* Invalid UTF-8, continue */
    }else if( c<0xE0 ){
      if( n<2 || ((z[1]&0xC0)!=0x80) ){
        result = -2; continue; /* Invalid 2-byte UTF-8, continue */
      }
      --n; ++j; ++z;
    }else if( c<0xF0 ){
      if( n<3 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) ){
        result = -2; continue; /* Invalid 3-byte UTF-8, continue */
      }
      n-=2; j+=2; z+=2;
    }else if( c<0xF8 ){
      if( n<4 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) || ((z[3]&0xC0)!=0x80) ){
        result = -2; continue; /* Invalid 4-byte UTF-8, continue */
      }
      n-=3; j+=3; z+=3;
    }else{
      result = -2;  /* Invalid multi-byte UTF-8, continue */
    }
  }
  if( j>LENGTH_MASK ){
    return 0;  /* Very long line -> binary */
  }
  return 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.







|
|
>
>
>
>
|








|



|





|


|





|





|




|






|
<
|







|


|




|




|



|





|







183
184
185
186
187
188
189
190
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
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
**         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.
**
** (-3) -- The content appears to consist entirely of text, with lines
**         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;
  int result = 0;  /* Assume UTF-8 text with no CR/NL */

  /* Check individual lines.
  */
  if( n==0 ) return 1;  /* Empty file -> text */
  c = *z;
  j = (c!='\n');
  if( c<0x80 ){
    if( c==0 ) return 0;  /* Zero byte in a file -> binary */
  }else if( c<0xC0 ){
    result |= 4;  /* Invalid UTF-8, continue */
  }else if( c<0xE0 ){
    if( n<2 || ((z[1]&0xC0)!=0x80) ){
      result |= 4; /* Invalid 2-byte UTF-8, continue */
    }else{
      --n; ++j; ++z;
    }
  }else if( c<0xF0 ){
    if( n<3 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) ){
      result |= 4; /* Invalid 3-byte UTF-8, continue */
    }else{
      n-=2; j+=2; z+=2;
    }
  }else if( c<0xF8 ){
    if( n<4 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) || ((z[3]&0xC0)!=0x80) ){
      result |= 4; /* Invalid 4-byte UTF-8, continue */
    }else{
      n-=3; j+=3; z+=3;
    }
  }else{
    result |= 4;  /* Invalid multi-byte UTF-8, continue */
  }
  while( --n>0 ){
    c = *++z; ++j;
    if( c<0x80 ){
      if( c==0 ) return 0;  /* Zero byte in a file -> binary */
      if( c=='\n' ){
        if( z[-1]=='\r'){

          result |= 2;  /* Contains CR/NL, continue */
        }
        if( j>LENGTH_MASK ){
          return 0;  /* Very long line -> binary */
        }
        j = 0;
      }
    }else if( c<0xC0 ){
      result |= 4;  /* Invalid UTF-8, continue */
    }else if( c<0xE0 ){
      if( n<2 || ((z[1]&0xC0)!=0x80) ){
        result |= 4; continue; /* Invalid 2-byte UTF-8, continue */
      }
      --n; ++j; ++z;
    }else if( c<0xF0 ){
      if( n<3 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) ){
        result |= 4; continue; /* Invalid 3-byte UTF-8, continue */
      }
      n-=2; j+=2; z+=2;
    }else if( c<0xF8 ){
      if( n<4 || ((z[1]&0xC0)!=0x80) || ((z[2]&0xC0)!=0x80) || ((z[3]&0xC0)!=0x80) ){
        result |= 4; continue; /* Invalid 4-byte UTF-8, continue */
      }
      n-=3; j+=3; z+=3;
    }else{
      result |= 4;  /* Invalid multi-byte UTF-8, continue */
    }
  }
  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.