-C Add\sthe\s".ar\sx"\scommand\sto\sthe\sshell.\sFor\sextracting\sthe\scontents\sof\ssqlar\narchives.
-D 2017-12-07T21:03:33.903
+C Improve\sparsing\sof\s".ar"\scommands.\sAdd\snew\stest\sfile\sfor\sthe\ssame.
+D 2017-12-09T17:58:02.648
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 17e220191860a64a18c084141e1a8b7309e166a6f2d42c02021af27ea080d157
-F src/shell.c.in 2f9ae0bee09bdd35922ab7ed264d88e1d7fb34d39d37fc633e6a3a1af60036be
+F src/shell.c.in 907661eeab82949420270b24f5989a399242cb8721e6140f73b3a46939fc4820
F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35458
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
+F test/shell8.test 98b1d7b218060e557b3a789f3396635a0c03873ea652b3154c7f3f238d4a1a8f
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c9827a01a6e107f38f85c2b2c1c7a599e443067b106217e965b6936441ca619d
-R 4b2bb930e9456062f8914cba7a04cf63
+P 0cc699d14adfe8c7b7be50c180186562861806c47425c80c935bce43ee5c5c12
+R 0b3e6167ae82d64c1e021b537a83d40a
U dan
-Z 4726613d4458219c808274490c55a044
+Z 9b95380c27ad603c463b4469d523a6d2
if( *pRc==SQLITE_OK ) *pRc = rc;
}
+/*
+** Structure representing a single ".ar" command.
+*/
+typedef struct ArCommand ArCommand;
+struct ArCommand {
+ int eCmd; /* An AR_CMD_* value */
+ const char *zFile; /* --file argument, or NULL */
+ const char *zDir; /* --directory argument, or NULL */
+ int bVerbose; /* True if --verbose */
+ int nArg; /* Number of command arguments */
+ char **azArg; /* Array of command arguments */
+};
+
+/*
+** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
+*/
+static int arUsage(void){
+ /* todo */
+ raw_printf(stderr, "error in .ar command line\n");
+ return SQLITE_ERROR;
+}
+
+/*
+** Values for ArCommand.eCmd.
+*/
+#define AR_CMD_CREATE 1
+#define AR_CMD_EXTRACT 2
+#define AR_CMD_LIST 3
+#define AR_CMD_UPDATE 4
+
+/*
+** Parse the command line for an ".ar" command. The results are written into
+** structure (*pAr). SQLITE_OK is returned if the command line is parsed
+** successfully, otherwise an error message is written to stderr and
+** SQLITE_ERROR returned.
+*/
+static int arParseCommand(
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg, /* Number of entries in azArg[] */
+ ArCommand *pAr /* Populate this object */
+){
+ if( nArg<=1 ){
+ return arUsage();
+ }else{
+ char *z = azArg[1];
+ memset(pAr, 0, sizeof(ArCommand));
+
+ if( z[0]!='-' ){
+ /* Traditional style [tar] invocation */
+ int i;
+ int iArg = 2;
+ for(i=0; z[i]; i++){
+ switch( z[i] ){
+ case 'c':
+ if( pAr->eCmd ) return arUsage();
+ pAr->eCmd = AR_CMD_CREATE;
+ break;
+ case 'x':
+ if( pAr->eCmd ) return arUsage();
+ pAr->eCmd = AR_CMD_EXTRACT;
+ break;
+ case 't':
+ if( pAr->eCmd ) return arUsage();
+ pAr->eCmd = AR_CMD_LIST;
+ break;
+ case 'u':
+ if( pAr->eCmd ) return arUsage();
+ pAr->eCmd = AR_CMD_UPDATE;
+ break;
+
+ case 'v':
+ pAr->bVerbose = 1;
+ break;
+ case 'f':
+ if( iArg>=nArg ) return arUsage();
+ pAr->zFile = azArg[iArg++];
+ break;
+ case 'C':
+ if( iArg>=nArg ) return arUsage();
+ pAr->zDir = azArg[iArg++];
+ break;
+
+ default:
+ return arUsage();
+ }
+ }
+
+ pAr->nArg = nArg-iArg;
+ if( pAr->nArg>0 ){
+ pAr->azArg = &azArg[iArg];
+ }
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of .ar "Update" command.
+*/
+static int arUpdateCmd(ShellState *p, ArCommand *pAr){
+ raw_printf(stderr, "todo...\n");
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of .ar "lisT" command.
+*/
+static int arListCommand(ShellState *p, ArCommand *pAr){
+ raw_printf(stderr, "todo...\n");
+ return SQLITE_OK;
+}
+
+
/*
** Implementation of .ar "eXtract" command.
*/
-static int arExtractCommand(ShellState *p, int bVerbose){
+static int arExtractCommand(ShellState *p, ArCommand *pAr){
const char *zSql1 =
"SELECT name, writefile(name, "
"CASE WHEN (data AND sz>=0 AND sz!=length(data)) THEN uncompress(data) "
shellPrepare(p, &rc, zSql1, &pSql);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
- if( bVerbose ){
+ if( pAr->bVerbose ){
raw_printf(stdout, "%s\n", sqlite3_column_text(pSql, 0));
}
}
*/
static int arCreateCommand(
ShellState *p, /* Shell state pointer */
- char **azFile, /* Array of files to add to archive */
- int nFile, /* Number of entries in azFile[] */
- int bVerbose /* True to be verbose on stdout */
+ ArCommand *pAr /* Command arguments and options */
){
const char *zSql =
"WITH f(n, m, t, d) AS ("
shellPrepare(p, &rc, zInsert, &pInsert);
shellPrepare(p, &rc, zSql, &pStmt);
- for(i=0; i<nFile && rc==SQLITE_OK; i++){
- sqlite3_bind_text(pStmt, 1, azFile[i], -1, SQLITE_STATIC);
+ for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
+ sqlite3_bind_text(pStmt, 1, pAr->azArg[i], -1, SQLITE_STATIC);
sqlite3_bind_int(pStmt, 2, S_IFDIR);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int sz;
int mode = sqlite3_column_int(pStmt, 1);
unsigned int mtime = sqlite3_column_int(pStmt, 2);
- if( bVerbose ){
+ if( pAr->bVerbose ){
raw_printf(stdout, "%s\n", zName);
}
char **azArg, /* Array of arguments passed to dot command */
int nArg /* Number of entries in azArg[] */
){
- int bVerbose = 0;
- char cmd = 0;
- int i;
- int n1;
- if( nArg<=1 ) goto usage;
+ ArCommand cmd;
+ int rc;
+ rc = arParseCommand(azArg, nArg, &cmd);
+ if( rc==SQLITE_OK ){
+ switch( cmd.eCmd ){
+ case AR_CMD_CREATE:
+ rc = arCreateCommand(pState, &cmd);
+ break;
- n1 = strlen(azArg[1]);
- for(i=0; i<n1; i++){
- char c = azArg[1][i];
- if( c=='c' || c=='x' ){
- if( cmd ) goto usage;
- cmd = c;
- }
- else if( c=='v' ){
- bVerbose = 1;
- }else{
- goto usage;
- }
- }
+ case AR_CMD_EXTRACT:
+ rc = arExtractCommand(pState, &cmd);
+ break;
- if( cmd=='c' ){
- return arCreateCommand(pState, &azArg[2], nArg-2, bVerbose);
- }
+ case AR_CMD_LIST:
+ rc = arListCommand(pState, &cmd);
+ break;
- if( cmd=='x' ){
- if( nArg!=2 ) goto usage;
- return arExtractCommand(pState, bVerbose);
+ default:
+ assert( cmd.eCmd==AR_CMD_UPDATE );
+ rc = arUpdateCmd(pState, &cmd);
+ break;
+ }
}
- usage:
- raw_printf(stderr, "Usage %s sub-command ?args...?\n", azArg[0]);
- return SQLITE_ERROR;
+ return rc;
}
--- /dev/null
+# 2017 December 9
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Test the shell tool ".ar" command.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix shell8
+set CLI [test_find_cli]
+
+proc populate_dir {dirname spec} {
+ # First delete the current tree, if one exists.
+ file delete -force $dirname
+
+ # Recreate the root of the new tree.
+ file mkdir $dirname
+
+ # Add each file to the new tree.
+ foreach {f d} $spec {
+ set path [file join $dirname $f]
+ file mkdir [file dirname $path]
+ set fd [open $path w]
+ puts -nonewline $fd $d
+ close $fd
+ }
+}
+
+proc dir_to_list {dirname} {
+ set res [list]
+ foreach f [glob -nocomplain $dirname/*] {
+ set mtime [file mtime $f]
+ set perm [file attributes $f -perm]
+ set relpath [file join {*}[lrange [file split $f] 1 end]]
+ lappend res
+ if {[file isdirectory $f]} {
+ lappend res [list $relpath / $mtime $perm]
+ lappend res {*}[dir_to_list $f]
+ } else {
+ set fd [open $f]
+ set data [read $fd]
+ close $fd
+ lappend res [list $relpath $data $mtime $perm]
+ }
+ }
+ lsort $res
+}
+
+proc dir_compare {d1 d2} {
+ set l1 [dir_to_list $d1]
+ set l2 [dir_to_list $d1]
+ string compare $l1 $l2
+}
+
+populate_dir ar1 {
+ file1 "abcd"
+ file2 "efgh"
+ dir1/file3 "ijkl"
+}
+
+set expected [dir_to_list ar1]
+# puts "# $expected"
+do_test 1.1 {
+ forcedelete test_ar.db
+
+ catchcmd test_ar.db ".ar c ar1"
+ file delete -force ar1
+ catchcmd test_ar.db ".ar x"
+
+ dir_to_list ar1
+} $expected
+
+
+
+finish_test