From 4ddb4999e2ec2de02a40085ad75f43c92a220f21 Mon Sep 17 00:00:00 2001
From: John Hodge <tpg@mutabah.net>
Date: Wed, 25 Dec 2013 08:49:39 +0800
Subject: [PATCH] Tools/DiskTool - Added script file support

---
 Tools/DiskTool/main.c | 263 +++++++++++++++++++++++++++++++-----------
 1 file changed, 198 insertions(+), 65 deletions(-)

diff --git a/Tools/DiskTool/main.c b/Tools/DiskTool/main.c
index f8781a49..3dd2aa09 100644
--- a/Tools/DiskTool/main.c
+++ b/Tools/DiskTool/main.c
@@ -5,9 +5,77 @@
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
+#include <ctype.h>
+#include <assert.h>
 #include <disktool_common.h>
 
+#define ACESS_VERSION	"0.15-pr"
+#define VERSION_STR	"Acess2 DiskTool v"ACESS_VERSION
+
+ int	main(int argc, const char *argv[]);
+void	PrintUsage(void);
+ int	RunCommand(int argc, const char *argv[]);
+void	RunScript(const char *Filename);
+
 // === CODE ===
+int main(int argc, const char *argv[])
+{
+	// Parse arguments
+	for( int i = 1; i < argc; i ++ )
+	{
+		const char *arg = argv[i];
+		if( arg[0] != '-' )
+		{
+			int rv = RunCommand(argc-i, argv+i);
+			if( rv == 0 ) {
+				PrintUsage();
+				return 1;
+			}
+			else if( rv < 0 ) {
+				return 0;
+			}
+			else {
+			}
+			i += rv;
+		}
+		else if( arg[1] != '-' )
+		{
+			switch( *++arg )
+			{
+			case 's':
+				if( i+1 >= argc ) {
+					fprintf(stderr, "Option '-s' requires an argument\n");
+					return 1;
+				}
+				RunScript( argv[++i] );
+				break;
+			default:
+				fprintf(stderr, "Unkown option '-%c', try --help\n", *arg);
+				return 1;
+			}
+		}
+		else
+		{
+			if( strcmp(arg, "--help") == 0 ) {
+				PrintUsage();
+				return 0;
+			}
+			else if( strcmp(arg, "--version") == 0 ) {
+				fprintf(stderr, VERSION_STR);
+				return 0;
+			}
+			else {
+				fprintf(stderr, "Unknown option '%s', try --help\n", arg);
+				return 1;
+			}
+		}
+	}
+	
+	DiskTool_Cleanup();
+	
+	return 0;
+}
+
 void PrintUsage(void)
 {
 	fprintf(stderr,
@@ -33,92 +101,157 @@ void PrintUsage(void)
 		);
 }
 
