Improve parsing of ".ar" commands. Add new test file for the same.

FossilOrigin-Name: 840401cc8ce3a09e0663b46973ecd2856d9607be71d2d1e9b21f7df7a82dcbe5
This commit is contained in:
dan 2017-12-09 17:58:02 +00:00
parent 25c1218e73
commit 88be020916
4 changed files with 232 additions and 43 deletions

View File

@ -1,5 +1,5 @@
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
@ -474,7 +474,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
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
@ -1214,6 +1214,7 @@ F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
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
@ -1681,7 +1682,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
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

View File

@ -1 +1 @@
0cc699d14adfe8c7b7be50c180186562861806c47425c80c935bce43ee5c5c12
840401cc8ce3a09e0663b46973ecd2856d9607be71d2d1e9b21f7df7a82dcbe5

View File

@ -4116,10 +4116,124 @@ static void shellReset(
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) "
@ -4136,7 +4250,7 @@ static int arExtractCommand(ShellState *p, int bVerbose){
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));
}
}
@ -4167,9 +4281,7 @@ static int arExtractCommand(ShellState *p, int bVerbose){
*/
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 ("
@ -4204,8 +4316,8 @@ static int arCreateCommand(
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;
@ -4213,7 +4325,7 @@ static int arCreateCommand(
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);
}
@ -4280,38 +4392,31 @@ static int arDotCommand(
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;
case AR_CMD_LIST:
rc = arListCommand(pState, &cmd);
break;
default:
assert( cmd.eCmd==AR_CMD_UPDATE );
rc = arUpdateCmd(pState, &cmd);
break;
}
}
if( cmd=='c' ){
return arCreateCommand(pState, &azArg[2], nArg-2, bVerbose);
}
if( cmd=='x' ){
if( nArg!=2 ) goto usage;
return arExtractCommand(pState, bVerbose);
}
usage:
raw_printf(stderr, "Usage %s sub-command ?args...?\n", azArg[0]);
return SQLITE_ERROR;
return rc;
}

83
test/shell8.test Normal file
View File

@ -0,0 +1,83 @@
# 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