Fossil

Check-in [f15d20e3]
Login

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

Overview
Comment:Fold print_changes() into status_cmd() (formerly changes_cmd()). Remove C_SHA1SUM, C_HEADER, and C_VERBOSE flags which are no longer needed for communicating options to print_changes(). Move locate_unmanaged_files() closer to the top of the file so status_cmd() can call it. Implement C_UNMODIFIED and C_EXTRA in status_report(). Document the fact that the changes and status commands take optional path arguments. Let changes and status commands accept --case-sensitive (was already done), --dotfiles, and --ignore for the benefit of --extras. Incorporate search for extra files into status_cmd().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | andygoth-changes
Files: files | file ages | folders
SHA1:f15d20e39b55c7ac3e007a5df84293885c4404a1
User & Date: andygoth 2016-11-06 02:35:35
Context
2016-11-06
02:39
Remove flag debug prints from status_cmd() now that it seems to be stable check-in: 31c6140e user: andygoth tags: andygoth-changes
02:35
Fold print_changes() into status_cmd() (formerly changes_cmd()). Remove C_SHA1SUM, C_HEADER, and C_VERBOSE flags which are no longer needed for communicating options to print_changes(). Move locate_unmanaged_files() closer to the top of the file so status_cmd() can call it. Implement C_UNMODIFIED and C_EXTRA in status_report(). Document the fact that the changes and status commands take optional path arguments. Let changes and status commands accept --case-sensitive (was already done), --dotfiles, and --ignore for the benefit of --extras. Incorporate search for extra files into status_cmd(). check-in: f15d20e3 user: andygoth tags: andygoth-changes
2016-11-05
23:11
Merge the status command into the changes command. check-in: 2c3a108c user: andygoth tags: andygoth-changes
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/checkin.c.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
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
..
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
...
148
149
150
151
152
153
154
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
...
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
282
...
316
317
318
319
320
321
322



323
324
325
326
327
328
329
...
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
...
407
408
409
410
411
412
413



414
415
416
417
418
419
420
...
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
...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
#include <assert.h>

/*
** Change filter options.
*/
enum {
  /* Zero-based bit indexes. */
  CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING   , CB_ADDED   , CB_DELETED,
  CB_RENAMED, CB_CONFLICT, CB_META   , CB_UNMODIFIED, CB_EXTRA   , CB_MERGE  ,
  CB_RELPATH, CB_SHA1SUM , CB_HEADER , CB_VERBOSE   , CB_CLASSIFY, CB_FATAL  ,
  CB_COMMENT,

  /* Bitmask values. */
  C_EDITED     = 1 << CB_EDITED,    /* Edited, merged, and conflicted files. */
  C_UPDATED    = 1 << CB_UPDATED,   /* Files updated by merge/integrate. */
  C_CHANGED    = 1 << CB_CHANGED,   /* Treated the same as the above two. */
  C_MISSING    = 1 << CB_MISSING,   /* Missing and non- files. */
  C_ADDED      = 1 << CB_ADDED,     /* Added files. */
................................................................................
  C_EXTRA      = 1 << CB_EXTRA,     /* Unmanaged files. */
  C_MERGE      = 1 << CB_MERGE,     /* Merge contributors. */
  C_FILTER     = C_EDITED  | C_UPDATED | C_CHANGED  | C_MISSING | C_ADDED
               | C_DELETED | C_RENAMED | C_CONFLICT | C_META    | C_UNMODIFIED
               | C_EXTRA   | C_MERGE,
  C_ALL        = C_FILTER & ~(C_EXTRA | C_MERGE),
  C_RELPATH    = 1 << CB_RELPATH,   /* Show relative paths. */
  C_SHA1SUM    = 1 << CB_SHA1SUM,   /* Use SHA1 checksums not mtimes. */
  C_HEADER     = 1 << CB_HEADER,    /* Display repository name if non-empty. */
  C_VERBOSE    = 1 << CB_VERBOSE,   /* Display "(none)" if empty. */
  C_CLASSIFY   = 1 << CB_CLASSIFY,  /* Show file change types. */
  C_DEFAULT    = (C_ALL & ~C_UNMODIFIED) | C_MERGE | C_CLASSIFY,
  C_FATAL      = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
  C_COMMENT    = 1 << CB_COMMENT,   /* Precede each line with "# ". */
};


















