-int main(int argc, char *argv[])
+int RunCommand(int argc, const char *argv[])
 {
-	// Parse arguments
-	for( int i = 1; i < argc; i ++ )
+	if( argc < 1 )	return 0;
+	
+	const char *name = argv[0];
+	if( strcmp("mount", name) == 0 )
 	{
-		if( strcmp("mount", argv[i]) == 0 || strcmp("-i", argv[i]) == 0 ) {
-			// Mount an image
-			if( argc - i < 3 ) {
-				fprintf(stderr, "mount takes 2 arguments (image and mountpoint)\n");
-				PrintUsage();
-				exit(-1);
-			}
+		// Mount an image
+		if( argc < 3 ) {
+			fprintf(stderr, "mount takes 2 arguments (image and mountpoint)\n");
+			return 0;
+		}
 
-			if( DiskTool_MountImage(argv[i+2], argv[i+1]) ) {
-				fprintf(stderr, "Unable to mount '%s' as '%s'\n", argv[i+1], argv[i+2]);
-				break;
-			}
+		if( DiskTool_MountImage(argv[2], argv[1]) ) {
+			fprintf(stderr, "Unable to mount '%s' as '%s'\n", argv[1], argv[2]);
+			return -1;
+		}
 
-			i += 2;
-			continue ;
+		return 2;
+	}
+	else if( strcmp("lvm", name) == 0 )
+	{
+		// Bind a "file" to LVM
+		if( argc < 3 ) {
+			fprintf(stderr, "lvm takes 2 arguments (iamge and ident)\n");
+			return 0;
 		}
-		
-		if( strcmp("mountlvm", argv[i]) == 0 || strcmp("lvm", argv[i]) == 0 ) {
-			
-			if( argc - i < 3 ) {
-				fprintf(stderr, "lvm takes 2 arguments (iamge and ident)\n");
-				PrintUsage();
-				exit(-1);
-			}
 
-			if( DiskTool_RegisterLVM(argv[i+2], argv[i+1]) ) {
-				fprintf(stderr, "Unable to register '%s' as LVM '%s'\n", argv[i+1], argv[i+2]);
-				break;
-			}
-			
-			i += 2;
-			continue ;
+		if( DiskTool_RegisterLVM(argv[2], argv[1]) ) {
+			fprintf(stderr, "Unable to register '%s' as LVM '%s'\n", argv[1], argv[2]);
+			return -1;
 		}
 		
-		if( strcmp("ls", argv[i]) == 0 ) {
-			if( argc - i < 2 ) {
-				fprintf(stderr, "ls takes 1 argument (path)\n");
-				PrintUsage();
-				break;
-			}
-
-			DiskTool_ListDirectory(argv[i+1]);
-			i += 1;
-			continue ;
+		return 2;
+	}
+	else if( strcmp("ls", name) == 0 )
+	{
+		if( argc < 2 ) {
+			fprintf(stderr, "ls takes 1 argument (path)\n");
+			return 0;
 		}
+
+		DiskTool_ListDirectory(argv[1]);
+		return 1;
+	}
+	else if( strcmp("cp", name) == 0 )
+	{
 		
-		if( strcmp("cp", argv[i]) == 0 ) {
-			
-			if( argc - i < 3 ) {
-				fprintf(stderr, "cp takes 2 arguments (source and destination)\n");
-				PrintUsage();
-				break;
-			}
+		if( argc < 3 ) {
+			fprintf(stderr, "cp takes 2 arguments (source and destination)\n");
+			return 0;
+		}
+
+		DiskTool_Copy(argv[1], argv[2]);
 
-			DiskTool_Copy(argv[i+1], argv[i+2]);			
+		return 2;
+	}
+	else if( strcmp("cat", name) == 0 ) {
 
-			i += 2;
-			continue ;
+		if( argc < 2 ) {
+			fprintf(stderr, "cat takes 1 argument (path)\n");
+			return 0;
 		}
 
-		if( strcmp("cat", argv[i]) == 0 ) {
+		DiskTool_Cat(argv[1]);
 
-			if( argc - 1 < 2 ) {
-				fprintf(stderr, "cat takes 1 argument (path)\n");
-				PrintUsage();
-				break;
+		return 1;
+	}
+	else {
+		fprintf(stderr, "Unknown command '%s'\n", name);
+		return 0;
+	}
+}
+
+int tokenise(const char **ptrs, int max_ptrs, char *buffer)
+{
+	 int	idx = 0;
+	while( *buffer )
+	{
+		// Eat leading whitespace
+		while( *buffer && isspace(*buffer) )
+			buffer ++;
+		if( *buffer == '"' ) {
+			// Double-quoted string
+			buffer ++;
+			ptrs[idx++] = buffer;
+			while( *buffer && *buffer != '"' )
+			{
+				if( *buffer == '\\' && buffer[1] == '"' ) {
+					char *tmp = buffer;
+					while( tmp[1] ) {
+						tmp[0] = tmp[1];
+						tmp ++;
+					}
+				}
+				buffer ++;
 			}
+			if( *buffer )
+				*buffer++ = '\0';
+		}
+		else {
+			// whitespace delimited string
+			ptrs[idx++] = buffer;
+			while( *buffer && !isspace(*buffer) )
+				buffer ++;
+			if( *buffer )
+				*buffer++ = '\0';
+		}
+	}
+	return idx;
+}
 
-			DiskTool_Cat(argv[i+1]);
+void RunScript(const char *Filename)
+{
+	FILE	*fp = fopen(Filename, "r");
+	if( !fp ) {
+		fprintf(stderr, "Unable to open script '%s': %s\n", Filename, strerror(errno));
+		exit(1);
+	}
 
-			i += 1;
-			continue;
+	 int	 line = 0;	
+	char	buf[128];
+	while( NULL != fgets(buf, sizeof(buf), fp) )
+	{
+		line ++;
+		const int max_tokens = 4;
+		const char *tokens[max_tokens];
+		int ntok = tokenise(tokens, max_tokens, buf);
+		
+		if( ntok > max_tokens ) {
+			// ... 
+			break ;
+		}
+		
+		int rv = RunCommand(ntok, tokens);
+		assert(rv + 1 <= ntok);
+		if( rv == 0 ) {
+			// Oops, bad command
+			break;
+		}
+		else if( rv == -1 ) {
+			// Internal error
+			break;
+		}
+		else if( rv + 1 != ntok ) {
+			// Too many arguments
+			break;
 		}
-	
-		fprintf(stderr, "Unknown command '%s'\n", argv[i]);
-		PrintUsage();
 	}
 	
-	DiskTool_Cleanup();
-	
-	return 0;
+	fclose(fp);
 }
 
 // NOTE: This is in a native compiled file because it needs access to the real errno macro
-- 
GitLab