Fossil

Check-in [dba4fd9b]
Login

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

Overview
Comment:Added -- support to wiki create/commit/export. Refactored/simplified how fetching of a dash-as-stdin/stdout argument is done from command-side code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | double-dash-flag
Files: files | file ages | folders
SHA3-256: dba4fd9b69c5d8c7cb24d6874dcbcc826c5306b69fa303423fe4b3d01b768d52
User & Date: stephan 2019-09-27 14:32:22
Wiki:double-dash-flag
Context
2019-09-27
16:10
Added -- support to (add, rm, mv). check-in: 9a7101d5 user: stephan tags: double-dash-flag
14:32
Added -- support to wiki create/commit/export. Refactored/simplified how fetching of a dash-as-stdin/stdout argument is done from command-side code. check-in: dba4fd9b user: stephan tags: double-dash-flag
11:47
Added -- support to: (branch new) (uv add/cat/edit/export/rm) check-in: 78a30d8d user: stephan tags: double-dash-flag
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

139
140
141
142
143
144
145



146
147
148
149
150
151
152
....
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
....
1093
1094
1095
1096
1097
1098
1099





































1100
1101
1102
1103
1104
1105
1106
  void *xPostEval;       /* Optional, called after Tcl_Eval*(). */
  void *pPostContext;    /* Optional, provided to xPostEval(). */
};
#endif

struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */



  char *nameOfExe;        /* Full path of executable. */
  const char *zErrlog;    /* Log errors to this file, if not NULL */
  int isConst;            /* True if the output is unchanging & cacheable */
  const char *zVfsName;   /* The VFS to use for database connections */
  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  char *zAuxSchema;       /* Main repository aux-schema */