/*
** Generate text describing all changes.
**
** We assume that vfile_check_signature has been run.
*/
static void status_report(
  Blob *report,          /* Append the status report here */
  unsigned flags         /* Filter and other configuration flags */
){
  Stmt q;
  int nErr = 0;
  Blob rewrittenPathname;
  Blob where;
  const char *zName;
  int i;


  blob_zero(&where);
  for(i=2; i<g.argc; i++){
    Blob fname;
    file_tree_name(g.argv[i], &fname, 0, 1);
    zName = blob_str(&fname);
    if( fossil_strcmp(zName, ".")==0 ){
      blob_reset(&where);
................................................................................
      "OR (pathname>'%q/' %s AND pathname<'%q0' %s)",
      (blob_size(&where)>0) ? "OR" : "AND", zName,
      filename_collation(), zName, filename_collation(),
      zName, filename_collation()
    );
  }

  db_prepare(&q,


    "SELECT pathname, deleted, chnged,"
    "       rid, coalesce(origname!=pathname,0), islink"
    "  FROM vfile "
    " WHERE is_selected(id) %s"




    "   AND (chnged OR deleted OR rid=0 OR pathname!=origname)"
    " ORDER BY 1 /*scan*/",





    blob_sql_text(&where)
  );









  blob_zero(&rewrittenPathname);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);
    const char *zClass = 0;

    int isDeleted = db_column_int(&q, 1);
    int isChnged = db_column_int(&q,2);
    int isNew = db_column_int(&q,3)==0;
    int isRenamed = db_column_int(&q,4);
    int isLink = db_column_int(&q,5);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    int isMissing = !file_wd_isfile_or_link(zFullName);

    /* Determine the file change classification, if any. */
    if( (flags & C_DELETED) && isDeleted ){
      zClass = "DELETED";
    }else if( (flags & C_MISSING) && isMissing ){
................................................................................
    }else if( (flags & C_META) && isChnged==8 ){
      zClass = "UNEXEC";
    }else if( (flags & C_META) && isChnged==9 ){
      zClass = "UNLINK";
    }else if( (flags & C_CONFLICT) && isChnged && !isLink
           && file_contains_merge_marker(zFullName) ){
      zClass = "CONFLICT";
    }else if( (flags & (C_EDITED | C_CHANGED)) && (isChnged<2 || isChnged>9) ){

      zClass = "EDITED";
    }else if( (flags & C_RENAMED) && isRenamed ){
      zClass = "RENAMED";
    }else if( (flags & C_UNMODIFIED) && !isDeleted && !isMissing && !isNew
                                     && !isChnged  && !isRenamed ){
      /* TODO: never gets executed because query only yields modified files. */
      zClass = "UNMODIFIED";
    }
    /* TODO: implement C_EXTRA. */
    /* TODO: reimplement ls and extras in terms of this function. */

    /* Only report files for which a change classification was determined. */
    if( zClass ){
      /* If C_COMMENT, precede each line with "# ". */
      if( flags & C_COMMENT ){
        blob_append(report, "# ", 2);
................................................................................
  int absPathOption = find_option("abs-paths", 0, 0)!=0;
  int relPathOption = find_option("rel-paths", 0, 0)!=0;
  if( absPathOption ){ relativePaths = 0; }
  if( relPathOption ){ relativePaths = 1; }
  return relativePaths;
}

void print_changes(
  unsigned flags      /* Configuration flags */
){
  Blob report;
  int vid;
  blob_zero(&report);

  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, flags & C_SHA1SUM ? CKSIG_SHA1 : 0);
  status_report(&report, flags);
  if( (flags & C_VERBOSE) && blob_size(&report)==0 ){
    blob_append(&report, "  (none)\n", -1);
  }
  if( (flags & C_HEADER) && blob_size(&report)>0 ){
    fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
                 g.zLocalRoot);
  }
  blob_write_to_file(&report, "-");
  blob_reset(&report);
}

