/* -*- 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 // find() #include #include // make_pair() #include // 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" An iterator pointing to the named OptionList entry. // "have" A bool that says whether the iterator points to // something valid. // "opt" A string reference that refers to the option value // if "have" 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 Session file to open at startup\n"); printf (" -rom ROM file to use at startup\n"); printf (" -ram_size Amount of RAM (in K) to emulate at startup\n"); printf (" -device Device type to use at startup\n"); printf (" -skin Name of skin to use for the device\n"); printf (" -load_apps Comma-seperated list of names of .prc files to load at startup\n"); printf (" -run_app Name of file to automatically run at startup\n"); printf (" -quit_on_exit Cause Poser to quit after -run application exits\n"); printf (" -pref 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 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 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 pref1 (kPrefKeyLastConfiguration); Preference 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; }