................................................................................
** flags). If fAllowDoubleDash is false then the "--" flag will
** trigger a fatal error exactly as if an unprocessed flag were
** encountered.
**
** Returns false (0) if fAllowDoubleDash is false or if "--" is not
** encountered. If fAllowDoubleDash is true and "--" is encountered,
** the argument index (in g.argv) at which "--" was encountered (and
** removed) is returned.
**
** Sidebar: the question of whether fAllowDoubleDash should be true or
** false would seem to boil down to: does the calling routine
** expect/allow arbitrary file/page/branch/whatever name arguments
** after its required arguments?
*/
static int verify_all_options_impl(int fAllowDoubleDash){
  int i;

  for(i=1; i<g.argc; i++){
    const char * arg = g.argv[i];
    if( arg[0]=='-' ){
      if( arg[1]=='-' && arg[2]==0 ){
        if(fAllowDoubleDash){
          /* Remove "--" from the list and assume any following
          ** arguments are file names. */
          remove_from_argv(i, 1);
          return i;
        }else{
          fossil_fatal("The -- flag is not allowed here.");
        }
      }else if( arg[1]!=0 ){
        fossil_fatal(
          "unrecognized command-line option, or missing argument: %s",
          arg);
................................................................................
/*
** Identical to verify_all_options() except that it honors the "--"
** flag and returns true (non-0) if that flag was encountered/consumed.
*/
int verify_all_options2(void){
  return verify_all_options_impl(1);
}






































/*
** This function returns a human readable version string.
*/
const char *get_version(){
  static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
                                MANIFEST_DATE " UTC";







>
>
>







 







|








>








|







 







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







139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
....
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
....
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
  void *xPostEval;       /* Optional, called after Tcl_Eval*(). */
  void *pPostContext;    /* Optional, provided to xPostEval(). */
};
#endif

struct Global {
  int argc; char **argv;  /* Command-line arguments to the program */
  int argDashDashIndex;   /* Index of the "--" flag in g.argv, if provided
                          ** (else 0). Not valid until verify_all_options()
                          ** or verify_all_options2() is called. */;
  char *nameOfExe;        /* Full path of executable. */
  const char *zErrlog;    /* Log errors to this file, if not NULL */
  int isConst;            /* True if the output is unchanging & cacheable */
  const char *zVfsName;   /* The VFS to use for database connections */
  sqlite3 *db;            /* The connection to the databases */
  sqlite3 *dbConfig;      /* Separate connection for global_config table */
  char *zAuxSchema;       /* Main repository aux-schema */
................................................................................
** flags). If fAllowDoubleDash is false then the "--" flag will
** trigger a fatal error exactly as if an unprocessed flag were
** encountered.
**
** Returns false (0) if fAllowDoubleDash is false or if "--" is not
** encountered. If fAllowDoubleDash is true and "--" is encountered,
** the argument index (in g.argv) at which "--" was encountered (and
** removed) is returned (that value will always be greater than 0).
**
** Sidebar: the question of whether fAllowDoubleDash should be true or
** false would seem to boil down to: does the calling routine
** expect/allow arbitrary file/page/branch/whatever name arguments
** after its required arguments?
*/
static int verify_all_options_impl(int fAllowDoubleDash){
  int i;
  g.argDashDashIndex = 0;
  for(i=1; i<g.argc; i++){
    const char * arg = g.argv[i];
    if( arg[0]=='-' ){
      if( arg[1]=='-' && arg[2]==0 ){
        if(fAllowDoubleDash){
          /* Remove "--" from the list and assume any following
          ** arguments are file names. */
          remove_from_argv(i, 1);
          return g.argDashDashIndex = i;
        }else{
          fossil_fatal("The -- flag is not allowed here.");
        }
      }else if( arg[1]!=0 ){
        fossil_fatal(
          "unrecognized command-line option, or missing argument: %s",
          arg);
................................................................................
/*
** Identical to verify_all_options() except that it honors the "--"
** flag and returns true (non-0) if that flag was encountered/consumed.
*/
int verify_all_options2(void){
  return verify_all_options_impl(1);
}

/*
** Expects nArgPos to be a valid index of g.argv. If nArgPos is a
** string with the value "-" and g.argDashDashIndex is greater than 0
** and <= nArgPos then the value "-" gets transformed to "./-". In all
** other cases, the value of g.argv[nArgPos] is returned as-is.
**
** The intention is that this function be called by commands which
** accept a filename argument for which "-" is interpreted as stdin or
** stdout. If the "--" flag was found BEFORE that filename flag then
** "-" is transformed such that it will be seen as a file named "./-"
** rather than "-" (stdin or stdout, depending on the context). Returns
** a string from g.argv or the static string "./-", so its lifetime is
** effectively that of the app.
*/
const char * get_dash_filename_arg(int nArgPos){
  const char * zName;
  assert(nArgPos < g.argc);
  zName = g.argv[nArgPos];
  if(zName!=0
     && g.argDashDashIndex>0 && g.argDashDashIndex<=nArgPos
     && fossil_strcmp("-",zName)==0){
    zName = "./-";
  }
  return zName;
};

/*
 ** Only for debugging during "--"-related refactoring. To be deleted
 ** before merging with trunk.
 */
void dump_g_argv(){
  int i;
  for( i = 0; i < g.argc; ++i ){
    fossil_print("\tg.argv[%d] = %s\n", i, g.argv[i]);
  }
}

/*
** This function returns a human readable version string.
*/
const char *get_version(){
  static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
                                MANIFEST_DATE " UTC";

Changes to src/unversioned.c.

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
...
380
381
382
383
384
385
386

387
388
389
390
391












392
393
394
395
396
397
398
399
  if( memcmp(zCmd, "add", nCmd)==0 ){
    const char *zError = 0;
    const char *zIn;
    const char *zAs;
    const char *zFileArg;
    Blob file;
    int i;
    int fDoubleDash;         /* True if "--" flag is provided */
    zAs = find_option("as",0,1);
    fDoubleDash = verify_all_options2();
    if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE");
    db_begin_transaction();
    content_rcvid_init("#!fossil unversioned add");
    for(i=3; i<g.argc; i++){
      zIn = zAs ? zAs : g.argv[i];
      if( zIn[0]==0 ){
        zError = "be empty string";
      }else if( zIn[0]=='/' ){
................................................................................
      }else if( contains_whitespace(zIn) ){
        zError = "contain whitespace";
      }
      if( zError ){
        fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn);
      }
      blob_init(&file,0,0);
      zFileArg = g.argv[i];
      if(fDoubleDash>0 && fDoubleDash<=i
         && fossil_strcmp("-",zFileArg)==0){
        zFileArg = "./-" /* do not treat "-" as stdin! */;
      }
      blob_read_from_file(&file, zFileArg, ExtFILE);
      unversioned_write(zIn, &file, mtime);
      blob_reset(&file);
    }
    db_end_transaction(0);
  }else if( memcmp(zCmd, "cat", nCmd)==0 ){
    int i;
................................................................................
    file_delete(zTFile);
    if( zMtime==0 ) mtime = time(0);
    unversioned_write(zUVFile, &content, mtime);
    db_end_transaction(0);
    blob_reset(&content);
  }else if( memcmp(zCmd, "export", nCmd)==0 ){
    Blob content;

    verify_all_options2();
    if( g.argc!=5 ) usage("export UVFILE OUTPUT");
    if( unversioned_content(g.argv[3], &content) ){
      fossil_fatal("no such uv-file: %Q", g.argv[3]);
    }












    blob_write_to_file(&content, g.argv[4]);
    blob_reset(&content);
  }else if( memcmp(zCmd, "hash", nCmd)==0 ){  /* undocumented */
    /* Show the hash value used during uv sync */
    int debugFlag = find_option("debug",0,0)!=0;
    fossil_print("%s\n", unversioned_content_hash(debugFlag));
  }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
    Stmt q;







<

|
|







 







|
<
<
<
<







 







>

|



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







294
295
296
297
298
299
300

301
302
303
304
305
306
307
308
309
310
...
314
315
316
317
318
319
320
321




322
323
324
325
326
327
328
...
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
404
405
406
407
  if( memcmp(zCmd, "add", nCmd)==0 ){
    const char *zError = 0;
    const char *zIn;
    const char *zAs;
    const char *zFileArg;
    Blob file;
    int i;

    zAs = find_option("as",0,1);
    verify_all_options2();
    if( zAs && g.argc!=4 ) usage("add --as UVFILE [--] DISKFILE");
    db_begin_transaction();
    content_rcvid_init("#!fossil unversioned add");
    for(i=3; i<g.argc; i++){
      zIn = zAs ? zAs : g.argv[i];
      if( zIn[0]==0 ){
        zError = "be empty string";
      }else if( zIn[0]=='/' ){
................................................................................
      }else if( contains_whitespace(zIn) ){
        zError = "contain whitespace";
      }
      if( zError ){
        fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn);
      }
      blob_init(&file,0,0);
      zFileArg = get_dash_filename_arg(i);




      blob_read_from_file(&file, zFileArg, ExtFILE);
      unversioned_write(zIn, &file, mtime);
      blob_reset(&file);
    }
    db_end_transaction(0);
  }else if( memcmp(zCmd, "cat", nCmd)==0 ){
    int i;
................................................................................
    file_delete(zTFile);
    if( zMtime==0 ) mtime = time(0);
    unversioned_write(zUVFile, &content, mtime);
    db_end_transaction(0);
    blob_reset(&content);
  }else if( memcmp(zCmd, "export", nCmd)==0 ){
    Blob content;
    const char * zOutfile;
    verify_all_options2();
    if( g.argc!=5 ) usage("export [--] UVFILE OUTPUT");
    if( unversioned_content(g.argv[3], &content) ){
      fossil_fatal("no such uv-file: %Q", g.argv[3]);
    }
    /*
    ** Pathological(?) corner case:
    **
    **   export -- --UVFILE -
    **
    ** We have no way of applying -- to just the UVFILE name but not
    ** the output file name, so the above would output the uv file
    ** literally named --UVFILE to a file literally named -. The only
    ** alternative is that we never apply -- to the output file name,
    ** which seems likely to cause yet more confusion.
    */
    zOutfile = get_dash_filename_arg(4);
    blob_write_to_file(&content, zOutfile);
    blob_reset(&content);
  }else if( memcmp(zCmd, "hash", nCmd)==0 ){  /* undocumented */
    /* Show the hash value used during uv sync */
    int debugFlag = find_option("debug",0,0)!=0;
    fossil_print("%s\n", unversioned_content_hash(debugFlag));
  }else if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){
    Stmt q;

Changes to src/wiki.c.

1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
....
1423
1424
1425
1426
1427
1428
1429





1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452

1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
....
1497
1498
1499
1500
1501
1502
1503

1504
1505
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518
1519
1520
/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
**    %fossil wiki export PAGENAME ?FILE?
**    %fossil wiki export ?FILE? -t|--technote DATETIME|TECHNOTE-ID
**
**       Sends the latest version of either a wiki page or of a tech note
**       to the given file or standard output.
**       If PAGENAME is provided, the wiki page will be output. For
**       a tech note either DATETIME or TECHNOTE-ID must be specified. If
**       DATETIME is used, the most recently modified tech note with that
**       DATETIME will be sent.
................................................................................
**
** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
** year-month-day form, it may be truncated, the "T" may be replaced by
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
** means UTC.
**





*/
void wiki_cmd(void){
  int n;
  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;
  }
  n = strlen(g.argv[2]);
  if( n==0 ){
    goto wiki_cmd_usage;
  }

  if( strncmp(g.argv[2],"export",n)==0 ){
    const char *zPageName;        /* Name of the wiki page to export */
    const char *zFile;            /* Name of the output file (0=stdout) */
    const char *zETime;           /* The name of the technote to export */
    int rid;                      /* Artifact ID of the wiki page */
    int i;                        /* Loop counter */
    char *zBody = 0;              /* Wiki page content */
    Blob body;                    /* Wiki page content */
    Manifest *pWiki = 0;          /* Parsed wiki page content */

    zETime = find_option("technote","t",1);

    if( !zETime ){
      if( (g.argc!=4) && (g.argc!=5) ){
        usage("export PAGENAME ?FILE?");
      }
      zPageName = g.argv[3];
      rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
        " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
        " ORDER BY x.mtime DESC LIMIT 1",
        zPageName
      );
      if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("wiki page [%s] not found",zPageName);
      }
      zFile = (g.argc==4) ? "-" : g.argv[4];
    }else{
      if( (g.argc!=3) && (g.argc!=4) ){
        usage("export ?FILE? --technote DATETIME|TECHNOTE-ID");
      }
      rid = wiki_technote_to_rid(zETime);
      if ( rid==-1 ){
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
      if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("technote [%s] not found",zETime);
      }
      zFile = (g.argc==3) ? "-" : g.argv[3];
    }
    for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){}
    zBody[i] = 0;
    blob_init(&body, zBody, -1);
    blob_append(&body, "\n", 1);
    blob_write_to_file(&body, zFile);
    blob_reset(&body);
................................................................................
    Blob content;                 /* Input content */
    int rid = 0;
    Manifest *pWiki = 0;          /* Parsed wiki page content */
    const char *zMimeType = find_option("mimetype", "M", 1);
    const char *zETime = find_option("technote", "t", 1);
    const char *zTags = find_option("technote-tags", NULL, 1);
    const char *zClr = find_option("technote-bgcolor", NULL, 1);

    if( g.argc!=4 && g.argc!=5 ){
      usage("commit|create PAGENAME ?FILE? [--mimetype TEXT-FORMAT]"
            " [--technote DATETIME] [--technote-tags TAGS]"
            " [--technote-bgcolor COLOR]");
    }
    zPageName = g.argv[3];
    if( g.argc==4 ){
      blob_read_from_channel(&content, stdin, -1);
    }else{

      blob_read_from_file(&content, g.argv[4], ExtFILE);
    }
    if( !zMimeType || !*zMimeType ){
      /* Try to deduce the mime type based on the prior version. */
      if ( !zETime ){
        rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
                     " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
                     " ORDER BY x.mtime DESC LIMIT 1",







|
|







 







>
>
>
>
>











<









<

>


|













|


|











|







 







>

|

|





>
|







1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
....
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445

1446
1447
1448
1449
1450
1451
1452
1453
1454

1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
....
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
**    %fossil wiki export PAGENAME [--] ?FILE?
**    %fossil wiki export -t|--technote DATETIME|TECHNOTE-ID [--] ?FILE?
**
**       Sends the latest version of either a wiki page or of a tech note
**       to the given file or standard output.
**       If PAGENAME is provided, the wiki page will be output. For
**       a tech note either DATETIME or TECHNOTE-ID must be specified. If
**       DATETIME is used, the most recently modified tech note with that
**       DATETIME will be sent.
................................................................................
**
** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
** year-month-day form, it may be truncated, the "T" may be replaced by
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
** means UTC.
**
** Options:
**   --                      For commands which support this, it means to treat
**                           all subsequent arguments as file names even if they
**                           start with a "-".
**
*/
void wiki_cmd(void){
  int n;
  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;
  }
  n = strlen(g.argv[2]);
  if( n==0 ){
    goto wiki_cmd_usage;
  }

  if( strncmp(g.argv[2],"export",n)==0 ){
    const char *zPageName;        /* Name of the wiki page to export */
    const char *zFile;            /* Name of the output file (0=stdout) */
    const char *zETime;           /* The name of the technote to export */
    int rid;                      /* Artifact ID of the wiki page */
    int i;                        /* Loop counter */
    char *zBody = 0;              /* Wiki page content */
    Blob body;                    /* Wiki page content */
    Manifest *pWiki = 0;          /* Parsed wiki page content */

    zETime = find_option("technote","t",1);
    verify_all_options2();
    if( !zETime ){
      if( (g.argc!=4) && (g.argc!=5) ){
        usage("export PAGENAME [--] ?FILE?");
      }
      zPageName = g.argv[3];
      rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
        " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
        " ORDER BY x.mtime DESC LIMIT 1",
        zPageName
      );
      if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("wiki page [%s] not found",zPageName);
      }
      zFile = g.argc==4 ? "-" : get_dash_filename_arg(4);
    }else{
      if( (g.argc!=3) && (g.argc!=4) ){
        usage("export --technote DATETIME|TECHNOTE-ID [--] ?FILE?");
      }
      rid = wiki_technote_to_rid(zETime);
      if ( rid==-1 ){
        fossil_fatal("ambiguous tech note id: %s", zETime);
      }
      if( (pWiki = manifest_get(rid, CFTYPE_EVENT, 0))!=0 ){
        zBody = pWiki->zWiki;
      }
      if( zBody==0 ){
        fossil_fatal("technote [%s] not found",zETime);
      }
      zFile = g.argc==3 ? "-" : get_dash_filename_arg(3);
    }
    for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){}
    zBody[i] = 0;
    blob_init(&body, zBody, -1);
    blob_append(&body, "\n", 1);
    blob_write_to_file(&body, zFile);
    blob_reset(&body);
................................................................................
    Blob content;                 /* Input content */
    int rid = 0;
    Manifest *pWiki = 0;          /* Parsed wiki page content */
    const char *zMimeType = find_option("mimetype", "M", 1);
    const char *zETime = find_option("technote", "t", 1);
    const char *zTags = find_option("technote-tags", NULL, 1);
    const char *zClr = find_option("technote-bgcolor", NULL, 1);
    verify_all_options2();
    if( g.argc!=4 && g.argc!=5 ){
      usage("commit|create PAGENAME [--mimetype TEXT-FORMAT]"
            " [--technote DATETIME] [--technote-tags TAGS]"
            " [--technote-bgcolor COLOR] [--] ?FILE?");
    }
    zPageName = g.argv[3];
    if( g.argc==4 ){
      blob_read_from_channel(&content, stdin, -1);
    }else{
      const char * zFilename = get_dash_filename_arg(4);
      blob_read_from_file(&content, zFilename, ExtFILE);
    }
    if( !zMimeType || !*zMimeType ){
      /* Try to deduce the mime type based on the prior version. */
      if ( !zETime ){
        rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
                     " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
                     " ORDER BY x.mtime DESC LIMIT 1",