From icculus at icculus.org Sat May 12 11:08:05 2007 From: icculus at icculus.org (Ryan C. Gordon) Date: Sat, 12 May 2007 11:08:05 -0400 Subject: test Message-ID: <4645D855.2060703@icculus.org> test. --ryan. From DONOTREPLY at icculus.org Sat May 12 11:09:40 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 12 May 2007 11:09:40 -0400 Subject: r258 - trunk Message-ID: <20070512150940.30477.qmail@icculus.org> Author: icculus Date: 2007-05-12 11:09:40 -0400 (Sat, 12 May 2007) New Revision: 258 Modified: trunk/fileio.c Log: Don't open file for write if we've already failed for some reason. Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-12 14:52:12 UTC (rev 257) +++ trunk/fileio.c 2007-05-12 15:09:40 UTC (rev 258) @@ -111,8 +111,11 @@ flen = in->length(in); STUBBED("fopen?"); + MojoPlatform_unlink(fname); - out = fopen(fname, "wb"); + if (!iofailure) + out = fopen(fname, "wb"); + if (out != NULL) { while (!iofailure) From DONOTREPLY at icculus.org Sat May 12 11:19:43 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 12 May 2007 11:19:43 -0400 Subject: r259 - trunk/scripts Message-ID: <20070512151943.7503.qmail@icculus.org> Author: icculus Date: 2007-05-12 11:19:43 -0400 (Sat, 12 May 2007) New Revision: 259 Modified: trunk/scripts/mojosetup_mainline.lua Log: Fixed progress of individual downloads (total progress is still boned, though.) Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-12 15:09:40 UTC (rev 258) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-12 15:19:43 UTC (rev 259) @@ -672,8 +672,8 @@ local fname = string.gsub(url, "^.*/", "", 1) -- chop the dirs off... local ptype = _("Downloading") -- !!! FIXME: localization. local component = option.description - local callback = function(ticks, bw, total) - MojoSetup.downloaded = MojoSetup.downloaded + bw + local callback = function(ticks, justwrote, bw, total) + MojoSetup.downloaded = MojoSetup.downloaded + justwrote local percent = calc_percent(MojoSetup.downloaded, MojoSetup.totaldownload) local item = fname .. ": " .. calc_percent(bw, total) .. "%" -- !!! FIXME: localization From DONOTREPLY at icculus.org Mon May 14 22:57:25 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 14 May 2007 22:57:25 -0400 Subject: r260 - trunk/scripts Message-ID: <20070515025725.28371.qmail@icculus.org> Author: icculus Date: 2007-05-14 22:57:25 -0400 (Mon, 14 May 2007) New Revision: 260 Modified: trunk/scripts/mojosetup_init.lua trunk/scripts/mojosetup_mainline.lua Log: Let you disable entire Setup.Package installers. Modified: trunk/scripts/mojosetup_init.lua =================================================================== --- trunk/scripts/mojosetup_init.lua 2007-05-12 15:19:43 UTC (rev 259) +++ trunk/scripts/mojosetup_init.lua 2007-05-15 02:57:25 UTC (rev 260) @@ -293,6 +293,7 @@ tab = sanitize("Package", tab, { { "id", nil, mustExist, mustBeString, cantBeEmpty }, + { "disabled", nil, mustBeBool }, { "description", nil, mustExist, mustBeString, cantBeEmpty }, { "version", nil, mustExist, mustBeString, cantBeEmpty }, { "destination", nil, mustBeString, cantBeEmpty }, Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-12 15:19:43 UTC (rev 259) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-15 02:57:25 UTC (rev 260) @@ -847,12 +847,13 @@ -- so it only spits out crap if debug-level logging is enabled. MojoSetup.dumptable("MojoSetup.installs", MojoSetup.installs) --- !!! FIXME: is MojoSetup.installs just nil? Should we lose saw_an_installer? local saw_an_installer = false for installkey,install in pairs(MojoSetup.installs) do - saw_an_installer = true - do_install(install) - MojoSetup.collectgarbage() -- nuke all the tables we threw around... + if not install.disabled then + saw_an_installer = true + do_install(install) + MojoSetup.collectgarbage() -- nuke all the tables we threw around... + end end if not saw_an_installer then From DONOTREPLY at icculus.org Tue May 15 09:14:48 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 15 May 2007 09:14:48 -0400 Subject: r261 - trunk/scripts Message-ID: <20070515131448.22092.qmail@icculus.org> Author: icculus Date: 2007-05-15 09:14:48 -0400 (Tue, 15 May 2007) New Revision: 261 Modified: trunk/scripts/mojosetup_init.lua Log: Removed some loki_setupisms. Modified: trunk/scripts/mojosetup_init.lua =================================================================== --- trunk/scripts/mojosetup_init.lua 2007-05-15 02:57:25 UTC (rev 260) +++ trunk/scripts/mojosetup_init.lua 2007-05-15 13:14:48 UTC (rev 261) @@ -5,6 +5,8 @@ -- This file written by Ryan C. Gordon. +-- !!! FIXME: go through the schema and ditch loki_setup things we don't want. + -- These are various things that need to be exposed to Lua, or are just -- better written in Lua than C. All work will be done in the "MojoSetup" -- table (for generic functionality) or the "Setup" table (for config file @@ -193,18 +195,6 @@ end end -local function mustBeValidSplashPos(fnname, elem, val) - schema_assert(val=="top" or val=="left", fnname, elem, - "must be 'top' or 'left'") -end - -local function mustBeValidInteraction(fnname, elem, val) - if (val ~= "expert") and (val ~= "normal") and (val ~= "none") then - schema_assert(false, fnname, elem, - "must be 'normal' or 'expert' or 'none'") - end -end - local function mustBeUrl(fnname, elem, val) mustBeString(fnname, elem, val) cantBeEmpty(fnname, elem, val) @@ -308,10 +298,8 @@ { "category", "Games", mustBeString, cantBeEmpty }, { "promptoverwrite", true, mustBeBool }, { "binarypath", nil, mustBeString, cantBeEmpty }, - { "splashpos", "top", mustBeString, mustBeValidSplashPos }, { "update_url", nil, mustBeString, mustBeUrl }, { "superuser", false, mustBeBool }, - { "interaction", "normal", mustBeString, mustBeValidInteraction }, }) tab._type_ = nil From DONOTREPLY at icculus.org Tue May 15 09:41:24 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 15 May 2007 09:41:24 -0400 Subject: r262 - trunk/scripts Message-ID: <20070515134124.4061.qmail@icculus.org> Author: icculus Date: 2007-05-15 09:41:24 -0400 (Tue, 15 May 2007) New Revision: 262 Modified: trunk/scripts/mojosetup_mainline.lua Log: Whoops, postinstall hook was in the wrong place... Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-15 13:14:48 UTC (rev 261) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-15 13:41:24 UTC (rev 262) @@ -756,11 +756,10 @@ end end + run_config_defined_hook(install.postinstall, install) return 1 -- go to next stage. end - run_config_defined_hook(install.postinstall, install) - -- Next stage: show results gui stages[#stages+1] = function(thisstage, maxstage) -- !!! FIXME: language. From DONOTREPLY at icculus.org Tue May 15 10:17:57 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 15 May 2007 10:17:57 -0400 Subject: r263 - trunk Message-ID: <20070515141757.23979.qmail@icculus.org> Author: icculus Date: 2007-05-15 10:17:57 -0400 (Tue, 15 May 2007) New Revision: 263 Added: trunk/docs.txt Log: First half-written, half-assed shot at documentation. Added: trunk/docs.txt =================================================================== --- trunk/docs.txt (rev 0) +++ trunk/docs.txt 2007-05-15 14:17:57 UTC (rev 263) @@ -0,0 +1,533 @@ + +Using MojoSetup. + +If there are gaps in this documentation, please ask on the MojoSetup mailing + list: to subscribe, send a blank email to mojosetup-subscribe at icculus.org, + and then questions can go to mojosetup at icculus.org. This document will + be updated as we see what parts are confusing, so feedback is appreciated. + + +Putting together a MojoSetup installer involves four general steps: +1) Compile the software. +2) Set up the installer filesystem structure. +3) Write a config file. +4) Package up the final file for distribution. + +Each step has a lot of details, but all installers basically follow those same + basic development steps. + + +Compile the software: + +You will need some tools. First, you'll need your platform's favorite build + tools. You'll also need CMake (http://www.cmake.org/), and a Subversion + (http://subversion.tigris.org/) client. These are all available for most + popular operating systems, and some not-so-popular ones. + +Get the latest version of MojoSetup from Subversion: + + svn svn://svn.icculus.org/mojosetup/trunk mojosetup + + +Then you'll need to point CMake at it: + + cd mojosetup + ccmake . + +Tweak the build settings to your liking. You'll want to set CMAKE_BUILD_TYPE + to MinSizeRel, to make the compiled binary be as small as possible, and + then trim out features you don't need. For example, you can drop the + HTTP and FTP support to save about 25 kilobytes on the binary. You can also + drop support for various archive types, pieces of Lua you don't plan to use, + etc. + +CMake will get you project files for whatever development environment you use + (Makefiles, XCode, Visual Studio, etc). Build the project. You should end + up with some shared libraries for whatever GUIs you left enabled, and + a mojsetup binary. Strip the debug symbols and put these aside for later. + +If you are building MojoSetup without the Lua parser, you'll want to build + the separate Lua compiler (MOJOSETUP_BUILD_LUAC in ccmake). That will produce + a "mojoluac" binary. Put that aside for later, too. + + +Set up the installer filesystem structure: + +This is fairly easy. The installer eventually wants to see a directory + tree like this: + + data/ + scripts/ + guis/ + +This is called the "base archive," even if it's a real directory tree in the + physical filesystem and not in an actual archive, such as a .zip file. + +"data" is where the installer looks for files included in the installer itself + that need installation (as opposed to those being read from the network + or a CD-ROM, etc). READMEs and EULAs go in here, too. The installer + doesn't care how things under data/ are arranged. + +"guis" is where the installer looks for those shared libraries that got + built in the first step. Copy them in here, if you built any. + +"scripts" is where Lua scripts go. You'll put your config file in here + (config.lua), the translation table (localizations.lua), and whatever other + scripts come with MojoSetup, which are required application logic. This + directory can hold either .lua files (source code), or their .luac + equivalents. If you built MojoSetup without the Lua parser to save space, + you'll need to compile the .lua sources into .luac objects now, or the + installer won't know what to do with them. It's safe to compile them even + if you include the parser. + + cd scripts + ../mojoluac -o config.luac config.lua + cd .. + +You can strip debug symbols from the compiled scripts to save more space, + but you'll get less useful information if there's a script error: + + cd scripts + ../mojoluac -s -o config.luac config.lua + cd .. + +Once you finish constructing this directory tree, put it aside for later. + + +Write a config file: + +This is the complicated part, and where most of your effort will be spent. + This document will try to cover all the provided facilities, but as the + configuration file also provides a robust programming language, not only + is the full scope beyond this document, you can also accomplish all sorts + of things we haven't even considered yet. + +Configuration files are Lua scripts. The Lua language and runtime library is + documented at http://www.lua.org/, and they sell an excellent book called + "Programming in Lua" which is a fast read and will demonstrate all manners + of wild and interesting features of the language. That being said, most + people rolling config files don't need any significant Lua expertise, and + basic config files don't need any programming experience at all. + +The config file is named config.lua, and it must be a text file in UTF-8 + encoding. + +Configuration files are a hierarchy of elements that take this form: + + Setup.DataType + { + someattribute = value1, + someotherattribute = value2, + } + +Elements can nest: + + Setup.DataType + { + someattribute = value1, + someotherattribute = value2, + Setup.AnotherDataType + { + something = value3, + } + } + + +Here are the elements, and the attributes they can possess. + + There are some specifiers by the attributes: + mustExist: Error if is nil (usually if you don't specify it). The other + "mustBe" descriptions consider nil to be valid when mustExist + isn't explicitly mentioned. + no default: This attribute will not have a default if not specified. + default X: This attribute defaults to X if not specified. + mustBeString: Error if isn't a string. + cantBeEmpty: Error is this string is "". String can be nil, though. + mustBeBool: Error if isn't true, false, or nil. + mustBeFunction: Error if isn't a function (can be C or Lua). + mustBeNumber: Error if isn't a number. + mustBeUrl: Error if isn't a string that matches the regexp "^.+://.-/.*". + mustBeStringOrTableOfStrings: Error if isn't a string or an array of strings. + + Attributes that aren't explicitly specified take on their default value. In + cases without a default, they are effectively set to Lua's "nil" value. + This makes boolean values be treated as "false." Plan accordingly. + + + Setup.Package: + + All configurations need at least one Setup.Package element. Everything other + element is added under Setup.Package. One full run of the installer is + done for each Setup.Package. You can have multiple packages in one file, and + the installer will run through for each one as if the program was started + multiple times. If there are multiple packages and an installation failure + occurs, all successfully-installed packages will remain. In most cases, you + only want one Setup.Package and should use Setup.Option to cull pieces + of the package. + + Setup.Package attributes: + + id (no default, mustExist, mustBeString, cantBeEmpty) + + This is a unique identifier for your package. Currently it is used as + the base of the install path, but future features may use it for other + things. Set this to something short, unique, and human-readable, like + "mygame". + + + disabled (no default, mustBeBool) + + If this is true, the entire package will be skipped by the installer. You + probably want this to be true, but you might need to programmatically shut + off a whole package. + + + description (no default, mustExist, mustBeString, cantBeEmpty) + + This is your product's name. This will be displayed in the title bar, and + other locations during installation. + + + version (no default, mustExist, mustBeString, cantBeEmpty) + + This is the version of this package. This is arbitrary, and doesn't matter + to the installer what you specify. It's usually a value like "1.0" or + "beta3" + + The installer may use this for future features, like upgrading previous + installations. + + + destination (no default, mustBeString, cantBeEmpty) + + This attribute can be used to force the installation into a specific + location in the physical filesystem. Unless you are building something + very specific (like device drivers for a well-defined platform), you + probably should not use this attribute. If destination isn't forced, + the installer will prompt the user for the destination, possibly + recommmending locations to her. + + + recommended_destinations (no default, mustBeStringOrTableOfStrings) + + This attribute lets you define some favorable places to install the + package. You can have a table of strings or a single string: + + recommended_destinations = MojoSetup.info.homedir, + ...or... + recommended_destinations = { "/usr/local/games", "/opt/games" }, + + These strings are presented in the UI to the user when selecting a + install destination, but they can override them with their own choice. + The "id" attribute is appended to these before displaying to the end + user, so they'll see, for example, "/usr/local/games/mygame" and + "/opt/games/mygame" ... if a listed directory is determined to be + unwritable to the user (lack of permissions), it will be removed from the + list before presentation to the user. + + + precheck (no default, mustBeFunction) + + If this attribute is defined, it is called by the installer after the + configuration is parsed and the GUI has started, but before the user has + interacted with the installer at all. It passes the finalized + Setup.Package table as a parameter. + + + preflight (no default, mustBeFunction) + + If this attribute is defined, it is called by the installer after the + user has chosen options to install. The heavy-lifting of the installer + is about to begin: downloading files and installing the Package. It + passes the finalized Setup.Package table as a parameter. + + + preinstall (no default, mustBeFunction) + + If this attribute is defined, it is called by the installer after all + needed external files are downloaded and installation of files is about + to begin. It passes the finalized Setup.Package table as a parameter. + + + postinstall (no default, mustBeFunction) + + If this attribute is defined, it is called by the installer after the + entire package was successfully installed to disk. It passes the finalized + Setup.Package table as a parameter. + + + splash (no default, mustBeString, cantBeEmpty) + + (!!! FIXME) This attribute is for future expansion. + + + url (no default, mustBeString, cantBeEmpty) + + (!!! FIXME) This attribute is for future expansion. + + + once (default true, mustBeBool) + + (!!! FIXME) This attribute is for future expansion. + + + category (default "Games", mustBeString, cantBeEmpty) + + (!!! FIXME) This attribute is for future expansion. + + + promptoverwrite (default true, mustBeBool) + + (!!! FIXME) This attribute is for future expansion. + Please refer to Setup.File.allowoverwrite for now. + + + binarypath (no default, mustBeString, cantBeEmpty) + + (!!! FIXME) This attribute is for future expansion. + + + update_url (no default, mustBeString, mustBeUrl) + + (!!! FIXME) This attribute is for future expansion. + + + superuser (default false, mustBeBool) + + (!!! FIXME) This attribute is for future expansion. + + + Setup.Readme: + + This element is a child of Setup.Package. It can be used to display a + information about the package to the end user, such as a welcome message, + FAQs, or other orientation information. There can be multiple Setup.Readme + elements listed, in which case the end user will be shown each readme + individually before installation may proceed. The readmes are shown first + before any other interaction occurs. + + Setup.Readme attributes: + + description (no default, mustExist, mustBeString, cantBeEmpty) + + This is a brief description of the Readme, used for title bars and such. + + + source (no default, mustExist, mustBeString, cantBeEmpty) + + This is a filename in the base archive's "data" directory that contains + the readme text. Currently this must be a text file in UTF-8 encoding. + + + Setup.Eula: + + This element is a child of Setup.Package. It can be used to display a + license agreement to the end user, which they must agree to before + installation can proceed. If they refuse the license, the installer + terminates without installing anything. There can be multiple Setup.Eula + elements listed, in which case the end user will be asked to agree to + each license individually before installation may proceed. The licenses are + shown after any readme elements. + + Setup.Eula attributes: + + description (no default, mustExist, mustBeString, cantBeEmpty) + + This is a brief description of the license, used for title bars and such. + + + source (no default, mustExist, mustBeString, cantBeEmpty) + + This is a filename in the base archive's "data" directory that contains + the license text. Currently this must be a text file in UTF-8 encoding. + + + + Setup.Media: + + This element is required if you need to install data from removable media, + such as a DVD-ROM drive. The installer needs a means to identify the + media as the correct source when it is connected to the system. + + Setup.Media attributes: + + id (no default, mustExist, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + description (no default, mustExist, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + uniquefile (no default, mustExist, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + + + Setup.File: + + (!!! FIXME write me.) + + Setup.File attributes: + + source (no default, mustBeUrl) + + (!!! FIXME write me.) + + + destination (no default, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + wildcards (no default, mustBeStringOrTableOfStrings) + + (!!! FIXME write me.) + + + filter (no default, mustBeFunction) + + (!!! FIXME write me.) + + + allowoverwrite (no default, mustBeBool) + + (!!! FIXME write me.) + + + + Setup.Option: + + (!!! FIXME write me.) + + Setup.Option attributes: + + value (default false, mustBeBool) + + (!!! FIXME write me.) + + + required (default false, mustBeBool) + + (!!! FIXME write me.) + + + disabled (default false, mustBeBool) + + (!!! FIXME write me.) + + + bytes (no default, mustExist, mustBeNumber) + + (!!! FIXME write me.) + + + description (no default, mustExist, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + + + Setup.OptionGroup: + + (!!! FIXME write me.) + + Setup.OptionGroup attributes: + + disabled (no default, mustBeBool) + + (!!! FIXME write me.) + + + description (no default, mustExist, mustBeString, cantBeEmpty) + + (!!! FIXME write me.) + + + + +Package up the final file for distribution: + +Now you have a MojoSetup binary and a directory tree containing your data, GUI + plugins, and scripts (including the config.lua you just wrote). Now you just + need to glue them together. MojoSetup will attempt to look at itself as an + archive on startup, which works in the same way "self-extracting" exe files + worked on other operating systems. If you want MojoSetup to be + self-extracting, zip your directory tree up and append it to the binary: + + zip -9r mydata.zip data guis scripts + cat mydata.zip >> mojosetup + +Now rename "mojosetup" to something meaningful (mygame-1.0-linux-x86.bin or + whatever), and you've got an installer. + +If you have the luxury of a real filesystem (inside a disk image or on a CD + you are shipping, for example), MojoSetup will use the binary's directory + if it doesn't find a zipfile appended to the binary itself, so you can just + have "data", "scripts" and "guis" in the same directory as "mojosetup" to + have it work, too. + + +Now you're done! Give your installer to the public. + + + +Extra credit: + +Localization: + +If you added strings to the installer or your config file that you want + translated at runtime, you need to add them to localization.lua. This is + a Lua script, too, of course, but you really should treat it like a basic + config file. + +Don't remove strings that are already in the file...MojoSetup uses these + internally. Just add your own strings. + +The format looks something like this: + + ["Yes"] = { + es = "Si"; + fr = "Oui"; + }; + + +As you can see, the ["Yes"] is a string to translate. These are always English + by convention, but this is whatever the string you wish to translate. Please + note that the brackets are important, and only used on this specific string. + +The fields in this structure are language abbreviations that match a user's + locale and the string of translated text. + +Please note that you can do locale-specific translations, too: + + ["colors"] = { + en_UK = "colours"; + }; + +All strings in this file (and all Lua scripts) are UTF-8 encoded. Using a + high-ASCII character will not work like you expect at runtime! + +These lookup tables are used at runtime to translate strings, both by you and + internally by MojoSetup. You can do a translation by calling: + + MojoSetup.translate("colors") + +We recommend making a convenience function like this at the top of your + config.lua... + + local function _ = MojoSetup.translate + +...so that you have a convention for translations that cause minimal clutter: + + Setup.Option { + description = _("Level editor utility"), + -- ...etc... + } + + From DONOTREPLY at icculus.org Wed May 16 04:45:01 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 04:45:01 -0400 Subject: r264 - trunk/scripts Message-ID: <20070516084501.29278.qmail@icculus.org> Author: icculus Date: 2007-05-16 04:44:58 -0400 (Wed, 16 May 2007) New Revision: 264 Modified: trunk/scripts/mojosetup_init.lua Log: Removed some cruft. Modified: trunk/scripts/mojosetup_init.lua =================================================================== --- trunk/scripts/mojosetup_init.lua 2007-05-15 14:17:57 UTC (rev 263) +++ trunk/scripts/mojosetup_init.lua 2007-05-16 08:44:58 UTC (rev 264) @@ -434,17 +434,5 @@ }) end -function Setup.UI(tab) - return sanitize("UI", tab, - { - -- You should add all existing UIs to this table. - { "generic", nil, mustBeString, cantBeEmpty }, - { "stdio", nil, mustBeString, cantBeEmpty }, - { "macosx", nil, mustBeString, cantBeEmpty }, - { "gtkplus", nil, mustBeString, cantBeEmpty }, - { "windows", nil, mustBeString, cantBeEmpty }, - }) -end - -- end of mojosetup_init.lua ... From DONOTREPLY at icculus.org Wed May 16 04:45:29 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 04:45:29 -0400 Subject: r265 - trunk Message-ID: <20070516084529.29764.qmail@icculus.org> Author: icculus Date: 2007-05-16 04:45:29 -0400 (Wed, 16 May 2007) New Revision: 265 Modified: trunk/docs.txt Log: More documentation work. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-16 08:44:58 UTC (rev 264) +++ trunk/docs.txt 2007-05-16 08:45:29 UTC (rev 265) @@ -133,6 +133,9 @@ } +Case is important! Setup.Option and Setup.option are NOT the same thing! + + Here are the elements, and the attributes they can possess. There are some specifiers by the attributes: @@ -342,7 +345,6 @@ the license text. Currently this must be a text file in UTF-8 encoding. - Setup.Media: This element is required if you need to install data from removable media, @@ -353,104 +355,232 @@ id (no default, mustExist, mustBeString, cantBeEmpty) - (!!! FIXME write me.) + A unique specifier for this media, such as "disc1" or "game-disc". This + will be used for Setup.File.source: "media://game-disc/path/filename.zip" description (no default, mustExist, mustBeString, cantBeEmpty) - (!!! FIXME write me.) + A human-readable description of this media, such as "MyGame Disc 2". This + string will be used when the end user must be prompted to insert a new + piece of media to continue the installation. uniquefile (no default, mustExist, mustBeString, cantBeEmpty) - (!!! FIXME write me.) + This is a path that is unique to this media, relative to its root + directory, such as "sounds/guitar.wav". The installer looks at all + media available to the system until it finds this path exists, to + determine if the correct media has been made available by the end user. + Setup.Option: + This element defines an optional section of the install, and is a child + of Setup.Package. You must have at least one Setup.Option in your + configuration, but you can make it mandatory with the "required" attribute + if you don't want it to be actually optional. - Setup.File: + The GUI will show all selectable options to the end user, and they can + pick and choose the parts they want. If there are no optional portions of + the install, the GUI will skip the option selection screen. - (!!! FIXME write me.) + Setup.Options can nest. If a parent option is unchecked in the GUI, its + child options become disabled and will be considered unchecked also when + installation proceeds. - Setup.File attributes: + Setup.Option + { + description = "Wing Commander 1" + source = "base:///wc1.zip", - source (no default, mustBeUrl) + -- This option can only install if "Wing Commander 1" is checked too. + Setup.Option + { + description = "WC1 Speech Pack", + source = "base:///wc1sp.zip", + }, + }, - (!!! FIXME write me.) + Setup.Option attributes: - destination (no default, mustBeString, cantBeEmpty) + disabled (default false, mustBeBool) - (!!! FIXME write me.) + If true, this whole group (including all children) will be removed from + the GUI, and the installer will treat all the child options as unchecked. + If an option has both "required" and "disabled" set to true, then + "disabled" takes precedence. - wildcards (no default, mustBeStringOrTableOfStrings) + value (default false, mustBeBool) - (!!! FIXME write me.) + If true, the checkbox will be checked by default in the GUI. Checked + options are installed. - filter (no default, mustBeFunction) + required (default false, mustBeBool) - (!!! FIXME write me.) + If true, the option won't be shown to the end user, but will just be + treated as if it was checked when installation proceeds. If an option + has both "required" and "disabled" set to true, then "disabled" takes + precedence. - allowoverwrite (no default, mustBeBool) + bytes (no default, mustExist, mustBeNumber) - (!!! FIXME write me.) + This is the size, in bytes, of files this option will write to disk. The + installer uses this to determine space requirements for the total install. + If you don't know the size, you should set this to -1, but this will + disable some functionality. + description (no default, mustExist, mustBeString, cantBeEmpty) - Setup.Option: + This string will be shown to the end user, as a label with the GUI's + checkbox. - (!!! FIXME write me.) - Setup.Option attributes: + Setup.OptionGroup: - value (default false, mustBeBool) + This element can be the parent or child of Setup.Option, or a child of + Setup.Package. It contains of a collection of Setup.Option elements. + The children Setup.Options will be grouped radio buttons in the GUI instead + of individual checkboxes. As such, only one child Setup.Option in an + Setup.OptionGroup will be checked in the GUI. - (!!! FIXME write me.) + Setup.OptionGroup + { + description = "Language", + Setup.Option { description = "English", source = "base:///en.zip" }, + Setup.Option { description = "French", source = "base:///fr.zip" }, + Setup.Option { description = "German", source = "base:///fr.zip" }, + }, + Setup.OptionGroup attributes: - required (default false, mustBeBool) + disabled (no default, mustBeBool) - (!!! FIXME write me.) + If true, this option (including all children) will be removed from + the GUI, and the installer will treat this and all child options as + unchecked. - disabled (default false, mustBeBool) + description (no default, mustExist, mustBeString, cantBeEmpty) - (!!! FIXME write me.) + This string will be shown to the end user, as a label with the GUI's + radio button group. - bytes (no default, mustExist, mustBeNumber) + Setup.File: - (!!! FIXME write me.) + This element specifies a fileset, a collection of files, to install. These + are children of Setup.Option, and you can specify as many as you like per + option. Each Setup.File represents an "archive," that is, some set of files, + such as a .zip file or a directory. + Setup.File attributes: - description (no default, mustExist, mustBeString, cantBeEmpty) + source (no default, mustBeUrl) - (!!! FIXME write me.) + This is a URL that provides the source for this fileset. You can only + specify archives (directories and files like .zip, .tar, etc), not + specific individual files. If you need a specific file, use its parent + directory here and a "wildcards" attribute. + There are some standard and non-standard URL handlers you can specify: + base:///path/file.ext + This references an archive in the Base Archive, where the "data" + directory is the root...so the above looks for data/path/file.ext in + the Base Archive. - Setup.OptionGroup: + This can install from an archive inside an archive, like this: - (!!! FIXME write me.) + base:///mydir/outside.zip/internalpath/inside.tar - Setup.OptionGroup attributes: - disabled (no default, mustBeBool) + media://id/path/file.ext - (!!! FIXME write me.) + This references a file on an external media with a specific id, + as defined in a Setup.Media element. The user will be prompted for + the correct media if the installer can't find it. This can install + archives-in-archives, like the base:/// version can. - description (no default, mustExist, mustBeString, cantBeEmpty) + ftp://hostname.dom/path/file.ext + http://hostname.dom/path/file.ext - (!!! FIXME write me.) + The references a file on an FTP or web server. These files will all be + downloaded before local files are installed. You may only specify + archives at this time, not individual files or directories. + MojoSetup must be built with support for the proper network protocol. + destination (no default, mustBeString, cantBeEmpty) + This attribute lets you, across the board, redirect files in this archive + to a specific destination. This is a path relative to the base of the + installation destination path. If the user specified an installation + destination of "/games/mygame", this attribute is "gamemod", and the + source produces a file "maps/level1.map", then the final file written to + disk would be "/games/mygame/gamemod/maps/level1.map". + After the path is prepared with this attribute, it is tested against the + "wildcards" attribute, and if it passes there, it is pushed through the + "filter" attribute. + + + wildcards (no default, mustBeStringOrTableOfStrings) + + This is the first step to culling files from an archive or directory. + Files are only installed if they match a specified wildcard. + Wildcards are simple to use: they only allow '?' for single character + matches and '*' to match a sequence of characters. You may specify a + single string, or a list of wildcards, like this: + + -- matches sounds/heroes/laser13.wav and sounds/villians/laser02.wav + wildcards = "sounds/*/laser??.wav" + + ...or... + + -- everything in the maps, sounds, and graphics directories. + -- (this includes subdirs! '*' matches past '/' separators!) + wildcards = { "maps/*", "sounds/*", "graphics/*" } + + + filter (no default, mustBeFunction) + + This is a function that takes one argument, a string that represents the + path of a single file relative to the root of the installation destination. + This function may return nil to choose not to install this file, which is + useful for culling files from an archive, or a string that represents a + new destination for the file, which is useful for renaming some files + on-the-fly: + + filter = function(dest) + if string.match(dest, ".exe$") then + return nil -- skip Windows .exe files on Unix. + end + if dest == "SOMEFILE.TXT" then + return "somefile.txt" -- force this to lowercase. + end + return dest -- everything else can go through as-is. + end + + + allowoverwrite (no default, mustBeBool) + + If true, the installer will overwrite existing files without warning. If + false, the user will be prompted before overwriting each file. + + Files are actually moved out of the way instead of overwritten, so the + installer can restore them if the install is cancelled or fails mid-way. + They are deleted only after a successful install. + + + Package up the final file for distribution: Now you have a MojoSetup binary and a directory tree containing your data, GUI @@ -531,3 +661,5 @@ } +--ryan. + From DONOTREPLY at icculus.org Wed May 16 04:52:06 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 04:52:06 -0400 Subject: r266 - trunk Message-ID: <20070516085206.2392.qmail@icculus.org> Author: icculus Date: 2007-05-16 04:52:06 -0400 (Wed, 16 May 2007) New Revision: 266 Modified: trunk/docs.txt Log: Documentation typo. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-16 08:45:29 UTC (rev 265) +++ trunk/docs.txt 2007-05-16 08:52:06 UTC (rev 266) @@ -26,7 +26,7 @@ Get the latest version of MojoSetup from Subversion: - svn svn://svn.icculus.org/mojosetup/trunk mojosetup + svn co svn://svn.icculus.org/mojosetup/trunk mojosetup Then you'll need to point CMake at it: From DONOTREPLY at icculus.org Wed May 16 05:55:35 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 05:55:35 -0400 Subject: r267 - trunk Message-ID: <20070516095535.16917.qmail@icculus.org> Author: icculus Date: 2007-05-16 05:55:35 -0400 (Wed, 16 May 2007) New Revision: 267 Modified: trunk/docs.txt Log: More documentation work! Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-16 08:52:06 UTC (rev 266) +++ trunk/docs.txt 2007-05-16 09:55:35 UTC (rev 267) @@ -7,11 +7,12 @@ be updated as we see what parts are confusing, so feedback is appreciated. -Putting together a MojoSetup installer involves four general steps: +Putting together a MojoSetup installer involves five general steps: 1) Compile the software. 2) Set up the installer filesystem structure. 3) Write a config file. -4) Package up the final file for distribution. +4) Add any localized strings. +5) Package up the final file for distribution. Each step has a lot of details, but all installers basically follow those same basic development steps. @@ -60,7 +61,7 @@ scripts/ guis/ -This is called the "base archive," even if it's a real directory tree in the +This is called the "Base Archive," even if it's a real directory tree in the physical filesystem and not in an actual archive, such as a .zip file. "data" is where the installer looks for files included in the installer itself @@ -109,8 +110,13 @@ people rolling config files don't need any significant Lua expertise, and basic config files don't need any programming experience at all. +MojoSetup provides some functions for your benefit, if you want to add any + programming logic to your config. These are documented below. + The config file is named config.lua, and it must be a text file in UTF-8 - encoding. + encoding. If you are doing any programming, you may use any symbol you like, + so long as the name isn't "Setup", "MojoSetup", or any of the standard Lua + runtime names like "string" or "table". Configuration files are a hierarchy of elements that take this form: @@ -159,7 +165,7 @@ Setup.Package: - All configurations need at least one Setup.Package element. Everything other + All configurations need at least one Setup.Package element. Every other element is added under Setup.Package. One full run of the installer is done for each Setup.Package. You can have multiple packages in one file, and the installer will run through for each one as if the program was started @@ -318,7 +324,7 @@ source (no default, mustExist, mustBeString, cantBeEmpty) - This is a filename in the base archive's "data" directory that contains + This is a filename in the Base Archive's "data" directory that contains the readme text. Currently this must be a text file in UTF-8 encoding. @@ -341,7 +347,7 @@ source (no default, mustExist, mustBeString, cantBeEmpty) - This is a filename in the base archive's "data" directory that contains + This is a filename in the Base Archive's "data" directory that contains the license text. Currently this must be a text file in UTF-8 encoding. @@ -580,37 +586,8 @@ They are deleted only after a successful install. +Add any localized strings: -Package up the final file for distribution: - -Now you have a MojoSetup binary and a directory tree containing your data, GUI - plugins, and scripts (including the config.lua you just wrote). Now you just - need to glue them together. MojoSetup will attempt to look at itself as an - archive on startup, which works in the same way "self-extracting" exe files - worked on other operating systems. If you want MojoSetup to be - self-extracting, zip your directory tree up and append it to the binary: - - zip -9r mydata.zip data guis scripts - cat mydata.zip >> mojosetup - -Now rename "mojosetup" to something meaningful (mygame-1.0-linux-x86.bin or - whatever), and you've got an installer. - -If you have the luxury of a real filesystem (inside a disk image or on a CD - you are shipping, for example), MojoSetup will use the binary's directory - if it doesn't find a zipfile appended to the binary itself, so you can just - have "data", "scripts" and "guis" in the same directory as "mojosetup" to - have it work, too. - - -Now you're done! Give your installer to the public. - - - -Extra credit: - -Localization: - If you added strings to the installer or your config file that you want translated at runtime, you need to add them to localization.lua. This is a Lua script, too, of course, but you really should treat it like a basic @@ -661,5 +638,260 @@ } ---ryan. +Package up the final file for distribution: + +Now you have a MojoSetup binary and a directory tree containing your data, GUI + plugins, and scripts (including the config.lua you just wrote). Now you just + need to glue them together. MojoSetup will attempt to look at itself as an + archive on startup, which works in the same way "self-extracting" exe files + worked on other operating systems. If you want MojoSetup to be + self-extracting, zip your directory tree up and append it to the binary: + + zip -9r mydata.zip data guis scripts + cat mydata.zip >> mojosetup + +Now rename "mojosetup" to something meaningful (mygame-1.0-linux-x86.bin or + whatever), and you've got an installer. + +If you have the luxury of a real filesystem (inside a disk image or on a CD + you are shipping, for example), MojoSetup will use the binary's directory + if it doesn't find a zipfile appended to the binary itself, so you can just + have "data", "scripts" and "guis" in the same directory as "mojosetup" to + have it work, too. + + +Now you're done! Give your installer to the public. + + + +MojoSetup-provided globals: + +Your config file is a Lua script, and as such, has access to all of Lua's + runtime library (presuming you didn't disable it when building MojoSetup) + and several other bits of MojoSetup-specific functionality. Everything the + installer provides to your script is under the "MojoSetup" table, so as not + to pollute the namespace. Also, the config files use the "Setup" table for + the basic config schema. Everything else is free game. Here are the globals + that MojoSetup provides: + + + MojoSetup.fatal(errstr) + + Display (errstr) to the end user and stop the installation. The installer + will attempt to clean up any half-finished installation, including rolling + back any files that would have been replaced had the installation succeeded. + You should never use error() in the standard Lua runtime; use this instead. + + + MojoSetup.runfile(script) + + Run the code in a given Lua file. This is JUST the base filename. MojoSetup + will look for it in the Base Archive in the scripts/ directory, both as + script.luac and script.lua. This code chunk will accept no arguments, and + return no results, but it can change the global state and alter tables, + etc, so it can have lasting side effects. Will return false if the file + couldn't be loaded, or true if the chunk successfully ran. Will not return + if there's a runtime error in the chunk, as it will call MojoSetup.fatal() + instead. You should use this instead of the "require" function in the Lua + runtime, as require() won't respect the Base Archive. + + + MojoSetup.translate(str) + + Find the proper translation for the end user's locale in the localization + table. Returns the translation, or the original string if no translation + was available. It's common to use this for shorthand: + + local function _ = MojoSetup.translate + + ...so you can be less verbose: print(_("translate this string")) + + + MojoSetup.ticks() + + Return the time, in milliseconds, that the process has been running. + + + MojoSetup.logwarning(str) + + Write a warning to the installation log, if logging settings permit. + + + MojoSetup.logerror(str) + + Write an error to the installation log, if logging settings permit. + + + MojoSetup.loginfo(str) + + Write an info string to the installation log, if logging settings permit. + + + MojoSetup.logdebug(str) + + Write debug info to the installation log, if logging settings permit. + + + MojoSetup.msgbox(str) + + Show (str) to the user with a GUI message box, and wait until they click + an "OK" button. + + + MojoSetup.promptyn(str) + + Show (str) to the user with a GUI message box, and wait until they click + either a "YES" or "NO" button. Returns true if they clicked YES, false + if they clicked "NO". + + + MojoSetup.stackwalk() + + This writes a backtrace of the current Lua callstack to the installation + log, if logging settings permit debug-level logging. + + + MojoSetup.cmdline(flag) + + See if a given flag was on the command line for the process. + MojoSetup.cmdline("nosound") will return true if "-nosound", "--nosound", + etc was on the command line. The option must start with a '-' on the + command line to be noticed by this function. Returns true if flag was on + the command line, false otherwise. + + + MojoSetup.cmdlinestr(flag, envr, deflt) + + Get robust command line options, with optional default for missing ones. + + If the command line was ./myapp --a=b -c=d ----e f + - cmdlinestr("a") will return "b" + - cmdlinestr("c") will return "d" + - cmdlinestr("e") will return "f" + - cmdlinestr("g") will return the default string. + + Like MojoSetup.cmdline(), the option must start with a '-'. + + (envr) is an optional environment var to check if command line wasn't + found. You can call this function without specifying this parameter, or + pass a nil here. + (deflt) is the return value if (flag) isn't on the command line. + + + MojoSetup.collectgarbage() + + Do a complete run of the Lua garbage collector. Use this instead of the + version in the Lua standard runtime, since this version does better debug + logging. + + MojoSetup.date() + + Return a string of the current date. This is roughly the same as os.date() + in the standard Lua runtime, but we didn't want to add the os table + dependencies just to write this string into the log. + + + MojoSetup.info.locale + + This is a string (not a function!) of the current locale, in the format + xx_YY, where "xx" is the language code (en for english, de for German, etc) + and "YY" is the country code: "en_US" for American English, fr_CA for + French Canadian, etc. + + + MojoSetup.info.platform + + This is a string (not a function!) of the current platform. This is + currently one of "macosx", "unix", "windows", or "beos". + + + MojoSetup.info.arch + + This is a string (not a function!) of the current platform's CPU type. + This is currently one of "x86", "x86-64", "powerpc", or "powerpc64". + + Please note that this is the arch of the installer binary...you can run + a 32-bit binary on an amd64 chip, in which case it will report "x86"! + + + MojoSetup.info.ostype + + This is a string (not a function!) of the current platform's operating + system. This is currently one of "macosx", "beos", "linux", "freebsd", + "netbsd", "openbsd", "bsdi", "aix", "hpux", or "irix". + + Please note that this is the OS target of the installer binary...you can + run a Linux binary on FreeBSD through the binary compatibility layer, + in which case it will report "linux"! + + + MojoSetup.info.osversion + + This is a string (not a function!) of the current platform's operating + system version. This may not be useful information on many platforms. + On Mac OS X, it's the system version (So it might be 10.4.9 on a Tiger + install, 10.3.8 on a Panther install, etc). + + On other Unixes, it's the "release" field from uname(), which on Linux + gives you the kernel version, which is usually not helpful, but could be + on, say, BeOS. + + + MojoSetup.info.ui + + This is a string (not a function!) of the UI plugin that MojoSetup chose. + system. This is currently one of "stdio", "macosx", or "gtkplus2". + + + MojoSetup.info.buildver + + This is a string (not a function!) of the build identifier for this binary. + You can print this string to stdout by running ./mojosetup --buildver + at the command line. + + + MojoSetup.info.loglevel + + This is a string (not a function!) of the logging level that MojoSetup + is enforcing. This is currently one of "nothing", "errors", "warnings", + "info", "debug", or "everything" ... each level includes the previous + level, so "warnings" will also log error messages, but not info or debug + messages. + + + MojoSetup.info.homedir + + This is a string (not a function!) of the "home directory" of the end-user + in the physical filesystem. This is useful if you want to determine a sane + default location to write files. + + + MojoSetup.info.argv + + This is a string array (not a function!) of the installer process's + command line arguments. You might find MojoSetup.cmdline() or + MojoSetup.cmdlinestr() to be more useful. + + + MojoSetup.info.supportedurls + + This is a string array (not a function!) of URL types the installer + supports. You can either iterate it... + + for k,v in pairs(MojoSetup.info.supportedurls) do + print("installer supports " .. v .. ":// URLs") + end + + ...or you can query it... + + if MojoSetup.info.supportedurls["http"] ~= nil then + print("installer supports http:// URLs") + end + + "base" and "media" are included in the list, always. The rest are + compile-time options. + + +// end of docs.txt ... + From DONOTREPLY at icculus.org Wed May 16 19:39:18 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 19:39:18 -0400 Subject: r268 - trunk/scripts Message-ID: <20070516233918.14335.qmail@icculus.org> Author: icculus Date: 2007-05-16 19:39:18 -0400 (Wed, 16 May 2007) New Revision: 268 Modified: trunk/scripts/mojosetup_mainline.lua Log: Don't crash if Setup.Package.recommended_destinations is a string instead of a table of strings. Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-16 09:55:35 UTC (rev 267) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-16 23:39:18 UTC (rev 268) @@ -534,9 +534,14 @@ set_destination(install.destination) else local recommend = nil - if install.recommended_destinations ~= nil then + local recommended_cfg = install.recommended_destinations + if recommended_cfg ~= nil then + if type(recommended_cfg) == "string" then + recommended_cfg = { recommended_cfg } + end + recommend = {} - for i,v in ipairs(install.recommended_destinations) do + for i,v in ipairs(recommended_cfg) do if MojoSetup.platform.isdir(v) then if MojoSetup.platform.writable(v) then recommend[#recommend+1] = v .. "/" .. install.id From DONOTREPLY at icculus.org Wed May 16 19:40:26 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 19:40:26 -0400 Subject: r269 - trunk Message-ID: <20070516234026.14960.qmail@icculus.org> Author: icculus Date: 2007-05-16 19:40:26 -0400 (Wed, 16 May 2007) New Revision: 269 Modified: trunk/docs.txt Log: Clarified docs a little. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-16 23:39:18 UTC (rev 268) +++ trunk/docs.txt 2007-05-16 23:40:26 UTC (rev 269) @@ -74,7 +74,8 @@ "scripts" is where Lua scripts go. You'll put your config file in here (config.lua), the translation table (localizations.lua), and whatever other - scripts come with MojoSetup, which are required application logic. This + scripts come with MojoSetup, which are required application logic. The + installer will not work if you don't include all these files! This directory can hold either .lua files (source code), or their .luac equivalents. If you built MojoSetup without the Lua parser to save space, you'll need to compile the .lua sources into .luac objects now, or the From DONOTREPLY at icculus.org Wed May 16 19:50:29 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 19:50:29 -0400 Subject: r270 - trunk Message-ID: <20070516235029.19584.qmail@icculus.org> Author: icculus Date: 2007-05-16 19:50:29 -0400 (Wed, 16 May 2007) New Revision: 270 Modified: trunk/docs.txt Log: Minor documentation correction from Timothee Besset. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-16 23:40:26 UTC (rev 269) +++ trunk/docs.txt 2007-05-16 23:50:29 UTC (rev 270) @@ -214,8 +214,8 @@ location in the physical filesystem. Unless you are building something very specific (like device drivers for a well-defined platform), you probably should not use this attribute. If destination isn't forced, - the installer will prompt the user for the destination, possibly - recommmending locations to her. + the installer will prompt the user, possibly recommmending locations + to him. recommended_destinations (no default, mustBeStringOrTableOfStrings) From DONOTREPLY at icculus.org Wed May 16 20:11:12 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 20:11:12 -0400 Subject: r271 - in trunk: . scripts Message-ID: <20070517001112.27241.qmail@icculus.org> Author: icculus Date: 2007-05-16 20:11:12 -0400 (Wed, 16 May 2007) New Revision: 271 Modified: trunk/gui_stdio.c trunk/scripts/localization.lua Log: stdio GUI chooses first install destination listed if user just hits enter. Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-16 23:50:29 UTC (rev 270) +++ trunk/gui_stdio.c 2007-05-17 00:11:12 UTC (rev 271) @@ -298,7 +298,7 @@ *command = -1; if (recnum > 0) - prompt = entry->xstrdup(entry->_("Choose install destination by number, or enter your own.")); + prompt = entry->xstrdup(entry->_("Choose install destination by number (hit enter for #1), or enter your own.")); else prompt = entry->xstrdup(entry->_("Enter path where files will be installed.")); @@ -311,6 +311,14 @@ if ((len = readstr(prompt, buf, sizeof (buf), can_back, false)) < 0) getout = true; + + else if ((len == 0) && (recnum > 0)) // default to first in list. + { + retval = entry->xstrdup(recommends[0]); + *command = 1; + getout = true; + } // else if + else if (len > 0) { char *endptr = NULL; Modified: trunk/scripts/localization.lua =================================================================== --- trunk/scripts/localization.lua 2007-05-16 23:50:29 UTC (rev 270) +++ trunk/scripts/localization.lua 2007-05-17 00:11:12 UTC (rev 271) @@ -92,7 +92,7 @@ ["Install destination:"] = { }; - ["Choose install destination by number, or enter your own."] = { + ["Choose install destination by number (hit enter for #1), or enter your own."] = { }; ["Enter path where files will be installed."] = { From DONOTREPLY at icculus.org Wed May 16 20:35:42 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 20:35:42 -0400 Subject: r272 - trunk Message-ID: <20070517003542.4923.qmail@icculus.org> Author: icculus Date: 2007-05-16 20:35:42 -0400 (Wed, 16 May 2007) New Revision: 272 Modified: trunk/gui_stdio.c Log: stdio gui: Don't show total progress if it's indeterminate. Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-17 00:11:12 UTC (rev 271) +++ trunk/gui_stdio.c 2007-05-17 00:35:42 UTC (rev 272) @@ -365,7 +365,10 @@ { percentTicks = now + 1000; // !!! FIXME: localization. - printf(entry->_("%s (total progress: %d%%)\n"), item, percent); + if (percent < 0) + printf(entry->_("%s\n"), item); + else + printf(entry->_("%s (total progress: %d%%)\n"), item, percent); } // if return true; From DONOTREPLY at icculus.org Wed May 16 20:36:23 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 16 May 2007 20:36:23 -0400 Subject: r273 - in trunk: . scripts Message-ID: <20070517003623.5115.qmail@icculus.org> Author: icculus Date: 2007-05-16 20:36:23 -0400 (Wed, 16 May 2007) New Revision: 273 Modified: trunk/fileio.c trunk/scripts/mojosetup_mainline.lua Log: Show download rate and estimated time remaining for transfer. Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-17 00:35:42 UTC (rev 272) +++ trunk/fileio.c 2007-05-17 00:36:23 UTC (rev 273) @@ -103,7 +103,7 @@ if (cb != NULL) { // !!! FIXME: need a way to say "we're just spinning without a goal." - if (!cb(MojoPlatform_ticks() - start, 0, 0, 100, data)) + if (!cb(MojoPlatform_ticks() - start, 0, 0, -1, data)) iofailure = true; } // if } // while Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-17 00:35:42 UTC (rev 272) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-17 00:36:23 UTC (rev 273) @@ -99,6 +99,48 @@ return MojoSetup.truncatenum((current / total) * 100) end + +local function make_bps_string(bps, bw, total) + -- !!! FIXME: localization on all this. + local bpsstr = nil + + if bps <= 0 then + bpsstr = _("(stalled)") + else + local bytesleft = total - bw + local secsleft = MojoSetup.truncatenum(bytesleft / bps) + local minsleft = MojoSetup.truncatenum(secsleft / 60) + local hoursleft = MojoSetup.truncatenum(minsleft / 60) + + secsleft = string.sub("00" .. (secsleft - (minsleft * 60)), -2) + minsleft = string.sub("00" .. (minsleft - (hoursleft * 60)), -2) + + if hoursleft < 10 then + hoursleft = "0" .. hoursleft; + else + hoursleft = tostring(hoursleft) + end + + local timeleft = hoursleft .. ":" .. minsleft .. ":" .. secsleft + if bps > 1024 then + local kps = MojoSetup.truncatenum(bps / 1024) + if total > 0 then + bpsstr = " (" .. kps .. _("Kb/s") .. ", " .. timeleft .. " remaining)" + else + bpsstr = " (" .. kps .. _("Kb/s") .. ")" + end + else + if total > 0 then + bpsstr = " (" .. bps .. _("b/s") .. ", " .. timeleft .. " remaining)" + else + bpsstr = " (" .. bps .. _("b/s") .. ")" + end + end + end + return bpsstr +end + + local function split_path(path) local retval = {} for item in string.gmatch(path .. "/", "(.-)/") do @@ -176,10 +218,13 @@ local component = option.description local keepgoing = true local callback = function(ticks, justwrote, bw, total) - MojoSetup.written = MojoSetup.written + justwrote - local percent = calc_percent(MojoSetup.written, - MojoSetup.totalwrite) - local item = fname .. ": " .. calc_percent(bw, total) .. "%" -- !!! FIXME: localization + local percent = -1 + local item = fname + if total >= 0 then + MojoSetup.written = MojoSetup.written + justwrote + percent = calc_percent(MojoSetup.written, MojoSetup.totalwrite) + item = fname .. ": " .. calc_percent(bw, total) .. "%" -- !!! FIXME: localization + end keepgoing = MojoSetup.gui.progress(ptype, component, percent, item) return keepgoing end @@ -677,11 +722,28 @@ local fname = string.gsub(url, "^.*/", "", 1) -- chop the dirs off... local ptype = _("Downloading") -- !!! FIXME: localization. local component = option.description + local bps = 0 + local bpsticks = 0 + local bpsstr = '' + local item = fname + local percent = -1 local callback = function(ticks, justwrote, bw, total) - MojoSetup.downloaded = MojoSetup.downloaded + justwrote - local percent = calc_percent(MojoSetup.downloaded, - MojoSetup.totaldownload) - local item = fname .. ": " .. calc_percent(bw, total) .. "%" -- !!! FIXME: localization + if total < 0 then + -- adjust start point for d/l rate calculation... + bpsticks = ticks + 1000 + else + if ticks >= bpsticks then + bpsstr = make_bps_string(bps, bw, total) + bpsticks = ticks + 1000 + bps = 0 + end + bps = bps + justwrote + MojoSetup.downloaded = MojoSetup.downloaded + justwrote + percent = calc_percent(MojoSetup.downloaded, + MojoSetup.totaldownload) + + item = fname .. ": " .. calc_percent(bw, total) .. "%" .. bpsstr -- !!! FIXME: localization + end return MojoSetup.gui.progress(ptype, component, percent, item) end From DONOTREPLY at icculus.org Thu May 17 01:50:57 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 01:50:57 -0400 Subject: r274 - trunk Message-ID: <20070517055057.11118.qmail@icculus.org> Author: icculus Date: 2007-05-17 01:50:57 -0400 (Thu, 17 May 2007) New Revision: 274 Added: trunk/examples/ Log: Added examples directory. From DONOTREPLY at icculus.org Thu May 17 02:25:45 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 02:25:45 -0400 Subject: r275 - in trunk/examples: . duke3d duke3d/data duke3d/scripts Message-ID: <20070517062545.24765.qmail@icculus.org> Author: icculus Date: 2007-05-17 02:25:45 -0400 (Thu, 17 May 2007) New Revision: 275 Added: trunk/examples/duke3d/ trunk/examples/duke3d/data/ trunk/examples/duke3d/data/duke3d_readme.txt trunk/examples/duke3d/data/gpl.txt trunk/examples/duke3d/data/mojosetup_readme.txt trunk/examples/duke3d/make.sh trunk/examples/duke3d/scripts/ trunk/examples/duke3d/scripts/config.lua Log: Added duke3d example installer to Subversion. Added: trunk/examples/duke3d/data/duke3d_readme.txt =================================================================== --- trunk/examples/duke3d/data/duke3d_readme.txt (rev 0) +++ trunk/examples/duke3d/data/duke3d_readme.txt 2007-05-17 06:25:45 UTC (rev 275) @@ -0,0 +1,56 @@ + +What is this? + +This is icculus.org's port of Duke Nukem 3D. + +The included installer can use the PC retail version of the game (the +"Atomic Edition"). If you don't have a retail disc, the installer can +also install the shareware data files, which leaves you with only +episode one, and various other shareware nagging. + +Retail discs can be found on eBay or in bargain bins for dirt cheap. +3DRealms actually did a new print run of discs in 2003 or so, and as of +this writing, sells them from their online store at + + http://www.3drealms.com/ + +Duke3D is not "Abandonware"...please do not pirate the game! There are +several legitimate channels to obtain a copy of the retail version. + +We do not provide support for this version of Duke3D, nor will 3DRealms. +We accept bug reports here... + + https://bugzilla.icculus.org/ + +...but don't promise to ever act on them. If it breaks, you get to keep +both shiny pieces. + +The editor is not necessarily obvious to use, but basically works like +the DOS version, so you can get the old school manual off the Internet. + +Networking is included, but is flakey, so we're not documenting it +here. Google might turn up some info for the brave. + + +Special thanks: + +3DRealms and Ken Silverman for releasing the Duke/Build sources. + I hope we've all lived up to your expectations! + +Dirk for the help with the French MacSoft disc +Adam Betts for the disc image graphics and icons +Forrest Walter for the installer splash graphic +Steven Fuller for picking at the MacSoft installer format and all the +porting work +Dan Olson for months battling Build. +The rest of the duke/rott/build crew +The icculus.org Mac Ninjas +Many others, thanks! + +--ryan. + + +Changelog: + +05122007: Initial release. + Added: trunk/examples/duke3d/data/gpl.txt =================================================================== --- trunk/examples/duke3d/data/gpl.txt (rev 0) +++ trunk/examples/duke3d/data/gpl.txt 2007-05-17 06:25:45 UTC (rev 275) @@ -0,0 +1,275 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +Preamble +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not price. +Our General Public Licenses are designed to make sure that you have the +freedom to distribute copies of free software (and charge for this +service if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis +or for a fee, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent +must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +the Program is not restricted, and the output from the Program is +covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the +Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + +2. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + +a) You must cause the modified files to carry prominent notices stating +that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. + +c) If the modified program normally reads commands interactively when +run, you must cause it, when started running for such interactive use +in the most ordinary way, to print or display an announcement including +an appropriate copyright notice and a notice that there is no warranty +(or else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling the user +how to view a copy of this License. (Exception: if the Program itself +is interactive but does not normally print such an announcement, your +work based on the Program is not required to print an announcement.) +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of a +storage or distribution medium does not bring the other work under the +scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source +code, which must be distributed under the terms of Sections 1 and 2 +above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, +to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + +c) Accompany it with the information you received as to the offer to +distribute corresponding source code. (This alternative is allowed only +for noncommercial distribution and only if you received the program in +object code or executable form with such an offer, in accord with +Subsection b above.) +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that +is normally distributed (in either source or binary form) with the +major components (compiler, kernel, and so on) of the operating system +on which the executable runs, unless that component itself accompanies +the executable. +If distribution of executable or object code is made by offering access +to copy from a designated place, then offering equivalent access to +copy the source code from the same place counts as distribution of the +source code, even though third parties are not compelled to copy the +source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such parties +remain in full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying the +Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further restrictions +on the recipients' exercise of the rights granted herein. You are not +responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent license +would not permit royalty-free redistribution of the Program by all +those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain +entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up +to the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail +to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a version +number of this License, you may choose any version ever published by +the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH +YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + +END OF TERMS AND CONDITIONS Added: trunk/examples/duke3d/data/mojosetup_readme.txt =================================================================== --- trunk/examples/duke3d/data/mojosetup_readme.txt (rev 0) +++ trunk/examples/duke3d/data/mojosetup_readme.txt 2007-05-17 06:25:45 UTC (rev 275) @@ -0,0 +1,37 @@ + +This is MojoSetup, a new installer application. + +This is a work in progress, so if you download this same installer later, + it may look radically different, or work better or worse. + +We are using this Duke3D installation as an initial testbed for MojoSetup. + +Please report bugs and irritations in this installer to Ryan: + + icculus at icculus.org + + +All suggestions are welcome. + +Please make sure you have the latest copy of this installer: + + http://icculus.org/mojosetup/example/duke3d/ + + +Please note that bug reports about Duke Nukem 3D are also welcome, but this + isn't an officially supported build. Don't expect game fixes from either + Ryan or 3DRealms for this build. Source code to Duke3D is here: + + http://icculus.org/duke3d/ + + +There is still a lot to be done with MojoSetup. Check back often! + +Enjoy, +--ryan. + + +CHANGELOG: + + 05122007: Initial release. + Added: trunk/examples/duke3d/make.sh =================================================================== --- trunk/examples/duke3d/make.sh (rev 0) +++ trunk/examples/duke3d/make.sh 2007-05-17 06:25:45 UTC (rev 275) @@ -0,0 +1,73 @@ +#!/bin/sh + +# This script is not robust for all platforms or situations. Use as a rough +# example, but invest effort in what it's trying to do, and what it produces. +# (make sure you don't build in features you don't need, etc). + +# Show everything that we do here on stdout. +set -x + +# Stop if anything produces an error. +set -e + +# Clean up previous run, build fresh dirs for Base Archive. +rm -rf image duke3d-installer pdata.zip +mkdir image +mkdir image/guis +mkdir image/scripts +mkdir image/data + +# Build MojoSetup binaries from scratch. +cd ../.. +rm -rf *.so mojosetup `svn propget svn:ignore .` +cmake \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DMOJOSETUP_ARCHIVE_TAR=FALSE \ + -DMOJOSETUP_ARCHIVE_TAR_BZ2=FALSE \ + -DMOJOSETUP_ARCHIVE_TAR_GZ=FALSE \ + -DMOJOSETUP_LUALIB_DB=FALSE \ + -DMOJOSETUP_LUALIB_IO=FALSE \ + -DMOJOSETUP_LUALIB_MATH=FALSE \ + -DMOJOSETUP_LUALIB_OS=FALSE \ + -DMOJOSETUP_LUALIB_PACKAGE=FALSE \ + -DMOJOSETUP_LUA_PARSER=FALSE \ + . +make -j5 + +# Strip the binaries and GUI plugins, put them somewhere useful. +strip ./mojosetup +mv ./mojosetup ./examples/duke3d/duke3d-installer +for feh in *.so ; do + strip $feh + mv $feh examples/duke3d/image/guis +done + +# Compile the Lua scripts, put them in the base archive. +for feh in scripts/*.lua ; do + ./mojoluac -s -o examples/duke3d/image/${feh}c $feh +done + +# Don't want the example config...use our's instead. +rm -f examples/duke3d/image/scripts/config.luac +./mojoluac -s -o examples/duke3d/image/scripts/config.luac examples/duke3d/scripts/config.lua + +# Fill in the rest of the Base Archive... +cd examples/duke3d +cp data/* image/data/ + +# Make a .zip archive of the Base Archive dirs and nuke the originals... +cd image +zip -9r ../pdata.zip * +cd .. +rm -rf image + +# Append the .zip archive to the mojosetup binary, so it's "self-extracting." +cat pdata.zip >> ./duke3d-installer +rm -f pdata.zip + +# ...and that's that. +set +e +set +x +echo "Successfully built!" +exit 0 + Property changes on: trunk/examples/duke3d/make.sh ___________________________________________________________________ Name: svn:executable + * Added: trunk/examples/duke3d/scripts/config.lua =================================================================== --- trunk/examples/duke3d/scripts/config.lua (rev 0) +++ trunk/examples/duke3d/scripts/config.lua 2007-05-17 06:25:45 UTC (rev 275) @@ -0,0 +1,124 @@ +local _ = MojoSetup.translate + +Setup.Package +{ + id = "duke3d", + description = "Duke Nukem 3D", + version = "1.5", + splash = "splash.jpg", + superuser = false, + recommended_destinations = + { + MojoSetup.info.homedir, + "/opt/games", + "/usr/local/games" + }, + + Setup.Eula + { + description = _("GNU General Public License"), + source = _("gpl.txt") + }, + + Setup.Readme + { + description = _("MojoSetup README"), + source = _("mojosetup_readme.txt") + }, + + Setup.Readme + { + description = _("Duke Nukem 3D README"), + source = _("duke3d_readme.txt") + }, + + Setup.Media + { + id = "mac-cd", + description = _("MacSoft Duke3D CD-ROM"), + uniquefile = "Goodies/Utilities/Duke File Typer" + }, + + Setup.Media + { + id = "pc-cd", + description = _("PC Atomic Edition CD-ROM"), + uniquefile = "atominst/duke3d.grp" + }, + + Setup.OptionGroup + { + description = _("Installation type"), + + Setup.Option + { + value = true, + required = false, + disabled = false, + bytes = 31102768, + description = _("Install Shareware version"), + + Setup.File + { + wildcards = "*.txt"; -- catch all the EULAs and READMEs. + }, + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_shareware_bins_" .. MojoSetup.info.ostype .. "_" .. MojoSetup.info.arch .. ".zip" + }, + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_shareware_data.zip" + }, + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_unified_content.zip" + }, + }, + + Setup.Option + { + value = false, + required = false, + disabled = false, + bytes = 64525364, + description = _("Install full game from Atomic Edition disc"), + + Setup.File + { + wildcards = "*.txt"; -- catch all the EULAs and READMEs. + }, + + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_retail_bins_" .. MojoSetup.info.ostype .. "_" .. MojoSetup.info.arch .. ".zip" + }, + + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_unified_content.zip" + }, + + Setup.File + { + source = "http://icculus.org/mojosetup/examples/duke3d/data/duke3d_retail_demos.zip" + }, + + Setup.File + { + source = "media://pc-cd/", + + -- do a filter to catch filename case differences. + filter = function(dest) + if string.lower(dest) == "atominst/duke3d.grp" then + return "duke3d.grp" -- chop "atominst/". + end + return nil -- don't install anything else here. + end + }, + }, + }, +} + +-- end of config.lua ... + From DONOTREPLY at icculus.org Thu May 17 12:06:37 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 12:06:37 -0400 Subject: r276 - trunk Message-ID: <20070517160637.14746.qmail@icculus.org> Author: icculus Date: 2007-05-17 12:06:37 -0400 (Thu, 17 May 2007) New Revision: 276 Modified: trunk/platform_unix.c Log: Mac OS X should log to stdout so it shows up in Console application. Modified: trunk/platform_unix.c =================================================================== --- trunk/platform_unix.c 2007-05-17 06:25:45 UTC (rev 275) +++ trunk/platform_unix.c 2007-05-17 16:06:37 UTC (rev 276) @@ -52,6 +52,7 @@ #endif #include "platform.h" +#include "gui.h" static struct timeval startup_time; @@ -590,6 +591,13 @@ void MojoPlatform_log(const char *str) { syslog(LOG_USER | LOG_INFO, "%s", str); + +#if PLATFORM_MACOSX + // put to stdout too, if this isn't the stdio UI. + // This will let the info show up in /Applications/Utilities/Console.app + if ((GGui != NULL) && (strcmp(GGui->name(), "stdio") != 0)) + printf("%s\n", str); +#endif } // MojoPlatform_log From DONOTREPLY at icculus.org Thu May 17 12:07:33 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 12:07:33 -0400 Subject: r277 - trunk Message-ID: <20070517160733.15361.qmail@icculus.org> Author: icculus Date: 2007-05-17 12:07:33 -0400 (Thu, 17 May 2007) New Revision: 277 Modified: trunk/CMakeLists.txt Log: Don't build GTK+ gui on Mac OS X, BeOS, or non-Unix systems for now. Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-17 16:06:37 UTC (rev 276) +++ trunk/CMakeLists.txt 2007-05-17 16:07:33 UTC (rev 277) @@ -288,6 +288,9 @@ ENDIF(MOJOSETUP_GUI_MACOSX) ENDIF(MACOSX) +IF(UNIX) +IF(NOT BEOS) +IF(NOT MACOSX) #FIND_PACKAGE(PkgConfig) #PKGCONFIG(libgtk-2.0 LIBGTK_INCLUDE_DIR LIBGTK_LINK_DIR LIBGTK_LINK_FLAGS LIBGTK_CFLAGS) # !!! FIXME @@ -312,6 +315,9 @@ ENDIF(MOJOSETUP_GUI_GTKPLUS2_STATIC) ENDIF(MOJOSETUP_GUI_GTKPLUS2) ENDIF(NOT LIBGTK_LINK_FLAGS) +ENDIF(NOT MACOSX) +ENDIF(NOT BEOS) +ENDIF(UNIX) # Archivers... From DONOTREPLY at icculus.org Thu May 17 12:08:18 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 12:08:18 -0400 Subject: r278 - trunk/examples/duke3d Message-ID: <20070517160818.15719.qmail@icculus.org> Author: icculus Date: 2007-05-17 12:08:18 -0400 (Thu, 17 May 2007) New Revision: 278 Modified: trunk/examples/duke3d/make.sh Log: Some fixes and cleanups in duke3d example make script. Modified: trunk/examples/duke3d/make.sh =================================================================== --- trunk/examples/duke3d/make.sh 2007-05-17 16:07:33 UTC (rev 277) +++ trunk/examples/duke3d/make.sh 2007-05-17 16:08:18 UTC (rev 278) @@ -19,7 +19,7 @@ # Build MojoSetup binaries from scratch. cd ../.. -rm -rf *.so mojosetup `svn propget svn:ignore .` +rm -rf `svn propget svn:ignore .` cmake \ -DCMAKE_BUILD_TYPE=MinSizeRel \ -DMOJOSETUP_ARCHIVE_TAR=FALSE \ @@ -31,15 +31,18 @@ -DMOJOSETUP_LUALIB_OS=FALSE \ -DMOJOSETUP_LUALIB_PACKAGE=FALSE \ -DMOJOSETUP_LUA_PARSER=FALSE \ + -DMOJOSETUP_URL_FTP=FALSE \ . make -j5 # Strip the binaries and GUI plugins, put them somewhere useful. strip ./mojosetup mv ./mojosetup ./examples/duke3d/duke3d-installer -for feh in *.so ; do - strip $feh - mv $feh examples/duke3d/image/guis +for feh in *.so *.dll *.dylib ; do + if [ -f $feh ]; then + strip $feh + mv $feh examples/duke3d/image/guis + fi done # Compile the Lua scripts, put them in the base archive. From DONOTREPLY at icculus.org Thu May 17 12:13:45 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 12:13:45 -0400 Subject: r279 - trunk/scripts Message-ID: <20070517161345.18330.qmail@icculus.org> Author: icculus Date: 2007-05-17 12:13:45 -0400 (Thu, 17 May 2007) New Revision: 279 Modified: trunk/scripts/mojosetup_mainline.lua Log: Whoops, rollback deletion was very very broken. Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-17 16:08:18 UTC (rev 278) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-17 16:13:45 UTC (rev 279) @@ -46,6 +46,19 @@ end end +local function delete_rollbacks() + if MojoSetup.rollbacks == nil then + return + end + local fnames = {} + local max = #MojoSetup.rollbacks + for id = 1,max,1 do + fnames[id] = MojoSetup.rollbackdir .. "/" .. id + end + MojoSetup.rollbacks = {} -- just in case this gets called again... + delete_files(fnames) +end + local function delete_scratchdirs() do_delete(MojoSetup.downloaddir) do_delete(MojoSetup.rollbackdir) @@ -70,6 +83,8 @@ end MojoSetup.loginfo("Restored rollback #" .. id .. ": '" .. src .. "' -> '" .. dest .. "'") end + + MojoSetup.rollbacks = {} -- just in case this gets called again... end @@ -877,7 +892,7 @@ -- !!! FIXME: write out manifest. -- Successful install, so delete conflicts we no longer need to rollback. - delete_files(MojoSetup.rollbacks) + delete_rollbacks() delete_files(MojoSetup.downloads) delete_scratchdirs() From DONOTREPLY at icculus.org Thu May 17 12:15:24 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 12:15:24 -0400 Subject: r280 - in trunk: . scripts Message-ID: <20070517161524.19072.qmail@icculus.org> Author: icculus Date: 2007-05-17 12:15:24 -0400 (Thu, 17 May 2007) New Revision: 280 Modified: trunk/docs.txt trunk/gui.h trunk/gui_gtkplus2.c trunk/gui_macosx.c trunk/gui_stdio.c trunk/lua_glue.c trunk/scripts/localization.lua trunk/scripts/mojosetup_mainline.lua Log: Let the UI ask "Yes/No/Always/Never" questions, and use it to stop nagging about overwriting every file. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/docs.txt 2007-05-17 16:15:24 UTC (rev 280) @@ -747,6 +747,13 @@ if they clicked "NO". + MojoSetup.promptynan(str) + + Show (str) to the user with a GUI message box, and wait until they click + either a "YES", "NO", "ALWAYS" or "NEVER" button. Returns the string + "yes", "no", "always", or "never". + + MojoSetup.stackwalk() This writes a backtrace of the current Lua callstack to the installation Modified: trunk/gui.h =================================================================== --- trunk/gui.h 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/gui.h 2007-05-17 16:15:24 UTC (rev 280) @@ -26,6 +26,16 @@ } MojoGuiPluginPriority; +typedef enum +{ + MOJOGUI_NO, + MOJOGUI_YES, + MOJOGUI_ALWAYS, + MOJOGUI_NEVER +} MojoGuiYNAN; + + + /* * Abstract GUI interfaces. */ @@ -43,6 +53,7 @@ MojoGuiSetupOptions *child; }; + #define MOJOGUI_ENTRY_POINT MojoSetup_Gui_GetInterface #define MOJOGUI_ENTRY_POINT_STR DEFINE_TO_STR(MOJOGUI_ENTRY_POINT) @@ -58,6 +69,7 @@ void (*deinit)(void); void (*msgbox)(const char *title, const char *text); boolean (*promptyn)(const char *title, const char *text); + MojoGuiYNAN (*promptynan)(const char *title, const char *text); boolean (*start)(const char *title, const char *splash); void (*stop)(void); int (*readme)(const char *name, const uint8 *data, size_t len, @@ -97,6 +109,8 @@ static void MojoGui_##module##_deinit(void); \ static void MojoGui_##module##_msgbox(const char *title, const char *text); \ static boolean MojoGui_##module##_promptyn(const char *t1, const char *t2); \ +static MojoGuiYNAN MojoGui_##module##_promptynan(const char *t1, \ + const char *t2); \ static boolean MojoGui_##module##_start(const char *t, const char *s); \ static void MojoGui_##module##_stop(void); \ static int MojoGui_##module##_readme(const char *name, const uint8 *data, \ @@ -120,6 +134,7 @@ MojoGui_##module##_deinit, \ MojoGui_##module##_msgbox, \ MojoGui_##module##_promptyn, \ + MojoGui_##module##_promptynan, \ MojoGui_##module##_start, \ MojoGui_##module##_stop, \ MojoGui_##module##_readme, \ Modified: trunk/gui_gtkplus2.c =================================================================== --- trunk/gui_gtkplus2.c 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/gui_gtkplus2.c 2007-05-17 16:15:24 UTC (rev 280) @@ -183,7 +183,8 @@ static gint do_msgbox(const char *title, const char *text, - GtkMessageType mtype, GtkButtonsType btype) + GtkMessageType mtype, GtkButtonsType btype, + void (*addButtonCallback)(GtkWidget *_msgbox)) { gint retval = 0; if (msgbox != NULL) @@ -192,6 +193,10 @@ mtype, btype, "%s", title); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgbox), "%s", text); + + if (addButtonCallback != NULL) + addButtonCallback(msgbox); + retval = gtk_dialog_run(GTK_DIALOG(msgbox)); gtk_widget_destroy(msgbox); msgbox = NULL; @@ -201,17 +206,52 @@ static void MojoGui_gtkplus2_msgbox(const char *title, const char *text) { - do_msgbox(title, text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK); + do_msgbox(title, text, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, NULL); } // MojoGui_gtkplus2_msgbox static boolean MojoGui_gtkplus2_promptyn(const char *title, const char *text) { - gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO); + gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, NULL); return (rc == GTK_RESPONSE_YES); } // MojoGui_gtkplus2_promptyn +static void promptynanButtonCallback(GtkWidget *_msgbox) +{ + char *always = entry->xstrdup(entry->_("Always")); + char *never = entry->xstrdup(entry->_("Never")); + gtk_dialog_add_buttons(GTK_DIALOG(_msgbox), + GTK_STOCK_YES, GTK_RESPONSE_YES, + GTK_STOCK_NO, GTK_RESPONSE_NO, + always, 1, + never, 0, + NULL, GTK_RESPONSE_NONE); + + free(always); + free(never); +} // promptynanButtonCallback + + +static MojoGuiYNAN MojoGui_gtkplus2_promptynan(const char *title, + const char *text) +{ + MojoGuiYNAN retval; + const gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, promptynanButtonCallback); + switch (rc) + { + case GTK_RESPONSE_YES: return MOJOGUI_YES; + case GTK_RESPONSE_NO: return MOJOGUI_NO; + case GTK_RESPONSE_ALWAYS: return MOJOGUI_ALWAYS; + case GTK_RESPONSE_NEVER: return MOJOGUI_NEVER; + } // switch + + return MOJOGUI_NO; // just in case. +} // MojoGui_gtkplus2_promptynan + + static GtkWidget *create_button(GtkWidget *box, const char *iconname, const char *text) { @@ -575,6 +615,7 @@ static boolean MojoGui_gtkplus2_insertmedia(const char *medianame) { + gint rc = 0; // !!! FIXME: Use stock GTK icon for "media"? // !!! FIXME: better text. const char *title = entry->_("Media change"); @@ -583,7 +624,8 @@ size_t len = strlen(fmt) + strlen(medianame) + 1; char *text = (char *) entry->xmalloc(len); snprintf(text, len, fmt, medianame); - gint rc = do_msgbox(title, text, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL); + rc = do_msgbox(title, text, GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK_CANCEL, NULL); return (rc == GTK_RESPONSE_OK); } // MojoGui_gtkplus2_insertmedia Modified: trunk/gui_macosx.c =================================================================== --- trunk/gui_macosx.c 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/gui_macosx.c 2007-05-17 16:15:24 UTC (rev 280) @@ -131,6 +131,14 @@ } // MojoGui_macosx_promptyn +static MojoGuiYNAN MojoGui_macosx_promptynan(const char *title, + const char *text) +{ + STUBBED("ynan"); + return MojoGui_macosx_promptyn(title, text); // !!! FIXME +} // MojoGui_macosx_promptynan + + static boolean MojoGui_macosx_start(const char *title, const char *splash) { return true; // !!! FIXME Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/gui_stdio.c 2007-05-17 16:15:24 UTC (rev 280) @@ -130,6 +130,51 @@ } // MojoGui_stdio_promptyn +static MojoGuiYNAN MojoGui_stdio_promptynan(const char *title, const char *txt) +{ + MojoGuiYNAN retval = MOJOGUI_NO; + if (!feof(stdin)) + { + const char *localized_no = entry->xstrdup(entry->_("N")); + const char *localized_yes = entry->xstrdup(entry->_("Y")); + const char *localized_always = entry->xstrdup(entry->_("Always")); + const char *localized_never = entry->xstrdup(entry->_("Never")); + boolean getout = false; + char buf[128]; + while (!getout) + { + printf(entry->_("%s\n[y/n/Always/Never]: "), txt); + fflush(stdout); + if (read_stdin(buf, sizeof (buf)) < 0) + getout = true; + else if (strcasecmp(buf, localized_no) == 0) + getout = true; + else if (strcasecmp(buf, localized_yes) == 0) + { + retval = MOJOGUI_YES; + getout = true; + } // else if + else if (strcasecmp(buf, localized_always) == 0) + { + retval = MOJOGUI_ALWAYS; + getout = true; + } // else if + else if (strcasecmp(buf, localized_never) == 0) + { + retval = MOJOGUI_NEVER; + getout = true; + } // else if + } // while + free((void *) localized_no); + free((void *) localized_yes); + free((void *) localized_always); + free((void *) localized_never); + } // if + + return retval; +} // MojoGui_stdio_promptynan + + static boolean MojoGui_stdio_start(const char *title, const char *splash) { printf("%s\n", title); Modified: trunk/lua_glue.c =================================================================== --- trunk/lua_glue.c 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/lua_glue.c 2007-05-17 16:15:24 UTC (rev 280) @@ -520,6 +520,30 @@ } // luahook_promptyn +static int luahook_promptynan(lua_State *L) +{ + MojoGuiYNAN rc = MOJOGUI_NO; + if (GGui != NULL) + { + const char *title = luaL_checkstring(L, 1); + const char *text = luaL_checkstring(L, 2); + rc = GGui->promptynan(title, text); + } // if + + // Never localize these strings! + switch (rc) + { + case MOJOGUI_YES: return retvalString(L, "yes"); + case MOJOGUI_NO: return retvalString(L, "no"); + case MOJOGUI_ALWAYS: return retvalString(L, "always"); + case MOJOGUI_NEVER: return retvalString(L, "never"); + } // switch + + assert(false && "BUG: unhandled case in switch statement"); + return 0; // shouldn't hit this. +} // luahook_promptynan + + static int luahook_logwarning(lua_State *L) { logWarning(luaL_checkstring(L, 1)); @@ -1289,6 +1313,7 @@ set_cfunc(luaState, luahook_fatal, "fatal"); set_cfunc(luaState, luahook_msgbox, "msgbox"); set_cfunc(luaState, luahook_promptyn, "promptyn"); + set_cfunc(luaState, luahook_promptynan, "promptynan"); set_cfunc(luaState, luahook_stackwalk, "stackwalk"); set_cfunc(luaState, luahook_logwarning, "logwarning"); set_cfunc(luaState, luahook_logerror, "logerror"); Modified: trunk/scripts/localization.lua =================================================================== --- trunk/scripts/localization.lua 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/scripts/localization.lua 2007-05-17 16:15:24 UTC (rev 280) @@ -49,6 +49,10 @@ ["%s\n[y/n]"] = { }; + -- stdio GUI plugin says this for yes/no/always/never prompts (printf format string). + ["%s\n[y/n/Always/Never]: "] = { + }; + -- This is utf8casecmp()'d for "yes" answers in stdio GUI's promptyn(). ["Y"] = { }; @@ -57,6 +61,14 @@ ["N"] = { }; + -- This is utf8casecmp()'d for "always" answers in stdio GUI's promptyn(). + ["Always"] = { + }; + + -- This is utf8casecmp()'d for "never" answers in stdio GUI's promptyn(). + ["Never"] = { + }; + ["Yes"] = { }; Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-17 16:13:45 UTC (rev 279) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-17 16:15:24 UTC (rev 280) @@ -305,13 +305,31 @@ if entinfo.type == "dir" then allowoverwrite = false else - allowoverwrite = file.allowoverwrite - if not allowoverwrite then - -- !!! FIXME: language and formatting. - MojoSetup.loginfo("File '" .. dest .. "' already exists.") - allowoverwrite = MojoSetup.promptyn(_("Conflict!"), _("File already exists! Replace?")) + if MojoSetup.forceoverwrite ~= nil then + allowoverwrite = MojoSetup.forceoverwrite + else + -- !!! FIXME: option/package-wide overwrite? + allowoverwrite = file.allowoverwrite + if not allowoverwrite then + -- !!! FIXME: language and formatting. + MojoSetup.loginfo("File '" .. dest .. "' already exists.") + local ynan = MojoSetup.promptynan(_("Conflict!"), _("File already exists! Replace?")) + if ynan == "always" then + MojoSetup.forceoverwrite = true + allowoverwrite = true + elseif ynan == "never" then + MojoSetup.forceoverwrite = false + allowoverwrite = false + elseif ynan == "yes" then + allowoverwrite = true + elseif ynan == "no" then + allowoverwrite = false + end + end end + -- !!! FIXME: Setup.File.mustoverwrite to override "never"? + if allowoverwrite then local id = #MojoSetup.rollbacks + 1 local f = MojoSetup.rollbackdir .. "/" .. id @@ -509,6 +527,7 @@ local function do_install(install) + MojoSetup.forceoverwrite = nil MojoSetup.written = 0 MojoSetup.totalwrite = 0 MojoSetup.downloaded = 0 @@ -910,6 +929,7 @@ MojoSetup.scratchdir = nil MojoSetup.rollbackdir = nil MojoSetup.downloaddir = nil + MojoSetup.forceoverwrite = nil MojoSetup.stages = nil MojoSetup.files = nil MojoSetup.media = nil From DONOTREPLY at icculus.org Thu May 17 13:07:28 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 17 May 2007 13:07:28 -0400 Subject: r281 - trunk Message-ID: <20070517170728.11433.qmail@icculus.org> Author: icculus Date: 2007-05-17 13:07:27 -0400 (Thu, 17 May 2007) New Revision: 281 Modified: trunk/gui_gtkplus2.c Log: Patched GTK+ UI to compile. Modified: trunk/gui_gtkplus2.c =================================================================== --- trunk/gui_gtkplus2.c 2007-05-17 16:15:24 UTC (rev 280) +++ trunk/gui_gtkplus2.c 2007-05-17 17:07:27 UTC (rev 281) @@ -227,8 +227,8 @@ GTK_STOCK_NO, GTK_RESPONSE_NO, always, 1, never, 0, - NULL, GTK_RESPONSE_NONE); - + NULL); + free(always); free(never); } // promptynanButtonCallback @@ -237,17 +237,17 @@ static MojoGuiYNAN MojoGui_gtkplus2_promptynan(const char *title, const char *text) { - MojoGuiYNAN retval; const gint rc = do_msgbox(title, text, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, promptynanButtonCallback); switch (rc) { case GTK_RESPONSE_YES: return MOJOGUI_YES; case GTK_RESPONSE_NO: return MOJOGUI_NO; - case GTK_RESPONSE_ALWAYS: return MOJOGUI_ALWAYS; - case GTK_RESPONSE_NEVER: return MOJOGUI_NEVER; + case 1: return MOJOGUI_ALWAYS; + case 0: return MOJOGUI_NEVER; } // switch + assert(false && "BUG: unhandled case in switch statement"); return MOJOGUI_NO; // just in case. } // MojoGui_gtkplus2_promptynan From DONOTREPLY at icculus.org Fri May 18 11:27:50 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 11:27:50 -0400 Subject: r282 - trunk Message-ID: <20070518152750.29875.qmail@icculus.org> Author: icculus Date: 2007-05-18 11:27:50 -0400 (Fri, 18 May 2007) New Revision: 282 Modified: trunk/fileio.c Log: Removed an already-fixed FIXME comment. Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-17 17:07:27 UTC (rev 281) +++ trunk/fileio.c 2007-05-18 15:27:50 UTC (rev 282) @@ -102,7 +102,6 @@ MojoPlatform_sleep(100); if (cb != NULL) { - // !!! FIXME: need a way to say "we're just spinning without a goal." if (!cb(MojoPlatform_ticks() - start, 0, 0, -1, data)) iofailure = true; } // if From DONOTREPLY at icculus.org Fri May 18 12:31:04 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 12:31:04 -0400 Subject: r283 - trunk/libfetch Message-ID: <20070518163104.705.qmail@icculus.org> Author: icculus Date: 2007-05-18 12:31:04 -0400 (Fri, 18 May 2007) New Revision: 283 Modified: trunk/libfetch/common.c Log: Whoops, race condition in my thread code. Modified: trunk/libfetch/common.c =================================================================== --- trunk/libfetch/common.c 2007-05-18 15:27:50 UTC (rev 282) +++ trunk/libfetch/common.c 2007-05-18 16:31:04 UTC (rev 283) @@ -990,6 +990,13 @@ uint32 avail = 0; while (!io->ready(io)) MojoPlatform_sleep(100); + + if (pthread_mutex_lock(&info->mutex) != 0) + { + info->stop = info->error = true; // oh well. + return -1; + } // if + avail = MojoRing_availableForGet(info->ring); if (avail > 0) { @@ -997,9 +1004,13 @@ avail = bufsize; MojoRing_get(info->ring, (uint8 *) buf, avail); info->bytes_read += avail; - return avail; } // if + pthread_mutex_unlock(&info->mutex); + + if (avail > 0) + return avail; + if (info->error) return -1; From DONOTREPLY at icculus.org Fri May 18 12:35:55 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 12:35:55 -0400 Subject: r284 - in trunk: . scripts Message-ID: <20070518163555.3975.qmail@icculus.org> Author: icculus Date: 2007-05-18 12:35:55 -0400 (Fri, 18 May 2007) New Revision: 284 Modified: trunk/docs.txt trunk/fileio.c trunk/lua_glue.c trunk/platform.h trunk/platform_unix.c trunk/scripts/mojosetup_init.lua trunk/scripts/mojosetup_mainline.lua Log: Permissions support...let mkdir set permissions, and let config file specify file/dir permissions. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/docs.txt 2007-05-18 16:35:55 UTC (rev 284) @@ -157,6 +157,7 @@ mustBeFunction: Error if isn't a function (can be C or Lua). mustBeNumber: Error if isn't a number. mustBeUrl: Error if isn't a string that matches the regexp "^.+://.-/.*". + mustBePerms: Error if isn't a valid permissions string for the platform. mustBeStringOrTableOfStrings: Error if isn't a string or an array of strings. Attributes that aren't explicitly specified take on their default value. In @@ -576,7 +577,21 @@ return dest -- everything else can go through as-is. end + Filters can optionally return a second argument, a string, that defines + the destination file's permissions. This can be omitted, or nil, to use + the default permissions: + filter = function(dest) + if dest == "mygame-binary" then + return dest, "0755" -- make sure it's executable. + end + return dest -- everything else just goes through as-is. + end + + Please see the documentation for Setup.File's "permissions" attribute for + further discussion. + + allowoverwrite (no default, mustBeBool) If true, the installer will overwrite existing files without warning. If @@ -587,6 +602,34 @@ They are deleted only after a successful install. + permissions (no default, mustBePerms) + + Override the permissions that these files will be created with. This is + a string for future expansion (non-Unix systems, extended attributes, etc), + and since Lua does not have syntax for specifying octal numbers directly. + + Currently this string maps to Unix permissions as an octal number: + "0644" would be read/write access for the user, and read-only for the + group and everyone else. + + If not specified, the permissions will be set to whatever is already + associated with the file (such as the Unix permissions in a .tar file's + entry). + + Please note that files coming from a real filesystem will have their + defaults overridden by the installer (to "0644"), since operating systems + tend to report every file on a CD-ROMs as read-only and executable on some + Unix systems. Plan accordingly. + + You can return a permissions string as the second value from your filter + function as well, which may be more efficient if you only need to change + a few files, as each Setup.File has to iterate the whole archive, or need + to adjust permissions in only a portion of a downloaded archive. This + attribute applies permissions to ever installed file through this element. + If this attribute is set and the filter returns a non-nil permission, the + filter takes precedence. + + Add any localized strings: If you added strings to the installer or your config file that you want Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/fileio.c 2007-05-18 16:35:55 UTC (rev 284) @@ -387,11 +387,11 @@ { ar->prevEnum.filesize = statbuf.st_size; - // !!! FIXME: not sure this is the best thing. // We currently force the perms from physical files, since CDs on // Linux tend to mark every files as executable and read-only. If you // want to install something with specific permissions, wrap it in a - // tarball or chmod it from a postinstall hook in your config file. + // tarball, or use Setup.File.permissions, or return a permissions + // string from Setup.File.filter. //ar->prevEnum.perms = statbuf.st_mode; ar->prevEnum.perms = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); Modified: trunk/lua_glue.c =================================================================== --- trunk/lua_glue.c 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/lua_glue.c 2007-05-18 16:35:55 UTC (rev 284) @@ -673,18 +673,37 @@ { MojoArchive *archive = (MojoArchive *) lua_touserdata(L, 1); const char *path = luaL_checkstring(L, 2); + uint16 perms = archive->prevEnum.perms; boolean retval = false; MojoInput *in = archive->openCurrentEntry(archive); if (in != NULL) { - retval = MojoInput_toPhysicalFile(in, path, archive->prevEnum.perms, - writeCallback, L); + if (!lua_isnil(L, 3)) + { + boolean valid = false; + const char *permstr = luaL_checkstring(L, 3); + perms = MojoPlatform_makePermissions(permstr, &valid); + if (!valid) + fatal(_("BUG: '%s' is not a valid permission string"), permstr); + } // if + retval = MojoInput_toPhysicalFile(in, path, perms, writeCallback, L); } // if return retvalBoolean(L, retval); } // luahook_writefile +static int luahook_isvalidperms(lua_State *L) +{ + boolean valid = false; + const char *permstr = NULL; + if (!lua_isnil(L, 1)) + permstr = luaL_checkstring(L, 1); + MojoPlatform_makePermissions(permstr, &valid); + return retvalBoolean(L, valid); +} // luahook_isvalidperms + + static int luahook_download(lua_State *L) { boolean retval = false; @@ -811,7 +830,18 @@ static int luahook_platform_mkdir(lua_State *L) { const char *dir = luaL_checkstring(L, 1); - return retvalBoolean(L, MojoPlatform_mkdir(dir)); + uint16 perms = 0; + if (lua_isnil(L, 2)) + perms = MojoPlatform_defaultDirPerms(); + else + { + boolean valid = false; + const char *permstr = luaL_checkstring(L, 2); + perms = MojoPlatform_makePermissions(permstr, &valid); + if (!valid) + fatal(_("BUG: '%s' is not a valid permission string"), permstr); + } // if + return retvalBoolean(L, MojoPlatform_mkdir(dir, perms)); } // luahook_platform_mkdir @@ -1330,6 +1360,7 @@ set_cfunc(luaState, luahook_wildcardmatch, "wildcardmatch"); set_cfunc(luaState, luahook_truncatenum, "truncatenum"); set_cfunc(luaState, luahook_date, "date"); + set_cfunc(luaState, luahook_isvalidperms, "isvalidperms"); // Set some information strings... lua_newtable(luaState); Modified: trunk/platform.h =================================================================== --- trunk/platform.h 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/platform.h 2007-05-18 16:35:55 UTC (rev 284) @@ -47,7 +47,7 @@ boolean MojoPlatform_symlink(const char *src, const char *dst); // !!! FIXME: comment me. -boolean MojoPlatform_mkdir(const char *path); +boolean MojoPlatform_mkdir(const char *path, uint16 perms); // Move a file to a new name. This has to be a fast (if not atomic) operation, // so if it would require a legitimate copy to another filesystem or device, @@ -73,6 +73,20 @@ // !!! FIXME: comment me. char *MojoPlatform_findMedia(const char *uniquefile); +// Convert a string into a permissions bitmask. On Unix, this is currently +// expected to be an octal string like "0755", but may except other forms +// in the future, and other platforms may need to interpret permissions +// differently. (str) may be NULL for defaults, and is considered valid. +// If (str) is not valid, return a reasonable default and set (*valid) to +// false. Otherwise, set (*valid) to true and return the converted value. +uint16 MojoPlatform_makePermissions(const char *str, boolean *valid); + +// Return a default, sane set of permissions for a newly-created file. +uint16 MojoPlatform_defaultFilePerms(void); + +// Return a default, sane set of permissions for a newly-created directory. +uint16 MojoPlatform_defaultDirPerms(void); + // Wrappers for Unix dlopen/dlsym/dlclose, sort of. Instead of a filename, // these take a memory buffer for the library. If you can't load this // directly in RAM, the platform should write it to a temporary file first, Modified: trunk/platform_unix.c =================================================================== --- trunk/platform_unix.c 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/platform_unix.c 2007-05-18 16:35:55 UTC (rev 284) @@ -482,10 +482,10 @@ } // MojoPlatform_symlink -boolean MojoPlatform_mkdir(const char *path) +boolean MojoPlatform_mkdir(const char *path, uint16 perms) { // !!! FIXME: error if already exists? - return (mkdir(path, 0755) == 0); + return (mkdir(path, perms) == 0); } // MojoPlatform_mkdir @@ -544,6 +544,37 @@ } // MojoPlatform_perms +uint16 MojoPlatform_defaultFilePerms(void) +{ + return 0644; +} // MojoPlatform_defaultFilePerms + + +uint16 MojoPlatform_defaultDirPerms(void) +{ + return 0755; +} // MojoPlatform_defaultDirPerms + + +uint16 MojoPlatform_makePermissions(const char *str, boolean *_valid) +{ + uint16 retval = 0644; + boolean valid = true; + if (str != NULL) + { + char *endptr = NULL; + long strval = strtol(str, &endptr, 8); + // complete string was a valid number? + valid = ((*endptr == '\0') && (strval >= 0) && (strval <= 0xFFFF)); + if (valid) + retval = (uint16) strval; + } // if + + *_valid = valid; + return retval; +} // MojoPlatform_makePermissions + + boolean MojoPlatform_chmod(const char *fname, uint16 p) { return (chmod(fname, p) != -1); Modified: trunk/scripts/mojosetup_init.lua =================================================================== --- trunk/scripts/mojosetup_init.lua 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/scripts/mojosetup_init.lua 2007-05-18 16:35:55 UTC (rev 284) @@ -128,6 +128,7 @@ local function schema_assert(test, fnname, elem, errstr) if not test then + -- !!! FIXME: error()? localization? error(fnname .. "::" .. elem .. " " .. errstr .. ".", 0) end end @@ -209,6 +210,12 @@ end end +local function mustBePerms(fnname, elem, val) + mustBeString(fnname, elem, val) + local valid = MojoSetup.isvalidperms(val) + schema_assert(valid, fnname, elem, "Permission string is invalid") +end + local function sanitize(fnname, tab, elems) mustBeTable(fnname, "", tab) tab._type_ = string.lower(fnname) .. "s"; -- "Eula" becomes "eulas". @@ -412,6 +419,7 @@ { "wildcards", nil, mustBeStringOrTableOfStrings }, { "filter", nil, mustBeFunction }, { "allowoverwrite", nil, mustBeBool }, + { "permissions", nil, mustBePerms }, }) end Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-18 16:31:04 UTC (rev 283) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-18 16:35:55 UTC (rev 284) @@ -226,7 +226,7 @@ end -local function install_file(path, archive, file, option) +local function install_file(path, archive, file, option, perms) -- Upvalued so we don't look these up each time... local fname = string.gsub(path, "^.*/", "", 1) -- chop the dirs off... local ptype = _("Installing") -- !!! FIXME: localization. @@ -245,7 +245,7 @@ end MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - if not MojoSetup.writefile(archive, path, callback) then + if not MojoSetup.writefile(archive, path, perms, callback) then -- !!! FIXME: formatting! if not keepgoing then MojoSetup.logerror("User cancelled install during file write.") @@ -270,9 +270,9 @@ end -local function install_directory(path) +local function install_directory(path, perms) MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - if not MojoSetup.platform.mkdir(path) then + if not MojoSetup.platform.mkdir(path, perms) then -- !!! FIXME: formatting MojoSetup.logerror("Failed to create dir '" .. path .. "'") MojoSetup.fatal(_("mkdir failed")) @@ -291,7 +291,7 @@ if item ~= "" then fullpath = fullpath .. "/" .. item if not MojoSetup.platform.exists(fullpath) then - install_directory(fullpath) + install_directory(fullpath, nil) end end end @@ -361,8 +361,14 @@ dest = dest .. "/" .. entdest end + local perms = file.permissions -- may be nil + if file.filter ~= nil then - dest = file.filter(dest) + local filterperms + dest, filterperms = file.filter(dest) + if filterperms ~= nil then + perms = filterperms + end end if dest ~= nil then -- Only install if file wasn't filtered out @@ -370,9 +376,9 @@ if permit_write(dest, ent, file) then install_parent_dirs(dest) if ent.type == "file" then - install_file(dest, archive, file, option) + install_file(dest, archive, file, option, perms) elseif ent.type == "dir" then - install_directory(dest) + install_directory(dest, perms) elseif ent.type == "symlink" then install_symlink(dest, ent.linkdest) else -- !!! FIXME: device nodes, etc... From DONOTREPLY at icculus.org Fri May 18 12:53:47 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 12:53:47 -0400 Subject: r285 - trunk Message-ID: <20070518165347.15181.qmail@icculus.org> Author: icculus Date: 2007-05-18 12:53:47 -0400 (Fri, 18 May 2007) New Revision: 285 Modified: trunk/docs.txt Log: Cleaned up my grammar in the new docs on file permissions. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-18 16:35:55 UTC (rev 284) +++ trunk/docs.txt 2007-05-18 16:53:47 UTC (rev 285) @@ -604,30 +604,32 @@ permissions (no default, mustBePerms) - Override the permissions that these files will be created with. This is - a string for future expansion (non-Unix systems, extended attributes, etc), - and since Lua does not have syntax for specifying octal numbers directly. + Override the permissions with which the files will be created. This is + a string, not a number...this allows both for future expansion (non-Unix + systems, extended attributes, etc), and works around the fact that Lua + does not have syntax for specifying octal numbers directly. Currently this string maps to Unix permissions as an octal number: "0644" would be read/write access for the user, and read-only for the group and everyone else. - If not specified, the permissions will be set to whatever is already - associated with the file (such as the Unix permissions in a .tar file's - entry). + If set to nil or not specified, the new file's permissions will be + whatever is already associated with the file (such as the Unix permissions + in a .tar file's entry). Please note that files coming from a real filesystem will have their - defaults overridden by the installer (to "0644"), since operating systems - tend to report every file on a CD-ROMs as read-only and executable on some - Unix systems. Plan accordingly. + defaults overridden by MojoSetup (to "0644"), since many operating systems + tend to report every file on a CD-ROM as read-only and executable, which + is frequently not what you want in the installed copy. Plan accordingly. You can return a permissions string as the second value from your filter function as well, which may be more efficient if you only need to change - a few files, as each Setup.File has to iterate the whole archive, or need - to adjust permissions in only a portion of a downloaded archive. This - attribute applies permissions to ever installed file through this element. - If this attribute is set and the filter returns a non-nil permission, the - filter takes precedence. + a few files, (each Setup.File has to iterate the whole archive, so you + want to avoid specifying multiple Setup.Files for one archive when + possible), or need to adjust permissions in only a portion of a downloaded + archive. This attribute applies permissions to every file installed + through this element. If this attribute is set and the filter returns a + non-nil permission, the filter takes precedence. Add any localized strings: From DONOTREPLY at icculus.org Fri May 18 14:26:14 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 14:26:14 -0400 Subject: r286 - trunk Message-ID: <20070518182614.2527.qmail@icculus.org> Author: icculus Date: 2007-05-18 14:26:14 -0400 (Fri, 18 May 2007) New Revision: 286 Modified: trunk/CMakeLists.txt Log: Renamed the shared libraries so they definitely won't conflict with anything. Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-18 16:53:47 UTC (rev 285) +++ trunk/CMakeLists.txt 2007-05-18 18:26:14 UTC (rev 286) @@ -267,7 +267,7 @@ ADD_DEFINITIONS(-DGUI_STATIC_LINK_STDIO=1) SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_stdio.c) ELSE(MOJOSETUP_GUI_STDIO_STATIC) - ADD_LIBRARY(stdio SHARED gui_stdio.c) + ADD_LIBRARY(mojosetupgui_stdio SHARED gui_stdio.c) ENDIF(MOJOSETUP_GUI_STDIO_STATIC) ENDIF(MOJOSETUP_GUI_STDIO) @@ -280,8 +280,8 @@ ADD_DEFINITIONS(-DGUI_STATIC_LINK_MACOSX=1) SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_macosx.c) ELSE(MOJOSETUP_GUI_MACOSX_STATIC) - ADD_LIBRARY(macosx SHARED gui_macosx.c) - TARGET_LINK_LIBRARIES(macosx + ADD_LIBRARY(mojosetupgui_macosx SHARED gui_macosx.c) + TARGET_LINK_LIBRARIES(mojosetupgui_macosx "-framework Carbon -mmacosx-version-min=10.2" ) ENDIF(MOJOSETUP_GUI_MACOSX_STATIC) @@ -309,9 +309,9 @@ SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_gtkplus2.c) SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} ${LIBGTK_LINK_FLAGS}) ELSE(MOJOSETUP_GUI_GTKPLUS2_STATIC) - ADD_LIBRARY(gtkplus2 SHARED gui_gtkplus2.c) + ADD_LIBRARY(mojosetupgui_gtkplus2 SHARED gui_gtkplus2.c) ADD_DEFINITIONS(${LIBGTK_CFLAGS}) - TARGET_LINK_LIBRARIES(gtkplus2 ${LIBGTK_LINK_FLAGS}) + TARGET_LINK_LIBRARIES(mojosetupgui_gtkplus2 ${LIBGTK_LINK_FLAGS}) ENDIF(MOJOSETUP_GUI_GTKPLUS2_STATIC) ENDIF(MOJOSETUP_GUI_GTKPLUS2) ENDIF(NOT LIBGTK_LINK_FLAGS) From DONOTREPLY at icculus.org Fri May 18 14:39:53 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 14:39:53 -0400 Subject: r287 - trunk Message-ID: <20070518183953.14422.qmail@icculus.org> Author: icculus Date: 2007-05-18 14:39:53 -0400 (Fri, 18 May 2007) New Revision: 287 Modified: trunk/ Log: Subversion should ignore shared libraries. Property changes on: trunk ___________________________________________________________________ Name: svn:ignore - MojoSetup.xcodeproj MojoSetup.build build Debug Release CMakeScripts CMakeOutput.log CMakeCache.txt CMakeError.log cmake_install.cmake mojosetup mojoluac CMakeTmp CMakeFiles Makefile *.exe + MojoSetup.xcodeproj MojoSetup.build build Debug Release CMakeScripts CMakeOutput.log CMakeCache.txt CMakeError.log cmake_install.cmake mojosetup mojoluac CMakeTmp CMakeFiles Makefile *.exe *.dll *.so *.dylib From DONOTREPLY at icculus.org Fri May 18 15:31:22 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 15:31:22 -0400 Subject: r288 - trunk Message-ID: <20070518193122.19815.qmail@icculus.org> Author: icculus Date: 2007-05-18 15:31:21 -0400 (Fri, 18 May 2007) New Revision: 288 Modified: trunk/gui.h trunk/gui_gtkplus2.c trunk/gui_macosx.c trunk/gui_stdio.c Log: Some general GUI tweaks. Modified: trunk/gui.h =================================================================== --- trunk/gui.h 2007-05-18 18:39:53 UTC (rev 287) +++ trunk/gui.h 2007-05-18 19:31:21 UTC (rev 288) @@ -22,6 +22,7 @@ MOJOGUI_PRIORITY_TRY_FIRST, MOJOGUI_PRIORITY_TRY_NORMAL, MOJOGUI_PRIORITY_TRY_LAST, + MOJOGUI_PRIORITY_TRY_ABSOLUTELY_LAST, MOJOGUI_PRIORITY_TOTAL } MojoGuiPluginPriority; Modified: trunk/gui_gtkplus2.c =================================================================== --- trunk/gui_gtkplus2.c 2007-05-18 18:39:53 UTC (rev 287) +++ trunk/gui_gtkplus2.c 2007-05-18 19:31:21 UTC (rev 288) @@ -171,7 +171,12 @@ int tmpargc = 0; char *args[] = { NULL, NULL }; char **tmpargv = args; - return gtk_init_check(&tmpargc, &tmpargv) ? true : false; + if (!gtk_init_check(&tmpargc, &tmpargv)) + { + entry->logInfo("gtkplus2: gtk_init_check() failed, use another UI."); + return false; + } // if + return true; } // MojoGui_gtkplus2_init Modified: trunk/gui_macosx.c =================================================================== --- trunk/gui_macosx.c 2007-05-18 18:39:53 UTC (rev 287) +++ trunk/gui_macosx.c 2007-05-18 19:31:21 UTC (rev 288) @@ -27,6 +27,7 @@ static uint8 MojoGui_macosx_priority(void) { + // obviously this is the thing you want on Mac OS X. return MOJOGUI_PRIORITY_TRY_FIRST; } // MojoGui_macosx_priority @@ -43,7 +44,11 @@ SetFrontProcess(&psn); } // if - return true; + // !!! FIXME: make sure we have access to the desktop...may be ssh'd in + // !!! FIXME: as another user that doesn't have the Finder loaded or + // !!! FIXME: something. + + return true; // always succeeds. } // MojoGui_macosx_init static void MojoGui_macosx_deinit(void) Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-18 18:39:53 UTC (rev 287) +++ trunk/gui_stdio.c 2007-05-18 19:31:21 UTC (rev 288) @@ -75,7 +75,7 @@ static uint8 MojoGui_stdio_priority(void) { - return MOJOGUI_PRIORITY_TRY_LAST; // always a last resort. + return MOJOGUI_PRIORITY_TRY_ABSOLUTELY_LAST; // always a last resort. } // MojoGui_stdio_priority From DONOTREPLY at icculus.org Fri May 18 15:55:15 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 18 May 2007 15:55:15 -0400 Subject: r289 - trunk Message-ID: <20070518195515.5404.qmail@icculus.org> Author: icculus Date: 2007-05-18 15:55:14 -0400 (Fri, 18 May 2007) New Revision: 289 Modified: trunk/gui.c Log: Log the UI that was selected. Modified: trunk/gui.c =================================================================== --- trunk/gui.c 2007-05-18 19:31:21 UTC (rev 288) +++ trunk/gui.c 2007-05-18 19:55:14 UTC (rev 289) @@ -66,7 +66,10 @@ for (i = plugins->next; i != NULL; i = i->next) { if ( (i->priority == p) && (i->gui->init()) ) + { + logInfo("Selected '%s' UI.", i->gui->name()); return i; + } // if } // for } // for From DONOTREPLY at icculus.org Sat May 19 01:23:39 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 19 May 2007 01:23:39 -0400 Subject: r290 - trunk Message-ID: <20070519052339.6229.qmail@icculus.org> Author: icculus Date: 2007-05-19 01:23:39 -0400 (Sat, 19 May 2007) New Revision: 290 Modified: trunk/CMakeLists.txt trunk/gui.c trunk/gui.h trunk/mojosetup.c Log: Try to deinit GUI during a panic(). Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-18 19:55:14 UTC (rev 289) +++ trunk/CMakeLists.txt 2007-05-19 05:23:39 UTC (rev 290) @@ -271,6 +271,27 @@ ENDIF(MOJOSETUP_GUI_STDIO_STATIC) ENDIF(MOJOSETUP_GUI_STDIO) +# BINARY SIZE += !!! FIXME: check this. +IF(UNIX) # !!! FIXME: use FindCurses instead... +IF(NOT BEOS) +IF(NOT MACOSX) +OPTION(MOJOSETUP_GUI_NCURSES "Enable ncurses GUI" TRUE) +IF(MOJOSETUP_GUI_NCURSES) + ADD_DEFINITIONS(-DSUPPORT_GUI_NCURSES=1) + OPTION(MOJOSETUP_GUI_NCURSES_STATIC "Statically link ncurses GUI" TRUE) + IF(MOJOSETUP_GUI_NCURSES_STATIC) + ADD_DEFINITIONS(-DGUI_STATIC_LINK_NCURSES=1) + SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_ncurses.c) + SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} -lncurses) # !!! FIXME + ELSE(MOJOSETUP_GUI_NCURSES_STATIC) + ADD_LIBRARY(mojosetupgui_ncurses SHARED gui_ncurses.c) + TARGET_LINK_LIBRARIES(mojosetupgui_ncurses "-lncurses") # !!! FIXME + ENDIF(MOJOSETUP_GUI_NCURSES_STATIC) +ENDIF(MOJOSETUP_GUI_NCURSES) +ENDIF(NOT MACOSX) +ENDIF(NOT BEOS) +ENDIF(UNIX) + IF(MACOSX) OPTION(MOJOSETUP_GUI_MACOSX "Enable Mac OS X GUI" TRUE) IF(MOJOSETUP_GUI_MACOSX) Modified: trunk/gui.c =================================================================== --- trunk/gui.c 2007-05-18 19:55:14 UTC (rev 289) +++ trunk/gui.c 2007-05-19 05:23:39 UTC (rev 290) @@ -32,6 +32,9 @@ #if GUI_STATIC_LINK_GTKPLUS2 MojoGuiPlugin_gtkplus2, #endif +#if GUI_STATIC_LINK_NCURSES + MojoGuiPlugin_ncurses, +#endif NULL }; Modified: trunk/gui.h =================================================================== --- trunk/gui.h 2007-05-18 19:55:14 UTC (rev 289) +++ trunk/gui.h 2007-05-19 05:23:39 UTC (rev 290) @@ -166,8 +166,8 @@ * some aren't... */ -// Probably want to support this always, unless explicitly overridden. const MojoGui *MojoGuiPlugin_stdio(int rev, const MojoSetupEntryPoints *e); +const MojoGui *MojoGuiPlugin_ncurses(int rev, const MojoSetupEntryPoints *e); const MojoGui *MojoGuiPlugin_gtkplus2(int rev, const MojoSetupEntryPoints *e); const MojoGui *MojoGuiPlugin_macosx(int rev, const MojoSetupEntryPoints *e); Modified: trunk/mojosetup.c =================================================================== --- trunk/mojosetup.c 2007-05-18 19:55:14 UTC (rev 289) +++ trunk/mojosetup.c 2007-05-19 05:23:39 UTC (rev 290) @@ -380,9 +380,14 @@ else if (panic_runs == 2) { - if ((GGui != NULL) && (GGui->msgbox != NULL)) + boolean domsgbox = ((GGui != NULL) && (GGui->msgbox != NULL)); + if (domsgbox) GGui->msgbox(_("PANIC"), err); - else + + if (GGui->deinit != NULL) + GGui->deinit(); + + if (!domsgbox) panic(err); /* no GUI plugin...double-panic. */ } // if From DONOTREPLY at icculus.org Sat May 19 05:52:15 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 19 May 2007 05:52:15 -0400 Subject: r291 - in trunk: . scripts Message-ID: <20070519095215.741.qmail@icculus.org> Author: icculus Date: 2007-05-19 05:52:15 -0400 (Sat, 19 May 2007) New Revision: 291 Added: trunk/gui_ncurses.c Modified: trunk/CMakeLists.txt trunk/gui_stdio.c trunk/scripts/localization.lua Log: Initial work on ncurses UI...incomplete! Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-19 05:23:39 UTC (rev 290) +++ trunk/CMakeLists.txt 2007-05-19 09:52:15 UTC (rev 291) @@ -275,7 +275,7 @@ IF(UNIX) # !!! FIXME: use FindCurses instead... IF(NOT BEOS) IF(NOT MACOSX) -OPTION(MOJOSETUP_GUI_NCURSES "Enable ncurses GUI" TRUE) +OPTION(MOJOSETUP_GUI_NCURSES "Enable ncurses GUI" FALSE) IF(MOJOSETUP_GUI_NCURSES) ADD_DEFINITIONS(-DSUPPORT_GUI_NCURSES=1) OPTION(MOJOSETUP_GUI_NCURSES_STATIC "Statically link ncurses GUI" TRUE) Added: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c (rev 0) +++ trunk/gui_ncurses.c 2007-05-19 09:52:15 UTC (rev 291) @@ -0,0 +1,606 @@ +/** + * MojoSetup; a portable, flexible installation application. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#if !SUPPORT_GUI_NCURSES +#error Something is wrong in the build system. +#endif + +#define BUILDING_EXTERNAL_PLUGIN 1 +#include "gui.h" + +MOJOGUI_PLUGIN(ncurses) + +#if !GUI_STATIC_LINK_NCURSES +CREATE_MOJOGUI_ENTRY_POINT(ncurses) +#endif + +#include +#include +#include + +// This was built to look roughly like dialog(1), but it's not nearly as +// robust. Also, I didn't use any of dialog's code, as it is GPL/LGPL, +// depending on what version you start with. There _is_ a libdialog, but +// it's never something installed on any systems, and I can't link it +// statically due to the license. +// +// ncurses is almost always installed as a shared library, though, so we'll +// just talk to it directly. Fortunately we don't need much of what dialog(1) +// offers, so rolling our own isn't too painful. +// +// Pradeep Padala's ncurses HOWTO was very helpful in teaching me curses +// quickly: http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/index.html + +typedef enum +{ + MOJOCOLOR_BACKGROUND=1, + MOJOCOLOR_BORDERTOP, + MOJOCOLOR_BORDERBOTTOM, + MOJOCOLOR_BORDERSHADOW, + MOJOCOLOR_TEXT, + MOJOCOLOR_BUTTONHOVER, + MOJOCOLOR_BUTTONNORMAL, +} MojoColor; + + +static int strcells(const char *str) +{ + // !!! FIXME: how to know how many _cells_ UTF-8 strings take in cursesw? + return (int) strlen(str); +} // strcells + + +typedef struct +{ + WINDOW *mainwin; + WINDOW *textwin; + WINDOW **buttons; + char *title; + char *text; + char **textlines; + char **buttontext; + int buttoncount; + int textlinecount; + int hoverover; + int textpos; + boolean hidecursor; + boolean ndelay; + int cursval; +} MojoBox; + + +// !!! FIXME: this is not really Unicode friendly... +static char **splitText(char *text, int *_count, int *_w) +{ + int i; + int scrw, scrh; + char **retval = NULL; + getmaxyx(stdscr, scrh, scrw); + int count = 0; + int w = 0; + + *_count = *_w = 0; + while (*text) + { + int furthest = 0; + for (i = 0; (*text) && (i < (scrw-4)); i++) + { + const int ch = text[i]; + if ((ch == '\r') || (ch == '\n')) + { + text[i] = '\0'; + count++; + retval = (char **) entry->xrealloc(retval, + count * sizeof (char *)); + retval[count-1] = entry->xstrdup(text); + *text = ch; + text += i; + if ((ch == '\r') && (text[1] == '\n')) + text++; + text++; + + if (i > w) + w = i; + i = -1; // will be zero on next iteration... + } // if + else if (isspace(ch)) + { + furthest = i; + } // else if + } // for + + if (*text) // line overflow, need to wrap... + { + int pos = furthest; + char ch; + if (furthest == 0) // uhoh, no split at all...hack it. + { + // !!! FIXME: might be chopping in the middle of a UTF-8 seq. + pos = strlen(text); + if (pos > scrw-4) + pos = scrw-4; + } // if + + ch = text[pos]; + text[pos] = '\0'; + count++; + retval = (char **) entry->xrealloc(retval, count * sizeof (char*)); + retval[count-1] = entry->xstrdup(text); + *text = ch; + text += pos; + if (pos > w) + w = pos; + } // if + } // while + + *_count = count; + *_w = w; + return retval; +} // splitText + + +static void drawButton(MojoBox *mojobox, int button) +{ + const boolean hover = (mojobox->hoverover == button); + WINDOW *win = mojobox->buttons[button]; + const char *str = mojobox->buttontext[button]; + int w, h; + getmaxyx(win, h, w); + + if (hover) + wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + else + wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONNORMAL)); + + wclear(win); + wmove(win, 0, 0); + waddch(win, '<'); + wmove(win, 0, w-1); + waddch(win, '>'); + wmove(win, 0, 2); + waddstr(win, str); +} // drawButton + + +static void drawText(MojoBox *mojobox) +{ + int i; + wclear(mojobox->textwin); + for (i = 0; i+mojobox->textpos < mojobox->textlinecount; i++) + mvwaddstr(mojobox->textwin, i, 0, mojobox->textlines[i]); +} // drawText + + +static MojoBox *makeBox(const char *title, const char *text, + char **buttons, int bcount, + boolean ndelay, boolean hidecursor) +{ + MojoBox *retval = NULL; + WINDOW *win = NULL; + int scrw, scrh; + int len = 0; + int buttonsw = 0; + int h = 0; + int w = 0; + int texth = 0; + int i; + + getmaxyx(stdscr, scrh, scrw); + if (scrw < 16) + return NULL; + + retval = (MojoBox *) entry->xmalloc(sizeof (MojoBox)); + retval->hidecursor = hidecursor; + retval->ndelay = ndelay; + retval->cursval = ((hidecursor) ? curs_set(0) : ERR); + retval->title = entry->xstrdup(title); + retval->text = entry->xstrdup(text); + retval->buttoncount = bcount; + retval->buttons = (WINDOW **) entry->xmalloc(sizeof (WINDOW*) * bcount); + retval->buttontext = (char **) entry->xmalloc(sizeof (char*) * bcount); + + for (i = 0; i < bcount; i++) + retval->buttontext[i] = entry->xstrdup(buttons[i]); + + retval->textlines = splitText(retval->text, &retval->textlinecount, &w); + + len = strcells(title); + if (len > scrw-4) + { + len = scrw-4; + strcpy(&retval->title[len-3], "..."); // !!! FIXME: not Unicode safe! + } // if + + if (len > w) + w = len; + + if (bcount > 0) + { + for (i = 0; i < bcount; i++) + buttonsw += strcells(buttons[i]) + 6; + if (buttonsw > w) + w = buttonsw; + // !!! FIXME: what if these overflow the screen? + } // if + + w += 4; + h = retval->textlinecount + 2; + if (bcount > 0) + h += 2; + + if (h > scrh) + h = scrh; + + win = retval->mainwin = newwin(h, w, (scrh - h) / 2, (scrw - w) / 2); + keypad(win, TRUE); + nodelay(win, ndelay); + wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + wclear(win); + waddch(win, ACS_ULCORNER | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP)); + whline(win, ACS_HLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), w-2); + wmove(win, 0, w-1); + waddch(win, ACS_URCORNER | COLOR_PAIR(MOJOCOLOR_BORDERBOTTOM)); + wmove(win, 1, 0); + wvline(win, ACS_VLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), h-2); + wmove(win, 1, w-1); + wvline(win, ACS_VLINE | COLOR_PAIR(MOJOCOLOR_BORDERBOTTOM), h-2); + wmove(win, h-1, 0); + waddch(win, ACS_LLCORNER | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP)); + whline(win, ACS_HLINE | COLOR_PAIR(MOJOCOLOR_BORDERBOTTOM), w-2); + wmove(win, h-1, w-1); + waddch(win, ACS_LRCORNER | COLOR_PAIR(MOJOCOLOR_BORDERBOTTOM)); + + len = strcells(retval->title); + wmove(win, 0, ((w-len)/2)-1); + waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_TEXT)); + waddstr(win, retval->title); + wmove(win, 0, ((w-len)/2)+len); + waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_TEXT)); + + if (bcount > 0) + { + int pos = (w - buttonsw) / 2; + wmove(win, h-3, 1); + whline(win, ACS_HLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), w-2); + for (i = 0; i < bcount; i++) + { + len = strcells(buttons[i]) + 4; + pos += len-2; + win = retval->buttons[i] = newwin(1, len, (((scrh - h) / 2) + h)-2, + (((scrw - w) / 2) + w)-pos); + + keypad(win, TRUE); + nodelay(win, ndelay); + } // for + } // if + + texth = h-2; + if (bcount > 0) + texth -= 2; + win = retval->textwin = newwin(texth, w-4, ((scrh-h)/2)+1, ((scrw-w)/2)+2); + keypad(win, TRUE); + nodelay(win, ndelay); + wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + drawText(retval); + + wclear(stdscr); + wrefresh(stdscr); + wrefresh(retval->mainwin); + wrefresh(retval->textwin); + for (i = 0; i < bcount; i++) + { + drawButton(retval, i); + wrefresh(retval->buttons[i]); + } // for + + return retval; +} // makeBox + + +static void freeBox(MojoBox *mojobox, boolean clearscreen) +{ + if (mojobox != NULL) + { + int i; + const int bcount = mojobox->buttoncount; + const int tcount = mojobox->textlinecount; + + if (mojobox->cursval != ERR) + curs_set(mojobox->cursval); + + for (i = 0; i < bcount; i++) + { + free(mojobox->buttontext[i]); + delwin(mojobox->buttons[i]); + } // for + + free(mojobox->buttontext); + free(mojobox->buttons); + + delwin(mojobox->textwin); + delwin(mojobox->mainwin); + + free(mojobox->title); + free(mojobox->text); + + for (i = 0; i < tcount; i++) + free(mojobox->textlines[i]); + + free(mojobox->textlines); + free(mojobox); + + if (clearscreen) + { + wclear(stdscr); + wrefresh(stdscr); + } // if + } // if +} // freeBox + + +static int upkeepBox(MojoBox **_mojobox, int ch) +{ + MojoBox *mojobox = *_mojobox; + if (mojobox == NULL) + return -2; + + switch (ch) + { + case ERR: + return -2; + + case '\r': + case '\n': + case KEY_ENTER: + case ' ': + return mojobox->hoverover; + + case '\e': + return mojobox->buttoncount-1; + + case KEY_RESIZE: + mojobox = makeBox(mojobox->title, mojobox->text, + mojobox->buttontext, mojobox->buttoncount, + mojobox->ndelay, mojobox->hidecursor); + freeBox(*_mojobox, false); + *_mojobox = mojobox; + return -1; + } // switch + + return -1; +} // upkeepBox + + +static char *lastComponent = NULL; +static uint32 percentTicks = 0; + +static uint8 MojoGui_ncurses_priority(void) +{ + if (getenv("DISPLAY") != NULL) + return MOJOGUI_PRIORITY_TRY_LAST; // let graphical stuff go first. + return MOJOGUI_PRIORITY_TRY_NORMAL; +} // MojoGui_ncurses_priority + + +static boolean MojoGui_ncurses_init(void) +{ + const char *badtty = NULL; + if (!isatty(0)) + badtty = "stdin"; + else if (!isatty(1)) + badtty = "stdout"; + + if (badtty != NULL) + { + entry->logInfo("ncurses: %s is not a tty, use another UI.", badtty); + return false; // stdin or stdout redirected, or maybe no xterm... + } // if + + if (initscr() == NULL) + { + entry->logInfo("ncurses: initscr() failed, use another UI."); + return false; + } // if + + cbreak(); + keypad(stdscr, TRUE); + noecho(); + //nodelay(stdscr, TRUE); + start_color(); + init_pair(MOJOCOLOR_BACKGROUND, COLOR_BLUE, COLOR_BLUE); + init_pair(MOJOCOLOR_BORDERTOP, COLOR_WHITE, COLOR_WHITE); + init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_BORDERSHADOW, COLOR_BLACK, COLOR_BLACK); + init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_WHITE, COLOR_BLUE); + init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); + wbkgdset(stdscr, COLOR_PAIR(MOJOCOLOR_BACKGROUND)); + wclear(stdscr); + wrefresh(stdscr); + + percentTicks = 0; + return true; // always succeeds. +} // MojoGui_ncurses_init + + +static void MojoGui_ncurses_deinit(void) +{ + endwin(); + delwin(stdscr); // not sure if this is safe, but valgrind said it leaks. + stdscr = NULL; + free(lastComponent); + lastComponent = NULL; +} // MojoGui_ncurses_deinit + + +static void MojoGui_ncurses_msgbox(const char *title, const char *text) +{ + char *localized_ok = entry->xstrdup(entry->_("OK")); + MojoBox *mojobox = makeBox(title, text, &localized_ok, 1, false, true); + while (upkeepBox(&mojobox, wgetch(mojobox->mainwin)) == -1) {} + freeBox(mojobox, true); + free(localized_ok); +} // MojoGui_ncurses_msgbox + + +static boolean MojoGui_ncurses_promptyn(const char *title, const char *text) +{ + char *localized_yes = entry->xstrdup(entry->_("Yes")); + char *localized_no = entry->xstrdup(entry->_("No")); + char *buttons[] = { localized_yes, localized_no }; + MojoBox *mojobox = makeBox(title, text, buttons, 2, false, true); + int rc = 0; + while ((rc = upkeepBox(&mojobox, wgetch(mojobox->mainwin))) == -1) {} + freeBox(mojobox, true); + free(localized_yes); + free(localized_no); + return (rc == 0); +} // MojoGui_ncurses_promptyn + + +static MojoGuiYNAN MojoGui_ncurses_promptynan(const char *title, + const char *text) +{ + char *loc_yes = entry->xstrdup(entry->_("Yes")); + char *loc_no = entry->xstrdup(entry->_("No")); + char *loc_always = entry->xstrdup(entry->_("Always")); + char *loc_never = entry->xstrdup(entry->_("Never")); + char *buttons[] = { loc_yes, loc_always, loc_never, loc_no }; + MojoBox *mojobox = makeBox(title, text, buttons, 4, false, true); + int rc = 0; + while ((rc = upkeepBox(&mojobox, wgetch(mojobox->mainwin))) == -1) {} + freeBox(mojobox, true); + free(loc_yes); + free(loc_no); + free(loc_always); + free(loc_never); + + switch (rc) + { + case 0: return MOJOGUI_YES; + case 1: return MOJOGUI_ALWAYS; + case 2: return MOJOGUI_NEVER; + case 3: return MOJOGUI_NO; + } // switch + + assert(false && "BUG: unhandled case in switch statement!"); + return MOJOGUI_NO; +} // MojoGui_ncurses_promptynan + + +static boolean MojoGui_ncurses_start(const char *title, const char *splash) +{ + wclear(stdscr); + wrefresh(stdscr); + return true; +} // MojoGui_ncurses_start + + +static void MojoGui_ncurses_stop(void) +{ + wclear(stdscr); + wrefresh(stdscr); +} // MojoGui_ncurses_stop + + +static int MojoGui_ncurses_readme(const char *name, const uint8 *data, + size_t datalen, boolean can_back, + boolean can_fwd) +{ + MojoBox *mojobox = NULL; + char *buttons[3] = { NULL, NULL, NULL }; + int bcount = 0; + int backbutton = -99; + int fwdbutton = -99; + int rc = 0; + int i = 0; + + if (can_fwd) + { + fwdbutton = bcount++; + buttons[fwdbutton] = entry->xstrdup(entry->_("Next")); + } // if + + if (can_back) + { + backbutton = bcount++; + buttons[backbutton] = entry->xstrdup(entry->_("Back")); + } // if + + buttons[bcount++] = entry->xstrdup(entry->_("Cancel")); + + mojobox = makeBox(name, (char *) data, buttons, bcount, false, true); + while ((rc = upkeepBox(&mojobox, wgetch(mojobox->mainwin))) == -1) {} + freeBox(mojobox, true); + + for (i = 0; i < bcount; i++) + free(buttons[i]); + + if (rc == backbutton) + return -1; + else if (rc == fwdbutton) + return 1; + + return 0; // error? Cancel? +} // MojoGui_ncurses_readme + + +static int MojoGui_ncurses_options(MojoGuiSetupOptions *opts, + boolean can_back, boolean can_fwd) +{ + return 1; +} // MojoGui_ncurses_options + + +static char *MojoGui_ncurses_destination(const char **recommends, int recnum, + int *command, boolean can_back, + boolean can_fwd) +{ + return NULL; +} // MojoGui_ncurses_destination + + +static boolean MojoGui_ncurses_insertmedia(const char *medianame) +{ + char *fmt = entry->xstrdup(entry->_("Please insert '%s'")); + const size_t len = strlen(fmt) + strlen(medianame) + 1; + char *text = (char *) entry->xmalloc(len); + char *localized_ok = entry->xstrdup(entry->_("Ok")); + char *localized_cancel = entry->xstrdup(entry->_("Cancel")); + char *buttons[] = { localized_ok, localized_cancel }; + MojoBox *mojobox = NULL; + int rc = 0; + + snprintf(text, len, fmt, medianame); + free(fmt); + + mojobox = makeBox(entry->_("Media change"), text, buttons, 2, false, true); + while ((rc = upkeepBox(&mojobox, wgetch(mojobox->mainwin))) == -1) {} + + freeBox(mojobox, true); + free(text); + free(localized_cancel); + free(localized_ok); + return (rc == 0); +} // MojoGui_ncurses_insertmedia + + +static boolean MojoGui_ncurses_progress(const char *type, const char *component, + int percent, const char *item) +{ + return true; +} // MojoGui_ncurses_progress + + +static void MojoGui_ncurses_final(const char *msg) +{ + MojoGui_ncurses_msgbox(entry->_("Finish"), msg); +} // MojoGui_ncurses_final + +// end of gui_ncurses.c ... + Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-19 05:23:39 UTC (rev 290) +++ trunk/gui_stdio.c 2007-05-19 09:52:15 UTC (rev 291) @@ -389,7 +389,8 @@ static boolean MojoGui_stdio_insertmedia(const char *medianame) { char buf[32]; - printf(entry->_("Please insert '%s'\n"), medianame); + printf(entry->_("Please insert '%s'"), medianame); + printf("\n"); return (readstr(NULL, buf, sizeof (buf), false, true) >= 0); } // MojoGui_stdio_insertmedia Modified: trunk/scripts/localization.lua =================================================================== --- trunk/scripts/localization.lua 2007-05-19 05:23:39 UTC (rev 290) +++ trunk/scripts/localization.lua 2007-05-19 09:52:15 UTC (rev 291) @@ -137,7 +137,7 @@ ["failed to load file '%s'"] = { }; - ["Please insert '%s'\n"] = { + ["Please insert '%s'"] = { }; }; From DONOTREPLY at icculus.org Sat May 19 15:04:55 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 19 May 2007 15:04:55 -0400 Subject: r292 - trunk Message-ID: <20070519190455.31960.qmail@icculus.org> Author: icculus Date: 2007-05-19 15:04:55 -0400 (Sat, 19 May 2007) New Revision: 292 Modified: trunk/gui_ncurses.c Log: Several fixes and improvements to the ncurses code. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-19 09:52:15 UTC (rev 291) +++ trunk/gui_ncurses.c 2007-05-19 19:04:55 UTC (rev 292) @@ -87,19 +87,21 @@ *_count = *_w = 0; while (*text) { + int pos = 0; int furthest = 0; - for (i = 0; (*text) && (i < (scrw-4)); i++) + + for (i = 0; (text[i]) && (i < (scrw-4)); i++) { const int ch = text[i]; if ((ch == '\r') || (ch == '\n')) { - text[i] = '\0'; count++; retval = (char **) entry->xrealloc(retval, count * sizeof (char *)); + text[i] = '\0'; retval[count-1] = entry->xstrdup(text); + text += i; *text = ch; - text += i; if ((ch == '\r') && (text[1] == '\n')) text++; text++; @@ -114,25 +116,25 @@ } // else if } // for - if (*text) // line overflow, need to wrap... + // line overflow or end of stream... + pos = (*text) ? furthest : i; + if ((*text) && (furthest == 0)) // uhoh, no split at all...hack it. { - int pos = furthest; - char ch; - if (furthest == 0) // uhoh, no split at all...hack it. - { - // !!! FIXME: might be chopping in the middle of a UTF-8 seq. - pos = strlen(text); - if (pos > scrw-4) - pos = scrw-4; - } // if + // !!! FIXME: might be chopping in the middle of a UTF-8 seq. + pos = strlen(text); + if (pos > scrw-4) + pos = scrw-4; + } // if - ch = text[pos]; - text[pos] = '\0'; + if (pos > 0) + { + char ch = text[pos]; count++; retval = (char **) entry->xrealloc(retval, count * sizeof (char*)); + text[pos] = '\0'; retval[count-1] = entry->xstrdup(text); + text += pos; *text = ch; - text += pos; if (pos > w) w = pos; } // if @@ -170,9 +172,13 @@ static void drawText(MojoBox *mojobox) { int i; - wclear(mojobox->textwin); - for (i = 0; i+mojobox->textpos < mojobox->textlinecount; i++) - mvwaddstr(mojobox->textwin, i, 0, mojobox->textlines[i]); + int pos = mojobox->textpos; + int w, h; + WINDOW *win = mojobox->textwin; + getmaxyx(win, h, w); + wclear(mojobox->textwin); // !!! FIXME: flickers... + for (i = 0; (pos < mojobox->textlinecount) && (i < h); i++, pos++) + mvwaddstr(win, i, 0, mojobox->textlines[pos]); } // drawText @@ -222,7 +228,7 @@ if (bcount > 0) { for (i = 0; i < bcount; i++) - buttonsw += strcells(buttons[i]) + 6; + buttonsw += strcells(buttons[i]) + 5; // '<', ' ', ' ', '>', ' ' if (buttonsw > w) w = buttonsw; // !!! FIXME: what if these overflow the screen? @@ -264,17 +270,17 @@ if (bcount > 0) { - int pos = (w - buttonsw) / 2; + const int buttony = (((scrh - h) / 2) + h)-2; + int buttonx = (((scrw - w) / 2) + w) - ((w - buttonsw) / 2); wmove(win, h-3, 1); whline(win, ACS_HLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), w-2); for (i = 0; i < bcount; i++) { len = strcells(buttons[i]) + 4; - pos += len-2; - win = retval->buttons[i] = newwin(1, len, (((scrh - h) / 2) + h)-2, - (((scrw - w) / 2) + w)-pos); - - keypad(win, TRUE); + buttonx -= len+1; + win = retval->buttons[i] = newwin(1, len, buttony, buttonx); + buttonx -= 1; + keypad(win, TRUE); nodelay(win, ndelay); } // for } // if @@ -345,6 +351,8 @@ static int upkeepBox(MojoBox **_mojobox, int ch) { + static boolean justResized = false; + int w, h; MojoBox *mojobox = *_mojobox; if (mojobox == NULL) return -2; @@ -352,6 +360,11 @@ switch (ch) { case ERR: + if (justResized) // !!! FIXME: this is a kludge. + { + justResized = false; + return -1; + } // if return -2; case '\r': @@ -363,11 +376,86 @@ case '\e': return mojobox->buttoncount-1; + case KEY_UP: + if (mojobox->textpos > 0) + { + mojobox->textpos--; + drawText(mojobox); + wrefresh(mojobox->textwin); + } // if + return -1; + + case KEY_DOWN: + getmaxyx(mojobox->textwin, h, w); + if (mojobox->textpos < (mojobox->textlinecount-h)) + { + mojobox->textpos++; + drawText(mojobox); + wrefresh(mojobox->textwin); + } // if + return -1; + + case KEY_PPAGE: + if (mojobox->textpos > 0) + { + getmaxyx(mojobox->textwin, h, w); + mojobox->textpos -= h; + if (mojobox->textpos < 0) + mojobox->textpos = 0; + drawText(mojobox); + wrefresh(mojobox->textwin); + } // if + return -1; + + case KEY_NPAGE: + getmaxyx(mojobox->textwin, h, w); + if (mojobox->textpos < (mojobox->textlinecount-h)) + { + mojobox->textpos += h; + if (mojobox->textpos > (mojobox->textlinecount-h)) + mojobox->textpos = (mojobox->textlinecount-h); + drawText(mojobox); + wrefresh(mojobox->textwin); + } // if + return -1; + + case KEY_LEFT: + if (mojobox->buttoncount > 1) + { + if (mojobox->hoverover < (mojobox->buttoncount-1)) + { + mojobox->hoverover++; + drawButton(mojobox, mojobox->hoverover-1); + drawButton(mojobox, mojobox->hoverover); + wrefresh(mojobox->buttons[mojobox->hoverover-1]); + wrefresh(mojobox->buttons[mojobox->hoverover]); + } // if + } // if + return -1; + + case KEY_RIGHT: + if (mojobox->buttoncount > 1) + { + if (mojobox->hoverover > 0) + { + mojobox->hoverover--; + drawButton(mojobox, mojobox->hoverover+1); + drawButton(mojobox, mojobox->hoverover); + wrefresh(mojobox->buttons[mojobox->hoverover+1]); + wrefresh(mojobox->buttons[mojobox->hoverover]); + } // if + } // if + return -1; + case KEY_RESIZE: + justResized = true; // !!! FIXME: kludge. mojobox = makeBox(mojobox->title, mojobox->text, mojobox->buttontext, mojobox->buttoncount, mojobox->ndelay, mojobox->hidecursor); + mojobox->cursval = (*_mojobox)->cursval; // keep this sane. freeBox(*_mojobox, false); + if (mojobox->hidecursor) + curs_set(0); // make sure this stays sane. *_mojobox = mojobox; return -1; } // switch From DONOTREPLY at icculus.org Sun May 20 03:50:52 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 03:50:52 -0400 Subject: r293 - trunk/examples/duke3d Message-ID: <20070520075052.16278.qmail@icculus.org> Author: icculus Date: 2007-05-20 03:50:38 -0400 (Sun, 20 May 2007) New Revision: 293 Modified: trunk/examples/duke3d/make.sh Log: Let you run "./make.sh --debug" for the duke3d example, to build MojoSetup for bug fixing in a real-world package. Modified: trunk/examples/duke3d/make.sh =================================================================== --- trunk/examples/duke3d/make.sh 2007-05-19 19:04:55 UTC (rev 292) +++ trunk/examples/duke3d/make.sh 2007-05-20 07:50:38 UTC (rev 293) @@ -4,11 +4,29 @@ # example, but invest effort in what it's trying to do, and what it produces. # (make sure you don't build in features you don't need, etc). +# Stop if anything produces an error. +set -e + +DEBUG=0 +if [ "$1" = "--debug" ]; then + echo "debug build!" + DEBUG=1 +fi + # Show everything that we do here on stdout. set -x -# Stop if anything produces an error. -set -e +if [ "$DEBUG" = "1" ]; then + LUASTRIPOPT=-s + BUILDTYPE=Debug + TRUEIFDEBUG=TRUE + FALSEIFDEBUG=FALSE +else + LUASTRIPOPT= + BUILDTYPE=MinSizeRel + TRUEIFDEBUG=FALSE + FALSEIFDEBUG=TRUE +fi # Clean up previous run, build fresh dirs for Base Archive. rm -rf image duke3d-installer pdata.zip @@ -21,7 +39,7 @@ cd ../.. rm -rf `svn propget svn:ignore .` cmake \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_BUILD_TYPE=$BUILDTYPE \ -DMOJOSETUP_ARCHIVE_TAR=FALSE \ -DMOJOSETUP_ARCHIVE_TAR_BZ2=FALSE \ -DMOJOSETUP_ARCHIVE_TAR_GZ=FALSE \ @@ -30,29 +48,34 @@ -DMOJOSETUP_LUALIB_MATH=FALSE \ -DMOJOSETUP_LUALIB_OS=FALSE \ -DMOJOSETUP_LUALIB_PACKAGE=FALSE \ - -DMOJOSETUP_LUA_PARSER=FALSE \ + -DMOJOSETUP_LUA_PARSER=$TRUEIFDEBUG \ -DMOJOSETUP_URL_FTP=FALSE \ . make -j5 # Strip the binaries and GUI plugins, put them somewhere useful. -strip ./mojosetup +if [ "$DEBUG" != "1" ]; then + strip ./mojosetup +fi + mv ./mojosetup ./examples/duke3d/duke3d-installer for feh in *.so *.dll *.dylib ; do if [ -f $feh ]; then - strip $feh + if [ "$DEBUG" != "1" ]; then + strip $feh + fi mv $feh examples/duke3d/image/guis fi done # Compile the Lua scripts, put them in the base archive. for feh in scripts/*.lua ; do - ./mojoluac -s -o examples/duke3d/image/${feh}c $feh + ./mojoluac $LUASTRIPOPT -o examples/duke3d/image/${feh}c $feh done # Don't want the example config...use our's instead. rm -f examples/duke3d/image/scripts/config.luac -./mojoluac -s -o examples/duke3d/image/scripts/config.luac examples/duke3d/scripts/config.lua +./mojoluac $LUASTRIPOPT -o examples/duke3d/image/scripts/config.luac examples/duke3d/scripts/config.lua # Fill in the rest of the Base Archive... cd examples/duke3d @@ -72,5 +95,19 @@ set +e set +x echo "Successfully built!" + +if [ "$DEBUG" = "1" ]; then + echo + echo + echo + echo 'ATTENTION: THIS IS A DEBUG BUILD!' + echo " DON'T DISTRIBUTE TO THE PUBLIC." + echo ' THIS IS PROBABLY BIGGER AND SLOWER THAN IT SHOULD BE.' + echo ' YOU HAVE BEEN WARNED!' + echo + echo + echo +fi + exit 0 From DONOTREPLY at icculus.org Sun May 20 04:14:19 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 04:14:19 -0400 Subject: r294 - trunk/scripts Message-ID: <20070520081419.23758.qmail@icculus.org> Author: icculus Date: 2007-05-20 04:14:11 -0400 (Sun, 20 May 2007) New Revision: 294 Modified: trunk/scripts/config.lua Log: Added some more nested options to example config file for UI testing purposes. Modified: trunk/scripts/config.lua =================================================================== --- trunk/scripts/config.lua 2007-05-20 07:50:38 UTC (rev 293) +++ trunk/scripts/config.lua 2007-05-20 08:14:11 UTC (rev 294) @@ -143,9 +143,27 @@ Setup.Option { value = string.match(MojoSetup.info.locale, "^fr_") ~= nil, - bytes = megabytes(10), + bytes = 0, description = "French", - Setup.File { source = "base:///Lang/French.zip" }, + Setup.OptionGroup + { + disabled = false, + description = "French locale", + Setup.Option + { + value = (MojoSetup.info.locale == fr_CA), + bytes = megabytes(10), + description = "French Canadian", + Setup.File { source = "base:///Lang/FrenchCA.zip" }, + }, + Setup.Option + { + value = (MojoSetup.info.locale ~= fr_CA), + bytes = megabytes(10), + description = "Generic French", + Setup.File { source = "base:///Lang/French.zip" }, + }, + }, }, Setup.Option { From DONOTREPLY at icculus.org Sun May 20 05:01:30 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 05:01:30 -0400 Subject: r295 - in trunk: . scripts Message-ID: <20070520090130.20187.qmail@icculus.org> Author: icculus Date: 2007-05-20 05:01:30 -0400 (Sun, 20 May 2007) New Revision: 295 Modified: trunk/gui_ncurses.c trunk/gui_stdio.c trunk/scripts/localization.lua Log: Bunch More Work on the ncurses UI...lots of fixes and tweaks, and a working Options page. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-20 08:14:11 UTC (rev 294) +++ trunk/gui_ncurses.c 2007-05-20 09:01:30 UTC (rev 295) @@ -31,7 +31,8 @@ // // ncurses is almost always installed as a shared library, though, so we'll // just talk to it directly. Fortunately we don't need much of what dialog(1) -// offers, so rolling our own isn't too painful. +// offers, so rolling our own isn't too painful (well, compared to massive +// head trauma, I guess). // // Pradeep Padala's ncurses HOWTO was very helpful in teaching me curses // quickly: http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/index.html @@ -74,6 +75,11 @@ } MojoBox; +static char *lastComponent = NULL; +static uint32 percentTicks = 0; +static char *title = NULL; + + // !!! FIXME: this is not really Unicode friendly... static char **splitText(char *text, int *_count, int *_w) { @@ -182,6 +188,18 @@ } // drawText +static void drawBackground(WINDOW *win) +{ + wclear(win); + if (title != NULL) + { + wattron(win, COLOR_PAIR(MOJOCOLOR_BACKGROUND) | A_BOLD); + mvwaddstr(win, 0, 0, title); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BACKGROUND) | A_BOLD); + } // if +} // drawBackground + + static MojoBox *makeBox(const char *title, const char *text, char **buttons, int bcount, boolean ndelay, boolean hidecursor) @@ -197,7 +215,8 @@ int i; getmaxyx(stdscr, scrh, scrw); - if (scrw < 16) + scrh--; // -1 to save the title at the top of the screen... + if ((scrw < 16) || (scrh < 16)) return NULL; retval = (MojoBox *) entry->xmalloc(sizeof (MojoBox)); @@ -242,7 +261,7 @@ if (h > scrh) h = scrh; - win = retval->mainwin = newwin(h, w, (scrh - h) / 2, (scrw - w) / 2); + win = retval->mainwin = newwin(h, w, ((scrh - h) / 2)+1, (scrw - w) / 2); keypad(win, TRUE); nodelay(win, ndelay); wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); @@ -270,7 +289,7 @@ if (bcount > 0) { - const int buttony = (((scrh - h) / 2) + h)-2; + const int buttony = (((scrh - h) / 2) + h)-1; int buttonx = (((scrw - w) / 2) + w) - ((w - buttonsw) / 2); wmove(win, h-3, 1); whline(win, ACS_HLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), w-2); @@ -279,7 +298,6 @@ len = strcells(buttons[i]) + 4; buttonx -= len+1; win = retval->buttons[i] = newwin(1, len, buttony, buttonx); - buttonx -= 1; keypad(win, TRUE); nodelay(win, ndelay); } // for @@ -288,13 +306,13 @@ texth = h-2; if (bcount > 0) texth -= 2; - win = retval->textwin = newwin(texth, w-4, ((scrh-h)/2)+1, ((scrw-w)/2)+2); + win = retval->textwin = newwin(texth, w-4, ((scrh-h)/2)+2, ((scrw-w)/2)+2); keypad(win, TRUE); nodelay(win, ndelay); wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); drawText(retval); - wclear(stdscr); + drawBackground(stdscr); wrefresh(stdscr); wrefresh(retval->mainwin); wrefresh(retval->textwin); @@ -357,14 +375,16 @@ if (mojobox == NULL) return -2; + if (justResized) // !!! FIXME: this is a kludge. + { + justResized = false; + if (ch == ERR) + return -1; + } // if + switch (ch) { case ERR: - if (justResized) // !!! FIXME: this is a kludge. - { - justResized = false; - return -1; - } // if return -2; case '\r': @@ -448,15 +468,16 @@ return -1; case KEY_RESIZE: - justResized = true; // !!! FIXME: kludge. mojobox = makeBox(mojobox->title, mojobox->text, mojobox->buttontext, mojobox->buttoncount, mojobox->ndelay, mojobox->hidecursor); mojobox->cursval = (*_mojobox)->cursval; // keep this sane. + mojobox->hoverover = (*_mojobox)->hoverover; freeBox(*_mojobox, false); if (mojobox->hidecursor) curs_set(0); // make sure this stays sane. *_mojobox = mojobox; + justResized = true; // !!! FIXME: kludge. return -1; } // switch @@ -464,9 +485,6 @@ } // upkeepBox -static char *lastComponent = NULL; -static uint32 percentTicks = 0; - static uint8 MojoGui_ncurses_priority(void) { if (getenv("DISPLAY") != NULL) @@ -498,15 +516,15 @@ cbreak(); keypad(stdscr, TRUE); noecho(); - //nodelay(stdscr, TRUE); start_color(); - init_pair(MOJOCOLOR_BACKGROUND, COLOR_BLUE, COLOR_BLUE); + init_pair(MOJOCOLOR_BACKGROUND, COLOR_CYAN, COLOR_BLUE); init_pair(MOJOCOLOR_BORDERTOP, COLOR_WHITE, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERSHADOW, COLOR_BLACK, COLOR_BLACK); init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_WHITE, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); + wbkgdset(stdscr, COLOR_PAIR(MOJOCOLOR_BACKGROUND)); wclear(stdscr); wrefresh(stdscr); @@ -521,6 +539,8 @@ endwin(); delwin(stdscr); // not sure if this is safe, but valgrind said it leaks. stdscr = NULL; + free(title); + title = NULL; free(lastComponent); lastComponent = NULL; } // MojoGui_ncurses_deinit @@ -581,9 +601,11 @@ } // MojoGui_ncurses_promptynan -static boolean MojoGui_ncurses_start(const char *title, const char *splash) +static boolean MojoGui_ncurses_start(const char *_title, const char *splash) { - wclear(stdscr); + free(title); + title = entry->xstrdup(_title); + drawBackground(stdscr); wrefresh(stdscr); return true; } // MojoGui_ncurses_start @@ -591,7 +613,9 @@ static void MojoGui_ncurses_stop(void) { - wclear(stdscr); + free(title); + title = NULL; + drawBackground(stdscr); wrefresh(stdscr); } // MojoGui_ncurses_stop @@ -638,10 +662,287 @@ } // MojoGui_ncurses_readme +static int toggle_option(MojoGuiSetupOptions *parent, + MojoGuiSetupOptions *opts, int *line, int target) +{ + int rc = -1; + if ((opts != NULL) && (target > *line)) + { + if (++(*line) == target) + { + const boolean toggled = ((opts->value) ? false : true); + + if (opts->is_group_parent) + return 0; + + // "radio buttons" in a group? + if ((parent) && (parent->is_group_parent)) + { + if (toggled) // drop unless we weren't the current toggle. + { + // set all siblings to false... + MojoGuiSetupOptions *i = parent->child; + while (i != NULL) + { + i->value = false; + i = i->next_sibling; + } // while + opts->value = true; // reset us to be true. + } // if + } // if + + else // individual "check box" was chosen. + { + opts->value = toggled; + } // else + + return 1; // we found it, bail. + } // if + + if (opts->value) // if option is toggled on, descend to children. + rc = toggle_option(opts, opts->child, line, target); + if (rc == -1) + rc = toggle_option(parent, opts->next_sibling, line, target); + } // if + + return rc; +} // toggle_option + + +// This code is pretty scary. +static void build_options(MojoGuiSetupOptions *opts, int *line, int level, + int maxw, char **lines) +{ + if (opts != NULL) + { + char *spacebuf = (char *) entry->xmalloc(maxw+1); + char *buf = (char *) entry->xmalloc(maxw+1); + int len = 0; + int spacing = 1+level; + + if (spacing > (maxw-5)) + spacing = 0; // oh well. + + if (spacing > 0) + memset(spacebuf, ' ', spacing); // null-term'd by xmalloc(). + + if (opts->is_group_parent) + len = snprintf(buf, maxw-2, "%s%s", spacebuf, opts->description); + else + { + (*line)++; + len = snprintf(buf, maxw-2, "%s[%c] %s", spacebuf, + opts->value ? 'X' : ' ', + opts->description); + } // else + + free(spacebuf); + + if (len >= maxw-1) + strcpy(buf+(maxw-4), "..."); // !!! FIXME: Unicode issues! + + *lines = (char*) entry->xrealloc(*lines, strlen(*lines)+strlen(buf)+2); + strcat(*lines, buf); + strcat(*lines, "\n"); // I'm sorry, Joel Spolsky! + + if ((opts->value) || (opts->is_group_parent)) + build_options(opts->child, line, level+1, maxw, lines); + build_options(opts->next_sibling, line, level, maxw, lines); + } // if +} // build_options + + static int MojoGui_ncurses_options(MojoGuiSetupOptions *opts, boolean can_back, boolean can_fwd) { - return 1; + char *title = entry->xstrdup(entry->_("Options")); + MojoBox *mojobox = NULL; + char *buttons[4] = { NULL, NULL, NULL, NULL }; + boolean ignoreerr = false; + int lasthoverover = 0; + int lasttextpos = 0; + int bcount = 0; + int backbutton = -99; + int fwdbutton = -99; + int togglebutton = -99; + int cancelbutton = -99; + int selected = 0; + int ch = 0; + int rc = -1; + int i = 0; + + if (can_fwd) + { + fwdbutton = bcount++; + buttons[fwdbutton] = entry->xstrdup(entry->_("Next")); + } // if + + if (can_back) + { + backbutton = bcount++; + buttons[backbutton] = entry->xstrdup(entry->_("Back")); + } // if + + lasthoverover = togglebutton = bcount++; + buttons[togglebutton] = entry->xstrdup(entry->_("Toggle")); + cancelbutton = bcount++; + buttons[cancelbutton] = entry->xstrdup(entry->_("Cancel")); + + do + { + if (mojobox == NULL) + { + int y = 0; + int line = 0; + int maxw, maxh; + getmaxyx(stdscr, maxh, maxw); + char *text = entry->xstrdup(""); + build_options(opts, &line, 1, maxw-6, &text); + mojobox = makeBox(title, text, buttons, bcount, false, true); + free(text); + + getmaxyx(mojobox->textwin, maxh, maxw); + + if (lasthoverover != mojobox->hoverover) + { + const int orighover = mojobox->hoverover; + mojobox->hoverover = lasthoverover; + drawButton(mojobox, orighover); + drawButton(mojobox, lasthoverover); + wrefresh(mojobox->buttons[orighover]); + wrefresh(mojobox->buttons[lasthoverover]); + } // if + + if (lasttextpos != mojobox->textpos) + { + mojobox->textpos = lasttextpos; + drawText(mojobox); + } // if + + if (selected >= (mojobox->textlinecount - 1)) + selected = mojobox->textlinecount - 1; + if (selected >= mojobox->textpos+maxh) + selected = (mojobox->textpos+maxh) - 1; + y = selected - lasttextpos; + + wattron(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + mvwhline(mojobox->textwin, y, 0, ' ', maxw); + mvwaddstr(mojobox->textwin, y, 0, mojobox->textlines[selected]); + wattroff(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wrefresh(mojobox->textwin); + } // if + + lasttextpos = mojobox->textpos; + lasthoverover = mojobox->hoverover; + + ch = wgetch(mojobox->mainwin); + + if (ignoreerr) // kludge. + { + ignoreerr = false; + if (ch == ERR) + continue; + } // if + + if (ch == KEY_RESIZE) + { + freeBox(mojobox, false); // catch and rebuild without upkeepBox, + mojobox = NULL; // so we can rebuild the text ourself. + ignoreerr = true; // kludge. + } // if + + else if (ch == KEY_UP) + { + if (selected > 0) + { + WINDOW *win = mojobox->textwin; + int maxw, maxh; + int y = --selected - mojobox->textpos; + getmaxyx(win, maxh, maxw); + if (selected < mojobox->textpos) + { + upkeepBox(&mojobox, ch); // upkeepBox does scrolling + y++; + } // if + else + { + wattron(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + mvwhline(win, y+1, 0, ' ', maxw); + mvwaddstr(win, y+1, 0, mojobox->textlines[selected+1]); + wattroff(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + } // else + wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + mvwhline(win, y, 0, ' ', maxw); + mvwaddstr(win, y, 0, mojobox->textlines[selected]); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wrefresh(win); + } // if + } // else if + + else if (ch == KEY_DOWN) + { + if (selected < (mojobox->textlinecount-1)) + { + WINDOW *win = mojobox->textwin; + int maxw, maxh; + int y = ++selected - mojobox->textpos; + getmaxyx(win, maxh, maxw); + if (selected >= mojobox->textpos+maxh) + { + upkeepBox(&mojobox, ch); // upkeepBox does scrolling + y--; + } // if + else + { + wattron(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + mvwhline(win, y-1, 0, ' ', maxw); + mvwaddstr(win, y-1, 0, mojobox->textlines[selected-1]); + wattroff(win, COLOR_PAIR(MOJOCOLOR_TEXT)); + } // else + wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + mvwhline(win, y, 0, ' ', maxw); + mvwaddstr(win, y, 0, mojobox->textlines[selected]); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wrefresh(win); + } // if + } // else if + + else if ((ch == KEY_NPAGE) || (ch == KEY_NPAGE)) + { + // !!! FIXME: maybe handle this when I'm not so lazy. + // !!! FIXME: For now, this if statement is to block + // !!! FIXME: upkeepBox() from scrolling and screwing up state. + } // else if + + else // let upkeepBox handle other input (button selection, etc). + { + rc = upkeepBox(&mojobox, ch); + if (rc == togglebutton) + { + int line = 0; + rc = -1; // reset so we don't stop processing input. + if (toggle_option(NULL, opts, &line, selected+1) == 1) + { + freeBox(mojobox, false); // rebuild to reflect new options... + mojobox = NULL; + } // if + } // if + } // else + } while (rc == -1); + + freeBox(mojobox, true); + + for (i = 0; i < bcount; i++) + free(buttons[i]); + + free(title); + + if (rc == backbutton) + return -1; + else if (rc == fwdbutton) + return 1; + + return 0; // error? Cancel? } // MojoGui_ncurses_options @@ -649,7 +950,9 @@ int *command, boolean can_back, boolean can_fwd) { - return NULL; + // !!! FIXME: clearly this isn't right. + *command = 1; + return entry->xstrdup("/home/icculus/duke3d"); } // MojoGui_ncurses_destination Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-20 08:14:11 UTC (rev 294) +++ trunk/gui_stdio.c 2007-05-20 09:01:30 UTC (rev 295) @@ -332,7 +332,7 @@ int *command, boolean can_back, boolean can_fwd) { - const char *instdeststr = entry->xstrdup(entry->_("Install destination:")); + const char *instdeststr = entry->xstrdup(entry->_("Destination")); const char *prompt = NULL; char *retval = NULL; boolean getout = false; Modified: trunk/scripts/localization.lua =================================================================== --- trunk/scripts/localization.lua 2007-05-20 08:14:11 UTC (rev 294) +++ trunk/scripts/localization.lua 2007-05-20 09:01:30 UTC (rev 295) @@ -98,10 +98,10 @@ ["> "] = { }; - ["Install options:"] = { + ["Options"] = { }; - ["Install destination:"] = { + ["Destination"] = { }; ["Choose install destination by number (hit enter for #1), or enter your own."] = { From DONOTREPLY at icculus.org Sun May 20 05:12:53 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 05:12:53 -0400 Subject: r296 - trunk Message-ID: <20070520091253.26603.qmail@icculus.org> Author: icculus Date: 2007-05-20 05:12:53 -0400 (Sun, 20 May 2007) New Revision: 296 Modified: trunk/gui_stdio.c Log: Print install component and type every time either changes in stdio UI's progress output. Modified: trunk/gui_stdio.c =================================================================== --- trunk/gui_stdio.c 2007-05-20 09:01:30 UTC (rev 295) +++ trunk/gui_stdio.c 2007-05-20 09:12:53 UTC (rev 296) @@ -21,6 +21,7 @@ #include +static char *lastProgressType = NULL; static char *lastComponent = NULL; static uint32 percentTicks = 0; @@ -88,7 +89,9 @@ static void MojoGui_stdio_deinit(void) { + free(lastProgressType); free(lastComponent); + lastProgressType = NULL; lastComponent = NULL; } // MojoGui_stdio_deinit @@ -399,9 +402,15 @@ int percent, const char *item) { const uint32 now = entry->ticks(); - if ((lastComponent == NULL) || (strcmp(lastComponent, component) != 0)) + + if ( (lastComponent == NULL) || + (strcmp(lastComponent, component) != 0) || + (lastProgressType == NULL) || + (strcmp(lastProgressType, type) != 0) ) { + free(lastProgressType); free(lastComponent); + lastProgressType = entry->xstrdup(type); lastComponent = entry->xstrdup(component); printf("%s\n%s\n", type, component); } // if From DONOTREPLY at icculus.org Sun May 20 06:43:18 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 06:43:18 -0400 Subject: r297 - trunk/scripts Message-ID: <20070520104318.8786.qmail@icculus.org> Author: icculus Date: 2007-05-20 06:43:18 -0400 (Sun, 20 May 2007) New Revision: 297 Modified: trunk/scripts/mojosetup_mainline.lua Log: Don't let percentages overflow. Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-20 09:12:53 UTC (rev 296) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-20 10:43:18 UTC (rev 297) @@ -111,7 +111,14 @@ elseif total < 0 then return -1 end - return MojoSetup.truncatenum((current / total) * 100) + + local retval = MojoSetup.truncatenum((current / total) * 100) + if retval > 100 then + retval = 100 + elseif retval < 0 then + retval = 0 + end + return retval end From DONOTREPLY at icculus.org Sun May 20 07:12:17 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 07:12:17 -0400 Subject: r298 - trunk Message-ID: <20070520111217.22060.qmail@icculus.org> Author: icculus Date: 2007-05-20 07:12:16 -0400 (Sun, 20 May 2007) New Revision: 298 Modified: trunk/gui_ncurses.c Log: More ncurses work: implemented progress box, fixed text wrapping. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-20 10:43:18 UTC (rev 297) +++ trunk/gui_ncurses.c 2007-05-20 11:12:16 UTC (rev 298) @@ -46,6 +46,8 @@ MOJOCOLOR_TEXT, MOJOCOLOR_BUTTONHOVER, MOJOCOLOR_BUTTONNORMAL, + MOJOCOLOR_TODO, + MOJOCOLOR_DONE, } MojoColor; @@ -75,9 +77,11 @@ } MojoBox; +static char *lastProgressType = NULL; static char *lastComponent = NULL; static uint32 percentTicks = 0; static char *title = NULL; +static MojoBox *progressBox = NULL; // !!! FIXME: this is not really Unicode friendly... @@ -123,8 +127,8 @@ } // for // line overflow or end of stream... - pos = (*text) ? furthest : i; - if ((*text) && (furthest == 0)) // uhoh, no split at all...hack it. + pos = (text[i]) ? furthest : i; + if ((text[i]) && (furthest == 0)) // uhoh, no split at all...hack it. { // !!! FIXME: might be chopping in the middle of a UTF-8 seq. pos = strlen(text); @@ -524,6 +528,8 @@ init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_WHITE, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_DONE, COLOR_YELLOW, COLOR_RED); + init_pair(MOJOCOLOR_TODO, COLOR_CYAN, COLOR_BLUE); wbkgdset(stdscr, COLOR_PAIR(MOJOCOLOR_BACKGROUND)); wclear(stdscr); @@ -536,6 +542,8 @@ static void MojoGui_ncurses_deinit(void) { + freeBox(progressBox, false); + progressBox = NULL; endwin(); delwin(stdscr); // not sure if this is safe, but valgrind said it leaks. stdscr = NULL; @@ -543,6 +551,8 @@ title = NULL; free(lastComponent); lastComponent = NULL; + free(lastProgressType); + lastProgressType = NULL; } // MojoGui_ncurses_deinit @@ -951,8 +961,14 @@ boolean can_fwd) { // !!! FIXME: clearly this isn't right. - *command = 1; - return entry->xstrdup("/home/icculus/duke3d"); + if (recnum > 0) + { + *command = 1; + return entry->xstrdup(recommends[0]); + } // if + + *command = 0; + return NULL; } // MojoGui_ncurses_destination @@ -982,9 +998,115 @@ static boolean MojoGui_ncurses_progress(const char *type, const char *component, - int percent, const char *item) + int percent, const char *item) { - return true; + const uint32 now = entry->ticks(); + boolean rebuild = (progressBox == NULL); + int ch = 0; + int rc = -1; + + if ( (lastComponent == NULL) || + (strcmp(lastComponent, component) != 0) || + (lastProgressType == NULL) || + (strcmp(lastProgressType, type) != 0) ) + { + free(lastProgressType); + free(lastComponent); + lastProgressType = entry->xstrdup(type); + lastComponent = entry->xstrdup(component); + rebuild = true; + } // if + + if (rebuild) + { + int w, h; + char *text = NULL; + char *localized_cancel = entry->xstrdup(entry->_("Cancel")); + char *buttons[] = { localized_cancel }; + char *spacebuf = NULL; + getmaxyx(stdscr, h, w); + w -= 10; + text = (char *) entry->xmalloc((w * 3) + 16); + if (snprintf(text, w, "%s", component) > (w-4)) + strcpy((text+w)-4, "..."); // !!! FIXME: Unicode problem. + strcat(text, "\n\n"); + spacebuf = (char *) entry->xmalloc(w+1); + memset(spacebuf, ' ', w); // xmalloc provides null termination. + strcat(text, spacebuf); + free(spacebuf); + strcat(text, "\n\n "); + + freeBox(progressBox, false); + progressBox = makeBox(type, text, buttons, 1, true, true); + free(text); + free(localized_cancel); + } // if + + // limit update spam... will only write every one second, tops. + if ((rebuild) || (percentTicks <= now)) + { + static boolean unknownToggle = false; + char *buf = NULL; + WINDOW *win = progressBox->textwin; + int w, h; + getmaxyx(win, h, w); + w -= 2; + buf = (char *) entry->xmalloc(w+1); + + if (percent < 0) + { + const boolean origToggle = unknownToggle; + int i; + wmove(win, h-3, 1); + for (i = 0; i < w; i++) + { + if (unknownToggle) + waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_TODO)); + else + waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_DONE)); + unknownToggle = !unknownToggle; + } // for + unknownToggle = !origToggle; // animate by reversing next time. + } // if + else + { + int cells = (int) ( ((double) w) * (((double) percent) / 100.0) ); + snprintf(buf, w+1, "%d%%", percent); + mvwaddstr(win, h-3, ((w+2) - strcells(buf)) / 2, buf); + mvwchgat(win, h-3, 1, cells, A_BOLD, MOJOCOLOR_DONE, NULL); + mvwchgat(win, h-3, 1+cells, w-cells, A_BOLD, MOJOCOLOR_TODO, NULL); + } // else + + wtouchln(win, h-3, 1, 1); // force reattributed cells to update. + + if (snprintf(buf, w+1, "%s", item) > (w-4)) + strcpy((buf+w)-4, "..."); // !!! FIXME: Unicode problem. + mvwhline(win, h-2, 1, ' ', w); + mvwaddstr(win, h-2, ((w+2) - strcells(buf)) / 2, buf); + + free(buf); + wrefresh(win); + + percentTicks = now + 1000; + } // if + + // !!! FIXME: check for input here for cancel button, resize, etc... + ch = wgetch(progressBox->mainwin); + if (ch == KEY_RESIZE) + { + freeBox(progressBox, false); + progressBox = NULL; + } // if + else if (ch == ERR) // can't distinguish between an error and a timeout! + { + // do nothing... + } // else if + else + { + rc = upkeepBox(&progressBox, ch); + } // else + + return (rc == -1); } // MojoGui_ncurses_progress From DONOTREPLY at icculus.org Sun May 20 07:14:27 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 07:14:27 -0400 Subject: r299 - trunk Message-ID: <20070520111427.23018.qmail@icculus.org> Author: icculus Date: 2007-05-20 07:14:27 -0400 (Sun, 20 May 2007) New Revision: 299 Modified: trunk/CMakeLists.txt Log: ncurses UI should be a shared lib by default. Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-20 11:12:16 UTC (rev 298) +++ trunk/CMakeLists.txt 2007-05-20 11:14:27 UTC (rev 299) @@ -275,10 +275,10 @@ IF(UNIX) # !!! FIXME: use FindCurses instead... IF(NOT BEOS) IF(NOT MACOSX) -OPTION(MOJOSETUP_GUI_NCURSES "Enable ncurses GUI" FALSE) +OPTION(MOJOSETUP_GUI_NCURSES "Enable ncurses GUI" TRUE) IF(MOJOSETUP_GUI_NCURSES) ADD_DEFINITIONS(-DSUPPORT_GUI_NCURSES=1) - OPTION(MOJOSETUP_GUI_NCURSES_STATIC "Statically link ncurses GUI" TRUE) + OPTION(MOJOSETUP_GUI_NCURSES_STATIC "Statically link ncurses GUI" FALSE) IF(MOJOSETUP_GUI_NCURSES_STATIC) ADD_DEFINITIONS(-DGUI_STATIC_LINK_NCURSES=1) SET(OPTIONAL_SRCS ${OPTIONAL_SRCS} gui_ncurses.c) From DONOTREPLY at icculus.org Sun May 20 19:24:37 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 19:24:37 -0400 Subject: r300 - trunk Message-ID: <20070520232437.20726.qmail@icculus.org> Author: icculus Date: 2007-05-20 19:24:36 -0400 (Sun, 20 May 2007) New Revision: 300 Modified: trunk/CMakeLists.txt trunk/fileio.c trunk/fileio.h trunk/mojosetup.c trunk/platform.h trunk/platform_unix.c Log: A shot at a kludge for launching a different binary from inside the Base Archive, so you can download/run a 32-bit installer but launch a real 64-bit process...this may help with amd64 systems that, say, have GTK+ support in the normal system, but not in their 32-bit compatibility layer. Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/CMakeLists.txt 2007-05-20 23:24:36 UTC (rev 300) @@ -213,6 +213,16 @@ ENDIF(MOJOSETUP_LUA_PARSER) +# Kludge for Linux x86/amd64 bins... +IF(UNIX AND NOT MACOSX) # Just use Mach-O Universal/"fat" binaries on OS X. + OPTION(MOJOSETUP_MULTIARCH "Allow multiarch hack." FALSE) + MARK_AS_ADVANCED(MOJOSETUP_MULTIARCH) + IF(MOJOSETUP_MULTIARCH) + ADD_DEFINITIONS(-DSUPPORT_MULTIARCH=1) + ENDIF(MOJOSETUP_MULTIARCH) +ENDIF(UNIX AND NOT MACOSX) + + # Optional bits of the Lua runtime library... # BINARY SIZE += 4.5 Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/fileio.c 2007-05-20 23:24:36 UTC (rev 300) @@ -483,15 +483,36 @@ MojoArchive *GBaseArchive = NULL; +const char *GBaseArchivePath = NULL; MojoArchive *MojoArchive_initBaseArchive(void) { + char *basepath = NULL; + const char *cmd = NULL; + MojoInput *io = NULL; + if (GBaseArchive != NULL) - return GBaseArchive; + return GBaseArchive; // already initialized. + + if ((cmd = cmdlinestr("base", "MOJOSETUP_BASE", NULL)) != NULL) + { + if (MojoPlatform_isdir(cmd)) + GBaseArchive = MojoArchive_newFromDirectory(cmd); + else + { + io = MojoInput_newFromFile(cmd); + if (io != NULL) + GBaseArchive = MojoArchive_newFromInput(io, cmd); + } // else + + if (GBaseArchive != NULL) + basepath = xstrdup(cmd); + } // else if + else { - char *basepath = MojoPlatform_appBinaryPath(); - MojoInput *io = MojoInput_newFromFile(basepath); + basepath = MojoPlatform_appBinaryPath(); + io = MojoInput_newFromFile(basepath); if (io != NULL) GBaseArchive = MojoArchive_newFromInput(io, basepath); @@ -499,21 +520,28 @@ if (GBaseArchive == NULL) { // Just use the same directory as the binary instead. - const char *parentdir = basepath; char *ptr = strrchr(basepath, '/'); if (ptr != NULL) *ptr = '\0'; else - parentdir = "."; // oh well. - GBaseArchive = MojoArchive_newFromDirectory(parentdir); + { + free(basepath); // oh well, try cwd. + basepath = MojoPlatform_currentWorkingDir(); + } // else + GBaseArchive = MojoArchive_newFromDirectory(basepath); // !!! FIXME: failing this, maybe default.mojosetup? - // !!! FIXME: maybe a command line? } // if - free(basepath); // appBinaryPath caller free()s this string. } // else + if (GBaseArchive == NULL) + { + free(basepath); + basepath = NULL; + } // if + GBaseArchivePath = basepath; + return GBaseArchive; } // MojoArchive_initBaseArchive @@ -525,6 +553,9 @@ GBaseArchive->close(GBaseArchive); GBaseArchive = NULL; } // if + + free((void *) GBaseArchivePath); + GBaseArchivePath = NULL; } // MojoArchive_deinitBaseArchive Modified: trunk/fileio.h =================================================================== --- trunk/fileio.h 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/fileio.h 2007-05-20 23:24:36 UTC (rev 300) @@ -93,6 +93,7 @@ MojoInput *MojoInput_newFromArchivePath(MojoArchive *ar, const char *fname); extern MojoArchive *GBaseArchive; +extern const char *GBaseArchivePath; MojoArchive *MojoArchive_initBaseArchive(void); void MojoArchive_deinitBaseArchive(void); Modified: trunk/mojosetup.c =================================================================== --- trunk/mojosetup.c 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/mojosetup.c 2007-05-20 23:24:36 UTC (rev 300) @@ -60,6 +60,56 @@ } // MojoSetup_crash +#if !SUPPORT_MULTIARCH +#define trySwitchBinaries() +#else +static void trySwitchBinary(MojoArchive *ar) +{ + MojoInput *io = ar->openCurrentEntry(ar); + if (io != NULL) + { + const uint32 imglen = (uint32) io->length(io); + uint8 *img = (uint8 *) xmalloc(imglen); + const uint32 br = io->read(io, img, imglen); + io->close(io); + if (br == imglen) + { + logInfo("Switching binary with '%s'...", ar->prevEnum.filename); + MojoPlatform_switchBin(img, imglen); // no return on success. + logError("...Switch binary failed."); + } // if + free(img); + } // if +} // trySwitchBinary + + +static void trySwitchBinaries(void) +{ + if (cmdlinestr("nobinswitch", "MOJOSETUP_NOBINSWITCH", NULL) != NULL) + return; // we are already switched or the user is preventing it. + + setenv("MOJOSETUP_NOSWITCHBIN", "1", 1); + setenv("MOJOSETUP_BASE", GBaseArchivePath, 1); + + if (GBaseArchive->enumerate(GBaseArchive)) + { + const MojoArchiveEntry *entinfo; + while ((entinfo = GBaseArchive->enumNext(GBaseArchive)) != NULL) + { + if (entinfo->type != MOJOARCHIVE_ENTRY_FILE) + continue; + + if (strncmp(entinfo->filename, "arch/", 5) != 0) + continue; + + trySwitchBinary(GBaseArchive); + } // while + } // if + +} // trySwitchBinaries +#endif + + static boolean initEverything(void) { MojoLog_initLogging(); @@ -75,7 +125,9 @@ if (!MojoArchive_initBaseArchive()) panic("Initial setup failed. Cannot continue."); - else if (!MojoGui_initGuiPlugin()) + trySwitchBinaries(); // may not return. + + if (!MojoGui_initGuiPlugin()) panic("Initial GUI setup failed. Cannot continue."); else if (!MojoLua_initLua()) Modified: trunk/platform.h =================================================================== --- trunk/platform.h 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/platform.h 2007-05-20 23:24:36 UTC (rev 300) @@ -22,6 +22,9 @@ char *MojoPlatform_appBinaryPath(void); // Caller must free returned string! +char *MojoPlatform_currentWorkingDir(void); + +// Caller must free returned string! char *MojoPlatform_homedir(void); uint32 MojoPlatform_ticks(void); @@ -97,6 +100,12 @@ void *MojoPlatform_dlsym(void *lib, const char *sym); void MojoPlatform_dlclose(void *lib); +#if !SUPPORT_MULTIARCH +#define MojoPlatform_switchBin(img, len) +#else +void MojoPlatform_switchBin(const uint8 *img, size_t len); +#endif + // Put the calling process to sleep for at least (ticks) milliseconds. // This is meant to yield the CPU while spinning in a loop that is polling // for input, etc. Pumping the GUI event queue happens elsewhere, not here. Modified: trunk/platform_unix.c =================================================================== --- trunk/platform_unix.c 2007-05-20 11:14:27 UTC (rev 299) +++ trunk/platform_unix.c 2007-05-20 23:24:36 UTC (rev 300) @@ -56,7 +56,7 @@ static struct timeval startup_time; -static char *getCurrentWorkingDir(void) +char *MojoPlatform_currentWorkingDir(void) { char *retval = NULL; size_t len; @@ -79,7 +79,7 @@ free(retval); return NULL; -} // getCurrentWorkingDir +} // MojoPlatform_currentWorkingDir static void *guaranteeAllocation(void *ptr, size_t len, size_t *_alloclen) @@ -123,7 +123,7 @@ retval = xstrdup(cwd); else { - if ((retval = getCurrentWorkingDir()) == NULL) + if ((retval = MojoPlatform_currentWorkingDir()) == NULL) return NULL; } // else len = strlen(retval); @@ -715,7 +715,42 @@ } // MojoPlatform_dlclose +#if SUPPORT_MULTIARCH +void MojoPlatform_switchBin(const uint8 *img, size_t len) +{ + const char *dirs[] = { "/dev/shm", getenv("TMPDIR"), P_tmpdir, "/tmp" }; + const char *tmpl = "mojosetup-switch-bin-XXXXXX"; + char fname[PATH_MAX]; + int i = 0; + for (i = 0; i < STATICARRAYLEN(dirs); i++) + { + if (testTmpDir(dirs[i], fname, len, tmpl)) + { + const int fd = mkstemp(fname); + if (fd != -1) + { + const size_t bw = write(fd, img, len); + const int rc = close(fd); + if ((bw == len) && (rc != -1)) + { + const char *tmpstr = GArgv[0]; + chmod(fname, 0700); + GArgv[0] = fname; + execv(fname, (char * const *) GArgv); + // only hits this line if process wasn't replaced. + GArgv[0] = tmpstr; + } // if + unlink(fname); + } // if + } // if + } // for + + // couldn't replace current process. +} // MojoPlatform_switchBin +#endif + + static void signal_catcher(int sig) { static boolean first_shot = true; From DONOTREPLY at icculus.org Sun May 20 21:07:38 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 20 May 2007 21:07:38 -0400 Subject: r301 - trunk Message-ID: <20070521010738.7066.qmail@icculus.org> Author: icculus Date: 2007-05-20 21:07:38 -0400 (Sun, 20 May 2007) New Revision: 301 Modified: trunk/mojosetup.c Log: Whoops, typo. Modified: trunk/mojosetup.c =================================================================== --- trunk/mojosetup.c 2007-05-20 23:24:36 UTC (rev 300) +++ trunk/mojosetup.c 2007-05-21 01:07:38 UTC (rev 301) @@ -88,7 +88,7 @@ if (cmdlinestr("nobinswitch", "MOJOSETUP_NOBINSWITCH", NULL) != NULL) return; // we are already switched or the user is preventing it. - setenv("MOJOSETUP_NOSWITCHBIN", "1", 1); + setenv("MOJOSETUP_NOBINSWITCH", "1", 1); setenv("MOJOSETUP_BASE", GBaseArchivePath, 1); if (GBaseArchive->enumerate(GBaseArchive)) From DONOTREPLY at icculus.org Sat May 26 15:46:32 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 15:46:32 -0400 Subject: r302 - trunk Message-ID: <20070526194632.7899.qmail@icculus.org> Author: icculus Date: 2007-05-26 15:46:31 -0400 (Sat, 26 May 2007) New Revision: 302 Modified: trunk/gui_ncurses.c Log: ncurses UI: better coloring for the buttons. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-21 01:07:38 UTC (rev 301) +++ trunk/gui_ncurses.c 2007-05-26 19:46:31 UTC (rev 302) @@ -46,6 +46,7 @@ MOJOCOLOR_TEXT, MOJOCOLOR_BUTTONHOVER, MOJOCOLOR_BUTTONNORMAL, + MOJOCOLOR_BUTTONBORDER, MOJOCOLOR_TODO, MOJOCOLOR_DONE, } MojoColor; @@ -159,23 +160,35 @@ static void drawButton(MojoBox *mojobox, int button) { const boolean hover = (mojobox->hoverover == button); + int borderattr = 0; WINDOW *win = mojobox->buttons[button]; const char *str = mojobox->buttontext[button]; int w, h; getmaxyx(win, h, w); - if (hover) + if (!hover) + wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONNORMAL)); + else + { + borderattr = COLOR_PAIR(MOJOCOLOR_BUTTONBORDER) | A_BOLD; wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); - else - wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONNORMAL)); + } // else wclear(win); wmove(win, 0, 0); - waddch(win, '<'); + waddch(win, borderattr | '<'); wmove(win, 0, w-1); - waddch(win, '>'); + waddch(win, borderattr | '>'); wmove(win, 0, 2); - waddstr(win, str); + + if (!hover) + waddstr(win, str); + else + { + wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); + waddstr(win, str); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); + } // else } // drawButton @@ -526,8 +539,9 @@ init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERSHADOW, COLOR_BLACK, COLOR_BLACK); init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); - init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_WHITE, COLOR_BLUE); + init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_YELLOW, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_BUTTONBORDER, COLOR_WHITE, COLOR_BLUE); init_pair(MOJOCOLOR_DONE, COLOR_YELLOW, COLOR_RED); init_pair(MOJOCOLOR_TODO, COLOR_CYAN, COLOR_BLUE); From DONOTREPLY at icculus.org Sat May 26 16:13:21 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 16:13:21 -0400 Subject: r303 - trunk Message-ID: <20070526201321.15527.qmail@icculus.org> Author: icculus Date: 2007-05-26 16:13:20 -0400 (Sat, 26 May 2007) New Revision: 303 Modified: trunk/gui_ncurses.c Log: ncurses UI: color fixes. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 19:46:31 UTC (rev 302) +++ trunk/gui_ncurses.c 2007-05-26 20:13:20 UTC (rev 303) @@ -42,7 +42,6 @@ MOJOCOLOR_BACKGROUND=1, MOJOCOLOR_BORDERTOP, MOJOCOLOR_BORDERBOTTOM, - MOJOCOLOR_BORDERSHADOW, MOJOCOLOR_TEXT, MOJOCOLOR_BUTTONHOVER, MOJOCOLOR_BUTTONNORMAL, @@ -537,7 +536,6 @@ init_pair(MOJOCOLOR_BACKGROUND, COLOR_CYAN, COLOR_BLUE); init_pair(MOJOCOLOR_BORDERTOP, COLOR_WHITE, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); - init_pair(MOJOCOLOR_BORDERSHADOW, COLOR_BLACK, COLOR_BLACK); init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_YELLOW, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); @@ -849,10 +847,10 @@ selected = (mojobox->textpos+maxh) - 1; y = selected - lasttextpos; - wattron(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattron(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); mvwhline(mojobox->textwin, y, 0, ' ', maxw); mvwaddstr(mojobox->textwin, y, 0, mojobox->textlines[selected]); - wattroff(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattroff(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); wrefresh(mojobox->textwin); } // if @@ -895,10 +893,10 @@ mvwaddstr(win, y+1, 0, mojobox->textlines[selected+1]); wattroff(win, COLOR_PAIR(MOJOCOLOR_TEXT)); } // else - wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); mvwhline(win, y, 0, ' ', maxw); mvwaddstr(win, y, 0, mojobox->textlines[selected]); - wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); wrefresh(win); } // if } // else if @@ -923,10 +921,10 @@ mvwaddstr(win, y-1, 0, mojobox->textlines[selected-1]); wattroff(win, COLOR_PAIR(MOJOCOLOR_TEXT)); } // else - wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattron(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); mvwhline(win, y, 0, ' ', maxw); mvwaddstr(win, y, 0, mojobox->textlines[selected]); - wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER) | A_BOLD); wrefresh(win); } // if } // else if From DONOTREPLY at icculus.org Sat May 26 16:23:05 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 16:23:05 -0400 Subject: r304 - trunk Message-ID: <20070526202305.18269.qmail@icculus.org> Author: icculus Date: 2007-05-26 16:23:04 -0400 (Sat, 26 May 2007) New Revision: 304 Modified: trunk/gui_ncurses.c Log: curses UI: changed titlebar color, cleaned up coordinate calculations a little. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 20:13:20 UTC (rev 303) +++ trunk/gui_ncurses.c 2007-05-26 20:23:04 UTC (rev 304) @@ -42,6 +42,7 @@ MOJOCOLOR_BACKGROUND=1, MOJOCOLOR_BORDERTOP, MOJOCOLOR_BORDERBOTTOM, + MOJOCOLOR_BORDERTITLE, MOJOCOLOR_TEXT, MOJOCOLOR_BUTTONHOVER, MOJOCOLOR_BUTTONNORMAL, @@ -225,6 +226,8 @@ int scrw, scrh; int len = 0; int buttonsw = 0; + int x = 0; + int y = 0; int h = 0; int w = 0; int texth = 0; @@ -277,7 +280,9 @@ if (h > scrh) h = scrh; - win = retval->mainwin = newwin(h, w, ((scrh - h) / 2)+1, (scrw - w) / 2); + x = (scrw - w) / 2; + y = ((scrh - h) / 2) + 1; + win = retval->mainwin = newwin(h, w, y, x); keypad(win, TRUE); nodelay(win, ndelay); wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); @@ -298,15 +303,17 @@ len = strcells(retval->title); wmove(win, 0, ((w-len)/2)-1); - waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_TEXT)); + wattron(win, COLOR_PAIR(MOJOCOLOR_BORDERTITLE) | A_BOLD); + waddch(win, ' '); waddstr(win, retval->title); wmove(win, 0, ((w-len)/2)+len); - waddch(win, ' ' | COLOR_PAIR(MOJOCOLOR_TEXT)); + waddch(win, ' '); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BORDERTITLE) | A_BOLD); if (bcount > 0) { - const int buttony = (((scrh - h) / 2) + h)-1; - int buttonx = (((scrw - w) / 2) + w) - ((w - buttonsw) / 2); + const int buttony = (y + h) - 2; + int buttonx = (x + w) - ((w - buttonsw) / 2); wmove(win, h-3, 1); whline(win, ACS_HLINE | A_BOLD | COLOR_PAIR(MOJOCOLOR_BORDERTOP), w-2); for (i = 0; i < bcount; i++) @@ -322,7 +329,7 @@ texth = h-2; if (bcount > 0) texth -= 2; - win = retval->textwin = newwin(texth, w-4, ((scrh-h)/2)+2, ((scrw-w)/2)+2); + win = retval->textwin = newwin(texth, w-4, y+1, x+2); keypad(win, TRUE); nodelay(win, ndelay); wbkgdset(win, COLOR_PAIR(MOJOCOLOR_TEXT)); @@ -536,6 +543,7 @@ init_pair(MOJOCOLOR_BACKGROUND, COLOR_CYAN, COLOR_BLUE); init_pair(MOJOCOLOR_BORDERTOP, COLOR_WHITE, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_BORDERTITLE, COLOR_YELLOW, COLOR_WHITE); init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_YELLOW, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); From DONOTREPLY at icculus.org Sat May 26 16:29:20 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 16:29:20 -0400 Subject: r305 - trunk Message-ID: <20070526202920.19858.qmail@icculus.org> Author: icculus Date: 2007-05-26 16:29:19 -0400 (Sat, 26 May 2007) New Revision: 305 Modified: trunk/gui_ncurses.c Log: ncurses UI: Draw an hline below the installer title. This matches what the Linux kernel's "make menuconfig" does, and it looks pretty good. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 20:23:04 UTC (rev 304) +++ trunk/gui_ncurses.c 2007-05-26 20:29:19 UTC (rev 305) @@ -210,8 +210,11 @@ wclear(win); if (title != NULL) { + int w, h; + getmaxyx(win, h, w); wattron(win, COLOR_PAIR(MOJOCOLOR_BACKGROUND) | A_BOLD); mvwaddstr(win, 0, 0, title); + mvwhline(win, 1, 1, ACS_HLINE, w-2); wattroff(win, COLOR_PAIR(MOJOCOLOR_BACKGROUND) | A_BOLD); } // if } // drawBackground @@ -277,8 +280,8 @@ if (bcount > 0) h += 2; - if (h > scrh) - h = scrh; + if (h > scrh-2) + h = scrh-2; x = (scrw - w) / 2; y = ((scrh - h) / 2) + 1; From DONOTREPLY at icculus.org Sat May 26 16:59:00 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 16:59:00 -0400 Subject: r306 - trunk Message-ID: <20070526205900.29414.qmail@icculus.org> Author: icculus Date: 2007-05-26 16:59:00 -0400 (Sat, 26 May 2007) New Revision: 306 Modified: trunk/gui_ncurses.c Log: ncurses UI: Put a percentage meter on the window if text can be scrolled. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 20:29:19 UTC (rev 305) +++ trunk/gui_ncurses.c 2007-05-26 20:59:00 UTC (rev 306) @@ -195,13 +195,24 @@ static void drawText(MojoBox *mojobox) { int i; + const int tcount = mojobox->textlinecount; int pos = mojobox->textpos; int w, h; WINDOW *win = mojobox->textwin; getmaxyx(win, h, w); + wclear(mojobox->textwin); // !!! FIXME: flickers... - for (i = 0; (pos < mojobox->textlinecount) && (i < h); i++, pos++) + for (i = 0; (pos < tcount) && (i < h); i++, pos++) mvwaddstr(win, i, 0, mojobox->textlines[pos]); + + if (tcount > h) + { + const int pct = (int) ((((double) pos) / ((double) tcount)) * 100.0); + win = mojobox->mainwin; + wattron(win, COLOR_PAIR(MOJOCOLOR_BORDERTITLE) | A_BOLD); + mvwprintw(win, h+1, w-5, "(%3d%%)", pct); + wattroff(win, COLOR_PAIR(MOJOCOLOR_BORDERTITLE) | A_BOLD); + } // if } // drawText From DONOTREPLY at icculus.org Sat May 26 18:04:23 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 18:04:23 -0400 Subject: r307 - trunk Message-ID: <20070526220423.13351.qmail@icculus.org> Author: icculus Date: 2007-05-26 18:04:21 -0400 (Sat, 26 May 2007) New Revision: 307 Modified: trunk/gui_ncurses.c Log: ncurses UI: hooked up extremely basic mouse interface. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 20:59:00 UTC (rev 306) +++ trunk/gui_ncurses.c 2007-05-26 22:04:21 UTC (rev 307) @@ -407,6 +407,7 @@ static int upkeepBox(MojoBox **_mojobox, int ch) { static boolean justResized = false; + MEVENT mevt; int w, h; MojoBox *mojobox = *_mojobox; if (mojobox == NULL) @@ -516,6 +517,24 @@ *_mojobox = mojobox; justResized = true; // !!! FIXME: kludge. return -1; + + case KEY_MOUSE: + if ((getmouse(&mevt) == OK) && (mevt.bstate & BUTTON1_CLICKED)) + { + int i; + for (i = 0; i < mojobox->buttoncount; i++) + { + int x1, y1, x2, y2; + getbegyx(mojobox->buttons[i], y1, x1); + getmaxyx(mojobox->buttons[i], y2, x2); + x2 += x1; + y2 += y1; + if ( (mevt.x >= x1) && (mevt.x < x2) && + (mevt.y >= y1) && (mevt.y < y2) ) + return i; + } // for + } // if + return -1; } // switch return -1; @@ -554,6 +573,7 @@ keypad(stdscr, TRUE); noecho(); start_color(); + mousemask(BUTTON1_CLICKED, NULL); init_pair(MOJOCOLOR_BACKGROUND, COLOR_CYAN, COLOR_BLUE); init_pair(MOJOCOLOR_BORDERTOP, COLOR_WHITE, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); From DONOTREPLY at icculus.org Sat May 26 18:42:56 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 18:42:56 -0400 Subject: r308 - trunk Message-ID: <20070526224256.24657.qmail@icculus.org> Author: icculus Date: 2007-05-26 18:42:55 -0400 (Sat, 26 May 2007) New Revision: 308 Modified: trunk/gui_ncurses.c Log: Fixed some redraw things to make them more efficient...text box no longer flickers while scrolling, too. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 22:04:21 UTC (rev 307) +++ trunk/gui_ncurses.c 2007-05-26 22:42:55 UTC (rev 308) @@ -174,7 +174,7 @@ wbkgdset(win, COLOR_PAIR(MOJOCOLOR_BUTTONHOVER)); } // else - wclear(win); + werase(win); wmove(win, 0, 0); waddch(win, borderattr | '<'); wmove(win, 0, w-1); @@ -201,7 +201,7 @@ WINDOW *win = mojobox->textwin; getmaxyx(win, h, w); - wclear(mojobox->textwin); // !!! FIXME: flickers... + werase(mojobox->textwin); // !!! FIXME: flickers... for (i = 0; (pos < tcount) && (i < h); i++, pos++) mvwaddstr(win, i, 0, mojobox->textlines[pos]); @@ -350,15 +350,17 @@ drawText(retval); drawBackground(stdscr); - wrefresh(stdscr); - wrefresh(retval->mainwin); - wrefresh(retval->textwin); + wnoutrefresh(stdscr); + wnoutrefresh(retval->mainwin); + wnoutrefresh(retval->textwin); for (i = 0; i < bcount; i++) { drawButton(retval, i); - wrefresh(retval->buttons[i]); + wnoutrefresh(retval->buttons[i]); } // for + doupdate(); // push it all to the screen. + return retval; } // makeBox From DONOTREPLY at icculus.org Sat May 26 18:43:38 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 26 May 2007 18:43:38 -0400 Subject: r309 - trunk Message-ID: <20070526224338.24942.qmail@icculus.org> Author: icculus Date: 2007-05-26 18:43:38 -0400 (Sat, 26 May 2007) New Revision: 309 Modified: trunk/gui_ncurses.c Log: Removed FIXME comment that has been fixed. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 22:42:55 UTC (rev 308) +++ trunk/gui_ncurses.c 2007-05-26 22:43:38 UTC (rev 309) @@ -201,7 +201,7 @@ WINDOW *win = mojobox->textwin; getmaxyx(win, h, w); - werase(mojobox->textwin); // !!! FIXME: flickers... + werase(mojobox->textwin); for (i = 0; (pos < tcount) && (i < h); i++, pos++) mvwaddstr(win, i, 0, mojobox->textlines[pos]); From DONOTREPLY at icculus.org Sun May 27 01:05:36 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 01:05:36 -0400 Subject: r310 - trunk Message-ID: <20070527050536.27649.qmail@icculus.org> Author: icculus Date: 2007-05-27 01:05:33 -0400 (Sun, 27 May 2007) New Revision: 310 Modified: trunk/gui_ncurses.c Log: ncurses UI: let ctrl-L redraw the whole screen, in case of corruption. Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-26 22:43:38 UTC (rev 309) +++ trunk/gui_ncurses.c 2007-05-27 05:05:33 UTC (rev 310) @@ -410,6 +410,7 @@ { static boolean justResized = false; MEVENT mevt; + int i; int w, h; MojoBox *mojobox = *_mojobox; if (mojobox == NULL) @@ -507,6 +508,21 @@ } // if return -1; + case 12: // ctrl-L...redraw everything on the screen. + redrawwin(stdscr); + wnoutrefresh(stdscr); + redrawwin(mojobox->mainwin); + wnoutrefresh(mojobox->mainwin); + redrawwin(mojobox->textwin); + wnoutrefresh(mojobox->textwin); + for (i = 0; i < mojobox->buttoncount; i++) + { + redrawwin(mojobox->buttons[i]); + wnoutrefresh(mojobox->buttons[i]); + } // for + doupdate(); // push it all to the screen. + return -1; + case KEY_RESIZE: mojobox = makeBox(mojobox->title, mojobox->text, mojobox->buttontext, mojobox->buttoncount, From DONOTREPLY at icculus.org Sun May 27 02:01:08 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 02:01:08 -0400 Subject: r311 - in trunk: . scripts Message-ID: <20070527060108.18806.qmail@icculus.org> Author: icculus Date: 2007-05-27 02:01:08 -0400 (Sun, 27 May 2007) New Revision: 311 Modified: trunk/gui_ncurses.c trunk/scripts/localization.lua Log: curses UI: implemented Destination page and a generic text input box for it. Still more scary code. :) Modified: trunk/gui_ncurses.c =================================================================== --- trunk/gui_ncurses.c 2007-05-27 05:05:33 UTC (rev 310) +++ trunk/gui_ncurses.c 2007-05-27 06:01:08 UTC (rev 311) @@ -44,6 +44,7 @@ MOJOCOLOR_BORDERBOTTOM, MOJOCOLOR_BORDERTITLE, MOJOCOLOR_TEXT, + MOJOCOLOR_TEXTENTRY, MOJOCOLOR_BUTTONHOVER, MOJOCOLOR_BUTTONNORMAL, MOJOCOLOR_BUTTONBORDER, @@ -597,6 +598,7 @@ init_pair(MOJOCOLOR_BORDERBOTTOM, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BORDERTITLE, COLOR_YELLOW, COLOR_WHITE); init_pair(MOJOCOLOR_TEXT, COLOR_BLACK, COLOR_WHITE); + init_pair(MOJOCOLOR_TEXTENTRY, COLOR_WHITE, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONHOVER, COLOR_YELLOW, COLOR_BLUE); init_pair(MOJOCOLOR_BUTTONNORMAL, COLOR_BLACK, COLOR_WHITE); init_pair(MOJOCOLOR_BUTTONBORDER, COLOR_WHITE, COLOR_BLUE); @@ -750,7 +752,11 @@ int rc = -1; if ((opts != NULL) && (target > *line)) { - if (++(*line) == target) + const char *desc = opts->description; + boolean blanked = false; + blanked = ( (opts->is_group_parent) && ((!desc) || (!(*desc))) ); + + if ((!blanked) && (++(*line) == target)) { const boolean toggled = ((opts->value) ? false : true); @@ -797,11 +803,15 @@ { if (opts != NULL) { - char *spacebuf = (char *) entry->xmalloc(maxw+1); - char *buf = (char *) entry->xmalloc(maxw+1); + const char *desc = opts->description; + char *spacebuf = (char *) entry->xmalloc(maxw + 1); + char *buf = (char *) entry->xmalloc(maxw + 1); int len = 0; - int spacing = 1+level; + int spacing = level * 2; + if ((desc != NULL) && (*desc == '\0')) + desc = NULL; + if (spacing > (maxw-5)) spacing = 0; // oh well. @@ -809,13 +819,15 @@ memset(spacebuf, ' ', spacing); // null-term'd by xmalloc(). if (opts->is_group_parent) - len = snprintf(buf, maxw-2, "%s%s", spacebuf, opts->description); + { + if (desc != NULL) + len = snprintf(buf, maxw-2, "%s%s", spacebuf, desc); + } // if else { (*line)++; len = snprintf(buf, maxw-2, "%s[%c] %s", spacebuf, - opts->value ? 'X' : ' ', - opts->description); + opts->value ? 'X' : ' ', desc); } // else free(spacebuf); @@ -823,21 +835,30 @@ if (len >= maxw-1) strcpy(buf+(maxw-4), "..."); // !!! FIXME: Unicode issues! - *lines = (char*) entry->xrealloc(*lines, strlen(*lines)+strlen(buf)+2); - strcat(*lines, buf); - strcat(*lines, "\n"); // I'm sorry, Joel Spolsky! + if (len > 0) + { + const size_t newlen = strlen(*lines) + strlen(buf) + 2; + *lines = (char*) entry->xrealloc(*lines, newlen); + strcat(*lines, buf); + strcat(*lines, "\n"); // I'm sorry, Joel Spolsky! + } // if if ((opts->value) || (opts->is_group_parent)) - build_options(opts->child, line, level+1, maxw, lines); + { + int newlev = level + 1; + if ((opts->is_group_parent) && (desc == NULL)) + newlev--; + build_options(opts->child, line, newlev, maxw, lines); + } // if + build_options(opts->next_sibling, line, level, maxw, lines); } // if } // build_options -static int MojoGui_ncurses_options(MojoGuiSetupOptions *opts, - boolean can_back, boolean can_fwd) +static int optionBox(const char *title, MojoGuiSetupOptions *opts, + boolean can_back, boolean can_fwd) { - char *title = entry->xstrdup(entry->_("Options")); MojoBox *mojobox = NULL; char *buttons[4] = { NULL, NULL, NULL, NULL }; boolean ignoreerr = false; @@ -879,7 +900,7 @@ int maxw, maxh; getmaxyx(stdscr, maxh, maxw); char *text = entry->xstrdup(""); - build_options(opts, &line, 1, maxw-6, &text); + build_options(opts, &line, 0, maxw-6, &text); mojobox = makeBox(title, text, buttons, bcount, false, true); free(text); @@ -1017,28 +1038,229 @@ for (i = 0; i < bcount; i++) free(buttons[i]); - free(title); - if (rc == backbutton) return -1; else if (rc == fwdbutton) return 1; return 0; // error? Cancel? +} // optionBox + + +static int MojoGui_ncurses_options(MojoGuiSetupOptions *opts, + boolean can_back, boolean can_fwd) +{ + char *title = entry->xstrdup(entry->_("Options")); + int rc = optionBox(title, opts, can_back, can_fwd); + free(title); + return rc; } // MojoGui_ncurses_options -static char *MojoGui_ncurses_destination(const char **recommends, int recnum, - int *command, boolean can_back, - boolean can_fwd) +static char *inputBox(const char *prompt, int *command, boolean can_back) { - // !!! FIXME: clearly this isn't right. - if (recnum > 0) + char *text = NULL; + int w, h; + int i; + int ch; + int rc = -1; + MojoBox *mojobox = NULL; + size_t retvalalloc = 64; + size_t retvallen = 0; + char *retval = (char *) entry->xmalloc(retvalalloc); + char *buttons[3] = { NULL, NULL, NULL }; + int drawpos = 0; + int drawlen = 0; + int bcount = 0; + int backbutton = -1; + int cancelbutton = -1; + + buttons[bcount++] = entry->xstrdup(entry->_("OK")); + + if (can_back) { + backbutton = bcount++; + buttons[backbutton] = entry->xstrdup(entry->_("Back")); + } // if + + cancelbutton = bcount++; + buttons[cancelbutton] = entry->xstrdup(entry->_("Cancel")); + + getmaxyx(stdscr, h, w); + w -= 10; + text = (char *) entry->xmalloc(w+4); + text[0] = '\n'; + memset(text+1, ' ', w); + text[w+1] = '\n'; + text[w+2] = ' '; + text[w+3] = '\0'; + mojobox = makeBox(prompt, text, buttons, bcount, false, false); + free(text); + text = NULL; + + do + { + getmaxyx(mojobox->textwin, h, w); + w -= 2; + + if (drawpos >= retvallen) + drawpos = 0; + while ((drawlen = (retvallen - drawpos)) >= w) + drawpos += 5; + + wattron(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_TEXTENTRY) | A_BOLD); + mvwhline(mojobox->textwin, 1, 1, ' ', w); // blank line... + mvwaddstr(mojobox->textwin, 1, 1, retval + drawpos); + wattroff(mojobox->textwin, COLOR_PAIR(MOJOCOLOR_TEXTENTRY) | A_BOLD); + wrefresh(mojobox->textwin); + + ch = wgetch(mojobox->mainwin); + if ( (ch > 0) && (ch < KEY_MIN) && (isprint(ch)) ) // regular key. + { + if (retvalalloc <= retvallen) + { + retvalalloc *= 2; + retval = entry->xrealloc(retval, retvalalloc); + } // if + retval[retvallen++] = (char) ch; + retval[retvallen] = '\0'; + } // if + + else if (ch == KEY_BACKSPACE) + { + if (retvallen > 0) + retval[--retvallen] = '\0'; + } // else if + + else if (ch == KEY_RESIZE) + { + wrefresh(stdscr); + getmaxyx(stdscr, h, w); + w -= 10; + text = (char *) entry->xrealloc(mojobox->text, w+4); + text[0] = '\n'; + memset(text+1, ' ', w); + text[w+1] = '\n'; + text[w+2] = ' '; + text[w+3] = '\0'; + mojobox->text = text; + text = NULL; + upkeepBox(&mojobox, KEY_RESIZE); // let real resize happen... + } // else if + + else + { + rc = upkeepBox(&mojobox, ch); + } // else + } while (rc == -1); + + freeBox(mojobox, true); + + for (i = 0; i < bcount; i++) + free(buttons[i]); + + if (rc == backbutton) + *command = -1; + else if (rc == cancelbutton) + *command = 0; + else *command = 1; - return entry->xstrdup(recommends[0]); + + if (*command <= 0) + { + free(retval); + retval = NULL; } // if + return retval; +} // inputBox + + +static char *MojoGui_ncurses_destination(const char **recommends, int recnum, + int *command, boolean can_back, + boolean can_fwd) +{ + char *retval = NULL; + while (true) + { + const char *localized = NULL; + char *title = NULL; + char *choosetxt = NULL; + int rc = 0; + + if (recnum > 0) // recommendations available. + { + int chosen = -1; + MojoGuiSetupOptions opts; + MojoGuiSetupOptions *prev = &opts; + MojoGuiSetupOptions *next = NULL; + MojoGuiSetupOptions *opt = NULL; + memset(&opts, '\0', sizeof (MojoGuiSetupOptions)); + int i; + for (i = 0; i < recnum; i++) + { + opt = (MojoGuiSetupOptions *) entry->xmalloc(sizeof (*opt)); + opt->description = recommends[i]; + opt->size = -1; + prev->next_sibling = opt; + prev = opt; + } // for + + choosetxt = entry->xstrdup(entry->_("(I want to specify a path.)")); + opt = (MojoGuiSetupOptions *) entry->xmalloc(sizeof (*opt)); + opt->description = choosetxt; + opt->size = -1; + prev->next_sibling = opt; + prev = opt; + + opts.child = opts.next_sibling; // fix this field. + opts.next_sibling = NULL; + opts.value = opts.child->value = true; // make first default. + opts.is_group_parent = true; + opts.size = -1; + + title = entry->xstrdup(entry->_("Destination")); + rc = optionBox(title, &opts, can_back, can_fwd); + free(title); + + for (i = 0, next = opts.child; next != NULL; i++) + { + if (next->value) + chosen = i; + prev = next; + next = prev->next_sibling; + free(prev); + } // for + + free(choosetxt); + + *command = rc; + if (rc <= 0) // back or cancel. + return NULL; + + else if ((chosen >= 0) && (chosen < recnum)) // a specific entry + return entry->xstrdup(recommends[chosen]); + } // if + + // either no recommendations or user wants to enter own path... + + localized = entry->_("Enter path where files will be installed."); + title = entry->xstrdup(localized); + retval = inputBox(title, &rc, (can_back) || (recnum > 0)); + free(title); + + // user cancelled or entered text, or hit back and we aren't falling + // back to the option list...return. + if ( (rc >= 0) || ((rc == -1) && (recnum == 0)) ) + { + *command = rc; + return retval; + } // if + + // falling back to the option list again...loop. + } // while + + // Shouldn't ever hit this, but just in case... *command = 0; return NULL; } // MojoGui_ncurses_destination Modified: trunk/scripts/localization.lua =================================================================== --- trunk/scripts/localization.lua 2007-05-27 05:05:33 UTC (rev 310) +++ trunk/scripts/localization.lua 2007-05-27 06:01:08 UTC (rev 311) @@ -139,6 +139,9 @@ ["Please insert '%s'"] = { }; + + ["(I want to specify a path.)"] = { + }; }; -- end of localization.lua ... From DONOTREPLY at icculus.org Sun May 27 11:56:12 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 11:56:12 -0400 Subject: r312 - in trunk: . scripts Message-ID: <20070527155612.29562.qmail@icculus.org> Author: icculus Date: 2007-05-27 11:56:12 -0400 (Sun, 27 May 2007) New Revision: 312 Added: trunk/checksum_crc32.c trunk/checksum_md5.c trunk/checksum_sha1.c Modified: trunk/CMakeLists.txt trunk/fileio.c trunk/fileio.h trunk/lua_glue.c trunk/mojosetup.c trunk/scripts/mojosetup_mainline.lua trunk/universal.h Log: Added support for various types of checksums. Modified: trunk/CMakeLists.txt =================================================================== --- trunk/CMakeLists.txt 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/CMakeLists.txt 2007-05-27 15:56:12 UTC (rev 312) @@ -178,6 +178,9 @@ fileio.c archive_zip.c archive_tar.c + checksum_crc32.c + checksum_md5.c + checksum_sha1.c platform_unix.c platform_beos.c lua_glue.c @@ -266,6 +269,27 @@ ENDIF(MOJOSETUP_LUALIB_PACKAGE) +# Checksums... + +# BINARY SIZE += !!! FIXME: check this. +OPTION(MOJOSETUP_CHECKSUM_CRC32 "Enable CRC-32 checksum support" TRUE) +IF(MOJOSETUP_CHECKSUM_CRC32) + ADD_DEFINITIONS(-DSUPPORT_CRC32=1) +ENDIF(MOJOSETUP_CHECKSUM_CRC32) + +# BINARY SIZE += !!! FIXME: check this. +OPTION(MOJOSETUP_CHECKSUM_MD5 "Enable MD5 checksum support" TRUE) +IF(MOJOSETUP_CHECKSUM_MD5) + ADD_DEFINITIONS(-DSUPPORT_MD5=1) +ENDIF(MOJOSETUP_CHECKSUM_MD5) + +# BINARY SIZE += !!! FIXME: check this. +OPTION(MOJOSETUP_CHECKSUM_SHA1 "Enable SHA-1 checksum support" TRUE) +IF(MOJOSETUP_CHECKSUM_SHA1) + ADD_DEFINITIONS(-DSUPPORT_SHA1=1) +ENDIF(MOJOSETUP_CHECKSUM_SHA1) + + # GUI plugins... # BINARY SIZE += 2.5 Added: trunk/checksum_crc32.c =================================================================== --- trunk/checksum_crc32.c (rev 0) +++ trunk/checksum_crc32.c 2007-05-27 15:56:12 UTC (rev 312) @@ -0,0 +1,81 @@ +#include "universal.h" + +#if SUPPORT_CRC32 + +void MojoCrc32_init(MojoCrc32 *context) +{ + *context = (MojoCrc32) 0xFFFFFFFF; +} // MojoCrc32_init + + +void MojoCrc32_append(MojoCrc32 *_crc, const uint8 *buf, uint32 len) +{ + uint32 crc = (uint32) *_crc; + + int n; + for (n = 0; n < len; n++) + { + uint32 xorval = (uint32) ((crc ^ buf[n]) & 0xFF); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + xorval = ((xorval & 1) ? (0xEDB88320 ^ (xorval >> 1)) : (xorval >> 1)); + crc = xorval ^ (crc >> 8); + } // for + + *_crc = (MojoCrc32) crc; +} // MojoCrc32_append + + +void MojoCrc32_finish(MojoCrc32 *context, uint32 *digest) +{ + *digest = (*context ^ 0xFFFFFFFF); +} // MojoCrc32_finish + + +#endif // SUPPORT_CRC32 + +#if TEST_CRC32 +int main(int argc, char **argv) +{ + int i = 0; + for (i = 1; i < argc; i++) + { + FILE *in = NULL; + MojoCrc32 ctx; + MojoCrc32_init(&ctx); + in = fopen(argv[i], "rb"); + if (!in) + perror("fopen"); + else + { + uint32 digest = 0; + int err = 0; + while ( (!err) && (!feof(in)) ) + { + uint8 buf[1024]; + size_t rc = fread(buf, 1, sizeof (buf), in); + if (rc > 0) + MojoCrc32_append(&ctx, buf, rc); + err = ferror(in); + } // while + + if (err) + perror("fread"); + fclose(in); + MojoCrc32_finish(&ctx, &digest); + if (!err) + printf("%s: %X\n", argv[i], (unsigned int) digest); + } // else + } // for + + return 0; +} // main +#endif + +// end of checksum_crc32.c ... + Added: trunk/checksum_md5.c =================================================================== --- trunk/checksum_md5.c (rev 0) +++ trunk/checksum_md5.c 2007-05-27 15:56:12 UTC (rev 312) @@ -0,0 +1,441 @@ +#include "universal.h" + +#if SUPPORT_MD5 + +// MD5 code originally from http://sourceforge.net/projects/libmd5-rfc/ +// License: zlib. +// I cleaned it up a little for MojoSetup's specific purposes. --ryan. + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost at aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +//#ifdef ARCH_IS_BIG_ENDIAN +//# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +//#else +//# define BYTE_ORDER 0 +//#endif +#if PLATFORM_BIGENDIAN +# define BYTE_ORDER 1 +#else +# define BYTE_ORDER -1 +#endif + +#define T_MASK ((uint32)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +MojoMd5_process(MojoMd5 *pms, const uint8 *data /*[64]*/) +{ + uint32 + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + uint32 t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + uint32 X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + uint32 xbuf[16]; + const uint32 *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const uint8 *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const uint8 *)0) & 3)) { + /* data are properly aligned */ + X = (const uint32 *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const uint8 *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +MojoMd5_init(MojoMd5 *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +MojoMd5_append(MojoMd5 *pms, const uint8 *data, int nbytes) +{ + const uint8 *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + uint32 nbits = (uint32)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + MojoMd5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + MojoMd5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +MojoMd5_finish(MojoMd5 *pms, uint8 digest[16]) +{ + const uint8 pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + uint8 data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (uint8)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + MojoMd5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + MojoMd5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (uint8)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +#endif // SUPPORT_MD5 + +#if TEST_MD5 +int main(int argc, char **argv) +{ + int i = 0; + for (i = 1; i < argc; i++) + { + FILE *in = NULL; + MojoMd5 ctx; + MojoMd5_init(&ctx); + in = fopen(argv[i], "rb"); + if (!in) + perror("fopen"); + else + { + uint8 dig[16]; + int err = 0; + while ( (!err) && (!feof(in)) ) + { + uint8 buf[1024]; + size_t rc = fread(buf, 1, sizeof (buf), in); + if (rc > 0) + MojoMd5_append(&ctx, buf, rc); + err = ferror(in); + } // while + + if (err) + perror("fread"); + fclose(in); + MojoMd5_finish(&ctx, dig); + + if (!err) + { + printf("%s: %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x\n", argv[i], + (int) dig[0], (int) dig[1], (int) dig[2], (int) dig[3], + (int) dig[4], (int) dig[5], (int) dig[6], (int) dig[7], + (int) dig[8], (int) dig[9], (int) dig[10], (int) dig[11], + (int) dig[12], (int) dig[13], (int) dig[14], (int) dig[15]); + } // if + } // else + } // for + + return 0; +} // main +#endif + +// end of checksum_md5.c ... + Added: trunk/checksum_sha1.c =================================================================== --- trunk/checksum_sha1.c (rev 0) +++ trunk/checksum_sha1.c 2007-05-27 15:56:12 UTC (rev 312) @@ -0,0 +1,210 @@ +#include "universal.h" + +#if SUPPORT_SHA1 + +// SHA-1 code originally from ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c +// License: public domain. +// I cleaned it up a little for MojoSetup's specific purposes. --ryan. + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if PLATFORM_LITTLEENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void MojoSha1_transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + static uint8_t workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* MojoSha1_init - Initialize new context */ + +void MojoSha1_init(MojoSha1 *context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void MojoSha1_append(MojoSha1 *context, const uint8_t *data, uint32_t len) +{ + uint32_t i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + MojoSha1_transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + MojoSha1_transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void MojoSha1_finish(MojoSha1 *context, uint8_t digest[20]) +{ + uint32_t i, j; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + MojoSha1_append(context, (uint8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + MojoSha1_append(context, (uint8_t *)"\0", 1); + } + MojoSha1_append(context, finalcount, 8); /* Should cause a MojoSha1_transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); + MojoSha1_transform(context->state, context->buffer); +} + +#endif // SUPPORT_SHA1 + +#if TEST_SHA1 +int main(int argc, char **argv) +{ + int i = 0; + for (i = 1; i < argc; i++) + { + FILE *in = NULL; + MojoSha1 ctx; + MojoSha1_init(&ctx); + in = fopen(argv[i], "rb"); + if (!in) + perror("fopen"); + else + { + uint8_t dig[20]; + int err = 0; + while ( (!err) && (!feof(in)) ) + { + uint8_t buf[1024]; + size_t rc = fread(buf, 1, sizeof (buf), in); + if (rc > 0) + MojoSha1_append(&ctx, buf, rc); + err = ferror(in); + } // while + + if (err) + perror("fread"); + fclose(in); + MojoSha1_finish(&ctx, dig); + + if (!err) + { + printf("%s: %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x\n", + argv[i], + (int) dig[0], (int) dig[1], (int) dig[2], (int) dig[3], + (int) dig[4], (int) dig[5], (int) dig[6], (int) dig[7], + (int) dig[8], (int) dig[9], (int) dig[10], (int) dig[11], + (int) dig[12], (int) dig[13], (int) dig[14], (int) dig[15], + (int) dig[16], (int) dig[17], (int) dig[18], (int) dig[19]); + } // if + } // else + } // for + + return 0; +} // main +#endif + +// end of checksum_sha1.c ... + Modified: trunk/fileio.c =================================================================== --- trunk/fileio.c 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/fileio.c 2007-05-27 15:56:12 UTC (rev 312) @@ -84,6 +84,7 @@ // !!! FIXME: I'd rather not use a callback here, but I can't see a cleaner // !!! FIXME: way right now... boolean MojoInput_toPhysicalFile(MojoInput *in, const char *fname, uint16 perms, + MojoChecksums *checksums, MojoInput_FileCopyCallback cb, void *data) { boolean retval = false; @@ -92,10 +93,17 @@ boolean iofailure = false; int64 flen = 0; int64 bw = 0; + MojoChecksumContext sumctx; if (in == NULL) return false; + if (checksums != NULL) + { + memset(checksums, '\0', sizeof (MojoChecksums)); + MojoChecksum_init(&sumctx); + } // if + // Wait for a ready(), so length() can be meaningful on network streams. while ((!in->ready(in)) && (!iofailure)) { @@ -137,7 +145,11 @@ if (fwrite(scratchbuf_128k, br, 1, out) != 1) iofailure = true; else + { + if (checksums != NULL) + MojoChecksum_append(&sumctx, scratchbuf_128k, br); bw += br; + } // else } // else } // else @@ -156,6 +168,8 @@ else { MojoPlatform_chmod(fname, perms); + if (checksums != NULL) + MojoChecksum_finish(&sumctx, checksums); retval = true; } // else } // if Modified: trunk/fileio.h =================================================================== --- trunk/fileio.h 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/fileio.h 2007-05-27 15:56:12 UTC (rev 312) @@ -100,6 +100,7 @@ typedef boolean (*MojoInput_FileCopyCallback)(uint32 ticks, int64 justwrote, int64 bw, int64 total, void *data); boolean MojoInput_toPhysicalFile(MojoInput *in, const char *fname, uint16 perms, + MojoChecksums *checksums, MojoInput_FileCopyCallback cb, void *data); MojoInput *MojoInput_fromURL(const char *url); Modified: trunk/lua_glue.c =================================================================== --- trunk/lua_glue.c 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/lua_glue.c 2007-05-27 15:56:12 UTC (rev 312) @@ -152,6 +152,49 @@ } // retvalLightUserData +static int retvalChecksums(lua_State *L, const MojoChecksums *sums) +{ + lua_newtable(L); + + #if SUPPORT_CRC32 + { + char buf[64]; + snprintf(buf, sizeof (buf), "%X", (unsigned int) sums->crc32); + set_string(L, buf, "crc32"); + } + #endif + + #if SUPPORT_MD5 + { + char buf[64]; + const uint8 *dig = sums->md5; + snprintf(buf, sizeof (buf), "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X", + (int) dig[0], (int) dig[1], (int) dig[2], (int) dig[3], + (int) dig[4], (int) dig[5], (int) dig[6], (int) dig[7], + (int) dig[8], (int) dig[9], (int) dig[10], (int) dig[11], + (int) dig[12], (int) dig[13], (int) dig[14], (int) dig[15]); + set_string(L, buf, "md5"); + } + #endif + + #if SUPPORT_SHA1 + { + char buf[64]; + const uint8 *dig = sums->sha1; + snprintf(buf, sizeof (buf), "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X", + (int) dig[0], (int) dig[1], (int) dig[2], (int) dig[3], + (int) dig[4], (int) dig[5], (int) dig[6], (int) dig[7], + (int) dig[8], (int) dig[9], (int) dig[10], (int) dig[11], + (int) dig[12], (int) dig[13], (int) dig[14], (int) dig[15], + (int) dig[16], (int) dig[17], (int) dig[18], (int) dig[19]); + set_string(L, buf, "sha1"); + } + #endif + + return 1; +} // retvalChecksums + + static inline int snprintfcat(char **ptr, size_t *len, const char *fmt, ...) { int bw = 0; @@ -673,8 +716,10 @@ { MojoArchive *archive = (MojoArchive *) lua_touserdata(L, 1); const char *path = luaL_checkstring(L, 2); + int retval = 0; + boolean rc = false; uint16 perms = archive->prevEnum.perms; - boolean retval = false; + MojoChecksums sums; MojoInput *in = archive->openCurrentEntry(archive); if (in != NULL) { @@ -686,10 +731,14 @@ if (!valid) fatal(_("BUG: '%s' is not a valid permission string"), permstr); } // if - retval = MojoInput_toPhysicalFile(in, path, perms, writeCallback, L); + rc = MojoInput_toPhysicalFile(in, path, perms, &sums, + writeCallback, L); } // if - return retvalBoolean(L, retval); + retval += retvalBoolean(L, rc); + if (rc) + retval += retvalChecksums(L, &sums); + return retval; } // luahook_writefile @@ -706,14 +755,23 @@ static int luahook_download(lua_State *L) { - boolean retval = false; const char *url = luaL_checkstring(L, 1); const char *dst = luaL_checkstring(L, 2); + int retval = 0; + boolean rc = false; + MojoChecksums sums; MojoInput *in = MojoInput_fromURL(url); - // !!! FIXME: Unix-specific permissions thing here. if (in != NULL) - retval = MojoInput_toPhysicalFile(in, dst, 0644, writeCallback, L); - return retvalBoolean(L, retval); + { + // !!! FIXME: Unix-specific permissions thing here. + rc = MojoInput_toPhysicalFile(in, dst, 0644, &sums, + writeCallback, L); + } // if + + retval += retvalBoolean(L, rc); + if (rc) + retval += retvalChecksums(L, &sums); + return retval; } // luahook_download @@ -858,7 +916,7 @@ { uint16 perms = 0; MojoPlatform_perms(src, &perms); - retval = MojoInput_toPhysicalFile(in, dst, perms, NULL, NULL); + retval = MojoInput_toPhysicalFile(in, dst, perms, NULL, NULL, NULL); if (retval) { retval = MojoPlatform_unlink(src); Modified: trunk/mojosetup.c =================================================================== --- trunk/mojosetup.c 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/mojosetup.c 2007-05-27 15:56:12 UTC (rev 312) @@ -159,6 +159,50 @@ } // deinitEverything +void MojoChecksum_init(MojoChecksumContext *ctx) +{ + memset(ctx, '\0', sizeof (MojoChecksumContext)); + #if SUPPORT_CRC32 + MojoCrc32_init(&ctx->crc32); + #endif + #if SUPPORT_MD5 + MojoMd5_init(&ctx->md5); + #endif + #if SUPPORT_SHA1 + MojoSha1_init(&ctx->sha1); + #endif +} // MojoChecksum_init + + +void MojoChecksum_append(MojoChecksumContext *ctx, const uint8 *d, uint32 len) +{ + #if SUPPORT_CRC32 + MojoCrc32_append(&ctx->crc32, d, len); + #endif + #if SUPPORT_MD5 + MojoMd5_append(&ctx->md5, d, len); + #endif + #if SUPPORT_SHA1 + MojoSha1_append(&ctx->sha1, d, len); + #endif +} // MojoChecksum_append + + +void MojoChecksum_finish(MojoChecksumContext *ctx, MojoChecksums *sums) +{ + memset(sums, '\0', sizeof (MojoChecksums)); + #if SUPPORT_CRC32 + MojoCrc32_finish(&ctx->crc32, &sums->crc32); + #endif + #if SUPPORT_MD5 + MojoMd5_finish(&ctx->md5, sums->md5); + #endif + #if SUPPORT_SHA1 + MojoSha1_finish(&ctx->sha1, sums->sha1); + #endif +} // MojoChecksum_finish + + boolean cmdline(const char *arg) { int argc = GArgc; Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-27 15:56:12 UTC (rev 312) @@ -252,7 +252,8 @@ end MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - if not MojoSetup.writefile(archive, path, perms, callback) then + local written, sums = MojoSetup.writefile(archive, path, perms, callback) + if not written then -- !!! FIXME: formatting! if not keepgoing then MojoSetup.logerror("User cancelled install during file write.") @@ -795,7 +796,8 @@ end MojoSetup.loginfo("Download '" .. url .. "' to '" .. f .. "'") - if not MojoSetup.download(url, f, callback) then + local downloaded, sums = MojoSetup.download(url, f, callback) + if not downloaded then -- !!! FIXME: formatting! MojoSetup.fatal(_("file download failed!")) end Modified: trunk/universal.h =================================================================== --- trunk/universal.h 2007-05-27 06:01:08 UTC (rev 311) +++ trunk/universal.h 2007-05-27 15:56:12 UTC (rev 312) @@ -181,6 +181,59 @@ void logInfo(const char *fmt, ...) ISPRINTF(1,2); void logDebug(const char *fmt, ...) ISPRINTF(1,2); + +// Checksums. + +typedef uint32 MojoCrc32; +void MojoCrc32_init(MojoCrc32 *context); +void MojoCrc32_append(MojoCrc32 *context, const uint8 *buf, uint32 len); +void MojoCrc32_finish(MojoCrc32 *context, uint32 *digest); + + +typedef struct MojoMd5 +{ + uint32 count[2]; + uint32 abcd[4]; + uint8 buf[64]; +} MojoMd5; + +void MojoMd5_init(MojoMd5 *pms); +void MojoMd5_append(MojoMd5 *pms, const uint8 *data, int nbytes); +void MojoMd5_finish(MojoMd5 *pms, uint8 digest[16]); + + +typedef struct +{ + uint32 state[5]; + uint32 count[2]; + uint8 buffer[64]; +} MojoSha1; + +void MojoSha1_init(MojoSha1 *context); +void MojoSha1_append(MojoSha1 *context, const uint8 *data, uint32 len); +void MojoSha1_finish(MojoSha1 *context, uint8 digest[20]); + +typedef struct MojoChecksumContext +{ + MojoCrc32 crc32; + MojoMd5 md5; + MojoSha1 sha1; +} MojoChecksumContext; + + +typedef struct MojoChecksums +{ + uint32 crc32; + uint8 md5[16]; + uint8 sha1[20]; +} MojoChecksums; + + +void MojoChecksum_init(MojoChecksumContext *ctx); +void MojoChecksum_append(MojoChecksumContext *c, const uint8 *data, uint32 ln); +void MojoChecksum_finish(MojoChecksumContext *c, MojoChecksums *sums); + + // A pointer to this struct is passed to plugins, so they can access // functionality in the base application. (Add to this as you need to.) typedef struct MojoSetupEntryPoints From DONOTREPLY at icculus.org Sun May 27 12:41:12 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 12:41:12 -0400 Subject: r313 - in trunk: . scripts Message-ID: <20070527164112.10170.qmail@icculus.org> Author: icculus Date: 2007-05-27 12:41:12 -0400 (Sun, 27 May 2007) New Revision: 313 Modified: trunk/docs.txt trunk/scripts/mojosetup_mainline.lua Log: Added MojoSetup.manifest. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-27 15:56:12 UTC (rev 312) +++ trunk/docs.txt 2007-05-27 16:41:12 UTC (rev 313) @@ -838,6 +838,7 @@ version in the Lua standard runtime, since this version does better debug logging. + MojoSetup.date() Return a string of the current date. This is roughly the same as os.date() @@ -946,5 +947,50 @@ compile-time options. + MojoSetup.destination + + This is a string (not a function!) of the path on the physical filesystem + where the package is being installed. This is not available until the + user has selected a destination, but could be useful in your postinstall + script. + + + MojoSetup.manifest + + This is an array of tables (not a function!) that is built during the + course of the installation. As changes are made to the destination + filesystem, they are noted in MojoSetup.manifest, so this will be + complete and most useful during a postinstall hook in your config file. + + As with most other globals listed here, MojoSetup depends on this data, + so you should treat it as read-only. Modifying this table from your config + script will result in undefined (but probably bad) behaviour. + + The format of the tables in the array vary depending on type. They all + have a "type" field, which is a string. Based on the type, different + fields are available: + + if (item.type = "file") then + print("file created at " .. item.path) + print("with permissions" ... item.mode) -- This is a string! + + -- Checksums may or may not exist in this table, depending on how + -- MojoSetup was compiled. You can iterate to find out what's there: + print("checksums:") + for k,v in pairs(item.checksums) do + print(" " .. k .. ": " .. v) -- "crc32: 92FAB211E", etc. + end + end + + if (item.type = "dir") then + print("directory created at " .. item.path) + print("with permissions" ... item.mode) -- This is a string! + end + + if (item.type = "symlink") then + print("symbolic link created at " .. item.path) + print("pointing to " .. item.linkdest) + end + // end of docs.txt ... Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-27 15:56:12 UTC (rev 312) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-27 16:41:12 UTC (rev 313) @@ -233,9 +233,9 @@ end -local function install_file(path, archive, file, option, perms) +local function install_file(dest, archive, file, option, perms) -- Upvalued so we don't look these up each time... - local fname = string.gsub(path, "^.*/", "", 1) -- chop the dirs off... + local fname = string.gsub(dest, "^.*/", "", 1) -- chop the dirs off... local ptype = _("Installing") -- !!! FIXME: localization. local component = option.description local keepgoing = true @@ -251,41 +251,66 @@ return keepgoing end - MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - local written, sums = MojoSetup.writefile(archive, path, perms, callback) + MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest + local written, sums = MojoSetup.writefile(archive, dest, perms, callback) if not written then -- !!! FIXME: formatting! if not keepgoing then MojoSetup.logerror("User cancelled install during file write.") MojoSetup.fatal(_("User cancelled installation.")) else - MojoSetup.logerror("Failed to create file '" .. path .. "'") + MojoSetup.logerror("Failed to create file '" .. dest .. "'") MojoSetup.fatal(_("File creation failed!")) end end - MojoSetup.loginfo("Created file '" .. path .. "'") + + MojoSetup.manifest[#MojoSetup.manifest+1] = + { + type = "file", + path = dest, + checksums = sums, + mode = perms, + } + + MojoSetup.loginfo("Created file '" .. dest .. "'") end -local function install_symlink(path, lndest) - MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - if not MojoSetup.platform.symlink(path, lndest) then +local function install_symlink(dest, lndest) + MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest + if not MojoSetup.platform.symlink(dest, lndest) then -- !!! FIXME: formatting! - MojoSetup.logerror("Failed to create symlink '" .. path .. "'") + MojoSetup.logerror("Failed to create symlink '" .. dest .. "'") MojoSetup.fatal(_("symlink creation failed!")) end - MojoSetup.loginfo("Created symlink '" .. path .. "' -> '" .. lndest .. "'") + + MojoSetup.manifest[#MojoSetup.manifest+1] = + { + type = "symlink", + path = dest, + linkdest = lndest, + } + + MojoSetup.loginfo("Created symlink '" .. dest .. "' -> '" .. lndest .. "'") end -local function install_directory(path, perms) - MojoSetup.installed_files[#MojoSetup.installed_files+1] = path - if not MojoSetup.platform.mkdir(path, perms) then +local function install_directory(dest, perms) + MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest + if not MojoSetup.platform.mkdir(dest, perms) then -- !!! FIXME: formatting - MojoSetup.logerror("Failed to create dir '" .. path .. "'") + MojoSetup.logerror("Failed to create dir '" .. dest .. "'") MojoSetup.fatal(_("mkdir failed")) end - MojoSetup.loginfo("Created directory '" .. path .. "'") + + MojoSetup.manifest[#MojoSetup.manifest+1] = + { + type = "dir", + path = dest, + mode = perms, + } + + MojoSetup.loginfo("Created directory '" .. dest .. "'") end @@ -894,6 +919,7 @@ -- Make the stages available elsewhere. MojoSetup.stages = stages + MojoSetup.manifest = {} MojoSetup.installed_files = {} MojoSetup.rollbacks = {} MojoSetup.downloads = {} @@ -940,6 +966,7 @@ -- Done with these things. Make them eligible for garbage collection. stages = nil + MojoSetup.manifest = nil MojoSetup.destination = nil MojoSetup.scratchdir = nil MojoSetup.rollbackdir = nil From DONOTREPLY at icculus.org Sun May 27 14:13:15 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 14:13:15 -0400 Subject: r314 - in trunk: . scripts Message-ID: <20070527181315.4640.qmail@icculus.org> Author: icculus Date: 2007-05-27 14:13:15 -0400 (Sun, 27 May 2007) New Revision: 314 Modified: trunk/docs.txt trunk/scripts/mojosetup_mainline.lua Log: More manifest work. Modified: trunk/docs.txt =================================================================== --- trunk/docs.txt 2007-05-27 16:41:12 UTC (rev 313) +++ trunk/docs.txt 2007-05-27 18:13:15 UTC (rev 314) @@ -957,7 +957,7 @@ MojoSetup.manifest - This is an array of tables (not a function!) that is built during the + This is a table of tables (not a function!) that is built during the course of the installation. As changes are made to the destination filesystem, they are noted in MojoSetup.manifest, so this will be complete and most useful during a postinstall hook in your config file. @@ -966,11 +966,21 @@ so you should treat it as read-only. Modifying this table from your config script will result in undefined (but probably bad) behaviour. - The format of the tables in the array vary depending on type. They all - have a "type" field, which is a string. Based on the type, different - fields are available: + There is one element in the array for each Setup.Option that generated + a change to the filesystem. Each of these elements is an array of tables. - if (item.type = "file") then + for option,items in pairs(MojoSetup.manifest) do + print("Option: " .. option.description) + for i,item in ipairs(items) do + -- ... do stuff with "item" here ... + end + end + + The format of the item tables vary depending on type. They all have a + "type" field, which is a string. Based on the type, different fields are + available: + + if item.type == "file" then print("file created at " .. item.path) print("with permissions" ... item.mode) -- This is a string! @@ -982,12 +992,12 @@ end end - if (item.type = "dir") then + if item.type == "dir" then print("directory created at " .. item.path) print("with permissions" ... item.mode) -- This is a string! end - if (item.type = "symlink") then + if item.type == "symlink" then print("symbolic link created at " .. item.path) print("pointing to " .. item.linkdest) end Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-27 16:41:12 UTC (rev 313) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-27 18:13:15 UTC (rev 314) @@ -233,7 +233,7 @@ end -local function install_file(dest, archive, file, option, perms) +local function install_file(dest, archive, file, perms, option) -- Upvalued so we don't look these up each time... local fname = string.gsub(dest, "^.*/", "", 1) -- chop the dirs off... local ptype = _("Installing") -- !!! FIXME: localization. @@ -264,19 +264,25 @@ end end - MojoSetup.manifest[#MojoSetup.manifest+1] = - { - type = "file", - path = dest, - checksums = sums, - mode = perms, - } + if option ~= nil then + if MojoSetup.manifest[option] == nil then + MojoSetup.manifest[option] = {} + end + local manifest = MojoSetup.manifest[option] + manifest[#manifest+1] = + { + type = "file", + path = dest, + checksums = sums, + mode = perms, + } + end MojoSetup.loginfo("Created file '" .. dest .. "'") end -local function install_symlink(dest, lndest) +local function install_symlink(dest, lndest, option) MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest if not MojoSetup.platform.symlink(dest, lndest) then -- !!! FIXME: formatting! @@ -284,18 +290,24 @@ MojoSetup.fatal(_("symlink creation failed!")) end - MojoSetup.manifest[#MojoSetup.manifest+1] = - { - type = "symlink", - path = dest, - linkdest = lndest, - } + if option ~= nil then + if MojoSetup.manifest[option] == nil then + MojoSetup.manifest[option] = {} + end + local manifest = MojoSetup.manifest[option] + manifest[#manifest+1] = + { + type = "symlink", + path = dest, + linkdest = lndest, + } + end MojoSetup.loginfo("Created symlink '" .. dest .. "' -> '" .. lndest .. "'") end -local function install_directory(dest, perms) +local function install_directory(dest, perms, option) MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest if not MojoSetup.platform.mkdir(dest, perms) then -- !!! FIXME: formatting @@ -303,18 +315,24 @@ MojoSetup.fatal(_("mkdir failed")) end - MojoSetup.manifest[#MojoSetup.manifest+1] = - { - type = "dir", - path = dest, - mode = perms, - } + if option ~= nil then + if MojoSetup.manifest[option] == nil then + MojoSetup.manifest[option] = {} + end + local manifest = MojoSetup.manifest[option] + manifest[#manifest+1] = + { + type = "dir", + path = dest, + mode = perms, + } + end MojoSetup.loginfo("Created directory '" .. dest .. "'") end -local function install_parent_dirs(path) +local function install_parent_dirs(path, option) -- Chop any '/' chars from the end of the string... path = string.gsub(path, "/+$", "") @@ -324,7 +342,7 @@ if item ~= "" then fullpath = fullpath .. "/" .. item if not MojoSetup.platform.exists(fullpath) then - install_directory(fullpath, nil) + install_directory(fullpath, nil, option) end end end @@ -367,7 +385,7 @@ local id = #MojoSetup.rollbacks + 1 local f = MojoSetup.rollbackdir .. "/" .. id -- !!! FIXME: don't add (f) to the installed_files table... - install_parent_dirs(f) + install_parent_dirs(f, nil) MojoSetup.rollbacks[id] = dest if not MojoSetup.movefile(dest, f) then -- !!! FIXME: formatting @@ -407,13 +425,13 @@ if dest ~= nil then -- Only install if file wasn't filtered out dest = MojoSetup.destination .. "/" .. dest if permit_write(dest, ent, file) then - install_parent_dirs(dest) + install_parent_dirs(dest, option) if ent.type == "file" then - install_file(dest, archive, file, option, perms) + install_file(dest, archive, file, perms, option) elseif ent.type == "dir" then - install_directory(dest, perms) + install_directory(dest, perms, option) elseif ent.type == "symlink" then - install_symlink(dest, ent.linkdest) + install_symlink(dest, ent.linkdest, option) else -- !!! FIXME: device nodes, etc... -- !!! FIXME: formatting! -- !!! FIXME: should this be fatal? @@ -571,6 +589,7 @@ MojoSetup.totalwrite = 0 MojoSetup.downloaded = 0 MojoSetup.totaldownload = 0 + MojoSetup.install = install -- !!! FIXME: try to sanity check everything we can here -- !!! FIXME: (unsupported URLs, bogus media IDs, etc.) @@ -787,7 +806,7 @@ for file,option in pairs(MojoSetup.files.downloads) do local f = MojoSetup.downloaddir .. "/" .. id -- !!! FIXME: don't add (f) to the installed_files table... - install_parent_dirs(f) + install_parent_dirs(f, nil) id = id + 1 -- Upvalued so we don't look these up each time... @@ -971,6 +990,7 @@ MojoSetup.scratchdir = nil MojoSetup.rollbackdir = nil MojoSetup.downloaddir = nil + MojoSetup.install = nil MojoSetup.forceoverwrite = nil MojoSetup.stages = nil MojoSetup.files = nil From DONOTREPLY at icculus.org Sun May 27 14:14:09 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 14:14:09 -0400 Subject: r315 - trunk/scripts Message-ID: <20070527181409.4988.qmail@icculus.org> Author: icculus Date: 2007-05-27 14:14:09 -0400 (Sun, 27 May 2007) New Revision: 315 Added: trunk/scripts/loki_setup_compat.lua Log: Initial shot at loki_setup manifest support, for legacy installs and bridging to loki_update, etc. Added: trunk/scripts/loki_setup_compat.lua =================================================================== --- trunk/scripts/loki_setup_compat.lua (rev 0) +++ trunk/scripts/loki_setup_compat.lua 2007-05-27 18:14:09 UTC (rev 315) @@ -0,0 +1,95 @@ +-- MojoSetup; a portable, flexible installation application. +-- +-- Please see the file LICENSE.txt in the source's root directory. +-- +-- This file written by Ryan C. Gordon. + + +-- Compatibility with loki_setup and related tools. +-- +-- You can cut-and-paste this file into your config script, or call this at +-- the start of it: MojoSetup.runfile("loki_setup_compat") +-- This code is optional, and not otherwise referenced by MojoSetup. It could +-- be useful for those that need to integrate with loki_update, etc. +-- +-- Using this code requires you to build with the Lua "io" runtime library. +-- (for now, at least). + +MojoSetup.Loki = {} + + +-- !!! FIXME: some of these are currently-undocumented MojoSetup.* methods... + +function MojoSetup.Loki.manifest(update_url) + local install = MojoSetup.install + local manifestdir = MojoSetup.destination .. "/.manifest" + MojoSetup.installed_files[#MojoSetup.installed_files+1] = manifestdir + if not MojoSetup.platform.mkdir(dest, perms) then + -- !!! FIXME: formatting + MojoSetup.logerror("Failed to create dir '" .. manifestdir .. "'") + MojoSetup.fatal(_("mkdir failed")) + end + + local manifestfile = manifestdir .. "/" .. install.id .. ".xml" + MojoSetup.installed_files[#MojoSetup.installed_files+1] = manifestfile + local f, err = io.open(manifestfile, "a") + if f == nil then + MojoSetup.logerror("Couldn't create manifest: " .. err) + MojoSetup.fatal(_("Couldn't create manifest")) + end + + if update_url ~= nil then + update_url = 'update_url="' .. update_url .. '"' + else + update_url = '' + end + + -- !!! FIXME: check i/o errors + f:write('\n') + f:write('\n'); + f:write(' \n') + + local destlen = string.length(MojoSetup.destination) + 2 + for option,items in pairs(MojoSetup.manifest) do + f:write(' \n') + f:write('\n\n') + + -- !!! FIXME: check i/o errors + f:close() +end + +-- end of loki_setup_compat.lua ... + From DONOTREPLY at icculus.org Sun May 27 14:20:51 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 14:20:51 -0400 Subject: r316 - trunk Message-ID: <20070527182051.7629.qmail@icculus.org> Author: icculus Date: 2007-05-27 14:20:51 -0400 (Sun, 27 May 2007) New Revision: 316 Modified: trunk/checksum_sha1.c Log: Patched to compile on Linux. Modified: trunk/checksum_sha1.c =================================================================== --- trunk/checksum_sha1.c 2007-05-27 18:14:09 UTC (rev 315) +++ trunk/checksum_sha1.c 2007-05-27 18:20:51 UTC (rev 316) @@ -43,15 +43,15 @@ /* Hash a single 512-bit block. This is the core of the algorithm. */ -static void MojoSha1_transform(uint32_t state[5], const uint8_t buffer[64]) +static void MojoSha1_transform(uint32 state[5], const uint8 buffer[64]) { - uint32_t a, b, c, d, e; + uint32 a, b, c, d, e; typedef union { - uint8_t c[64]; - uint32_t l[16]; + uint8 c[64]; + uint32 l[16]; } CHAR64LONG16; CHAR64LONG16* block; - static uint8_t workspace[64]; + static uint8 workspace[64]; block = (CHAR64LONG16*)workspace; memcpy(block, buffer, 64); /* Copy context->state[] to working vars */ @@ -108,9 +108,9 @@ /* Run your data through this. */ -void MojoSha1_append(MojoSha1 *context, const uint8_t *data, uint32_t len) +void MojoSha1_append(MojoSha1 *context, const uint8 *data, uint32 len) { - uint32_t i, j; + uint32 i, j; j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; @@ -130,22 +130,22 @@ /* Add padding and return the message digest. */ -void MojoSha1_finish(MojoSha1 *context, uint8_t digest[20]) +void MojoSha1_finish(MojoSha1 *context, uint8 digest[20]) { - uint32_t i, j; - uint8_t finalcount[8]; + uint32 i, j; + uint8 finalcount[8]; for (i = 0; i < 8; i++) { - finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] + finalcount[i] = (uint8)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } - MojoSha1_append(context, (uint8_t *)"\200", 1); + MojoSha1_append(context, (uint8 *)"\200", 1); while ((context->count[0] & 504) != 448) { - MojoSha1_append(context, (uint8_t *)"\0", 1); + MojoSha1_append(context, (uint8 *)"\0", 1); } MojoSha1_append(context, finalcount, 8); /* Should cause a MojoSha1_transform() */ for (i = 0; i < 20; i++) { - digest[i] = (uint8_t) + digest[i] = (uint8) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } /* Wipe variables */ @@ -173,11 +173,11 @@ perror("fopen"); else { - uint8_t dig[20]; + uint8 dig[20]; int err = 0; while ( (!err) && (!feof(in)) ) { - uint8_t buf[1024]; + uint8 buf[1024]; size_t rc = fread(buf, 1, sizeof (buf), in); if (rc > 0) MojoSha1_append(&ctx, buf, rc); From DONOTREPLY at icculus.org Sun May 27 14:37:53 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 14:37:53 -0400 Subject: r317 - trunk Message-ID: <20070527183753.11826.qmail@icculus.org> Author: icculus Date: 2007-05-27 14:37:53 -0400 (Sun, 27 May 2007) New Revision: 317 Modified: trunk/lua_glue.c Log: Minor argument checking fixes in the lua_glue. Modified: trunk/lua_glue.c =================================================================== --- trunk/lua_glue.c 2007-05-27 18:20:51 UTC (rev 316) +++ trunk/lua_glue.c 2007-05-27 18:37:53 UTC (rev 317) @@ -626,8 +626,8 @@ { const int argc = lua_gettop(L); const char *arg = luaL_checkstring(L, 1); - const char *envr = (argc < 2) ? NULL : lua_tostring(L, 2); - const char *deflt = (argc < 3) ? NULL : lua_tostring(L, 3); + const char *envr = (argc < 2) ? NULL : luaL_checkstring(L, 2); + const char *deflt = (argc < 3) ? NULL : luaL_checkstring(L, 3); return retvalString(L, cmdlinestr(arg, envr, deflt)); } // luahook_cmdlinestr @@ -887,9 +887,10 @@ static int luahook_platform_mkdir(lua_State *L) { + const int argc = lua_gettop(L); const char *dir = luaL_checkstring(L, 1); uint16 perms = 0; - if (lua_isnil(L, 2)) + if ( (argc < 2) || (lua_isnil(L, 2)) ) perms = MojoPlatform_defaultDirPerms(); else { From DONOTREPLY at icculus.org Sun May 27 14:44:31 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 14:44:31 -0400 Subject: r318 - trunk/examples/duke3d Message-ID: <20070527184431.13908.qmail@icculus.org> Author: icculus Date: 2007-05-27 14:44:31 -0400 (Sun, 27 May 2007) New Revision: 318 Modified: trunk/examples/duke3d/make.sh Log: Whoops, reversed if block in duke3d's make.sh ... Modified: trunk/examples/duke3d/make.sh =================================================================== --- trunk/examples/duke3d/make.sh 2007-05-27 18:37:53 UTC (rev 317) +++ trunk/examples/duke3d/make.sh 2007-05-27 18:44:31 UTC (rev 318) @@ -17,12 +17,12 @@ set -x if [ "$DEBUG" = "1" ]; then - LUASTRIPOPT=-s + LUASTRIPOPT= BUILDTYPE=Debug TRUEIFDEBUG=TRUE FALSEIFDEBUG=FALSE else - LUASTRIPOPT= + LUASTRIPOPT=-s BUILDTYPE=MinSizeRel TRUEIFDEBUG=FALSE FALSEIFDEBUG=TRUE From DONOTREPLY at icculus.org Sun May 27 15:03:01 2007 From: DONOTREPLY at icculus.org (DONOTREPLY at icculus.org) Date: 27 May 2007 15:03:01 -0400 Subject: r319 - trunk/scripts Message-ID: <20070527190301.18648.qmail@icculus.org> Author: icculus Date: 2007-05-27 15:03:01 -0400 (Sun, 27 May 2007) New Revision: 319 Modified: trunk/scripts/loki_setup_compat.lua trunk/scripts/mojosetup_mainline.lua Log: Bunch of fixes and work on loki_setup_compat.lua ... Modified: trunk/scripts/loki_setup_compat.lua =================================================================== --- trunk/scripts/loki_setup_compat.lua 2007-05-27 18:44:31 UTC (rev 318) +++ trunk/scripts/loki_setup_compat.lua 2007-05-27 19:03:01 UTC (rev 319) @@ -20,11 +20,10 @@ -- !!! FIXME: some of these are currently-undocumented MojoSetup.* methods... -function MojoSetup.Loki.manifest(update_url) - local install = MojoSetup.install +function MojoSetup.Loki.manifest(install, update_url) local manifestdir = MojoSetup.destination .. "/.manifest" MojoSetup.installed_files[#MojoSetup.installed_files+1] = manifestdir - if not MojoSetup.platform.mkdir(dest, perms) then + if not MojoSetup.platform.mkdir(manifestdir) then -- !!! FIXME: formatting MojoSetup.logerror("Failed to create dir '" .. manifestdir .. "'") MojoSetup.fatal(_("mkdir failed")) @@ -52,7 +51,7 @@ f:write(' \n') - local destlen = string.length(MojoSetup.destination) + 2 + local destlen = string.len(MojoSetup.destination) + 2 for option,items in pairs(MojoSetup.manifest) do f:write(' \n') end f:write(' \n') Modified: trunk/scripts/mojosetup_mainline.lua =================================================================== --- trunk/scripts/mojosetup_mainline.lua 2007-05-27 18:44:31 UTC (rev 318) +++ trunk/scripts/mojosetup_mainline.lua 2007-05-27 19:03:01 UTC (rev 319) @@ -264,6 +264,8 @@ end end + -- !!! FIXME: perms may be null...we need a MojoSetup.defaultPermsString()... + if option ~= nil then if MojoSetup.manifest[option] == nil then MojoSetup.manifest[option] = {}