aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Startup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcShared/Startup.cpp')
-rw-r--r--SrcShared/Startup.cpp1642
1 files changed, 1642 insertions, 0 deletions
diff --git a/SrcShared/Startup.cpp b/SrcShared/Startup.cpp
new file mode 100644
index 0000000..a9150fa
--- /dev/null
+++ b/SrcShared/Startup.cpp
@@ -0,0 +1,1642 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries.
+ All rights reserved.
+
+ This file is part of the Palm OS Emulator.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+\* ===================================================================== */
+
+#include "EmCommon.h"
+#include "Startup.h"
+
+#include "EmDocument.h" // EmDocument::AskNewSession
+#include "EmPalmStructs.h" // EmProxyDatabaseHdrType
+#include "EmSession.h" // gSession, EmSessionStopper
+#include "EmStreamFile.h" // EmStreamFile
+#include "Hordes.h" // Hordes::SetGremlinsHome
+#include "Miscellaneous.h" // IsExecutable, GetLoadableFileList
+#include "Platform.h" // ForceStartupScreen
+#include "PreferenceMgr.h" // Preference
+#include "Strings.r.h" // kStr_Autoload, etc.
+
+#include <algorithm> // find()
+#include <string>
+#include <utility> // make_pair()
+#include <vector>
+
+// Startup actions.
+//static Bool gAskWhatToDo;
+static Bool gCreateSession;
+static Bool gOpenSession;
+static Bool gMinimize;
+
+// Post-startup actions.
+static Bool gStartNewHorde;
+static Bool gHordeQuitWhenDone;
+static Bool gMinimizeQuitWhenDone;
+// Quit actions.
+static Bool gQuitOnExit;
+
+// Action-specific data.
+static Configuration gCfg; // For CreateSession.
+static EmFileRef gSessionOpenRef; // For OpenSession.
+static EmFileRef gMinimizeRef; // For Minimize
+static HordeInfo gHorde; // For StartNewGremlin
+static StringList gHordeApps; // For StartNewGremlin
+
+ // These are the files listed on the command line.
+static string gAutoRunApp;
+static EmFileRefList gAutoLoadFiles1;
+//static EmFileRefList gAutoRunFiles1;
+//static EmFileRefList gAutoRunAndQuitFiles1;
+
+ // These are the files found in the Auto* directories.
+static EmFileRefList gAutoLoadFiles2;
+static EmFileRefList gAutoRunFiles2;
+static EmFileRefList gAutoRunAndQuitFiles2;
+
+
+// These are the keys we use when tracking what the user has specified.
+
+static const char kOptPSF[] = "psf";
+static const char kOptROM[] = "rom";
+static const char kOptRAM[] = "ram";
+static const char kOptDevice[] = "device";
+static const char kOptSkin[] = "skin";
+static const char kOptLoad[] = "load";
+static const char kOptRun[] = "run";
+static const char kOptMinimize[] = "minimize";
+static const char kOptQuitOnExit[] = "quit_on_exit";
+static const char kOptPreference[] = "preference";
+static const char kOptHordeFirst[] = "horde_first";
+static const char kOptHordeLast[] = "horde_last";
+static const char kOptHordeApps[] = "horde_apps";
+static const char kOptHordeSaveDir[] = "horde_save_dir";
+static const char kOptHordeSaveFreq[] = "horde_save_freq";
+static const char kOptHordeDepthMax[] = "horde_depth_max";
+static const char kOptHordeDepthSwitch[] = "horde_depth_switch";
+static const char kOptHordeQuitWhenDone[] = "horde_quit_when_done";
+
+
+// These are the options the user can specify on the command line.
+
+static const struct
+{
+ const char* option;
+ const char* optKey;
+ int optType; // 0 == no parameter, 1 = has parameter
+}
+kOptionMap [] =
+{
+ { "-psf", kOptPSF, 1 },
+ { "-rom", kOptROM, 1 },
+ { "-ram", kOptRAM, 1 },
+ { "-ram_size", kOptRAM, 1 },
+ { "-device", kOptDevice, 1 },
+ { "-skin", kOptSkin, 1 },
+ { "-silkscreen", kOptSkin, 1 },
+ { "-load_apps", kOptLoad, 1 },
+ { "-run_app", kOptRun, 1 },
+ { "-minimize", kOptMinimize, 1 },
+ { "-quit_on_exit", kOptQuitOnExit, 0 },
+ { "-preference", kOptPreference, 1 },
+ { "-pref", kOptPreference, 1 },
+ { "-d", kOptPreference, 1 },
+ { "-horde", kOptHordeFirst, 1 },
+ { "-horde_first", kOptHordeFirst, 1 },
+ { "-horde_last", kOptHordeLast, 1 },
+ { "-horde_apps", kOptHordeApps, 1 },
+ { "-horde_save_dir", kOptHordeSaveDir, 1 },
+ { "-horde_save_freq", kOptHordeSaveFreq, 1 },
+ { "-horde_depth_max", kOptHordeDepthMax, 1 },
+ { "-horde_depth_switch", kOptHordeDepthSwitch, 1 },
+ { "-horde_quit_when_done", kOptHordeQuitWhenDone, 0 }
+};
+
+
+
+
+// Handy macro for helping us find and access options in the OptionList.
+// For the option with the base name "name", this macro defines:
+//
+// "iter<name>" An iterator pointing to the named OptionList entry.
+// "have<name>" A bool that says whether the iterator points to
+// something valid.
+// "opt<name>" A string reference that refers to the option value
+// if "have<name>" is true.
+
+#define DEFINE_VARS(name) \
+ OptionList::iterator iter##name = options.find(kOpt##name); \
+ Bool have##name = iter##name != options.end(); \
+ string& opt##name = iter##name->second
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvGetDatabaseInfosFromAppNames
+ *
+ * DESCRIPTION: Given a list of application names (as determined either
+ * by their 'tAIN' resources or their database names) and
+ * return AppInfos for all applications installed in the
+ * system with those names.
+ *
+ * PARAMETERS: names - the StringList with the names of the applications
+ * to search for. *All* executables are considered,
+ * includes .prc's and .pqa's.
+ *
+ * results - the DatabaseInfoList to receive the DatabaseInfos of
+ * the executables with a name that appears in the
+ * "names" collection.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::PrvGetDatabaseInfosFromAppNames (const StringList& names, DatabaseInfoList& results)
+{
+ StringList namesCopy (names);
+
+ if (!namesCopy.empty())
+ {
+ // If the string list begins with a "-", then the list is
+ // a list of files to be *skipped*.
+
+ Bool mustBeFound = true;
+ string firstName = namesCopy[0];
+ if (firstName[0] == '-')
+ {
+ mustBeFound = false;
+ firstName.erase (firstName.begin ());
+ namesCopy[0] = firstName;
+ }
+
+ // Get a list of installed applications.
+
+ DatabaseInfoList dbInfos;
+ ::GetDatabases (dbInfos, kApplicationsOnly);
+
+ // For each application in the list we just got, see if it was
+ // specified in the user's name list.
+
+ DatabaseInfoList::iterator infoIter = dbInfos.begin();
+ while (infoIter != dbInfos.end())
+ {
+ string appInfoName(infoIter->name);
+ StringList::const_iterator nameIter = find (namesCopy.begin(), namesCopy.end(), appInfoName);
+ Bool found = nameIter != namesCopy.end();
+
+ // Check to see if one of two things are true:
+ //
+ // * The installed application is on the include list.
+ // * The installed application in not on the exclude list.
+ //
+ // If either case is true, push it onto our "results" list.
+
+ if (found == mustBeFound)
+ {
+ results.push_back (*infoIter);
+ }
+
+ ++infoIter;
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvDontUnderstand
+ * FUNCTION: PrvMissingArgument
+ * FUNCTION: PrvInvalidRAMSize
+ * FUNCTION: PrvInvalidSkin
+ *
+ * DESCRIPTION: Display error messages concerning poor, misunderstood
+ * switches and their parameters.
+ *
+ * PARAMETERS: The switch ("-foo") guy who caused the problem.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+static string PrvWrap (const string& s, int chars_per_line)
+{
+ string result (s);
+ int index = 0;
+ int last_space = -1;
+ int last_cr = -1;
+
+ while (index < (int) result.size ())
+ {
+ char ch = result[index];
+
+ if (ch == ' ')
+ {
+ last_space = index;
+ }
+ else if (ch == '\n')
+ {
+ last_cr = index;
+ last_space = -1;
+ }
+
+ // Have we accumulated enough characters?
+
+ if (index - last_cr >= chars_per_line)
+ {
+ EmAssert (last_space >= 0);
+
+ result [last_space] = '\n';
+ last_cr = last_space;
+ last_space = -1;
+ }
+
+ ++index;
+ }
+
+ return result;
+}
+
+
+void Startup::PrvError (const char* msg)
+{
+#if PLATFORM_UNIX
+ printf ("%s\n", msg);
+#else
+ EmDlg::DoCommonDialog (msg, kDlgFlags_OK);
+#endif
+}
+
+void Startup::PrvDontUnderstand (const char* arg)
+{
+ char buffer[200];
+ sprintf (buffer, "Don't understand the command line parameter \"%s\".", arg);
+ Startup::PrvError (buffer);
+}
+
+void Startup::PrvMissingArgument (const char* arg)
+{
+ char buffer[200];
+ sprintf (buffer, "The command line parameter \"%s\" needs to be followed by an "
+ "argument (\"No, it doesn't.\" \"Yes, it does.\" \"No, it doesn't...\").", arg);
+ Startup::PrvError (buffer);
+}
+
+void Startup::PrvInvalidRAMSize (const char* arg)
+{
+ char buffer[200];
+ sprintf (buffer, "\"%s\" is an invalid RAM size. Specify 128, 256, 512, 1024, "
+ "2048, 4096, 8192, or 16384.", arg);
+ Startup::PrvError (buffer);
+}
+
+void Startup::PrvInvalidSkin (const char* argSkin, const char* argDevice)
+{
+ char buffer[200];
+ sprintf (buffer, "The skin \"%s\" cannot be used with the device \"%s\".", argSkin, argDevice);
+ Startup::PrvError (buffer);
+}
+
+void Startup::PrvInvalidPreference (const char* pref)
+{
+ char buffer[200];
+ sprintf (buffer, "Don't understand the preference parameter \"%s\".", pref);
+ Startup::PrvError (buffer);
+}
+
+void Startup::PrvPrintHelp (void)
+{
+ printf ("Options are:\n");
+ printf (" -psf <file> Session file to open at startup\n");
+ printf (" -rom <file> ROM file to use at startup\n");
+ printf (" -ram_size <size> Amount of RAM (in K) to emulate at startup\n");
+ printf (" -device <name> Device type to use at startup\n");
+ printf (" -skin <name> Name of skin to use for the device\n");
+ printf (" -load_apps <name(s)> Comma-seperated list of names of .prc files to load at startup\n");
+ printf (" -run_app <name> Name of file to automatically run at startup\n");
+ printf (" -quit_on_exit Cause Poser to quit after -run application exits\n");
+ printf (" -pref <key=value> Change a preference setting\n");
+ printf ("\n");
+
+ Platform::PrintHelp ();
+
+ string help (
+ "\n"
+ "Specifying the -psf option on the command line causes Poser to attempt "
+ "to load and run the specified session file at startup.\n"
+ "\n"
+ "Specifying the -rom, -ram_size, and -device options on the command line "
+ "causes Poser to create a new session based on those specifications. If "
+ "only some of those three options are specified, then Poser will present "
+ "a New Session dialog with the specified items already filled in.\n"
+ "\n"
+ "The parameter passed with the -skin option is the name "
+ "of the silkscreen as defined in the .skin file.\n"
+ "\n"
+ "The parameter passed with the -load_apps option is a comma-seperated list "
+ "of file names. The parameter passed with the -run_app option is the name "
+ "of the Palm OS application itself, not the name of the file it came from. "
+ "This is generally the name that appears in the Palm OS Launcher.\n"
+ "\n"
+ "The -pref option can be used to change a preference setting. The parameter "
+ "passed with is is of the for key=value, where \"key\" is any of the keys "
+ "displayed in the preference file, and value is the value you want it to be. "
+ "Note that using this option *changes* the preference. It does not override "
+ "the preference. Thus, when the emulator exits, the value specified on the "
+ "command line will be written to the preference file.\n"
+ "\n"
+ );
+
+ help = ::PrvWrap (help, 78);
+ printf ("%s", help.c_str ());
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvCollectOptions
+ *
+ * DESCRIPTION: Breaks up the command line text into pairs of switches
+ * (the "-foo" part) and their optional parameters (anything
+ * that comes after the "-foo" part). Switches are
+ * validated, and they and any parameter are added to
+ * the given OptionList.
+ *
+ * PARAMETERS: argc, argv - standard C parameters describing the
+ * command line.
+ *
+ * options - the OptionList to received the parsed and
+ * validated parameters.
+ *
+ * RETURNED: True if everything went swimmingly. If an error occurred
+ * (for instance, an invalid switch was specified or a
+ * switch that needed a parameter didn't have one), the
+ * error is reported and the function returns false.
+ *
+ ***********************************************************************/
+
+static OptionList* gOptions;
+static PreferenceList* gPreferences;
+
+int Startup::PrvParseOneOption (int argc, char** argv, int& argIndex)
+{
+ const char* arg = argv[argIndex];
+
+ // For this argument, see if it is a recognized switch.
+
+ for (size_t ii = 0; ii < countof (kOptionMap); ++ii)
+ {
+ if (_stricmp (arg, kOptionMap[ii].option) == 0)
+ {
+ // It's recognized; see if we need to also collect a parameter.
+
+ if (kOptionMap[ii].optType == 0)
+ {
+ // No parameter, just add the switch to our collection.
+
+ (*gOptions)[kOptionMap[ii].optKey] = "";
+ argIndex += 1;
+ return 1;
+ }
+ else if (kOptionMap[ii].optType == 1)
+ {
+ if ((argIndex + 1) < argc)
+ {
+ // Add the switch and parameter to our collection.
+ // Put preferences on a seperate list -- a multimap
+ // -- so that we can support more than one. All others
+ // go into a map collection so that we respond to just
+ // the last specified option.
+
+ if (kOptionMap[ii].optKey == kOptPreference)
+ gPreferences->insert (make_pair (kOptionMap[ii].optKey, argv[argIndex + 1]));
+ else
+ (*gOptions)[kOptionMap[ii].optKey] = argv[argIndex + 1];
+
+ argIndex += 2;
+ return 2;
+ }
+ else
+ {
+ // Needed a parameter, but there wasn't one.
+ Startup::PrvMissingArgument (arg);
+ return 0;
+ }
+ }
+ }
+ }
+
+ // If we got here, we didn't understand the argument. Perhap someone
+ // provided a file name without a preceding -psf or -rom (this can happen
+ // in Windows when someone drops such a file on the application's icon).
+ // See if that's the case and try to support it.
+
+ EmFileRef ref (arg);
+ if (ref.Exists ())
+ {
+ if (ref.IsType (kFileTypeROM))
+ {
+ (*gOptions)[kOptROM] = arg;
+ argIndex += 1;
+ return 1;
+ }
+
+ if (ref.IsType (kFileTypeSession))
+ {
+ (*gOptions)[kOptPSF] = arg;
+ argIndex += 1;
+ return 1;
+ }
+ }
+
+ // And if we got this far, return an error.
+
+ return 0;
+}
+
+
+Bool Startup::PrvCollectOptions (int argc, char** argv,
+ OptionList& options,
+ PreferenceList& prefs)
+{
+ // Iterate over the command line arguments.
+
+ gOptions = &options;
+ gPreferences = &prefs;
+
+ int errorArg;
+
+ if (!Platform::CollectOptions (argc, argv, errorArg, &Startup::PrvParseOneOption))
+ {
+ Startup::PrvDontUnderstand (argv[errorArg]);
+ Startup::PrvPrintHelp ();
+ return false;
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvConvertRAM
+ *
+ * DESCRIPTION: Convert a -ram parameter into a number and validate it.
+ *
+ * PARAMETERS: str - the switch parameter.
+ *
+ * ramSize - the RAMSizeType to receive the converted value.
+ *
+ * RETURNED: True if everything went well. If the resulting value
+ * was not a valid RAMSizeType value, then returns false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvConvertRAM (const string& str, RAMSizeType& ramSize)
+{
+ ramSize = atol (str.c_str ());
+
+ MemoryTextList sizes;
+ ::GetMemoryTextList (sizes);
+
+ MemoryTextList::iterator iter = sizes.begin ();
+ while (iter != sizes.end ())
+ {
+ if (ramSize == iter->first)
+ {
+ return true;
+ }
+
+ ++iter;
+ }
+
+ return false;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvParseFileList
+ *
+ * DESCRIPTION: Break up a comma-delimited list of files, returning the
+ * pieces in a EmFileRefList.
+ *
+ * PARAMETERS: fileList - the EmFileRefList to receive the files from the
+ * comma-delimited list. This collection is *not* first
+ * cleared out, so it's possible to add to the
+ * collection with this function.
+ *
+ * option - the string containing the comma-delimited files.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::PrvParseFileList (EmFileRefList& fileList, string option)
+{
+ StringList items;
+ ::SeparateList (items, option, ',');
+
+ StringList::iterator iter = items.begin ();
+ while (iter != items.end ())
+ {
+ fileList.push_back (EmFileRef (*iter));
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandleOpenSessionParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptPSF
+ * kOptMinimize
+ *
+ * PARAMETERS: options - the OptionList containing the complete set
+ * of parsed switches and parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandleOpenSessionParameters (OptionList& options)
+{
+ DEFINE_VARS(PSF);
+ DEFINE_VARS(Minimize);
+
+ if (havePSF)
+ {
+ // Clear out any previous action
+
+ Startup::ScheduleAskWhatToDo ();
+
+ // Schedule the new action
+
+ EmFileRef psfRef = EmFileRef (optPSF);
+ Startup::ScheduleOpenSession (psfRef);
+ }
+
+ if (haveMinimize)
+ {
+ // Clear out any previous action
+
+ Startup::ScheduleAskWhatToDo ();
+
+ // Schedule the new action
+
+ EmFileRef MinimizeRef = EmFileRef (optMinimize);
+ Startup::ScheduleMinimize (MinimizeRef);
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandleCreateSessionParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptROM
+ * kOptRAM
+ * kOptDevice
+ *
+ * PARAMETERS: options - the OptionList containing the complete set
+ * of parsed switches and parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandleCreateSessionParameters (OptionList& options)
+{
+ DEFINE_VARS(ROM);
+ DEFINE_VARS(RAM);
+ DEFINE_VARS(Device);
+
+ Bool haveSome = haveROM || haveRAM || haveDevice;
+ Bool haveAll = haveROM && haveRAM && haveDevice;
+
+ if (haveSome)
+ {
+ Preference<Configuration> prefConfig (kPrefKeyLastConfiguration);
+ Configuration cfg = *prefConfig;
+
+ // Check for a specified ROM file.
+
+ if (haveROM)
+ {
+ cfg.fROMFile = EmFileRef (optROM);
+ }
+
+ // Check for a specified RAM size.
+
+ if (haveRAM)
+ {
+ if (!Startup::PrvConvertRAM (optRAM, cfg.fRAMSize))
+ {
+ Startup::PrvInvalidRAMSize (optRAM.c_str ());
+ return false;
+ }
+ }
+
+ // Check for a specified device type.
+
+ if (haveDevice)
+ {
+ EmDevice device (optDevice);
+ if (device.Supported ())
+ {
+ cfg.fDevice = device;
+ }
+ else
+ {
+ Startup::PrvDontUnderstand (optDevice.c_str ());
+ return false;
+ }
+ }
+
+ // Try to start up with the specified parameters.
+ // If the command line didn't specify all the required values, ask for them.
+
+ if (!haveAll && !EmDocument::AskNewSession (cfg))
+ {
+ // User cancelled the "New Configuration" dialog.
+ // Bring up the dialog with the New/Open/Download/Exit buttons.
+
+ Startup::ScheduleAskWhatToDo ();
+ }
+ else
+ {
+ // Clear out any previous action
+
+ Startup::ScheduleAskWhatToDo ();
+
+ // Schedule the new action
+
+ Startup::ScheduleCreateSession (cfg);
+ }
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandleNewHordeParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptHordeFirst
+ * kOptHordeLast
+ * kOptHordeApps
+ * kOptHordeSaveDir
+ * kOptHordeSaveFreq
+ * kOptHordeDepthMax
+ * kOptHordeDepthSwitch
+ * kOptHordeQuitWhenDone
+ *
+ * PARAMETERS: options - the OptionList containing the complete set
+ * of parsed switches and parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandleNewHordeParameters (OptionList& options)
+{
+ DEFINE_VARS(HordeFirst);
+ DEFINE_VARS(HordeLast);
+ DEFINE_VARS(HordeApps);
+ DEFINE_VARS(HordeSaveDir);
+ DEFINE_VARS(HordeSaveFreq);
+ DEFINE_VARS(HordeDepthMax);
+ DEFINE_VARS(HordeDepthSwitch);
+ DEFINE_VARS(HordeQuitWhenDone);
+
+ UNUSED_PARAM(optHordeQuitWhenDone);
+
+ if (haveHordeFirst ||
+ haveHordeLast ||
+ haveHordeApps ||
+ haveHordeSaveDir ||
+ haveHordeSaveFreq ||
+ haveHordeDepthMax ||
+ haveHordeDepthSwitch)
+ {
+ HordeInfo info;
+ StringList appNames;
+
+ if (haveHordeFirst)
+ {
+ info.fStartNumber = atoi (optHordeFirst.c_str ());
+
+ if (!haveHordeLast)
+ {
+ info.fStopNumber = info.fStartNumber;
+ }
+ }
+
+ if (haveHordeLast)
+ {
+ info.fStopNumber = atoi (optHordeLast.c_str ());
+
+ if (!haveHordeFirst)
+ {
+ info.fStartNumber = info.fStopNumber;
+ }
+ }
+
+ if (!haveHordeFirst && !haveHordeLast)
+ {
+ info.fStartNumber = 0;
+ info.fStopNumber = 0;
+ }
+
+ if (haveHordeApps)
+ {
+ // Get the list of user-specified names.
+ // We can't do much more with them now -- like look up
+ // the applications on the device -- as the device may
+ // not be up and running at this time. We have to defer
+ // doing that until we're ready to start the Gremlin.
+
+ ::SeparateList (appNames, optHordeApps, ',');
+
+ }
+
+ if (haveHordeSaveDir)
+ {
+ Hordes::SetGremlinsHome (optHordeSaveDir);
+ }
+ else
+ {
+ Hordes::SetGremlinsHomeToDefault ();
+ }
+
+ if (haveHordeSaveFreq)
+ {
+ info.fSaveFrequency = atoi (optHordeSaveFreq.c_str ());
+ }
+
+ if (haveHordeDepthMax)
+ {
+ info.fMaxDepth = atoi (optHordeDepthMax.c_str ());
+ }
+
+ if (haveHordeDepthSwitch)
+ {
+ info.fSwitchDepth = atoi (optHordeDepthSwitch.c_str ());
+ }
+
+ if (haveHordeFirst || haveHordeLast)
+ {
+ info.OldToNew (); // Transfer old fields to new.
+
+ Startup::ScheduleNewHorde (info, appNames);
+ }
+ }
+
+ gHordeQuitWhenDone = haveHordeQuitWhenDone;
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandleAutoLoadParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptLoad
+ * kOptRun
+ * kOptQuitOnExit
+ *
+ * PARAMETERS: options - the OptionList containing the complete set
+ * of parsed switches and parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandleAutoLoadParameters (OptionList& options)
+{
+ DEFINE_VARS(Load);
+ DEFINE_VARS(Run);
+ DEFINE_VARS(QuitOnExit);
+
+ UNUSED_PARAM (optQuitOnExit)
+
+ if (haveLoad)
+ {
+ Startup::PrvParseFileList (gAutoLoadFiles1, optLoad);
+ }
+
+ if (haveRun)
+ {
+ gAutoRunApp = optRun;
+ }
+
+ if (haveQuitOnExit)
+ {
+ Startup::ScheduleQuitOnExit ();
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandleSkinParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptDevice
+ * kOptSkin
+ *
+ * PARAMETERS: options - the OptionList containing the complete set
+ * of parsed switches and parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandleSkinParameters (OptionList& options)
+{
+ DEFINE_VARS(Device);
+ DEFINE_VARS(Skin);
+
+ if (haveSkin && haveDevice)
+ {
+ EmDevice device (optDevice);
+
+ if (!device.Supported ())
+ {
+ Startup::PrvDontUnderstand (optDevice.c_str ());
+ return false;
+ }
+
+ if (!::SkinValidSkin (device, optSkin))
+ {
+ Startup::PrvInvalidSkin (optSkin.c_str (), optDevice.c_str ());
+ return false;
+ }
+
+ ::SkinSetSkinName (device, optSkin);
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvHandlePreferenceParameters
+ *
+ * DESCRIPTION: Handle the following command line options:
+ *
+ * kOptPreference
+ *
+ * PARAMETERS: prefs - the PreferenceList containing the complete set
+ * of parsed preference parameters.
+ *
+ * RETURNED: True if everything when OK. If there's something wrong
+ * with the specifications, this function displays an
+ * error message and return false.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvHandlePreferenceParameters (PreferenceList& prefs)
+{
+ PreferenceList::iterator iter = prefs.begin ();
+ while (iter != prefs.end ())
+ {
+ string fullPrefString = iter->second;
+ string::size_type equalsPos = fullPrefString.find ('=');
+
+ if (equalsPos == string::npos)
+ {
+ Startup::PrvInvalidPreference (fullPrefString.c_str ());
+ return false;
+ }
+
+ string key = fullPrefString.substr (0, equalsPos);
+ string value = fullPrefString.substr (equalsPos + 1);
+
+ Preference<string> pref (key.c_str ());
+ pref = value;
+
+ ++iter;
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvParseCommandLine
+ *
+ * DESCRIPTION: Parse up the command line into its consituent parts,
+ * validate the parts, and act on the specifications.
+ *
+ * PARAMETERS: argc, argv - standard C parameters describing the
+ * command line.
+ *
+ * RETURNED: Nothing. All actions to be taken based on the users
+ * specifications are recorded in global variables.
+ *
+ ***********************************************************************/
+
+Bool Startup::PrvParseCommandLine (int argc, char** argv)
+{
+ OptionList options;
+ PreferenceList prefs;
+
+ // Convert the command line into a map of switch/parameter pairs.
+
+ if (!Startup::PrvCollectOptions (argc, argv, options, prefs))
+ goto BadParameter;
+
+ // Handle kOptPSF.
+
+ if (!Startup::PrvHandleOpenSessionParameters (options))
+ goto BadParameter;
+
+ // Handle kOptROM, kOptRAM, and kOptDevice.
+
+ if (!Startup::PrvHandleCreateSessionParameters (options))
+ goto BadParameter;
+
+ // Handle kOptHordeFirst, kOptHordeLast, kOptHordeApps, kOptHordeSaveDir,
+ // kOptHordeSaveFreq, kOptHordeDepthMax, kOptHordeDepthSwitch, and
+ // kOptHordeQuitWhenDone.
+
+ if (!Startup::PrvHandleNewHordeParameters (options))
+ goto BadParameter;
+
+ // Handle kOptLoad, kOptRun, and kOptQuitOnExit.
+
+ if (!Startup::PrvHandleAutoLoadParameters (options))
+ goto BadParameter;
+
+ // Handle kOptSkin
+ if (!Startup::PrvHandleSkinParameters (options))
+ goto BadParameter;
+
+ // Handle preference changes.
+ if (!Startup::PrvHandlePreferenceParameters (prefs))
+ goto BadParameter;
+
+ return true;
+
+BadParameter:
+ // All bets are off. Bring up the dialog with the
+ // New/Open/Download/Exit buttons.
+
+ Startup::ScheduleAskWhatToDo ();
+ return false;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::DetermineStartupActions
+ *
+ * DESCRIPTION: Determine what to do at startup time, based on any
+ * command-line options, what the user was doing when they
+ * last ran Poser, and whether or not the CapsLock key
+ * is toggled.
+ *
+ * In general, the startup rules are as follows:
+ *
+ * 1 If the Caps Lock key is toggled in the ON position, always bring
+ * up the New/Open/... dialog.
+ *
+ * 2 Scan the command line for startup parameters. If an error occurs
+ * trying to scan the command line, the error is reported and the user
+ * is presented with the New/Open/... dialog.
+ *
+ * 3 Use the .psf file if one is specified. If an error occurs trying
+ * to load the file, the error is reported and the user is presented
+ * with the New/Open/... dialog.
+ *
+ * 4 If any of -rom, -ram, -device, or -silkscreen are specified, try
+ * to start a new session based on those values. If all are specified,
+ * the new session is automatically created. If any of those four
+ * values are missing, the "New Configuration" dialog is displayed.
+ * If the user cancels the dialog, or if there is an error creating
+ * the new session, any error is reported and the user is presented
+ * with the New/Open/... dialog.
+ *
+ * 5 If no command line options are specified, try re-opening the last
+ * saved .psf file (this step is skipped if the user last created a
+ * new session, but did NOT save that session to a file). If an error
+ * occurs trying to load the file, the error is reported and the user
+ * is presented with the New/Open/... dialog.
+ *
+ * 6 Try creating a new session based on the settings the user last
+ * specified when creating a session. If there is an error creating
+ * the new session, the error is reported and the user is presented
+ * with the New/Open/... dialog.
+ *
+ * 7 Finally, if all else fails, present the user with the New/Open/...
+ * dialog.
+ *
+ * PARAMETERS: argc, argv - standard C parameters describing the
+ * command line.
+ *
+ * RETURNED: True if we were able to determine a startup course of
+ * action. If false is returned, something horrible happened.
+ * The caller should assume that an error was reported,
+ * and that the application should quit.
+ *
+ ***********************************************************************/
+
+Bool Startup::DetermineStartupActions (int argc, char** argv)
+{
+ // By default, throw up our hands.
+
+ Startup::ScheduleAskWhatToDo ();
+
+ // See if the user wants to force the appearance of the Startup
+ // screen (by holding down the ShiftLock key) and skip the auto-
+ // loading of the previous session file.
+
+ if (!Platform::ForceStartupScreen ())
+ {
+ Preference<Configuration> pref1 (kPrefKeyLastConfiguration);
+ Preference<EmFileRef> pref2 (kPrefKeyLastPSF);
+
+ Configuration cfg = *pref1;
+ EmFileRef ramFileRef = *pref2;
+
+ // See if there was a previously saved RAM file. If so, open it.
+
+ if (ramFileRef.IsSpecified ())
+ {
+ Startup::ScheduleOpenSession (ramFileRef);
+ }
+
+ // Else, see if there was a previously created document. If so,
+ // create a new document based on its settings.
+
+ else if (cfg.IsValid () )
+ {
+ Startup::ScheduleCreateSession (cfg);
+ }
+
+ // Now that default actions have been established, let's see if
+ // there's anything interesting on the command line.
+
+ if (!Startup::PrvParseCommandLine (argc, argv))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::GetAutoLoads
+ *
+ * DESCRIPTION: Return the list of applications that should automatically
+ * be loaded at startup time, regardless of whether a new
+ * session was created or an old one loaded. The list of
+ * applications is collected from the command line and from
+ * the specially-named AutoLoad, AutoRun, and AutoRunAndQuit
+ * directories.
+ *
+ * PARAMETERS: fileList - the EmFileRefList to receive the files to load.
+ * The collection is cleared out before the new items
+ * are added to it.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::PrvLookForAutoloads (void)
+{
+ gAutoLoadFiles2.clear();
+ gAutoRunFiles2.clear();
+ gAutoRunAndQuitFiles2.clear();
+
+ ::GetLoadableFileList (Platform::GetString (kStr_Autoload), gAutoLoadFiles2);
+ ::GetLoadableFileList (Platform::GetString (kStr_Autorun), gAutoRunFiles2);
+ ::GetLoadableFileList (Platform::GetString (kStr_AutorunAndQuit), gAutoRunAndQuitFiles2);
+}
+
+void Startup::PrvAppendFiles (EmFileRefList& list1, const EmFileRefList& list2)
+{
+ list1.insert(list1.end(), list2.begin(), list2.end());
+}
+
+void Startup::GetAutoLoads (EmFileRefList& fileList)
+{
+ fileList.clear();
+
+ Startup::PrvLookForAutoloads();
+
+ Startup::PrvAppendFiles (fileList, gAutoLoadFiles1);
+// Startup::PrvAppendFiles (fileList, gAutoRunFiles1);
+// Startup::PrvAppendFiles (fileList, gAutoRunAndQuitFiles1);
+
+ Startup::PrvAppendFiles (fileList, gAutoLoadFiles2);
+ Startup::PrvAppendFiles (fileList, gAutoRunFiles2);
+ Startup::PrvAppendFiles (fileList, gAutoRunAndQuitFiles2);
+
+ if (/*gAutoRunAndQuitFiles1.size() +*/ gAutoRunAndQuitFiles2.size() > 0)
+ {
+ Startup::ScheduleQuitOnExit ();
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::GetAutoRunApp
+ *
+ * DESCRIPTION: Returns the *database name* of the application to
+ * switch to at startup time.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: The name of the database of the executable.
+ *
+ ***********************************************************************/
+
+string Startup::PrvTryGetApp (const EmFileRefList& fileList)
+{
+ string result;
+
+ EmFileRefList::const_iterator iter = fileList.begin();
+ while (iter != fileList.end())
+ {
+ if ((*iter).IsType (kFileTypePalmApp)) // egcs can't handle iter->IsType()!!!
+ {
+ try
+ {
+ EmStreamFile stream (*iter, kOpenExistingForRead);
+
+ EmProxyDatabaseHdrType header;
+ stream.GetBytes (header.GetPtr (), header.GetSize ());
+
+ if (::IsExecutable (header.type, header.creator, header.attributes))
+ {
+ result = (char*) header.name.GetPtr ();
+ break;
+ }
+ }
+ catch (...)
+ {
+ }
+ }
+
+ ++iter;
+ }
+
+ return result;
+}
+
+string Startup::GetAutoRunApp (void)
+{
+ string result;
+
+ // Get the name the user specified on the command line (if any)
+ // and get the DatabaseInfo for it, so that we can get the database name.
+
+ if (!gAutoRunApp.empty())
+ {
+ StringList appNames;
+ appNames.push_back (gAutoRunApp);
+
+ DatabaseInfoList dbInfos;
+ Startup::PrvGetDatabaseInfosFromAppNames (appNames, dbInfos);
+
+ if (dbInfos.size() > 0)
+ {
+ result = dbInfos.begin()->dbName;
+ }
+ }
+
+ // If the user didn't specify an executable, or we couldn't find
+ // that executable, then work from the files found in the AutoRun
+ // and AutoRunAndQuit directories.
+
+// if (result.empty())
+// result = Startup::PrvTryGetApp (gAutoRunFiles1);
+
+ if (result.empty())
+ result = Startup::PrvTryGetApp (gAutoRunFiles2);
+
+// if (result.empty())
+// result = Startup::PrvTryGetApp (gAutoRunAndQuitFiles1);
+
+ if (result.empty())
+ result = Startup::PrvTryGetApp (gAutoRunAndQuitFiles2);
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::AskWhatToDo
+ *
+ * DESCRIPTION: Return whether or not we are supposed to ask the user
+ * what to do (that is, display the dialog box with the
+ * New, Open, Download, and Quit buttons). In general,
+ * this function returns true if there's nothing else
+ * scheduled to be done (create a session, open a session,
+ * or quit the emulator).
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::AskWhatToDo (void)
+{
+// Bool result = gAskWhatToDo;
+// gAskWhatToDo = false;
+// return result;
+
+ return !gCreateSession && !gOpenSession;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::CreateSession
+ *
+ * DESCRIPTION: Return whether or not we are supposed to create a new
+ * session based on previously determined criteria. This
+ * is a one-shot function: subsequent calls will return
+ * false until ScheduleCreateSession is called again.
+ *
+ * PARAMETERS: cfg - the Configuration to receive the information to
+ * be used when creating the new session.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::CreateSession (Configuration& cfg)
+{
+ Bool result = gCreateSession;
+ if (result)
+ cfg = gCfg;
+ gCreateSession = false;
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::OpenSession
+ *
+ * DESCRIPTION: Return whether or not we are supposed to open an old
+ * session based on previously determined criteria. This
+ * is a one-shot function: subsequent calls will return
+ * false until ScheduleOpenSession is called again.
+ *
+ * PARAMETERS: ref - the EmFileRef to receive the reference to
+ * the .psf file to be opened.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::OpenSession (EmFileRef& ref)
+{
+ Bool result = gOpenSession;
+
+ if (result)
+ {
+ ref = gSessionOpenRef;
+ }
+
+ gOpenSession = false;
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::Minimize
+ *
+ * DESCRIPTION: Return whether or not we are supposed to open an old
+ * session based on previously determined criteria. This
+ * is a one-shot function: subsequent calls will return
+ * false until ScheduleOpenSession is called again.
+ *
+ * PARAMETERS: ref - the EmFileRef to receive the reference to
+ * the .psf file to be opened.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::Minimize (EmFileRef& ref)
+{
+ Bool result = gMinimize;
+
+ if (result)
+ {
+ ref = gMinimizeRef;
+ }
+
+ gMinimize = false;
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::NewHorde
+ *
+ * DESCRIPTION: Return whether or not we are supposed to start a horde
+ * session based on previously determined criteria. This
+ * is a one-shot function: subsequent calls will return
+ * false until ScheduleNewHorde is called again.
+ *
+ * PARAMETERS: info - the HordeInfo to receive the information used to
+ * create the new horde.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::NewHorde (HordeInfo* info)
+{
+ Bool result = gStartNewHorde;
+
+ if (info != NULL)
+ {
+ if (result)
+ {
+ *info = gHorde;
+
+ // Find the AppInfos for the user-specified applications.
+
+ EmSessionStopper stopper (gSession, kStopOnSysCall);
+
+ Startup::PrvGetDatabaseInfosFromAppNames (gHordeApps, info->fAppList);
+ }
+
+ gStartNewHorde = false;
+ }
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::HordeQuitWhenDone
+ *
+ * DESCRIPTION: Return whether or not we are supposed to quit the
+ * emulator session when the Horde has completed.
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::HordeQuitWhenDone (void)
+{
+ return gHordeQuitWhenDone;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::MinimizeQuitWhenDone
+ *
+ * DESCRIPTION: Return whether or not we are supposed to quit the
+ * emulator session when the Horde has completed.
+ *
+ * PARAMETERS: none.
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::MinimizeQuitWhenDone (void)
+{
+ return gMinimizeQuitWhenDone;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::QuitOnExit
+ *
+ * DESCRIPTION: Return whether or not Poser is supposed to quit when
+ * a particular application exits.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: True if so.
+ *
+ ***********************************************************************/
+
+Bool Startup::QuitOnExit (void)
+{
+ Bool result = gQuitOnExit;
+// gQuitOnExit = false;
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::Clear
+ *
+ * DESCRIPTION: Clear all settings.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::Clear (void)
+{
+ gCreateSession = false;
+ gOpenSession = false;
+ gStartNewHorde = false;
+ gQuitOnExit = false;
+
+ gAutoRunApp = "";
+ gAutoLoadFiles1.clear();
+ gAutoLoadFiles2.clear();
+ gAutoRunFiles2.clear();
+ gAutoRunAndQuitFiles2.clear();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleAskWhatToDo
+ *
+ * DESCRIPTION: Schedule our "state machine" so that AskWhatToDo will
+ * return True.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleAskWhatToDo (void)
+{
+ Startup::Clear ();
+// gAskWhatToDo = true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleCreateSession
+ *
+ * DESCRIPTION: Schedule our "state machine" so that CreateSession will
+ * return True.
+ *
+ * PARAMETERS: cfg - the Configuration returned to the caller of
+ * CreatSession.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleCreateSession (const Configuration& cfg)
+{
+ gCreateSession = true;
+// gAskWhatToDo = false;
+ gCfg = cfg;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleOpenSession
+ *
+ * DESCRIPTION: Schedule our "state machine" so that OpenSession will
+ * return True.
+ *
+ * PARAMETERS: ref - the EmFileRef returned to the caller of
+ * OpenSession.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleOpenSession (const EmFileRef& ref)
+{
+ gOpenSession = true;
+// gAskWhatToDo = false;
+ gSessionOpenRef = ref;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleMinimize
+ *
+ * DESCRIPTION: Schedule our "state machine" so that OpenSession will
+ * return True.
+ *
+ * PARAMETERS: ref - the EmFileRef returned to the caller of
+ * OpenSession.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleMinimize (const EmFileRef& ref)
+{
+ gMinimize = true;
+ gMinimizeQuitWhenDone = true;
+// gAskWhatToDo = false;
+ gMinimizeRef = ref;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleNewHorde
+ *
+ * DESCRIPTION: Schedule our "state machine" so that NewHorde will
+ * return True.
+ *
+ * PARAMETERS: info - the HordeInfo returned to the caller of NewHorde.
+ *
+ * appNames - names of the applications to inflict the
+ * Gremlins on. Normally, this information is
+ * specified in the fAppList field of the HordeInfo.
+ * However, at the time this function is called,
+ * we may not be able to generate the DatabaseInfoList
+ * (the emulator may be just starting up and not
+ * emulating a Palm OS environment, yet). So we
+ * remember the names here. When NewHorde is called,
+ * the appNames list is converted into an DatabaseInfoList.
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleNewHorde (const HordeInfo& info, const StringList& appNames)
+{
+ gStartNewHorde = true;
+ gHorde = info;
+ gHordeApps = appNames;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: Startup::ScheduleQuitOnExit
+ *
+ * DESCRIPTION: Schedule our "state machine" so that QuitOnExit will
+ * return True.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void Startup::ScheduleQuitOnExit (void)
+{
+ gQuitOnExit = true;
+}