From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46583) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZYgiQ-0006sx-V3 for qemu-devel@nongnu.org; Sun, 06 Sep 2015 16:39:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZYgiN-0004JY-H2 for qemu-devel@nongnu.org; Sun, 06 Sep 2015 16:39:06 -0400 Received: from mail-qg0-x233.google.com ([2607:f8b0:400d:c04::233]:36341) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZYgiN-0004IA-8D for qemu-devel@nongnu.org; Sun, 06 Sep 2015 16:39:03 -0400 Received: by qgx61 with SMTP id 61so51111677qgx.3 for ; Sun, 06 Sep 2015 13:39:02 -0700 (PDT) From: Programmingkid Content-Type: multipart/alternative; boundary=Apple-Mail-1--591727424 Date: Sun, 6 Sep 2015 16:39:00 -0400 Message-Id: <9D97AF3E-9B5D-414C-84DA-A8279A8A21DF@gmail.com> Mime-Version: 1.0 (Apple Message framework v1084) Subject: [Qemu-devel] [PATCH] ui/cocoa.m: Add configuration file support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Peter Maydell , qemu-devel qemu-devel --Apple-Mail-1--591727424 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Having to type out all the arguments to QEMU isn't fun. That is why we = need an easier way to setup QEMU. With a configuration file system, we just make = this file once, and allow QEMU to do the work for us. This configuration file = system is similar to how a shell like Bash works.=20 A configuration file is just a text file with QEMU's arguments in it. Configuration files can have comments in them making them easy to = document. The comment character is '#'. Everything including this character is ignored = up to the next newline character.=20 With this patch, QEMU could be placed in the dock and launched with a = single click. This is way faster, easier, and more user-friendly than the current = system.=20 Using a terminal to launch QEMU still works just the way it always has = for those who wish to continue using it. When QEMU is launched and no arguments are given to it, it will look for = a default configuration file in the same folder that QEMU is kept. If this = file is found, it is then loaded. If it isn't found, a file open dialog box is = displayed asking the user to select a configuration file to load. Being able to = select a configuration file gives the user options for how he may want QEMU to = run. There could be a configuration file for a Linux guest. Another one for a Mac = OS X guest. Another for a debug configuration for a Mac OS 9 guest. The = possibilites are endless. Signed-off-by: John Arbuckle --- This code in this patch is pretty portable. I would not be surprised if = someone implemented this patch in Linux.=20 ui/cocoa.m | 160 = +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 136 insertions(+), 24 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 334e6f6..3fcfd57 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -69,6 +69,8 @@ char **gArgv; bool stretch_video; NSTextField *pauseLabel; NSArray * supportedImageFileTypes; +bool configFileLoaded =3D false; +char *programPath; /* Used by loadConfigFile() */ =20 // keymap conversion int keymap[] =3D @@ -264,6 +266,124 @@ static void handleAnyDeviceErrors(Error * err) } =20 /* + * Loads QEMU's config file. + * Output is set using gArgv and gArgc variables. + */ +static void loadConfigFile(char *filePath) +{ + const int maxWordSize =3D 1024; + const int maxNumberOfWords =3D 1000; + char argvReplacement[maxNumberOfWords][maxWordSize]; + const char commentCharacter =3D '#'; + char c; + int index, word; + FILE *configFile; + bool lookingForOtherDoubleQuote; + bool lookingForOtherSingleQuote; + + COCOA_DEBUG("loadConfigFile(): opening file %s\n", filePath); + configFile =3D fopen(filePath, "r"); + if (!configFile) { + printf("Error: Failed to open file %s!\n", filePath); + printf("Reason: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + lookingForOtherDoubleQuote =3D false; + lookingForOtherSingleQuote =3D false; + index =3D 0; + word =3D 0; + + /* Read every character in the config file */ + while ((c =3D fgetc(configFile)) !=3D EOF) { + + if (c =3D=3D commentCharacter) { + while(fgetc(configFile) !=3D '\n') { /* Skip to end of line = */ } + continue; /* Skip comment lines */ + } + + if (c =3D=3D '"') { + lookingForOtherDoubleQuote =3D !lookingForOtherDoubleQuote; + continue; + } + + if(c =3D=3D '\'') { + lookingForOtherSingleQuote =3D !lookingForOtherSingleQuote; + continue; + } + + if((c =3D=3D '\n' || c =3D=3D ' ') && = !lookingForOtherDoubleQuote && + = !lookingForOtherSingleQuote) { + argvReplacement[word][index] =3D '\0'; + index =3D 0; + if(strlen(argvReplacement[word]) > 0) { /* If not empty = line */ + word++; + } + if (word >=3D maxNumberOfWords) { + printf("Error: word limit in config file reached!\n"); + exit(EXIT_FAILURE); + } + continue; + } + + argvReplacement[word][index] =3D c; + index++; + if(index >=3D maxWordSize) { + printf("Error: max word size reached in config file!\n"); + exit(EXIT_FAILURE); + } + } + + /* Initialize global variables */ + gArgc =3D word+1; /* Add one for the application's path */ + gArgv =3D (char **) g_malloc(sizeof(char*) * gArgc); + + /* Add program's name to global variable */ + gArgv[0] =3D programPath; + + /* Copy data from temporary buffer to global variable */ + for(index =3D 1; index < gArgc; index++) { + gArgv[index] =3D g_strdup_printf("%s", = argvReplacement[index-1]); + } + configFileLoaded =3D true; + fclose(configFile); + +#ifdef DEBUG + printf("Printing out every argument being used:\n"); + for (index =3D 0; index < gArgc; index++) { + printf("argv[%d] =3D %s\n", index, gArgv[index]); + } +#endif +} + +/* Finds and loads the default configuration file */ +static void loadDefaultConfigFile(char *programPath) +{ + int index; + + /* Obtain the program's file path only */ + index =3D strlen(programPath) - 1; + while(programPath[index] !=3D '/' && index > 0) { + index--; + } + char *pathOnlyString; /* file path minus file name */ + pathOnlyString =3D g_strndup(programPath, index+1); /* +1 for the = '/' */ + + char *defaultConfigFilePath; + const char *fileName =3D "QEMU_config.txt"; + defaultConfigFilePath =3D g_strdup_printf("%s%s", pathOnlyString, = fileName); + FILE *configFile; + configFile =3D fopen(defaultConfigFilePath, "r"); + if (configFile) { /* See if the file is there */ + fclose(configFile); + loadConfigFile(defaultConfigFilePath); + printf("Using default configuration file\n"); + } + g_free(defaultConfigFilePath); + g_free(pathOnlyString); +} + +/* ------------------------------------------------------ QemuCocoaView ------------------------------------------------------ @@ -898,12 +1018,12 @@ QemuCocoaView *cocoaView; =20 // Display an open dialog box if no arguments were passed or // if qemu was launched from the finder ( the Finder passes "-psn" = ) - if( gArgc <=3D 1 || strncmp ((char *)gArgv[1], "-psn", 4) =3D=3D 0) = { + // and no default configuration file was loaded. + if (configFileLoaded =3D=3D false && gArgc <=3D 1) { NSOpenPanel *op =3D [[NSOpenPanel alloc] init]; - [op setPrompt:@"Boot image"]; - [op setMessage:@"Select the disk image you want to boot.\n\nHit = the \"Cancel\" button to quit"]; + [op setPrompt:@"Load Config File"]; + [op setMessage:@"Select the configuration file you want to = load"]; #if (MAC_OS_X_VERSION_MAX_ALLOWED >=3D MAC_OS_X_VERSION_10_6) - [op setAllowedFileTypes:supportedImageFileTypes]; [op beginSheetModalForWindow:normalWindow completionHandler:^(NSInteger returnCode) { [self openPanelDidEnd:op @@ -955,20 +1075,10 @@ QemuCocoaView *cocoaView; if (returnCode =3D=3D NSFileHandlingPanelCancelButton) { exit(0); } else if (returnCode =3D=3D NSFileHandlingPanelOKButton) { - char *img =3D (char*)[ [ [ sheet URL ] path ] = cStringUsingEncoding:NSASCIIStringEncoding]; - - char **argv =3D g_new(char *, 4); - + char *file =3D (char*)[ [ [ sheet URL ] path ] = cStringUsingEncoding:NSASCIIStringEncoding]; [sheet close]; - - argv[0] =3D g_strdup(gArgv[0]); - argv[1] =3D g_strdup("-hda"); - argv[2] =3D g_strdup(img); - argv[3] =3D NULL; - - // printf("Using argc %d argv %s -hda %s\n", 3, gArgv[0], img); - - [self startEmulationWithArgc:3 argv:(char**)argv]; + loadConfigFile(file); + [self startEmulationWithArgc:gArgc argv:gArgv]; } } =20 @@ -1127,16 +1237,20 @@ QemuCocoaView *cocoaView; =20 @end =20 - int main (int argc, const char * argv[]) { - + NSAutoreleasePool * pool =3D [NSAutoreleasePool new]; + programPath =3D g_strdup_printf("%s", argv[0]); gArgc =3D argc; gArgv =3D (char **)argv; - int i; =20 + if(argc =3D=3D 1) { /* If only the program's name was given */ + loadDefaultConfigFile(programPath); + } + + int i; /* In case we don't need to display a window, let's not do that */ - for (i =3D 1; i < argc; i++) { - const char *opt =3D argv[i]; + for (i =3D 1; i < gArgc; i++) { + const char *opt =3D gArgv[i]; =20 if (opt[0] =3D=3D '-') { /* Treat --foo the same as -foo. */ @@ -1154,8 +1268,6 @@ int main (int argc, const char * argv[]) { } } =20 - NSAutoreleasePool * pool =3D [[NSAutoreleasePool alloc] init]; - // Pull this console process up to being a fully-fledged graphical // app with a menubar and Dock icon ProcessSerialNumber psn =3D { 0, kCurrentProcess }; --=20 1.7.5.4 --Apple-Mail-1--591727424 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii
Having = to type out all the arguments to QEMU isn't fun. That is why we need = an
file once, and allow QEMU to do the work for us. = This configuration file system
is similar to how a shell like Bash = works. 

A configuration file is just a = text file with QEMU's arguments in it.
Configuration files can have = comments in them making them easy to document. The
the next newline character. 

With this patch, QEMU could be placed = in the dock and launched with a single click.
This = is way faster, easier, and more user-friendly than the current = system. 
Using a terminal to launch QEMU still works just = the way it always has for those
who wish to continue using = it.

When QEMU is launched and no = arguments are given to it, it will look for a
found, it is then loaded. If it isn't found, a file = open dialog box is displayed
asking the user to select a = configuration file to load. Being able to select a
could be a configuration file for a Linux guest. = Another one for a Mac OS X
guest. Another for a debug = configuration for a Mac OS 9 guest. The possibilites
are = endless.

Signed-off-by: John Arbuckle = <programmingkidx@gmail.com>= ;

---
This code in this patch is = pretty portable. I would not be surprised if someone


diff --git a/ui/cocoa.m = b/ui/cocoa.m
index 334e6f6..3fcfd57 100644
--- = a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -69,6 +69,8 @@ char = **gArgv;
 bool stretch_video;
 NSArray * = supportedImageFileTypes;
+bool configFileLoaded =3D = false;
+char *programPath; /* Used by loadConfigFile() = */

 

 int keymap[] =3D
@@ = -264,6 +266,124 @@ static void handleAnyDeviceErrors(Error * = err)
 }

 

 /*
+ * Loads QEMU's config = file.
+ * Output is set using gArgv and gArgc = variables.
+ */
+static void loadConfigFile(char = *filePath)
+{
+    const int maxWordSize = =3D 1024;
+    const int maxNumberOfWords =3D = 1000;
+    char = argvReplacement[maxNumberOfWords][maxWordSize];
+    int index, = word;
+    FILE *configFile;
+    COCOA_DEBUG("loadConfigFile(): = opening file %s\n", filePath);
+    configFile =3D = fopen(filePath, "r");
+    if (!configFile) {
+        printf("Reason: %s\n", = strerror(errno));
+        = exit(EXIT_FAILURE);
+    }
+
+    = lookingForOtherDoubleQuote =3D false;
+    = lookingForOtherSingleQuote =3D false;
+    index =3D = 0;
+
+    /* Read every = character in the config file */
+    while ((c =3D = fgetc(configFile)) !=3D EOF) {
+
+        if (c =3D=3D= commentCharacter) {
+            = while(fgetc(configFile) !=3D '\n') { /* Skip to end of line */ = }
+        }
+        if (c =3D=3D '"') = {
+          =   continue;
+        }
+        if(c =3D=3D '\'') = {
+          =   continue;
+        }
+        if((c =3D=3D '\n' || c = =3D=3D ' ') && !lookingForOtherDoubleQuote &&
+        =     index =3D 0;
+          =   if(strlen(argvReplacement[word]) > 0) {  /* If not empty = line */
+              =   word++;
+            = }
+              =   printf("Error: word limit in config file reached!\n");
+            = }
+
+        = argvReplacement[word][index] =3D c;
+        = index++;
+        if(index >=3D = maxWordSize) {
+            = printf("Error: max word size reached in config file!\n");
+        }
+
+    /* Initialize global variables = */
+
+    /* Add program's name to global = variable */
+    gArgv[0] =3D programPath;
+    /* Copy data from temporary buffer = to global variable */
+    for(index =3D 1; index < gArgc; = index++) {
+        gArgv[index] =3D = g_strdup_printf("%s", argvReplacement[index-1]);
+    configFileLoaded =3D true;
+
+#ifdef DEBUG
+    for (index =3D 0; index < gArgc; = index++) {
+        printf("argv[%d] =3D = %s\n", index, gArgv[index]);
+    }
+}
+
+/* Finds and loads the default = configuration file */
+static void loadDefaultConfigFile(char = *programPath)
+{
+    int index;
+    /* Obtain the program's file path = only */
+    index =3D strlen(programPath) - = 1;
+        index--;
+    char *pathOnlyString; /* file path = minus file name */
+    pathOnlyString =3D = g_strndup(programPath, index+1); /* +1 for the '/' */
+    char = *defaultConfigFilePath;
+    const char *fileName =3D= "QEMU_config.txt";
+    defaultConfigFilePath =3D = g_strdup_printf("%s%s", pathOnlyString, fileName);
+    configFile =3D = fopen(defaultConfigFilePath, "r");
+    if (configFile) { /* = See if the file is there */
+        = fclose(configFile);
+        = loadConfigFile(defaultConfigFilePath);
+        = printf("Using default configuration file\n");
+    = g_free(defaultConfigFilePath);
+    = g_free(pathOnlyString);
+}
+
+/*
  = ------------------------------------------------------
  = ------------------------------------------------------
@@ = -898,12 +1018,12 @@ QemuCocoaView *cocoaView;

 

     // if qemu was launched from = the finder ( the Finder passes "-psn" )
-    if( gArgc <=3D= 1 || strncmp ((char *)gArgv[1], "-psn", 4) =3D=3D 0) {
+    if (configFileLoaded =3D=3D false = && gArgc <=3D 1) {
         = NSOpenPanel *op =3D [[NSOpenPanel alloc] init];
+        [op = setMessage:@"Select the configuration file you want to load"];
-        [op = setAllowedFileTypes:supportedImageFileTypes];
       =       completionHandler:^(NSInteger returnCode)
@@ -955,20 +1075,10 @@ QemuCocoaView = *cocoaView;
     if (returnCode =3D=3D = NSFileHandlingPanelCancelButton) {
         = exit(0);
     } else if (returnCode =3D=3D = NSFileHandlingPanelOKButton) {
-        char = *img =3D (char*)[ [ [ sheet URL ] path ] = cStringUsingEncoding:NSASCIIStringEncoding];
-        char **argv =3D = g_new(char *, 4);
-
+        char *file =3D = (char*)[ [ [ sheet URL ] path ] = cStringUsingEncoding:NSASCIIStringEncoding];
-        argv[0] =3D = g_strdup(gArgv[0]);
-        argv[1] =3D = g_strdup("-hda");
-        argv[2] =3D = g_strdup(img);
-        argv[3] =3D = NULL;
-
-        // printf("Using argc = %d argv %s -hda %s\n", 3, gArgv[0], img);
-
-        = [self startEmulationWithArgc:3 argv:(char**)argv];
     }
 }

 

@@ = -1127,16 +1237,20 @@ QemuCocoaView *cocoaView;

 

 

-
 int main (int argc, const char = * argv[]) {
-
+    NSAutoreleasePool * pool =3D = [NSAutoreleasePool new];
+    programPath =3D = g_strdup_printf("%s", argv[0]);
     gArgc =3D = argc;
     gArgv =3D (char = **)argv;
-    int i;

 

+        = loadDefaultConfigFile(programPath);
+    }
+    int i;
     /* In case = we don't need to display a window, let's not do that */
 

@@ -1154,8 +1268,6 @@ int main (int argc, const = char * argv[]) {
         }
 

-    NSAutoreleasePool * = pool =3D [[NSAutoreleasePool alloc] init];
-
     // Pull = this console process up to being a fully-fledged graphical
1.7.5.4