/*
** COMMAND: changes
** COMMAND: status
**
** Usage: %fossil changes|status ?OPTIONS?
**
** Report the change status of files in the current checkout.


**
** The status command is similar to the changes command, except it lacks
** several of the options supported by changes and it has its own header
** and footer information.  The header information is a subset of that
** shown by the info command, and the footer shows if there are any forks.
** Change type classification is always enabled for the status command.
**
................................................................................
**
** General options:
**    --abs-paths       Display absolute pathnames.
**    --rel-paths       Display pathnames relative to the current working
**                      directory.
**    --sha1sum         Verify file status using SHA1 hashing rather than
**                      relying on file mtimes.



**
** Options specific to the changes command:
**    --header          Identify the repository if report is non-empty.
**    -v|--verbose      Say "(none)" if the change report is empty.
**    --classify        Start each line with the file's change type.
**    --no-classify     Do not print file change types.
**
................................................................................
  } flagDefs[] = {
    {"edited"  , C_EDITED , 0}, {"updated"    , C_UPDATED   , 0},
    {"changed" , C_CHANGED, 0}, {"missing"    , C_MISSING   , 0},
    {"added"   , C_ADDED  , 0}, {"deleted"    , C_DELETED   , 0},
    {"renamed" , C_RENAMED, 0}, {"conflict"   , C_CONFLICT  , 0},
    {"meta"    , C_META   , 0}, {"unmodified" , C_UNMODIFIED, 0},
    {"all"     , C_ALL    , 0}, {"extra"      , C_EXTRA     , 0},
    {"merge"   , C_MERGE  , 0}, {"sha1sum"    , C_SHA1SUM   , 0},
    {"header"  , C_HEADER , 1}, {"v"          , C_VERBOSE   , 1},
    {"verbose" , C_VERBOSE, 1}, {"classify"   , C_CLASSIFY  , 1},
  }, noFlagDefs[] = {
    {"no-merge", C_MERGE  , 0}, {"no-classify", C_CLASSIFY  , 1},
  };

#ifdef FOSSIL_DEBUG
  static const char *const bits[] = {
    "EDITED", "UPDATED", "CHANGED", "MISSING", "ADDED", "DELETED", "RENAMED",
    "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "SHA1SUM",
    "HEADER", "VERBOSE", "CLASSIFY",
  };
#endif







  int changes = g.argv[1][0]=='c';
  unsigned flags = 0;
  int vid, i;











  /* Load affirmative flag options. */
  for( i=0; i<count(flagDefs); ++i ){
    if( (!flagDefs[i].changesOnly || changes)
     && find_option(flagDefs[i].option, 0, 0) ){
      flags |= flagDefs[i].mask;
    }
................................................................................
      flags &= ~noFlagDefs[i].mask;
    }
  }

  /* Confirm current working directory is within checkout. */
  db_must_be_within_tree();




  /* Relative path flag determination is done by a shared function. */
  if( determine_cwd_relative_option() ){
    flags |= C_RELPATH;
  }

#ifdef FOSSIL_DEBUG
  for( i=0; i<count(bits); ++i ){
................................................................................
    }
  }
  printf("\n");
#endif

  /* We should be done with options. */
  verify_all_options();













  /* The status command prints general information before the change list. */
  if( !changes ){
    vid = db_lget_int("checkout", 0);
    fossil_print("repository:   %s\n", db_repository_filename());
    fossil_print("local-root:   %s\n", g.zLocalRoot);
    if( g.zConfigDbName ){
      fossil_print("config-db:    %s\n", g.zConfigDbName);
    }
    if( vid ){
      show_common_info(vid, "checkout:", 1, 1);
    }
    db_record_repository_filename(0);
  }

  /* Print all requested changes. */
  print_changes(flags);












  /* The status command ends with warnings about ambiguous leaves (forks). */
  if( !changes ){
    leaf_ambiguity_warning(vid, vid);
  }
}

................................................................................
      fossil_print("%s%s\n", type, zPathname);
    }
    free(zFullName);
  }
  db_finalize(&q);
}

