qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] ui/cocoa.m: Add configuration file support


From: Programmingkid
Subject: [Qemu-devel] [PATCH] ui/cocoa.m: Add configuration file support
Date: Sun, 6 Sep 2015 16:39:00 -0400

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. 

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. 

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
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 <address@hidden>

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

 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 = false;
+char *programPath; /* Used by loadConfigFile() */

 

 // keymap conversion
 int keymap[] =
@@ -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 = 1024;
+    const int maxNumberOfWords = 1000;
+    char argvReplacement[maxNumberOfWords][maxWordSize];
+    const char commentCharacter = '#';
+    char c;
+    int index, word;
+    FILE *configFile;
+    bool lookingForOtherDoubleQuote;
+    bool lookingForOtherSingleQuote;
+
+    COCOA_DEBUG("loadConfigFile(): opening file %s\n", filePath);
+    configFile = fopen(filePath, "r");
+    if (!configFile) {
+        printf("Error: Failed to open file %s!\n", filePath);
+        printf("Reason: %s\n", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    lookingForOtherDoubleQuote = false;
+    lookingForOtherSingleQuote = false;
+    index = 0;
+    word = 0;
+
+    /* Read every character in the config file */
+    while ((c = fgetc(configFile)) != EOF) {
+
+        if (c == commentCharacter) {
+            while(fgetc(configFile) != '\n') { /* Skip to end of line */ }
+            continue; /* Skip comment lines */
+        }
+
+        if (c == '"') {
+            lookingForOtherDoubleQuote = !lookingForOtherDoubleQuote;
+            continue;
+        }
+
+        if(c == '\'') {
+            lookingForOtherSingleQuote = !lookingForOtherSingleQuote;
+            continue;
+        }
+
+        if((c == '\n' || c == ' ') && !lookingForOtherDoubleQuote &&
+                                                !lookingForOtherSingleQuote) {
+            argvReplacement[word][index] = '\0';
+            index = 0;
+            if(strlen(argvReplacement[word]) > 0) {  /* If not empty line */
+                word++;
+            }
+            if (word >= maxNumberOfWords) {
+                printf("Error: word limit in config file reached!\n");
+                exit(EXIT_FAILURE);
+            }
+            continue;
+        }
+
+        argvReplacement[word][index] = c;
+        index++;
+        if(index >= maxWordSize) {
+            printf("Error: max word size reached in config file!\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    /* Initialize global variables */
+    gArgc = word+1; /* Add one for the application's path */
+    gArgv = (char **) g_malloc(sizeof(char*) * gArgc);
+
+    /* Add program's name to global variable */
+    gArgv[0] = programPath;
+
+    /* Copy data from temporary buffer to global variable */
+    for(index = 1; index < gArgc; index++) {
+        gArgv[index] = g_strdup_printf("%s", argvReplacement[index-1]);
+    }
+    configFileLoaded = true;
+    fclose(configFile);
+
+#ifdef DEBUG
+    printf("Printing out every argument being used:\n");
+    for (index = 0; index < gArgc; index++) {
+        printf("argv[%d] = %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 = strlen(programPath) - 1;
+    while(programPath[index] != '/' && index > 0) {
+        index--;
+    }
+    char *pathOnlyString; /* file path minus file name */
+    pathOnlyString = g_strndup(programPath, index+1); /* +1 for the '/' */
+
+    char *defaultConfigFilePath;
+    const char *fileName = "QEMU_config.txt";
+    defaultConfigFilePath = g_strdup_printf("%s%s", pathOnlyString, fileName);
+    FILE *configFile;
+    configFile = 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;

 

     // Display an open dialog box if no arguments were passed or
     // if qemu was launched from the finder ( the Finder passes "-psn" )
-    if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
+    // and no default configuration file was loaded.
+    if (configFileLoaded == false && gArgc <= 1) {
         NSOpenPanel *op = [[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 >= 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 == NSFileHandlingPanelCancelButton) {
         exit(0);
     } else if (returnCode == NSFileHandlingPanelOKButton) {
-        char *img = (char*)[ [ [ sheet URL ] path ] cStringUsingEncoding:NSASCIIStringEncoding];
-
-        char **argv = g_new(char *, 4);
-
+        char *file = (char*)[ [ [ sheet URL ] path ] cStringUsingEncoding:NSASCIIStringEncoding];
         [sheet close];
-
-        argv[0] = g_strdup(gArgv[0]);
-        argv[1] = g_strdup("-hda");
-        argv[2] = g_strdup(img);
-        argv[3] = 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];
     }
 }

 

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

 

 @end

 

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

 

+    if(argc == 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 = 1; i < argc; i++) {
-        const char *opt = argv[i];
+    for (i = 1; i < gArgc; i++) {
+        const char *opt = gArgv[i];

 

         if (opt[0] == '-') {
             /* Treat --foo the same as -foo.  */
@@ -1154,8 +1268,6 @@ int main (int argc, const char * argv[]) {
         }
     }

 

-    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
     // Pull this console process up to being a fully-fledged graphical
     // app with a menubar and Dock icon
     ProcessSerialNumber psn = { 0, kCurrentProcess };
-- 
1.7.5.4


reply via email to

[Prev in Thread] Current Thread [Next in Thread]