/*
** Create a TEMP table named SFILE and add all unmanaged files named on
** the command-line to that table.  If directories are named, then add
** all unmanaged files contained underneath those directories.  If there
** are no files or directories named on the command-line, then add all
** unmanaged files anywhere in the checkout.
*/
static void locate_unmanaged_files(
  int argc,           /* Number of command-line arguments to examine */
  char **argv,        /* values of command-line arguments */
  unsigned scanFlags, /* Zero or more SCAN_xxx flags */
  Glob *pIgnore1,     /* Do not add files that match this GLOB */
  Glob *pIgnore2      /* Omit files matching this GLOB too */
){
  Blob name;   /* Name of a candidate file or directory */
  char *zName; /* Name of a candidate file or directory */
  int isDir;   /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
  int i;       /* Loop counter */
  int nRoot;   /* length of g.zLocalRoot */

  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
                filename_collation());
  nRoot = (int)strlen(g.zLocalRoot);
  if( argc==0 ){
    blob_init(&name, g.zLocalRoot, nRoot - 1);
    vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
    blob_reset(&name);
  }else{
    for(i=0; i<argc; i++){
      file_canonical_name(argv[i], &name, 0);
      zName = blob_str(&name);
      isDir = file_wd_isdir(zName);
      if( isDir==1 ){
        vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
      }else if( isDir==0 ){
        fossil_warning("not found: %s", &zName[nRoot]);
      }else if( file_access(zName, R_OK) ){
        fossil_fatal("cannot open %s", &zName[nRoot]);
      }else{
        db_multi_exec(
           "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
           &zName[nRoot]
        );
      }
      blob_reset(&name);
    }
  }
}

/*
** COMMAND: extras
**
** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
**
** Print a list of all files in the source tree that are not part of the
** current checkout. See also the "clean" command. If paths are specified,







|
|
|
<







 







<
<
<





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













|



>







 







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


|

>

|
|
|
|







 







|
>



|
|
|
|
|
|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




|

|
>
>







 







>
>
>







 







<
<
|







|
<



>
>
>
>
>
>



>
>
>
>
>
>
>
>
>
>







 







>
>
>







 







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



<











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







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







23
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
..
45
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
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
...
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
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
...
307
308
309
310
311
312
313





















314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
...
404
405
406
407
408
409
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
...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
...
489
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
532
533
534
535
536
537
538
539
540
541
...
752
753
754
755
756
757
758

















































759
760
761
762
763
764
765
#include <assert.h>

/*
** Change filter options.
*/
enum {
  /* Zero-based bit indexes. */
  CB_EDITED , CB_UPDATED , CB_CHANGED, CB_MISSING   , CB_ADDED, CB_DELETED,
  CB_RENAMED, CB_CONFLICT, CB_META   , CB_UNMODIFIED, CB_EXTRA, CB_MERGE  ,
  CB_RELPATH, CB_CLASSIFY, CB_FATAL  , CB_COMMENT   ,


  /* Bitmask values. */
  C_EDITED     = 1 << CB_EDITED,    /* Edited, merged, and conflicted files. */
  C_UPDATED    = 1 << CB_UPDATED,   /* Files updated by merge/integrate. */
  C_CHANGED    = 1 << CB_CHANGED,   /* Treated the same as the above two. */
  C_MISSING    = 1 << CB_MISSING,   /* Missing and non- files. */
  C_ADDED      = 1 << CB_ADDED,     /* Added files. */
................................................................................
  C_EXTRA      = 1 << CB_EXTRA,     /* Unmanaged files. */
  C_MERGE      = 1 << CB_MERGE,     /* Merge contributors. */
  C_FILTER     = C_EDITED  | C_UPDATED | C_CHANGED  | C_MISSING | C_ADDED
               | C_DELETED | C_RENAMED | C_CONFLICT | C_META    | C_UNMODIFIED
               | C_EXTRA   | C_MERGE,
  C_ALL        = C_FILTER & ~(C_EXTRA | C_MERGE),
  C_RELPATH    = 1 << CB_RELPATH,   /* Show relative paths. */



  C_CLASSIFY   = 1 << CB_CLASSIFY,  /* Show file change types. */
  C_DEFAULT    = (C_ALL & ~C_UNMODIFIED) | C_MERGE | C_CLASSIFY,
  C_FATAL      = (1 << CB_FATAL) | C_MISSING, /* Fail on MISSING/NOT_A_FILE. */
  C_COMMENT    = 1 << CB_COMMENT,   /* Precede each line with "# ". */
};

/*
** Create a TEMP table named SFILE and add all unmanaged files named on
** the command-line to that table.  If directories are named, then add
** all unmanaged files contained underneath those directories.  If there
** are no files or directories named on the command-line, then add all
** unmanaged files anywhere in the checkout.
*/
static void locate_unmanaged_files(
  int argc,           /* Number of command-line arguments to examine */
  char **argv,        /* values of command-line arguments */
  unsigned scanFlags, /* Zero or more SCAN_xxx flags */
  Glob *pIgnore1,     /* Do not add files that match this GLOB */
  Glob *pIgnore2      /* Omit files matching this GLOB too */
){
  Blob name;   /* Name of a candidate file or directory */
  char *zName; /* Name of a candidate file or directory */
  int isDir;   /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
  int i;       /* Loop counter */
  int nRoot;   /* length of g.zLocalRoot */

  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
                filename_collation());
  nRoot = (int)strlen(g.zLocalRoot);
  if( argc==0 ){
    blob_init(&name, g.zLocalRoot, nRoot - 1);
    vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
    blob_reset(&name);
  }else{
    for(i=0; i<argc; i++){
      file_canonical_name(argv[i], &name, 0);
      zName = blob_str(&name);
      isDir = file_wd_isdir(zName);
      if( isDir==1 ){
        vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
      }else if( isDir==0 ){
        fossil_warning("not found: %s", &zName[nRoot]);
      }else if( file_access(zName, R_OK) ){
        fossil_fatal("cannot open %s", &zName[nRoot]);
      }else{
        db_multi_exec(
           "INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
           &zName[nRoot]
        );
      }
      blob_reset(&name);
    }
  }
}

/*
** Generate text describing all changes.
**
** We assume that vfile_check_signature has been run.
*/
static void status_report(
  Blob *report,          /* Append the status report here */
  unsigned flags         /* Filter and other configuration flags */
){
  Stmt q;
  int nErr = 0;
  Blob rewrittenPathname;
  Blob sql = BLOB_INITIALIZER, where = BLOB_INITIALIZER;
  const char *zName;
  int i;

  /* Assemble the path-limiting WHERE clause, if any. */
  blob_zero(&where);
  for(i=2; i<g.argc; i++){
    Blob fname;
    file_tree_name(g.argv[i], &fname, 0, 1);
    zName = blob_str(&fname);
    if( fossil_strcmp(zName, ".")==0 ){
      blob_reset(&where);
................................................................................
      "OR (pathname>'%q/' %s AND pathname<'%q0' %s)",
      (blob_size(&where)>0) ? "OR" : "AND", zName,
      filename_collation(), zName, filename_collation(),
      zName, filename_collation()
    );
  }

  /* Start building the SELECT statement. */
  blob_zero(&sql);
  blob_append_sql(&sql,
    "SELECT pathname, deleted, chnged, rid,"
    "       coalesce(origname!=pathname,0) AS renamed, islink, 1 AS managed"
    "  FROM vfile"
    " WHERE is_selected(id)%s", blob_sql_text(&where));

  /* Exclude unmodified files unless requested. */
  if( !(flags & C_UNMODIFIED) ){
    blob_append_sql(&sql,
        " AND (chnged OR deleted OR rid=0 OR pathname!=origname)");

  }

  /* If C_EXTRA, add unmanaged files to the query result too. */
  if( flags & C_EXTRA ){
    blob_append_sql(&sql, " UNION ALL SELECT x AS pathname, 0, 0, 0, 0, 0, 0"
                          " FROM sfile WHERE 1%s", blob_sql_text(&where));

  }

  /* Append an ORDER BY clause then compile the query. */
  blob_append_sql(&sql, " ORDER BY pathname");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  blob_reset(&sql);
  blob_reset(&where);

  /* Execute the query and assemble the report. */
  blob_zero(&rewrittenPathname);
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q, 0);
    const char *zClass = 0;
    int isManaged = db_column_int(&q, 6);
    int isDeleted = db_column_int(&q, 1);
    int isChnged = db_column_int(&q, 2);
    int isNew = isManaged && !db_column_int(&q, 3);
    int isRenamed = db_column_int(&q, 4);
    int isLink = db_column_int(&q, 5);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    int isMissing = !file_wd_isfile_or_link(zFullName);

    /* Determine the file change classification, if any. */
    if( (flags & C_DELETED) && isDeleted ){
      zClass = "DELETED";
    }else if( (flags & C_MISSING) && isMissing ){
................................................................................
    }else if( (flags & C_META) && isChnged==8 ){
      zClass = "UNEXEC";
    }else if( (flags & C_META) && isChnged==9 ){
      zClass = "UNLINK";
    }else if( (flags & C_CONFLICT) && isChnged && !isLink
           && file_contains_merge_marker(zFullName) ){
      zClass = "CONFLICT";
    }else if( (flags & (C_EDITED | C_CHANGED)) && isChnged
           && (isChnged<2 || isChnged>9) ){
      zClass = "EDITED";
    }else if( (flags & C_RENAMED) && isRenamed ){
      zClass = "RENAMED";
    }else if( (flags & C_UNMODIFIED) && isManaged && !isDeleted && !isMissing
                                     && !isNew    && !isChnged  && !isRenamed ){
      zClass = "UNMODIFIED";
    }else if( (flags & C_EXTRA) && !isManaged ){
      zClass = "EXTRA";
    }
    /* TODO: reimplement ls and extras in terms of this function. */

    /* Only report files for which a change classification was determined. */
    if( zClass ){
      /* If C_COMMENT, precede each line with "# ". */
      if( flags & C_COMMENT ){
        blob_append(report, "# ", 2);
................................................................................
  int absPathOption = find_option("abs-paths", 0, 0)!=0;
  int relPathOption = find_option("rel-paths", 0, 0)!=0;
  if( absPathOption ){ relativePaths = 0; }
  if( relPathOption ){ relativePaths = 1; }
  return relativePaths;
}






















/*
** COMMAND: changes
** COMMAND: status
**
** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
**
** Report the change status of files in the current checkout.  If one or
** more PATHS are specified, only changes among the named files and
** directories are reported.  Directories are searched recursively.
**
** The status command is similar to the changes command, except it lacks
** several of the options supported by changes and it has its own header
** and footer information.  The header information is a subset of that
** shown by the info command, and the footer shows if there are any forks.
** Change type classification is always enabled for the status command.
**
................................................................................
**
** General options:
**    --abs-paths       Display absolute pathnames.
**    --rel-paths       Display pathnames relative to the current working
**                      directory.
**    --sha1sum         Verify file status using SHA1 hashing rather than
**                      relying on file mtimes.
**    --case-sensitive <BOOL>  Override case-sensitive setting.
**    --dotfiles        Include unmanaged files beginning with a dot.
**    --ignore <CSG>    Ignore unmanaged files matching CSG glob patterns.
**
** Options specific to the changes command:
**    --header          Identify the repository if report is non-empty.
**    -v|--verbose      Say "(none)" if the change report is empty.
**    --classify        Start each line with the file's change type.
**    --no-classify     Do not print file change types.
**
................................................................................
  } flagDefs[] = {
    {"edited"  , C_EDITED , 0}, {"updated"    , C_UPDATED   , 0},
    {"changed" , C_CHANGED, 0}, {"missing"    , C_MISSING   , 0},
    {"added"   , C_ADDED  , 0}, {"deleted"    , C_DELETED   , 0},
    {"renamed" , C_RENAMED, 0}, {"conflict"   , C_CONFLICT  , 0},
    {"meta"    , C_META   , 0}, {"unmodified" , C_UNMODIFIED, 0},
    {"all"     , C_ALL    , 0}, {"extra"      , C_EXTRA     , 0},


    {"merge"   , C_MERGE  , 0}, {"classify"   , C_CLASSIFY  , 1},
  }, noFlagDefs[] = {
    {"no-merge", C_MERGE  , 0}, {"no-classify", C_CLASSIFY  , 1},
  };

#ifdef FOSSIL_DEBUG
  static const char *const bits[] = {
    "EDITED", "UPDATED", "CHANGED", "MISSING", "ADDED", "DELETED", "RENAMED",
    "CONFLICT", "META", "UNMODIFIED", "EXTRA", "MERGE", "RELPATH", "CLASSIFY",

  };
#endif

  Blob report = BLOB_INITIALIZER;
  int useSha1sum = find_option("sha1sum", 0, 0)!=0;
  int showHdr = find_option("header",0,0)!=0;
  int verboseFlag = find_option("verbose","v",0)!=0;
  const char *zIgnoreFlag = find_option("ignore", 0, 1);
  unsigned scanFlags = 0;
  int changes = g.argv[1][0]=='c';
  unsigned flags = 0;
  int vid, i;

  /* If --ignore is not specified, use the ignore-glob setting. */
  if( !zIgnoreFlag ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }

  /* Get the --dotfiles argument, or read it from the dotfiles setting. */
  if( find_option("dotfiles", 0, 0) || db_get_boolean("dotfiles", 0) ){
    scanFlags = SCAN_ALL;
  }

  /* Load affirmative flag options. */
  for( i=0; i<count(flagDefs); ++i ){
    if( (!flagDefs[i].changesOnly || changes)
     && find_option(flagDefs[i].option, 0, 0) ){
      flags |= flagDefs[i].mask;
    }
................................................................................
      flags &= ~noFlagDefs[i].mask;
    }
  }

  /* Confirm current working directory is within checkout. */
  db_must_be_within_tree();

  /* Get checkout version. l*/
  vid = db_lget_int("checkout", 0);

  /* Relative path flag determination is done by a shared function. */
  if( determine_cwd_relative_option() ){
    flags |= C_RELPATH;
  }

#ifdef FOSSIL_DEBUG
  for( i=0; i<count(bits); ++i ){
................................................................................
    }
  }
  printf("\n");
#endif

  /* We should be done with options. */
  verify_all_options();

  /* Check for changed files. */
  vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);

  /* Search for unmanaged files if requested.  Exclude reserved files. */
  if( flags & C_EXTRA ){
    Glob *pIgnore = glob_create(zIgnoreFlag);
    locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
    glob_free(pIgnore);
    db_multi_exec("DELETE FROM sfile WHERE x IN (%s)",
        fossil_all_reserved_names(0));
  }

  /* The status command prints general information before the change list. */
  if( !changes ){

    fossil_print("repository:   %s\n", db_repository_filename());
    fossil_print("local-root:   %s\n", g.zLocalRoot);
    if( g.zConfigDbName ){
      fossil_print("config-db:    %s\n", g.zConfigDbName);
    }
    if( vid ){
      show_common_info(vid, "checkout:", 1, 1);
    }
    db_record_repository_filename(0);
  }

  /* Find and print all requested changes. */
  blob_zero(&report);
  status_report(&report, flags);
  if( blob_size(&report) ){
    if( showHdr ){
      fossil_print("Changes for %s at %s:\n", db_get("project-name", "???"),
                   g.zLocalRoot);
    }
    blob_write_to_file(&report, "-");
  }else if( verboseFlag ){
    fossil_print("  (none)\n");
  }
  blob_reset(&report);

  /* The status command ends with warnings about ambiguous leaves (forks). */
  if( !changes ){
    leaf_ambiguity_warning(vid, vid);
  }
}

................................................................................
      fossil_print("%s%s\n", type, zPathname);
    }
    free(zFullName);
  }
  db_finalize(&q);
}


















































/*
** COMMAND: extras
**
** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
**
** Print a list of all files in the source tree that are not part of the
** current checkout. See also the "clean" command. If paths are specified,