This list is closed, nobody may subscribe to it.
| 2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(12) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2001 |
Jan
(13) |
Feb
(2) |
Mar
(1) |
Apr
(1) |
May
|
Jun
(38) |
Jul
(10) |
Aug
(70) |
Sep
(63) |
Oct
(61) |
Nov
(41) |
Dec
(28) |
| 2002 |
Jan
(43) |
Feb
(11) |
Mar
(9) |
Apr
(2) |
May
(97) |
Jun
(94) |
Jul
(13) |
Aug
(49) |
Sep
(41) |
Oct
(24) |
Nov
(55) |
Dec
(126) |
| 2003 |
Jan
(90) |
Feb
(75) |
Mar
(32) |
Apr
(24) |
May
(54) |
Jun
(54) |
Jul
(22) |
Aug
(4) |
Sep
(16) |
Oct
(8) |
Nov
(6) |
Dec
(13) |
| 2004 |
Jan
|
Feb
(17) |
Mar
(60) |
Apr
(21) |
May
(12) |
Jun
|
Jul
(13) |
Aug
|
Sep
(29) |
Oct
|
Nov
|
Dec
(2) |
| 2005 |
Jan
(22) |
Feb
(3) |
Mar
(2) |
Apr
(13) |
May
(82) |
Jun
(18) |
Jul
(30) |
Aug
(17) |
Sep
(3) |
Oct
(19) |
Nov
(4) |
Dec
(8) |
| 2006 |
Jan
(1) |
Feb
(6) |
Mar
(2) |
Apr
(40) |
May
|
Jun
(21) |
Jul
(1) |
Aug
(410) |
Sep
(3) |
Oct
|
Nov
(56) |
Dec
(7) |
| 2007 |
Jan
(19) |
Feb
|
Mar
(4) |
Apr
(8) |
May
(19) |
Jun
(6) |
Jul
(4) |
Aug
(6) |
Sep
|
Oct
(4) |
Nov
(3) |
Dec
(2) |
| 2008 |
Jan
(13) |
Feb
(18) |
Mar
(12) |
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
| 2009 |
Jan
|
Feb
(6) |
Mar
(8) |
Apr
(2) |
May
(2) |
Jun
|
Jul
|
Aug
(2) |
Sep
(11) |
Oct
(13) |
Nov
(17) |
Dec
(6) |
| 2010 |
Jan
(24) |
Feb
(10) |
Mar
(27) |
Apr
(20) |
May
(108) |
Jun
(8) |
Jul
(23) |
Aug
(38) |
Sep
(49) |
Oct
(17) |
Nov
(12) |
Dec
(14) |
| 2011 |
Jan
(17) |
Feb
(7) |
Mar
(28) |
Apr
(8) |
May
(20) |
Jun
(11) |
Jul
(7) |
Aug
(12) |
Sep
(4) |
Oct
(20) |
Nov
(19) |
Dec
(2) |
| 2012 |
Jan
(2) |
Feb
(6) |
Mar
(5) |
Apr
(24) |
May
(5) |
Jun
(4) |
Jul
(6) |
Aug
(18) |
Sep
(38) |
Oct
(26) |
Nov
(12) |
Dec
(6) |
| 2013 |
Jan
(19) |
Feb
(18) |
Mar
(44) |
Apr
(35) |
May
(18) |
Jun
(21) |
Jul
(10) |
Aug
(19) |
Sep
(44) |
Oct
(25) |
Nov
(1) |
Dec
(2) |
| 2014 |
Jan
(8) |
Feb
|
Mar
|
Apr
(5) |
May
(1) |
Jun
(3) |
Jul
|
Aug
(3) |
Sep
|
Oct
(4) |
Nov
(4) |
Dec
(7) |
| 2015 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(2) |
Jun
(4) |
Jul
(6) |
Aug
(2) |
Sep
(8) |
Oct
(2) |
Nov
(1) |
Dec
(3) |
| 2016 |
Jan
(7) |
Feb
(9) |
Mar
(5) |
Apr
(5) |
May
(9) |
Jun
(4) |
Jul
(20) |
Aug
(4) |
Sep
(7) |
Oct
(6) |
Nov
(9) |
Dec
(2) |
| 2017 |
Jan
(7) |
Feb
(7) |
Mar
(5) |
Apr
|
May
(1) |
Jun
(4) |
Jul
(12) |
Aug
(4) |
Sep
(1) |
Oct
(4) |
Nov
(11) |
Dec
(14) |
| 2018 |
Jan
(3) |
Feb
(3) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
1
(2) |
2
|
3
(1) |
4
|
5
|
6
|
|
7
|
8
|
9
|
10
|
11
|
12
(1) |
13
|
|
14
(1) |
15
|
16
|
17
|
18
|
19
|
20
|
|
21
|
22
(1) |
23
(1) |
24
|
25
(1) |
26
|
27
|
|
28
|
29
(1) |
30
(1) |
31
|
|
|
|
|
From: Keith M. <no...@so...> - 2013-07-30 19:45:52
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 87282fc4615912edb256ec35185dd418f334adf0 (commit)
via 3d3dd448679665b54b99942fbbdf078f318ae0ac (commit)
via 9adf1e772839647f997ba23543c4a9b47c84b1d0 (commit)
via 2f03be0794da22056b25d996a5e69ca3f1bb4d9b (commit)
via 31d0a301318e3b225a581df457507fe436197005 (commit)
from 162f37bd962f36011251a3c23966f1d47a344e0e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/87282fc4615912edb256ec35185dd418f334adf0/
commit 87282fc4615912edb256ec35185dd418f334adf0
Author: Keith Marshall <kei...@us...>
Date: Tue Jul 30 20:34:57 2013 +0100
Minor modification to "about" dialogue dismissal button.
diff --git a/ChangeLog b/ChangeLog
index a8e664d..b8d3996 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2013-07-30 Keith Marshall <kei...@us...>
+ Minor modification to "about" dialogue dismissal button.
+
+ * src/guimain.rc (IDD_HELP_ABOUT) <DEFPUSHBUTTON>: Change label text
+ to "Dismiss"; add WS_TABSTOP style.
+
+2013-07-30 Keith Marshall <kei...@us...>
+
Match "about" dialogue caption to main window.
* src/guimain.rc (IDM_HELP_ABOUT) <MENUITEM>: Match it to...
diff --git a/src/guimain.rc b/src/guimain.rc
index 3813569..15cb2ec 100644
--- a/src/guimain.rc
+++ b/src/guimain.rc
@@ -54,7 +54,7 @@ CAPTION "About MinGW Installation Manager"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_DLGFRAME
FONT 9, "Verdana"
BEGIN
- DEFPUSHBUTTON "OK", IDOK, 100, 155, 50, 14, WS_GROUP
+ DEFPUSHBUTTON "Dismiss", IDOK, 100, 155, 50, 14, WS_GROUP | WS_TABSTOP
ICON ID_MAIN_WINDOW, ID_MAIN_WINDOW, 115, 30, 0, 0
CTEXT "%PACKAGE_NAME% version %PACKAGE_VERSION%", -1, 0, 10, 250, 20
CTEXT "Written by Keith Marshall", -1, 0, 60, 250, 12
https://sf.net/p/mingw/mingw-get/ci/3d3dd448679665b54b99942fbbdf078f318ae0ac/
commit 3d3dd448679665b54b99942fbbdf078f318ae0ac
Author: Keith Marshall <kei...@us...>
Date: Tue Jul 30 16:57:13 2013 +0100
Match "about" dialogue caption to main window.
diff --git a/ChangeLog b/ChangeLog
index 207d3f7..a8e664d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2013-07-30 Keith Marshall <kei...@us...>
+ Match "about" dialogue caption to main window.
+
+ * src/guimain.rc (IDM_HELP_ABOUT) <MENUITEM>: Match it to...
+ (IDD_HELP_ABOUT) <CAPTION>: ...this; make it representative of...
+ (ID_MAIN_WINDOW_CAPTION): ...this.
+
+2013-07-30 Keith Marshall <kei...@us...>
+
Implement "icon legend" display as "help" menu item.
* src/guimain.rc (IDM_HELP_LEGEND): Make menu item active; define
diff --git a/src/guimain.rc b/src/guimain.rc
index b468363..3813569 100644
--- a/src/guimain.rc
+++ b/src/guimain.rc
@@ -50,7 +50,7 @@ ID_MAIN_WINDOW ICON DISCARDABLE "pkgicon.ico"
* which is called out by the "Help --> About mingw-get" menu pick.
*/
IDD_HELP_ABOUT DIALOG DISCARDABLE 80, 50, 250, 185
-CAPTION "About mingw-get"
+CAPTION "About MinGW Installation Manager"
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_DLGFRAME
FONT 9, "Verdana"
BEGIN
@@ -121,10 +121,10 @@ BEGIN
*/
POPUP "&Help", HELP
BEGIN
- MENUITEM "&Contents", IDM_HELP_CONTENTS, GRAYED
- MENUITEM "Quick &Introduction", IDM_HELP_INTRO, GRAYED
- MENUITEM "Icon &Legend", IDM_HELP_LEGEND
- MENUITEM "&About mingw-get", IDM_HELP_ABOUT
+ MENUITEM "&Contents", IDM_HELP_CONTENTS, GRAYED
+ MENUITEM "Quick &Introduction", IDM_HELP_INTRO, GRAYED
+ MENUITEM "Icon &Legend", IDM_HELP_LEGEND
+ MENUITEM "&About MinGW Installation Manager", IDM_HELP_ABOUT
END
END
https://sf.net/p/mingw/mingw-get/ci/9adf1e772839647f997ba23543c4a9b47c84b1d0/
commit 9adf1e772839647f997ba23543c4a9b47c84b1d0
Author: Keith Marshall <kei...@us...>
Date: Tue Jul 30 14:28:19 2013 +0100
Implement "icon legend" display as "help" menu item.
diff --git a/ChangeLog b/ChangeLog
index 4592edc..207d3f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2013-07-30 Keith Marshall <kei...@us...>
+ Implement "icon legend" display as "help" menu item.
+
+ * src/guimain.rc (IDM_HELP_LEGEND): Make menu item active; define
+ template for the dialogue box which it is to call out.
+
+ * src/guiexec.cpp (AppWindowMaker::OnCommand) [IDM_HELP_LEGEND]: New
+ case handler; implement dialogue box call out, as a variation on...
+ [IDM_HELP_ABOUT]: ...this; modify it accordingly.
+
+2013-07-30 Keith Marshall <kei...@us...>
+
Avoid discarding pending changes when catalogue is updated.
* src/guimain.h (IDD_CONFIRMATION): New manifest constant; define it.
diff --git a/src/guiexec.cpp b/src/guiexec.cpp
index 11edb9c..733a9ed 100644
--- a/src/guiexec.cpp
+++ b/src/guiexec.cpp
@@ -715,11 +715,14 @@ long AppWindowMaker::OnCommand( WPARAM cmd )
*/
switch( cmd )
{ case IDM_HELP_ABOUT:
- /* This request is initiated by selecting "About mingw-get"
- * from the "Help" menu; we respond by displaying the "about"
+ /* This request is initiated by selecting "About ...", ...
+ */
+ case IDM_HELP_LEGEND:
+ /* ...and this one by selecting "Icon Legend", from the "Help"
+ * menu; in both cases, we respond by displaying an associated
* dialogue box.
*/
- WTK::GenericDialogue( AppInstance, AppWindow, IDD_HELP_ABOUT );
+ WTK::GenericDialogue( AppInstance, AppWindow, cmd );
break;
case IDM_PACKAGE_INSTALL:
diff --git a/src/guimain.rc b/src/guimain.rc
index e077640..b468363 100644
--- a/src/guimain.rc
+++ b/src/guimain.rc
@@ -123,7 +123,7 @@ BEGIN
BEGIN
MENUITEM "&Contents", IDM_HELP_CONTENTS, GRAYED
MENUITEM "Quick &Introduction", IDM_HELP_INTRO, GRAYED
- MENUITEM "Icon &Legend", IDM_HELP_LEGEND, GRAYED
+ MENUITEM "Icon &Legend", IDM_HELP_LEGEND
MENUITEM "&About mingw-get", IDM_HELP_ABOUT
END
@@ -151,6 +151,48 @@ ID_PKGSTATE_BROKEN ICON DISCARDABLE "state11.ico"
ID_PKGSTATE_REMOVE ICON DISCARDABLE "state12.ico"
ID_PKGSTATE_PURGE ICON DISCARDABLE "state13.ico"
+/* Template for dialogue box to document the meanings of these icons;
+ * (display is restricted to subset in current active deployment).
+ */
+IDM_HELP_LEGEND DIALOG DISCARDABLE 10, 20, 190, 140
+CAPTION "Icon Legend"
+STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_CAPTION | WS_DLGFRAME
+FONT 10, "Verdana"
+BEGIN
+ LTEXT "mingw-get indicates the status of all packages using the " \
+ "following set of icons, one of which is displayed to the left " \
+ "of each entry within the package list:", -1, 5, 4, 180, 24
+ CONTROL ID_PKGSTATE_AVAILABLE, ID_PKGSTATE_AVAILABLE, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 34, 0, 0
+ LTEXT "Package available in repository; not installed.", \
+ -1, 20, 34, 186, 10
+ CONTROL ID_PKGSTATE_AVAILABLE_INSTALL, ID_PKGSTATE_AVAILABLE_INSTALL, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 44, 0, 0
+ LTEXT "Package selected; marked for installation.", \
+ -1, 20, 44, 186, 10
+ CONTROL ID_PKGSTATE_INSTALLED_CURRENT, ID_PKGSTATE_INSTALLED_CURRENT, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 54, 0, 0
+ LTEXT "Package installed; version is latest available.", \
+ -1, 20, 54, 186, 10
+ CONTROL ID_PKGSTATE_INSTALLED_OLD, ID_PKGSTATE_INSTALLED_OLD, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 64, 0, 0
+ LTEXT "Package installed; newer version available.", \
+ -1, 20, 64, 186, 10
+ CONTROL ID_PKGSTATE_UPGRADE, ID_PKGSTATE_UPGRADE, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 74, 0, 0
+ LTEXT "Package installed; marked for upgrade.", \
+ -1, 20, 74, 186, 10
+ CONTROL ID_PKGSTATE_REINSTALL, ID_PKGSTATE_REINSTALL, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 84, 0, 0
+ LTEXT "Package installed; marked for reinstallation.", \
+ -1, 20, 84, 186, 10
+ CONTROL ID_PKGSTATE_REMOVE, ID_PKGSTATE_REMOVE, \
+ "Static", SS_ICON | SS_REALSIZEIMAGE, 7, 94, 0, 0
+ LTEXT "Package installed; marked for removal.", \
+ -1, 20, 94, 186, 10
+ DEFPUSHBUTTON "Dismiss", IDOK, 70, 115, 50, 14, WS_GROUP | WS_TABSTOP
+END
+
#define SS_CTEXTBOX SS_SUNKEN | SS_CENTER
#define ES_VT100 ES_LEFT | ES_READONLY | ES_MULTILINE | ES_AUTOVSCROLL
https://sf.net/p/mingw/mingw-get/ci/2f03be0794da22056b25d996a5e69ca3f1bb4d9b/
commit 2f03be0794da22056b25d996a5e69ca3f1bb4d9b
Author: Keith Marshall <kei...@us...>
Date: Tue Jul 30 10:22:31 2013 +0100
Avoid discarding pending changes when catalogue is updated.
diff --git a/ChangeLog b/ChangeLog
index 0276bb0..4592edc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2013-07-30 Keith Marshall <kei...@us...>
+
+ Avoid discarding pending changes when catalogue is updated.
+
+ * src/guimain.h (IDD_CONFIRMATION): New manifest constant; define it.
+ (AppWindowMaker::ConfirmActionDialogue): New static method; declare it.
+ (AppWindowMaker::ConfirmActionRequest): New method; declare it.
+
+ * src/guimain.rc (IDD_CONFIRMATION): Implement new dialogue template.
+
+ * src/guiexec.cpp (pkgConfirmAction, pkgConfirmActionClient): New
+ static variables; they are used as pseudo-arguments, together with...
+ (DIALOGUE_DISPATCH, DIALOGUE_RESPONSE, DIALOGUE_CHKSTATE): ...these
+ new macros; define them; they facilitate the implementation of...
+ (AppWindowMaker::ConfirmActionDialogue): ...this; implement it.
+ (AppWindowMaker::ConfirmActionRequest): Implement it; use it...
+ (AppWindowMaker::OnCommand) [IDM_REPO_UPDATE]: ...here, and...
+
+ * src/pkgdata.cpp (AppWindowMaker::OnClose): ...here.
+
2013-07-26 Keith Marshall <kei...@us...>
Make a minor GUI layout adjustment.
diff --git a/src/guiexec.cpp b/src/guiexec.cpp
index 32cef95..11edb9c 100644
--- a/src/guiexec.cpp
+++ b/src/guiexec.cpp
@@ -34,6 +34,7 @@
#include <unistd.h>
#include <wtkexcept.h>
+#include <wtkalign.h>
/* The DMH sub-system provides the following function, but it does not
* declare the prototype; (this is to obviate any automatic requirement
@@ -567,6 +568,145 @@ int AppWindowMaker::Invoked( void )
return WTK::MainWindowMaker::Invoked();
}
+/* The following static entities are provided to facilitate the
+ * implementation of the "discard changes" confirmation dialogue.
+ */
+static const char *pkgConfirmAction = NULL;
+static AppWindowMaker *pkgConfirmActionClient = NULL;
+
+static void dlgReplaceText( HWND dlg, ... )
+{
+ /* Local helper routine, used by AppWindowMaker::ConfirmActionDialogue(),
+ * to substitute the designated action description into the format strings,
+ * as specified within the dialogue box template.
+ *
+ * First step is to copy the format specification from the dialogue item.
+ */
+ int len = 1 + SendMessage( dlg, WM_GETTEXTLENGTH, 0, 0 );
+ char fmt[len]; SendMessage( dlg, WM_GETTEXT, len, (LPARAM)(fmt) );
+
+ /* Having established the format, we allocate a sufficient buffer, in
+ * which we prepare the formatted text...
+ */
+ va_list argv; va_start( argv, dlg );
+ char text[1 + vsnprintf( NULL, 0, fmt, argv )];
+ vsnprintf( text, sizeof( text ), fmt, argv );
+ va_end( argv );
+
+ /* ...which we then copy back to the active dialogue item.
+ */
+ SendMessage( dlg, WM_SETTEXT, 0, (LPARAM)(text) );
+}
+
+int CALLBACK AppWindowMaker::ConfirmActionDialogue
+( HWND dlg, unsigned int msg, WPARAM wparam, LPARAM lparam )
+#define DIALOGUE_CHKSTATE pkgConfirmActionClient->EnumerateActions
+#define DIALOGUE_DISPATCH pkgConfirmActionClient->DispatchDialogueThread
+#define DIALOGUE_RESPONSE pkgConfirmActionClient->DialogueResponse
+{
+ /* Call back handler for the messages generated by the "discard changes"
+ * confirmation dialogue.
+ */
+ switch( msg )
+ { case WM_INITDIALOG:
+ /* When the confirmation dialogue is invoked, we centre it within
+ * its owner window, and replace the format specification strings
+ * from its text controls with their formatted equivalents.
+ */
+ WTK::AlignWindow( dlg, WTK_ALIGN_CENTRED );
+ dlgReplaceText( GetDlgItem( dlg, IDD_PROGRESS_MSG ), pkgConfirmAction );
+ dlgReplaceText( GetDlgItem( dlg, IDD_PROGRESS_TXT ), pkgConfirmAction,
+ pkgConfirmAction
+ );
+ return TRUE;
+
+ case WM_COMMAND:
+ /* Process the messages from the dialogue's three command buttons:
+ */
+ switch( msg = LOWORD( wparam ) )
+ {
+ case IDIGNORE:
+ /* Sent when the user selects the "Discard Changes" option,
+ * we return "IDOK" to confirm that the action should be
+ * progressed, ignoring any uncommitted changes.
+ */
+ EndDialog( dlg, IDOK );
+ return TRUE;
+
+ case IDOK:
+ /* Sent when the user selects the "Review Changes" option; we
+ * shelve the active dialogue, and delegate the decision as to
+ * whether to proceed to the "Apply Changes" dialogue.
+ */
+ ShowWindow( dlg, SW_HIDE );
+ switch( DIALOGUE_RESPONSE( IDD_APPLY_APPROVE, pkgApplyApproved ) )
+ {
+ case ID_DEFER:
+ /* Handle a "Defer" request from the "Apply Changes"
+ * dialogue as equivalent to our own "Cancel Request"
+ * option.
+ */
+ msg = IDCANCEL;
+ break;
+
+ case ID_APPLY:
+ /* When "Apply" confirmation is forthcoming, we proceed to
+ * download any required packages, and invoke the scheduled
+ * remove, upgrade, or install actions.
+ */
+ DIALOGUE_DISPATCH( IDD_APPLY_DOWNLOAD, pkgInvokeDownload );
+ DIALOGUE_DISPATCH( IDD_APPLY_EXECUTE, pkgApplyChanges );
+
+ /* Ensure that all "Apply" actions completed successfully...
+ */
+ if( DIALOGUE_CHKSTATE( ACTION_UNSUCCESSFUL ) > 0 )
+ /*
+ * ...otherwise, cancel the ensuing action, so that the
+ * user may have an opportunity to remedy the problem.
+ */
+ msg = IDCANCEL;
+ }
+ /* Regardless of the outcome from the "Review Changes" activity,
+ * simply fall through to terminate the dialogue appropriately.
+ */
+ case IDCANCEL:
+ /* Sent when the user selects the "Cancel Request" option; we
+ * simply allow the message ID to propagate back to the caller,
+ * as the response code.
+ */
+ EndDialog( dlg, msg );
+ return TRUE;
+ }
+ }
+ /* We don't handle any other message; if any is received, mark it as
+ * "unhandled", and pass it on to the default dialogue handler.
+ */
+ return FALSE;
+}
+
+bool AppWindowMaker::ConfirmActionRequest( const char *desc )
+{
+ /* Helper to confirm user's intent to proceed, when a request
+ * to update the catalogue, or to quit, would result in pending
+ * installation actions being discarded.
+ *
+ * We begin by saving reference data to be passed to the static
+ * dialogue handler method...
+ */
+ pkgConfirmAction = desc;
+ pkgConfirmActionClient = this;
+
+ /* ...prior to checking for pending actions, and invoking the
+ * dialogue procedure when appropriate, or simply allowing the
+ * action to proceed, otherwise.
+ */
+ return (pkgData->Schedule()->EnumeratePendingActions() > 0)
+ ? DialogBox( AppInstance, MAKEINTRESOURCE( IDD_CONFIRMATION ),
+ AppWindow, ConfirmActionDialogue
+ ) == IDOK
+ : true;
+}
+
long AppWindowMaker::OnCommand( WPARAM cmd )
#define ACTION_PRESERVE_FAILED (ACTION_DOWNLOAD_FAILED | ACTION_APPLY_FAILED)
{
@@ -623,8 +763,15 @@ long AppWindowMaker::OnCommand( WPARAM cmd )
* dialogue, from which a background thread is invoked to download
* fresh copies of the package catalogue files from the remote
* repository, and consolidate them into the local catalogue.
+ *
+ * Note that this activity will cause any pending installation
+ * actions to be discarded; seek confirmation of user's intent
+ * to proceed, when this situation prevails.
*/
- DispatchDialogueThread( IDD_REPO_UPDATE, pkgInvokeUpdate );
+ if( ConfirmActionRequest( "update the catalogue" ) )
+ { DispatchDialogueThread( IDD_REPO_UPDATE, pkgInvokeUpdate );
+ UpdatePackageMenuBindings();
+ }
break;
case IDM_REPO_MARK_UPGRADES:
diff --git a/src/guimain.h b/src/guimain.h
index 383727f..c2795c5 100644
--- a/src/guimain.h
+++ b/src/guimain.h
@@ -97,6 +97,7 @@
#define IDD_PROGRESS_MAX 616
#define IDD_PROGRESS_PCT 617
#define IDD_PROGRESS_TXT 618
+#define IDD_CONFIRMATION 619
#define IDD_APPLY_APPROVE 630
#define IDD_APPLY_DOWNLOAD 631
@@ -218,6 +219,8 @@ class AppWindowMaker: public WTK::MainWindowMaker
HWND PackageListView;
void InitPackageListView( void );
void UpdatePackageMenuBindings( void );
+ bool ConfirmActionRequest( const char * );
+ static int CALLBACK ConfirmActionDialogue( HWND, unsigned, WPARAM, LPARAM );
void Schedule( unsigned long, const char * = NULL, const char * = NULL );
inline void MarkSchedule( pkgActionItem * );
void SelectPackageAction( unsigned );
diff --git a/src/guimain.rc b/src/guimain.rc
index b40d745..e077640 100644
--- a/src/guimain.rc
+++ b/src/guimain.rc
@@ -175,6 +175,27 @@ BEGIN
LTEXT "", IDD_PROGRESS_MSG, 7, 6, 256, 12
END
+IDD_CONFIRMATION DIALOG DISCARDABLE 10, 20, 270, 115
+CAPTION "Action Requires Confirmation"
+STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_CAPTION | WS_DLGFRAME
+FONT 10, "Verdana"
+BEGIN
+ ICON IDI_WARNING, IDI_WARNING, 15, 16, 0, 0
+ LTEXT "You have marked packages for installation, upgrade, or " \
+ "removal, but you have not yet committed these changes; " \
+ "if you %s without committing these changes, they will " \
+ "be discarded, and you may need to reschedule them.", \
+ IDD_PROGRESS_MSG, 42, 10, 219, 35
+ LTEXT "You are advised to review your marked changes, before you " \
+ "%s; (you may select the ""Review Changes"" option button " \
+ "below), or alternatively, you may simply discard the changes, " \
+ "unseen, or you may cancel this request to %s.", \
+ IDD_PROGRESS_TXT, 9, 50, 260, 35
+ DEFPUSHBUTTON "Review Changes", IDOK, 10, 91, 76, 13, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Discard Changes", IDIGNORE, 97, 91, 76, 13, WS_TABSTOP
+ PUSHBUTTON "Cancel Request", IDCANCEL, 184, 91, 76, 13, WS_TABSTOP
+END
+
/* Template for dialogue requesting user confirmation of intent
* to proceed with scheduled change actions.
*/
diff --git a/src/pkgdata.cpp b/src/pkgdata.cpp
index 68fc24c..841e07b 100644
--- a/src/pkgdata.cpp
+++ b/src/pkgdata.cpp
@@ -1483,15 +1483,7 @@ long AppWindowMaker::OnClose()
* option for the termination request, so that the user
* has an opportunity to complete such actions.
*/
- if( (pkgData->Schedule()->EnumeratePendingActions() > 0)
- && (MessageBox( AppWindow,
- "You have marked changes which have not been applied;\n"
- "these will be lost, if you quit without applying them.\n\n"
- "Are you sure you want to discard these marked changes?",
- "Discard Marked Changes?", MB_YESNO | MB_ICONWARNING
- ) == IDNO)
- ) return 0;
- return -1;
+ return ConfirmActionRequest( "quit" ) ? -1 : 0;
}
/* $RCSfile$: end of file */
https://sf.net/p/mingw/mingw-get/ci/31d0a301318e3b225a581df457507fe436197005/
commit 31d0a301318e3b225a581df457507fe436197005
Author: Keith Marshall <kei...@us...>
Date: Fri Jul 26 11:18:59 2013 +0100
Make a minor GUI layout adjustment.
diff --git a/ChangeLog b/ChangeLog
index f094054..0276bb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-07-26 Keith Marshall <kei...@us...>
+
+ Make a minor GUI layout adjustment.
+
+ * src/pkgview.cpp (VSASH_INIT_POS): Increment from 0.30 to 0.35; this
+ sets the initial height of the package list pane to be 35% of the main
+ window height, which, at the default initial window size, neatly fits
+ the entire "Basic Setup" package group, without scrolling, on my
+ 1366x768 pixel Win7-VM display.
+
2013-07-25 Keith Marshall <kei...@us...>
Implement setup tool installer "plugin".
diff --git a/src/pkgview.cpp b/src/pkgview.cpp
index 61a3593..a1ec38d 100644
--- a/src/pkgview.cpp
+++ b/src/pkgview.cpp
@@ -52,7 +52,7 @@ static const double HSASH_MAX_POS = 0.40;
* measured from its top edge.
*/
static const double VSASH_MIN_POS = 0.25;
-static const double VSASH_INIT_POS = 0.30;
+static const double VSASH_INIT_POS = 0.35;
static const double VSASH_MAX_POS = 0.60;
HWND AppWindowMaker::Create( const char *class_name, const char *caption )
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 56 +++++++++++++++++++
src/guiexec.cpp | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/guimain.h | 3 +
src/guimain.rc | 75 ++++++++++++++++++++++++--
src/pkgdata.cpp | 10 +---
src/pkgview.cpp | 2 +-
6 files changed, 284 insertions(+), 20 deletions(-)
hooks/post-receive
--
Repository: mingw-get
|
|
From: Earnie B. <no...@so...> - 2013-07-29 01:55:02
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-org-wsl".
The branch, 4.0-dev has been updated
via b95d3b266051084843c1ae03878c1de1d3bc6c1b (commit)
from e1b06ae715fd7eefa1cf4465c89c4fb660b44bff (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-org-wsl/ci/b95d3b266051084843c1ae03878c1de1d3bc6c1b/
commit b95d3b266051084843c1ae03878c1de1d3bc6c1b
Author: Earnie Boyd <ea...@us...>
Date: Sun Jul 28 21:54:19 2013 -0400
Correction for issue #2007.
diff --git a/ChangeLog b/ChangeLog
index 0e4caac..0e00230 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2013-07-28 Earnie Boyd <ea...@us...>
+
+ Correction for issue #2007.
+
+ * Makefile.in: Corrected for missing libgmon.a objects and headers.
+ * misc/gpl/profile/profil.h: Move to ...
+ * misc/gpl/include/profil.h: Here.
+ * misc/src/libcrt/profile/gmon.h: Move to ...
+ * misc/src/include/gmon.h: Here.
+
2013-06-28 Earnie Boyd <ea...@us...>
* include/tchar.h (_tcsclen): Add missing define.
diff --git a/Makefile.in b/Makefile.in
index 0314737..377cfd2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -58,6 +58,7 @@ MKDIR_P = @MKDIR_P@
INCLUDES=-I$(top_srcdir)/include -I$(srcdir)/include \
-I$(top_srcdir)/src/libcrt/include -I$(top_srcdir)/misc/src/include \
+ -I$(top_srcdir)/misc/include -I$(top_srcdir)/misc/gpl/include \
-nostdinc -iwithprefixbefore include
ALL_CFLAGS=$(CFLAGS) $(INCLUDES) -DNTDDI_VERSION=0x04000000
@@ -527,7 +528,7 @@ SRCDIR := misc/src/libcrt/profile
profile_SOURCES := \
$(SRCDIR)/gmon.c \
$(SRCDIR)/mcount.c \
- misc/gpl/profile/profil.c \
+ misc/gpl/profile/profil.c
libgmon_a_SOURCES := $(profile_SOURCES)
libgmon_a_OBJECTS := $(libgmon_a_SOURCES:.c=.o)
@@ -948,12 +949,24 @@ install-includes:
for INC in $(top_srcdir)/include/*.h; do \
$(INSTALL_DATA) $$INC $(DESTDIR)$(includedir) ; \
done
+ for INC in $(top_srcdir)/misc/include/*.h; do \
+ $(INSTALL_DATA) $$INC $(DESTDIR)$(includedir) ; \
+ done
+ for INC in $(top_srcdir)/misc/gpl/include/*.h; do \
+ $(INSTALL_DATA) $$INC $(DESTDIR)$(includedir) ; \
+ done
for I in `find $(top_srcdir)/include/* -type d`; do \
J=`basename $$I`; \
for INC in $$I/*.h; do \
$(INSTALL_DATA) $$INC $(DESTDIR)$(includedir)/$$J ; \
done \
done
+ for I in `find $(top_srcdir)/misc/include/* -type d`; do \
+ J=`basename $$I`; \
+ for INC in $$I/*.h; do \
+ $(INSTALL_DATA) $$INC $(DESTDIR)$(includedir)/$$J ; \
+ done \
+ done
install-bins: all
for BIN in $(bin_LIBRARIES); do \
@@ -991,6 +1004,9 @@ mingwrt_lib_SYS_INCLUDES := \
fcntl.h locking.h stat.h timeb.h unistd.h \
file.h param.h time.h types.h utime.h
+mingwrt_lib_MISC_INCLUDES := \
+ misc/include/profile.h \
+ misc/gpl/include/profil.h
install-mingwrt: install-mingwrt-dirs
for BIN in $(mingwrt_bin_LIBRARIES); do \
@@ -1002,6 +1018,9 @@ install-mingwrt: install-mingwrt-dirs
for INC in $(addprefix $(top_srcdir)/include/sys/,$(mingwrt_lib_SYS_INCLUDES)); do \
$(INSTALL_DATA) $$INC $(DESTDIR)$(includedir)/sys/ ; \
done
+ for INC in $(addprefix $(top_srcdir)/,$(mingwrt_lib_MISC_INCLUDES)); do \
+ $(INSTALL_DATA) $$INC $(DESTDIR)$(includedir)/ ; \
+ done
for LIB in $(mingwrt_lib_LIBRARIES); do \
$(INSTALL_DATA) $$LIB $(DESTDIR)$(libdir)/ ; \
done
diff --git a/misc/gpl/profile/profil.h b/misc/gpl/include/profil.h
similarity index 100%
rename from misc/gpl/profile/profil.h
rename to misc/gpl/include/profil.h
diff --git a/misc/src/libcrt/profile/gmon.h b/misc/src/include/gmon.h
similarity index 100%
rename from misc/src/libcrt/profile/gmon.h
rename to misc/src/include/gmon.h
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 10 ++++++++++
Makefile.in | 21 ++++++++++++++++++++-
misc/gpl/{profile => include}/profil.h | 0
misc/src/{libcrt/profile => include}/gmon.h | 0
4 files changed, 30 insertions(+), 1 deletions(-)
rename misc/gpl/{profile => include}/profil.h (100%)
rename misc/src/{libcrt/profile => include}/gmon.h (100%)
hooks/post-receive
--
Repository: mingw-org-wsl
|
|
From: Keith M. <no...@so...> - 2013-07-25 21:55:02
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 162f37bd962f36011251a3c23966f1d47a344e0e (commit)
via fbc3eaa39e32067578a43138a2a15ba6a0e00d30 (commit)
from 68841d602208bf7bf73bdd38173a2aa10444d385 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/162f37bd962f36011251a3c23966f1d47a344e0e/
commit 162f37bd962f36011251a3c23966f1d47a344e0e
Author: Keith Marshall <kei...@us...>
Date: Thu Jul 25 21:48:45 2013 +0100
Implement setup tool installer "plugin".
diff --git a/ChangeLog b/ChangeLog
index 9cfbaa8..f094054 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
2013-07-25 Keith Marshall <kei...@us...>
+ Implement setup tool installer "plugin".
+
+ * src/setup.h (SETUP_HOOK_RUN_INSTALLER): Define request code.
+
+ * src/dllhook.cpp (run_basic_system_installer): Implement handler...
+ (setup_hook) [SETUP_HOOK_RUN_INSTALLER]: ...and invoke it.
+ (setup_hook) [default]: Collect diagnostics in common message digest.
+ (AppWindowMaker::SetupHookInvoked): Define and initialise it; in this
+ context, which does not conflict with prior definition in guimain.exe,
+ it must always remain true.
+
+ * src/setup.cpp (SetupTool) [constructor]: Invoke...
+ (SetupTool::DispatchSetupHookRequest): ...this, on user's request...
+ (SETUP_HOOK_RUN_INSTALLER): ...with this action code; this replaces...
+ (SetupTool::RunInstalledProgram): ...one reference instance for this
+ external program fork, leaving only one such reference remaining;
+ declare it to be "inline".
+
+ * Makefile.in (GUIMAIN_LIB_OBJECTS): New macro; define it. It
+ abstracts a subset of the object modules originally enumerated...
+ (GUIMAIN_OBJECTS): ...here, whence use it; also incorporate into...
+ (SETUP_DLL_OBJECTS): ...this.
+ (SETUP_DLL_LIBS): Make it equivalent to...
+ (GUIMAIN_LIBS): ...this.
+ (mingw-get-setup-0.dll): Use...
+ (GUI_LDFLAGS): ...this, to specify linking options, rather than...
+ (LDFLAGS): ...this.
+
+2013-07-25 Keith Marshall <kei...@us...>
+
Add "Basic Setup" as a built-in standard package group.
* src/guimain.h (AppWindowMaker::SetupToolInvoked): New private
diff --git a/Makefile.in b/Makefile.in
index 9abc7af..7717e56 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -173,17 +173,22 @@ CLI_EXE_OBJECTS = \
clistub.$(OBJEXT) version.$(OBJEXT) approot.$(OBJEXT) getopt.$(OBJEXT)
GUIMAIN_OBJECTS = \
- guimain.$(OBJEXT) guiexec.$(OBJEXT) dmhguix.$(OBJEXT) \
- approot.$(OBJEXT) pkgview.$(OBJEXT) pkgtree.$(OBJEXT) pkglist.$(OBJEXT) \
- pkgdata.$(OBJEXT) pkgnget.$(OBJEXT) guimain.res.$(OBJEXT)
+ guimain.$(OBJEXT) dmhguix.$(OBJEXT) $(GUIMAIN_LIB_OBJECTS) \
+ approot.$(OBJEXT) guimain.res.$(OBJEXT)
+
+GUIMAIN_LIB_OBJECTS = \
+ guiexec.$(OBJEXT) pkgview.$(OBJEXT) pkgtree.$(OBJEXT) pkglist.$(OBJEXT) \
+ pkgdata.$(OBJEXT) pkgnget.$(OBJEXT)
GUIMAIN_LIBS = -lwtklite -lcomctl32
SETUP_TOOL_OBJECTS = setup.$(OBJEXT) setup.res.$(OBJEXT) apihook.$(OBJEXT)
SETUP_TOOL_LIBS = -lwtklite -lwininet -lcomctl32 -lole32 -Wl,-Bstatic -llzma
-SETUP_DLL_OBJECTS = dllhook.$(OBJEXT)
-SETUP_DLL_LIBS =
+SETUP_DLL_OBJECTS = \
+ dllhook.$(OBJEXT) $(GUIMAIN_LIB_OBJECTS) guimain.res.$(OBJEXT)
+
+SETUP_DLL_LIBS = $(GUIMAIN_LIBS)
script_srcdir = ${srcdir}/scripts/libexec
@@ -225,7 +230,7 @@ mingw-get-0.dll: $(CORE_DLL_OBJECTS)
$(CXX) -shared -o $@ $(CXXFLAGS) $(LDFLAGS) $+ $(LIBS)
mingw-get-setup-0.dll: $(SETUP_DLL_OBJECTS) mingw-get-0.dll
- $(CXX) -shared -o $@ $(CXXFLAGS) $(LDFLAGS) $+ $(SETUP_DLL_LIBS)
+ $(CXX) -shared -o $@ $(CXXFLAGS) $(GUI_LDFLAGS) $+ $(SETUP_DLL_LIBS)
# The following recursive invocation hook provides a mechanism for
# accessing make's facility for reporting what it is doing, even when
diff --git a/src/dllhook.cpp b/src/dllhook.cpp
index 06394f9..3d117e3 100644
--- a/src/dllhook.cpp
+++ b/src/dllhook.cpp
@@ -48,6 +48,13 @@ static const char *setup_key = "setup";
#include <sys/stat.h>
#include <fcntl.h>
+/* This file implements the plugin variant of the mingw-get
+ * GUI installer, for use by the setup tool; in this context
+ * this AppWindowMaker static attribute must be initialised
+ * to indicate this mode of use.
+ */
+bool AppWindowMaker::SetupToolInvoked = true;
+
static const char *internal_error = "internal error";
#define MSG_INTERNAL_ERROR(MSG) "%s: "MSG_##MSG"\n", internal_error
@@ -204,6 +211,59 @@ void update_catalogue( HWND owner )
free( (void *)(dfile) );
}
+static inline
+int run_basic_system_installer( const wchar_t *dll_name )
+{
+ /* Hook to emulate a subset of the mingw-get GUI installer
+ * capabilities, via an embedded subset of its functions.
+ */
+ try
+ { /* Identify the DLL module, whence we may retrieve resources
+ * similar to those of the free-standing GUI application, and
+ * create a clone of that application's main window.
+ */
+ HINSTANCE instance;
+ AppWindowMaker MainWindow( instance = GetModuleHandleW( dll_name ) );
+ MainWindow.Create( WTK::StringResource( instance, ID_MAIN_WINDOW_CLASS ),
+ WTK::StringResource( instance, ID_MAIN_WINDOW_CAPTION )
+ );
+
+ /* Show this window, and paint its initial content...
+ */
+ MainWindow.Show( SW_SHOW );
+ MainWindow.Update();
+
+ /* ...then invoke its message loop, ultimately returning the
+ * status code which prevails, when the user closes it.
+ */
+ return MainWindow.Invoked();
+ }
+ catch( dmh_exception &e )
+ {
+ /* Here, we handle any fatal exception which has been raised
+ * and identified by the diagnostic message handler...
+ */
+ MessageBox( NULL, e.what(), "WinMain", MB_ICONERROR );
+ return EXIT_FAILURE;
+ }
+ catch( WTK::runtime_error &e )
+ {
+ /* ...while here, we diagnose any other error which was captured
+ * during the creation of the application's window hierarchy, or
+ * processing of its message loop...
+ */
+ MessageBox( NULL, e.what(), "WinMain", MB_ICONERROR );
+ return EXIT_FAILURE;
+ }
+ catch(...)
+ { /* ...and here, we diagnose any other error which we weren't
+ * able to explicitly identify.
+ */
+ MessageBox( NULL, "Unknown exception", "WinMain", MB_ICONERROR );
+ return EXIT_FAILURE;
+ }
+}
+
EXTERN_C __declspec(dllexport)
void setup_hook( unsigned int request, va_list argv )
{
@@ -230,12 +290,21 @@ void setup_hook( unsigned int request, va_list argv )
update_catalogue( va_arg( argv, HWND ) );
break;
+ case SETUP_HOOK_RUN_INSTALLER:
+ /* This hook invokes the mingw-get GUI, in setup tool mode, to
+ * facilitate installation of a user configured basic system.
+ */
+ run_basic_system_installer( va_arg( argv, const wchar_t * ) );
+ break;
+
default:
/* We should never get to here; it's a programming error in
* the setup tool, if we do.
*/
+ dmh_control( DMH_BEGIN_DIGEST );
dmh_notify( DMH_ERROR, MSG_INTERNAL_ERROR( INVALID_REQUEST ) );
dmh_notify( DMH_ERROR, MSG_INTERNAL_ERROR( NOTIFY_MAINTAINER ) );
+ dmh_control( DMH_END_DIGEST );
}
}
diff --git a/src/setup.cpp b/src/setup.cpp
index 4616be8..e9597d9 100644
--- a/src/setup.cpp
+++ b/src/setup.cpp
@@ -188,7 +188,7 @@ class SetupTool
( HWND, unsigned, WPARAM, LPARAM );
static const wchar_t *gui_program;
- int RunInstalledProgram( const wchar_t * );
+ inline int RunInstalledProgram( const wchar_t * );
inline wchar_t *setup_dll( void )
{ /* Helper function to ensure that the static "approot_path" buffer
@@ -1051,6 +1051,17 @@ base_dll( NULL ), hook_dll( NULL )
MAKEINTRESOURCE( IDD_SETUP_BEGIN ), NULL, OpeningDialogue
);
+ /* When the user has requested progression to package installation...
+ */
+ if( Status == EXIT_CONTINUE )
+ {
+ /* ...then delegate that to the embedded mingw-get plugin, before
+ * reasserting successful completion status for the setup tool.
+ */
+ DispatchSetupHookRequest( SETUP_HOOK_RUN_INSTALLER, setup_dll() );
+ Status = EXIT_SUCCESS;
+ }
+
/* If the mingw-get-0.dll and mingw-get-setup-0.dll libraries
* were successfully loaded, to complete the installation process,
* then we must now unload them; we also have no further use for
@@ -1062,17 +1073,6 @@ base_dll( NULL ), hook_dll( NULL )
/* We're done with the COM subsystem; release it.
*/
CoUninitialize();
-
- /* When the user has requested progression to advanced installation...
- */
- if( Status == EXIT_CONTINUE )
- {
- /* ...the delegate that to mingw-get itself, before reasserting
- * the successful completion status for the setup tool.
- */
- RunInstalledProgram( gui_program );
- Status = EXIT_SUCCESS;
- }
}
}
@@ -1285,7 +1285,7 @@ inline HMODULE SetupTool::HaveWorkingInstallation( void )
*/
const wchar_t *SetupTool::gui_program = L"libexec\\mingw-get\\guimain.exe";
-int SetupTool::RunInstalledProgram( const wchar_t *program )
+inline int SetupTool::RunInstalledProgram( const wchar_t *program )
{
/* Helper method to spawn an external process, into which a
* specified program image is loaded; (typically this will be
diff --git a/src/setup.h b/src/setup.h
index 155be28..9463c0c 100644
--- a/src/setup.h
+++ b/src/setup.h
@@ -86,7 +86,8 @@ enum
* serviced by mingw-get-setup-0.dll
*/
SETUP_HOOK_DMH_BIND = 0,
- SETUP_HOOK_POST_INSTALL
+ SETUP_HOOK_POST_INSTALL,
+ SETUP_HOOK_RUN_INSTALLER
};
class pkgSetupAction
https://sf.net/p/mingw/mingw-get/ci/fbc3eaa39e32067578a43138a2a15ba6a0e00d30/
commit fbc3eaa39e32067578a43138a2a15ba6a0e00d30
Author: Keith Marshall <kei...@us...>
Date: Thu Jul 25 12:15:52 2013 +0100
Add "Basic Setup" as a built-in standard package group.
diff --git a/ChangeLog b/ChangeLog
index b5423b0..9cfbaa8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2013-07-25 Keith Marshall <kei...@us...>
+
+ Add "Basic Setup" as a built-in standard package group.
+
+ * src/guimain.h (AppWindowMaker::SetupToolInvoked): New private
+ static member variable; declare it.
+
+ * src/guimain.cpp (AppWindowMaker::SetupToolInvoked): Define and
+ initialise it; this instance is specific to guimain.exe, where it
+ must always remain false.
+
+ * src/pkgtree.cpp (PKG_AFFILIATE_ALL): New constant; define it.
+ (load_package_group_hierarchy): Use it to specify those groups which
+ have all packages as affiliates, rather than just first root group.
+ (group_attributes): New static inline function; implement it, then...
+ (is_affiliated) [PKG_AFFILIATE_ALL]: ...use it to identify groups
+ which are specified as having all packages as affiliates.
+ (AppWindowMaker::InitPackageTreeView): Construct a temporary XML
+ specification for the "Basic Setup" package group, thence add it to
+ the package tree view; mark it as default group selection when...
+ [AppWindowMaker::SetupToolInvoked]: ...this is true.
+
2013-07-14 Keith Marshall <kei...@us...>
Implement GUI filtering of package list by group selection.
diff --git a/src/guimain.cpp b/src/guimain.cpp
index e4c89d7..2b0e11a 100644
--- a/src/guimain.cpp
+++ b/src/guimain.cpp
@@ -29,6 +29,12 @@
#include "pkglock.h"
#include "dmh.h"
+/* This is the main program source for the full, free-standing
+ * mingw-get GUI installer; initialise this static AppWindowMaker
+ * attribute, indicating that this is not a setup tool plugin.
+ */
+bool AppWindowMaker::SetupToolInvoked = false;
+
using WTK::StringResource;
using WTK::WindowClassMaker;
using WTK::MainWindowMaker;
diff --git a/src/guimain.h b/src/guimain.h
index 0677e6b..383727f 100644
--- a/src/guimain.h
+++ b/src/guimain.h
@@ -212,6 +212,7 @@ class AppWindowMaker: public WTK::MainWindowMaker
HFONT DefaultFont;
static HWND PackageTreeView;
+ static bool SetupToolInvoked;
void InitPackageTreeView( void );
HWND PackageListView;
diff --git a/src/pkgtree.cpp b/src/pkgtree.cpp
index 4cfdc52..62ac2ee 100644
--- a/src/pkgtree.cpp
+++ b/src/pkgtree.cpp
@@ -32,6 +32,8 @@
#include "pkgbase.h"
#include "pkgkeys.h"
+#define PKG_AFFILIATE_ALL 1
+
static const char *package_group_key = "package-group";
static const char *package_group_all = "All Packages";
@@ -148,12 +150,15 @@ load_package_group_hierarchy( HWND display, HTREEITEM parent, pkgXmlNode *group
* database representation, into a Windows tree view control.
*/
TVINSERTSTRUCT ref;
+ static long root_affiliate = PKG_AFFILIATE_ALL;
/* Establish initial state for the tree view item insertion control.
*/
ref.hParent = parent;
- ref.item.mask = TVIF_TEXT | TVIF_CHILDREN;
ref.hInsertAfter = TVI_FIRST;
+ ref.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
+ ref.item.lParam = root_affiliate;
+ root_affiliate = 0;
do { /* For each package group specified at the current level in the
* package group hierarchy, retrieve its name from the XML record...
@@ -168,6 +173,7 @@ load_package_group_hierarchy( HWND display, HTREEITEM parent, pkgXmlNode *group
* ...and add a corresponding entry to the tree view.
*/
ref.hInsertAfter = TreeView_InsertItem( display, &ref );
+ ref.item.lParam = 0;
/* Check if the current group is to be made the initial selection,
* when the tree view is first displayed; the last entry so marked
@@ -274,12 +280,36 @@ void AppWindowMaker::InitPackageTreeView()
TreeView_InsertItem( PackageTreeView, &entry );
}
else
- /* The package group hierarchy has been incorporated into
+ { /* The package group hierarchy has been incorporated into
* the in-core image of the XML database; create a windows
* "tree view", into which we load a representation of the
* structure of this hierarchy.
*/
load_package_group_hierarchy( PackageTreeView, TVI_ROOT, tree );
+
+ /* Augment this "All Packages" hierarchy...
+ */
+ if( (tree = new pkgXmlNode( package_group_key )) != NULL )
+ {
+ /* ...by the addition of a further "Basic Setup"
+ * category at root level...
+ */
+ tree->SetAttribute( name_key, "Basic Setup" );
+ if( SetupToolInvoked )
+ /*
+ * ...which becomes the default group selection when
+ * running the installer from within the setup tool.
+ */
+ tree->SetAttribute( select_key, value_true );
+ load_package_group_hierarchy( PackageTreeView, TVI_ROOT, tree );
+
+ /* The XML node, from which we created the "Basic Setup"
+ * group entry, has not been attached to the in-core image
+ * of the XML database; we have no need to keep it.
+ */
+ delete tree;
+ }
+ }
}
static bool is_child_affiliate( HWND tree, TVITEM *ref, const char *name )
@@ -322,6 +352,16 @@ static bool is_child_affiliate( HWND tree, TVITEM *ref, const char *name )
return false;
}
+static inline long group_attributes( HWND tree, TVITEM *ref )
+{
+ /* Helper to retrieve the application specific attributes
+ * which are associated with a package group tree item.
+ */
+ ref->mask = TVIF_PARAM;
+ TreeView_GetItem( tree, ref );
+ return ref->lParam;
+}
+
static inline bool is_affiliated( HWND tree, const char *name )
{
/* Helper to initiate a determination if a specified package
@@ -331,11 +371,11 @@ static inline bool is_affiliated( HWND tree, const char *name )
*/
TVITEM ref;
if( ((ref.hItem = TreeView_GetSelection( tree )) == NULL)
- || (ref.hItem == TreeView_GetRoot( tree )) )
+ || ((group_attributes( tree, &ref ) & PKG_AFFILIATE_ALL) != 0) )
/*
* Before proceeding further, we may note that ANY group name
- * is considered to be IMPLICITLY matched, at the root of the
- * package group tree.
+ * is considered to be IMPLICITLY matched, for specified groups
+ * (nominally at the root) within the package group tree.
*/
return true;
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 52 +++++++++++++++++++++++++++++++++++++++++
Makefile.in | 17 ++++++++----
src/dllhook.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/guimain.cpp | 6 ++++
src/guimain.h | 1 +
src/pkgtree.cpp | 50 +++++++++++++++++++++++++++++++++++----
src/setup.cpp | 26 ++++++++++----------
src/setup.h | 3 +-
8 files changed, 199 insertions(+), 25 deletions(-)
hooks/post-receive
--
Repository: mingw-get
|
|
From: Keith M. <no...@so...> - 2013-07-23 21:30:59
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-dist".
The branch, master has been updated
via 5982d124564b71ea2bbd7ab4e3d51a10db545eff (commit)
from 96b8f690a9efadeba780e2d94f07b60b958ab099 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-dist/ci/5982d124564b71ea2bbd7ab4e3d51a10db545eff/
commit 5982d124564b71ea2bbd7ab4e3d51a10db545eff
Author: Keith Marshall <kei...@us...>
Date: Tue Jul 23 22:30:04 2013 +0100
Correct some "Basic Setup" package group affiliations.
diff --git a/ChangeLog b/ChangeLog
index 844a17c..29794ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2013-07-23 Keith Marshall <kei...@us...>
+
+ Correct some "Basic Setup" package group affiliations.
+
+ * msys/msys-base.xml (msys-tiny): Drop erroneous affiliation.
+ (msys-base): Affiliate this instead, as originally intended.
+
+ * msys/mingw-developer-toolkit.xml: Add affiliation for...
+ (mingw-developer-toolkit): ...this.
+
+ * common/package-list.xml.lzma msys/msys-package-list.xml.lzma:
+ Regenerated and published.
+
+ * common/issue.log msys/issue.log: Updated.
+
2013-07-22 Keith Marshall <kei...@us...>
Add hooks to support mingw-get-setup.exe
diff --git a/common/issue.log b/common/issue.log
index eaa5b2e..d8ebb80 100644
--- a/common/issue.log
+++ b/common/issue.log
@@ -23,6 +23,6 @@
# MinGW Project, accept liability for any damages, however caused,
# arising from the use of this software.
#
- 75fc52dde8d408d798c0be51070d5d02f4c63085 2013072201 package-list.xml
+ 75fc52dde8d408d798c0be51070d5d02f4c63085 2013072300 package-list.xml
#
# $RCSfile$: end of file
diff --git a/msys/issue.log b/msys/issue.log
index 7ecfdd0..38fec4d 100644
--- a/msys/issue.log
+++ b/msys/issue.log
@@ -23,11 +23,11 @@
# MinGW Project, accept liability for any damages, however caused,
# arising from the use of this software.
#
- 71d9784c4b1d73fd13e665b8416d89dfa226720d 2011082600 mingw-developer-toolkit.xml
+ 6c0df6cc51c6ff5c12cf69daca779822a58e70ec 2013072300 mingw-developer-toolkit.xml
450bfc448c104abff6126411662b993922afea1a 2012073100 msys-autoconf.xml
8384936e52651ea2fcdbb8cba5fb7eb880699118 2012073100 msys-autogen.xml
a7ff50459cd0958291619c918690c2a716149aa0 2012073100 msys-automake.xml
- d5d18adb8625b7c70ffbabc16aea7a88b94ddefb 2013072200 msys-base.xml
+ 99df5097edfe73e5081a1234d84f6c87ce5f46d2 2013072300 msys-base.xml
56b441272a03bc5ade62d4c7dc9595468baa922f 2012073100 msys-bash.xml
e52982cbff0b0bb825461deb9af0411f72f2e4a2 2010090600 msys-binutils.xml
098df570908eec421a271133cd0556f5894cce65 2012073100 msys-bison.xml
@@ -73,7 +73,7 @@
ec0f6517ee5afb3d8f4887dd0061b558604fd3f5 2012073100 msys-mktemp.xml
243df0057053eebc442d922dff075e09fb579805 2012073100 msys-openssh.xml
0103c79956ba9fa128755cd93374f0fc334c7cf6 2012073100 msys-openssl.xml
- 0defc38585dbedbe010d82bdf6e4dbbae8fb1398 2013072200 msys-package-list.xml
+ 0defc38585dbedbe010d82bdf6e4dbbae8fb1398 2013072300 msys-package-list.xml
d19e1e39e5fab25a3d40acb92b98b40a60b0da90 2012073100 msys-patch.xml
245093d35b43710010bc2d13296a6492d2336204 2012073100 msys-perl.xml
19ddf46e23e23010a440af1b423d986712c3bda7 2012073100 msys-popt.xml
diff --git a/msys/mingw-developer-toolkit.xml b/msys/mingw-developer-toolkit.xml
index d8cc9f8..e03bd79 100644
--- a/msys/mingw-developer-toolkit.xml
+++ b/msys/mingw-developer-toolkit.xml
@@ -13,7 +13,10 @@
<download-host uri="http://prdownloads.sourceforge.net/mingw/%F?download" />
<package name="mingw-developer-toolkit" alias="mingw-dtk" class="virtual">
+
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Developer Toolkit" />
+
<description lang="en" title="An MSYS Installation for MinGW Developers (meta)">
<paragraph>This meta package contains the components necessary to
create a relatively complete MSYS installation suitable for most
diff --git a/msys/msys-base.xml b/msys/msys-base.xml
index 31927a3..ab5f01e 100644
--- a/msys/msys-base.xml
+++ b/msys/msys-base.xml
@@ -13,7 +13,6 @@
<package name="msys-tiny" alias="msys-minimal" class="virtual">
- <affiliate group="Basic Setup" />
<affiliate group="MSYS Base System" />
<description lang="en" title="A Tiny MSYS Installation (meta)">
@@ -32,7 +31,10 @@
</package>
<package name="msys-base" alias="msys" class="virtual">
+
+ <affiliate group="Basic Setup" />
<affiliate group="MSYS Base System" />
+
<description lang="en" title="A Basic MSYS Installation (meta)">
<paragraph>This meta package contains the components necessary
to create a basic, small, but relatively useful MSYS installation.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 15 +++++++++++++++
common/issue.log | 2 +-
msys/issue.log | 6 +++---
msys/mingw-developer-toolkit.xml | 3 +++
msys/msys-base.xml | 4 +++-
5 files changed, 25 insertions(+), 5 deletions(-)
hooks/post-receive
--
Repository: mingw-dist
|
|
From: Keith M. <no...@so...> - 2013-07-22 21:53:01
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-dist".
The branch, master has been updated
via 96b8f690a9efadeba780e2d94f07b60b958ab099 (commit)
from 95d09656467e0a9cd45745645af93a6bd5c8f507 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-dist/ci/96b8f690a9efadeba780e2d94f07b60b958ab099/
commit 96b8f690a9efadeba780e2d94f07b60b958ab099
Author: Keith Marshall <kei...@us...>
Date: Mon Jul 22 22:52:35 2013 +0100
Add hooks to support mingw-get-setup.exe
diff --git a/ChangeLog b/ChangeLog
index 0205a65..844a17c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2013-07-22 Keith Marshall <kei...@us...>
+
+ Add hooks to support mingw-get-setup.exe
+
+ * msys/msys-base.xml (msys-base):
+ * mingw32/mingw32-base.xml (mingw32-base):
+ * mingw32/mingw32-gcc4.xml (mingw32-gcc-ada, mingw32-gcc-g++):
+ (mingw32-gcc-fortran, mingw32-gcc-objc): Affiliate all with the
+ internally defined "Basic Setup" package group; regenerate and
+ publish all associated .lzma files.
+
+ * common/package-list.xml.lzma msys/msys-package-list.xml.lzma:
+ * mingw32/mingw32-package-list.xml.lzma: All regenerated and
+ published.
+
+ * common/issue.log mingw32/issue.log msys/issue.log: Updated.
+
2013-07-01 Earnie Boyd <ea...@us...>
* mingw32/mingw32-wsl-candidate.xml: Add wsl_rc-4.0-1-mingw32-rc-4.
diff --git a/common/issue.log b/common/issue.log
index 44254f7..eaa5b2e 100644
--- a/common/issue.log
+++ b/common/issue.log
@@ -23,6 +23,6 @@
# MinGW Project, accept liability for any damages, however caused,
# arising from the use of this software.
#
- 75fc52dde8d408d798c0be51070d5d02f4c63085 2013070100 package-list.xml
+ 75fc52dde8d408d798c0be51070d5d02f4c63085 2013072201 package-list.xml
#
# $RCSfile$: end of file
diff --git a/mingw32/issue.log b/mingw32/issue.log
index 263cd02..d29cd9e 100644
--- a/mingw32/issue.log
+++ b/mingw32/issue.log
@@ -26,7 +26,7 @@
cda14ddeaf475d6b912e23bba4b58d77f6f96d95 2012073100 mingw32-autoconf.xml
699b91750ed3187c613fb09ad6a4a048aba56c02 2012073100 mingw32-automake.xml
e2f730e78dc27254776b672fc007a4bef3dd0f56 2010090601 mingw32-autotools.xml
- 9de97172522316bb359227b484cfc9bc4c5b6c5a 2011060500 mingw32-base.xml
+ 31874b31b811211470b739b8af7fc6b9a97331e6 2013072200 mingw32-base.xml
221dd61fa0e2d7745ba41d05d18a3114e946c513 2012073100 mingw32-basic-bsdtar.xml
d1b4081a78ca60cac8c67fa84a6fb6b697075309 2012111500 mingw32-binutils.xml
b4c60a4702749a0369b5059e7c1f50ce567e2c95 2012073100 mingw32-bzip2.xml
@@ -35,7 +35,7 @@
a95192db0a6f7de983c642096ce2a335dcad8393 2012073100 mingw32-expat.xml
bc4b331f9bdfbf72a11a310fbc17a027396d09d5 2012073100 mingw32-gcc-tools.xml
9d1d9deeccee4fb04f2944e3cd5e7b85757308ce 2011050500 mingw32-gcc3.xml
- 78e642a82c7c5ace4a813c7f352dceb55e1d5c70 2012110500 mingw32-gcc4.xml
+ e6931e30df8003e7388f801e734a99a6ab9d1ff4 2013072200 mingw32-gcc4.xml
2aec3c75d5ccba91607e343bcc304f3baf24ae56 2012082702 mingw32-gdb.xml
14dd10ab97b27430bdb688f4e85993cd821f7a05 2012073100 mingw32-gendef.xml
84ba9fe58d5492be57bd8e41d10daa9fd8be4721 2012073100 mingw32-gettext.xml
@@ -50,7 +50,7 @@
cd33ad74b608bce33ea297801253e6efbafce27c 2012073100 mingw32-mingw-utils.xml
d31c39c6584fde6d4b9ddafbca913509b32a1dfc 2012073100 mingw32-mpc.xml
99995a8e17659b6514f71ae2b17bbbcd8eb4c0a9 2012073100 mingw32-mpfr.xml
- 983af8ad24a6f97da867784dfeeecc6661d54d88 2013070100 mingw32-package-list.xml
+ 983af8ad24a6f97da867784dfeeecc6661d54d88 2013072200 mingw32-package-list.xml
bad22da9b9ec9bcea1d539e29ee2976cc88d9fc2 2013053000 mingw32-pexports.xml
cdb2a4dbedfc9f2cdfc92340f6f9b12da061c0d9 2012073100 mingw32-popt.xml
9399cb6c2efd8fd907c42a278a6f41bbde9e440c 2011091400 mingw32-pthreads-w32.xml
diff --git a/mingw32/mingw32-base.xml b/mingw32/mingw32-base.xml
index bec3879..fd173d8 100644
--- a/mingw32/mingw32-base.xml
+++ b/mingw32/mingw32-base.xml
@@ -11,7 +11,10 @@
<download-host uri="http://prdownloads.sourceforge.net/mingw/%F?download" />
<package name="mingw32-base" alias="base mingw mingw32" class="virtual" >
+
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Base System" />
+
<description lang="en" title="A Basic MinGW Installation" >
<paragraph>This meta package provides a basic GCC installation,
and includes the C compiler, linker and other binary tools,
diff --git a/mingw32/mingw32-gcc4.xml b/mingw32/mingw32-gcc4.xml
index 27e5f4b..a8f3e13 100644
--- a/mingw32/mingw32-gcc4.xml
+++ b/mingw32/mingw32-gcc4.xml
@@ -113,6 +113,7 @@
</package>
<package name="mingw32-gcc-ada" alias="gcc-ada ada">
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Compiler Suite" />
<description lang="en" title="The GNU Ada Compiler">
<paragraph>
@@ -174,6 +175,7 @@
</package>
<package name="mingw32-gcc-g++" alias="gcc-g++ g++ gcc-c++ c++">
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Compiler Suite" />
<description lang="en" title="The GNU C++ Compiler">
<paragraph>
@@ -230,6 +232,7 @@
</package>
<package name="mingw32-gcc-fortran" alias="gcc-fortran gfortran fortran">
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Compiler Suite" />
<description lang="en" title="The GNU FORTRAN Compiler">
<paragraph>
@@ -310,6 +313,7 @@
</package> -->
<package name="mingw32-gcc-objc" alias="gcc-objc objc">
+ <affiliate group="Basic Setup" />
<affiliate group="MinGW Compiler Suite" />
<description lang="en" title="The GNU Objective-C Compiler">
<paragraph>
diff --git a/msys/issue.log b/msys/issue.log
index d86717b..7ecfdd0 100644
--- a/msys/issue.log
+++ b/msys/issue.log
@@ -27,7 +27,7 @@
450bfc448c104abff6126411662b993922afea1a 2012073100 msys-autoconf.xml
8384936e52651ea2fcdbb8cba5fb7eb880699118 2012073100 msys-autogen.xml
a7ff50459cd0958291619c918690c2a716149aa0 2012073100 msys-automake.xml
- b065e9528568d9250b98cf6a15e5f0b5ce5df559 2012040200 msys-base.xml
+ d5d18adb8625b7c70ffbabc16aea7a88b94ddefb 2013072200 msys-base.xml
56b441272a03bc5ade62d4c7dc9595468baa922f 2012073100 msys-bash.xml
e52982cbff0b0bb825461deb9af0411f72f2e4a2 2010090600 msys-binutils.xml
098df570908eec421a271133cd0556f5894cce65 2012073100 msys-bison.xml
@@ -73,7 +73,7 @@
ec0f6517ee5afb3d8f4887dd0061b558604fd3f5 2012073100 msys-mktemp.xml
243df0057053eebc442d922dff075e09fb579805 2012073100 msys-openssh.xml
0103c79956ba9fa128755cd93374f0fc334c7cf6 2012073100 msys-openssl.xml
- 0defc38585dbedbe010d82bdf6e4dbbae8fb1398 2013042100 msys-package-list.xml
+ 0defc38585dbedbe010d82bdf6e4dbbae8fb1398 2013072200 msys-package-list.xml
d19e1e39e5fab25a3d40acb92b98b40a60b0da90 2012073100 msys-patch.xml
245093d35b43710010bc2d13296a6492d2336204 2012073100 msys-perl.xml
19ddf46e23e23010a440af1b423d986712c3bda7 2012073100 msys-popt.xml
diff --git a/msys/msys-base.xml b/msys/msys-base.xml
index 5cfeed0..31927a3 100644
--- a/msys/msys-base.xml
+++ b/msys/msys-base.xml
@@ -12,7 +12,10 @@
<download-host uri="http://prdownloads.sourceforge.net/mingw/%F?download" />
<package name="msys-tiny" alias="msys-minimal" class="virtual">
+
+ <affiliate group="Basic Setup" />
<affiliate group="MSYS Base System" />
+
<description lang="en" title="A Tiny MSYS Installation (meta)">
<paragraph>This meta package provides the smallest possible
functional MSYS installation. It includes only MSYS itself,
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 17 +++++++++++++++++
common/issue.log | 2 +-
mingw32/issue.log | 6 +++---
mingw32/mingw32-base.xml | 3 +++
mingw32/mingw32-gcc4.xml | 4 ++++
msys/issue.log | 4 ++--
msys/msys-base.xml | 3 +++
7 files changed, 33 insertions(+), 6 deletions(-)
hooks/post-receive
--
Repository: mingw-dist
|
|
From: Keith M. <no...@so...> - 2013-07-14 21:21:42
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 68841d602208bf7bf73bdd38173a2aa10444d385 (commit)
from 69409177957a7886b1137bbef9e93355cd8ec595 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/68841d602208bf7bf73bdd38173a2aa10444d385/
commit 68841d602208bf7bf73bdd38173a2aa10444d385
Author: Keith Marshall <kei...@us...>
Date: Sun Jul 14 22:13:50 2013 +0100
Implement GUI filtering of package list by group selection.
diff --git a/ChangeLog b/ChangeLog
index 9146036..b5423b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2013-07-14 Keith Marshall <kei...@us...>
+
+ Implement GUI filtering of package list by group selection.
+
+ * src/pkgbase.h (pkgXmlNode::IsVisibleGroupMember):
+ (pkgXmlNode::IsVisibleClass): New inline methods; declare them.
+ (pkgXmlNode::MapPackageGroupHierarchy): New inline method; declare it.
+ (pkgXmlNode::SetPackageGroupHierarchyMapper): Likewise; it sets up...
+ (pkgXmlNode::PackageGroupHierarchyMapper): ...this new private static
+ function pointer; declare it as a function reference, in terms of...
+ (pkgXmlNode::GroupHierarchyMapper): ...this new typedef; define it.
+
+ * src/guimain.h (AppWindowMaker::PackageTreeView): Make it static.
+ (AppWindowMaker::IsPackageGroupAffiliate): Declare new static method.
+
+ * src/pkgbind.cpp (pkgRepository::GetPackageList): Make it invoke...
+ (pkgXmlNode::MapPackageGroupHierarchy): ...this; implement it.
+
+ * src/pkglist.cpp (pkgXmlNode::IsVisibleGroupMember): Implement it.
+ (pkgXmlNode::IsVisibleClass): Likewise; just provide a stub, for now.
+ (pkgListViewMaker::Dispatch): Use them to filter package list content.
+ (AppWindowMaker::UpdatePackageList): Redraw main window when done.
+
+ * src/pkgtree.cpp [_WIN32_IE >= 0x0400]: Require this.
+ (AppWindowMaker::PackageTreeView): Define and initialise it.
+ (AppWindowMaker::InitPackageTreeView): Extend implementation; use...
+ (map_package_group_hierarchy_recursive, load package_group_hierarchy):
+ (is_existing_group, map_package_group_hierarchy): ...these; implement
+ them locally, as file scoped static helper functions.
+ (select_key): New static local string constant; define it.
+ (pkgInitCategoryTreeGraft): Use it; also have it invoke...
+ (pkgXmlNode::SetPackageGroupHierarchyMapper): ...this; implement it.
+ (AppWindowMaker::IsPackageGroupAffiliate): Implement it; it uses...
+ (is_affiliated, is_child_affiliate): ...these helpers; provide them as
+ locally implemented, file scoped static functions.
+
+ * src/pkgdata.cpp (AppWindowMaker::OnNotify): Add handler for...
+ [ID_PACKAGE_TREEVIEW && TVN_SELCHANGED]: ...this notification.
+
2013-07-12 Keith Marshall <kei...@us...>
Correct a static string buffer aliasing issue.
diff --git a/src/guimain.h b/src/guimain.h
index 9c6b49d..0677e6b 100644
--- a/src/guimain.h
+++ b/src/guimain.h
@@ -185,6 +185,7 @@ class AppWindowMaker: public WTK::MainWindowMaker
int DispatchDialogueThread( int, pkgDialogueThread * );
void LoadPackageData( bool = false );
+ static bool IsPackageGroupAffiliate( pkgXmlNode * );
void ClearPackageList( void ){ ListView_DeleteAllItems( PackageListView ); }
void UpdatePackageList( void );
@@ -210,7 +211,7 @@ class AppWindowMaker: public WTK::MainWindowMaker
pkgProgressMeter *AttachedProgressMeter;
HFONT DefaultFont;
- HWND PackageTreeView;
+ static HWND PackageTreeView;
void InitPackageTreeView( void );
HWND PackageListView;
diff --git a/src/pkgbase.h b/src/pkgbase.h
index a801467..716829c 100644
--- a/src/pkgbase.h
+++ b/src/pkgbase.h
@@ -151,12 +151,28 @@ class pkgXmlNode : public TiXmlElement
return this ? strcmp( GetName(), tagname ) == 0 : false;
}
+ /* Methods to determine which packages should be displayed
+ * in the package list pane of the GUI client.
+ */
+ inline bool IsVisibleGroupMember();
+ inline bool IsVisibleClass();
+
/* Methods for retrieving the system root management records
* for a specified installed subsystem.
*/
pkgXmlNode *GetSysRoot( const char* );
pkgXmlNode *GetInstallationRecord( const char* );
+ /* Methods for mapping the package group hierarchy.
+ */
+ inline void SetPackageGroupHierarchyMapper();
+ inline void MapPackageGroupHierarchy( pkgXmlNode* );
+
+ /* Type definition for a helper function, which must be assigned
+ * to the package group hierarchy mapper, in order to enable it.
+ */
+ typedef void (*GroupHierarchyMapper)( pkgXmlNode*, pkgXmlNode* );
+
/* The following pair of methods provide an iterator
* for enumerating the contained nodes, within the owner,
* which themselves exhibit a specified tagname.
@@ -195,6 +211,11 @@ class pkgXmlNode : public TiXmlElement
*/
int InvokeScript( int, const char* );
int DispatchScript( int, const char*, const char*, pkgXmlNode* );
+
+ /* Hook via which the requisite helper function is attached
+ * to the package group hierarchy mapper.
+ */
+ static GroupHierarchyMapper PackageGroupHierarchyMapper;
};
enum { to_remove = 0, to_install, selection_types };
diff --git a/src/pkgbind.cpp b/src/pkgbind.cpp
index b6559c6..c713f3f 100644
--- a/src/pkgbind.cpp
+++ b/src/pkgbind.cpp
@@ -83,6 +83,21 @@ pkgRepository::pkgRepository
owner( client ), dbase( db ), repository( ref ), force_update( mode ),
expected_issue( value_assumed_new ){}
+/* Provide the hook, via which the package group hierarchy builder
+ * may gain access to its configuration data, during loading of the
+ * package list files.
+ */
+pkgXmlNode::GroupHierarchyMapper
+pkgXmlNode::PackageGroupHierarchyMapper = NULL;
+inline void pkgXmlNode::MapPackageGroupHierarchy( pkgXmlNode *catalogue )
+{
+ /* This is a no-op, unless the client attaches a handler to the
+ * hook, before invoking the package list loader.
+ */
+ if( PackageGroupHierarchyMapper != NULL )
+ PackageGroupHierarchyMapper( this, catalogue );
+}
+
void pkgRepository::GetPackageList( const char *dname )
{
/* Helper to retrieve and recursively process a named package list.
@@ -179,7 +194,11 @@ void pkgRepository::GetPackageList( const char *dname )
pkgXmlNode *catalogue, *pkglist;
if( (catalogue = merge.GetRoot()) != NULL )
{
- /* ...read it, selecting each of the "package-collection"
+ /* ...map any package group hierarchy which it specifies...
+ */
+ dbase->MapPackageGroupHierarchy( catalogue );
+
+ /* ...then read it, selecting each of the "package-collection"
* records contained within it...
*/
pkglist = catalogue->FindFirstAssociate( package_collection_key );
diff --git a/src/pkgdata.cpp b/src/pkgdata.cpp
index 3bbab20..68fc24c 100644
--- a/src/pkgdata.cpp
+++ b/src/pkgdata.cpp
@@ -1328,6 +1328,66 @@ long AppWindowMaker::OnNotify( WPARAM client_id, LPARAM data )
SelectPackageAction( LVHT_ONITEMICON );
}
break;
+
+ /* We also need to consider notifications from the tree view...
+ */
+ case ID_PACKAGE_TREEVIEW:
+ if( ((NMHDR *)(data))->code == TVN_SELCHANGED )
+ {
+ /* ...from which we are interested only in notifications
+ * that the user has changed the package group selection.
+ *
+ * First, we ensure that any children of the selected
+ * package group are made visible.
+ */
+ TreeView_Expand( PackageTreeView,
+ ((NMTREEVIEW *)(data))->itemNew.hItem, TVE_EXPAND
+ );
+
+ /* We then clear out the previous content of the list view
+ * pane, and reconstruct it with new content, as determined
+ * by the new package group selection...
+ */
+ ClearPackageList();
+ UpdatePackageList();
+
+ /* ...and reapply any scheduled action markers, which may
+ * be applicable.
+ */
+ MarkSchedule( pkgData->Schedule() );
+
+ /* Finally, provided the previous selection is not an
+ * ancestor of the current, we may collapse any visible
+ * subtree descending from the previous.
+ *
+ * FIXME: We may wish to avoid collapsing any subtree
+ * which was designated as "expanded", in the original
+ * group hierarchy specification. We may also wish to
+ * provide a user option, to disable this feature.
+ */
+ bool may_fold = true;
+ HTREEITEM prev = ((NMTREEVIEW *)(data))->itemNew.hItem;
+ while( may_fold && (prev != NULL) )
+ { if( prev == ((NMTREEVIEW *)(data))->itemOld.hItem )
+ /*
+ * Previous selection IS an ancestor of current;
+ * we must not collapse it.
+ */
+ may_fold = false;
+
+ else
+ /* Continue tracing ancestry, back to the root.
+ */
+ prev = TreeView_GetParent( PackageTreeView, prev );
+ }
+ if( may_fold )
+ /*
+ * Previous selection may be collapsed; do so.
+ */
+ TreeView_Expand( PackageTreeView,
+ ((NMTREEVIEW *)(data))->itemOld.hItem, TVE_COLLAPSE
+ );
+ }
}
/* Otherwise, this return causes any other notifiable events
* to be simply ignored, (as they were by the original stub).
diff --git a/src/pkglist.cpp b/src/pkglist.cpp
index 24f760a..db36205 100644
--- a/src/pkglist.cpp
+++ b/src/pkglist.cpp
@@ -113,8 +113,24 @@ void AppWindowMaker::UpdatePackageList()
pkgDirectory *dir = pkgData->CatalogueAllPackages();
dir->InOrder( &PackageList );
delete dir;
+
+ /* Force a redraw of the application window, to ensure that the
+ * data pane content remains synchronised.
+ */
+ InvalidateRect( AppWindow, NULL, FALSE );
+ UpdateWindow( AppWindow );
}
+inline bool pkgXmlNode::IsVisibleGroupMember()
+{
+ /* Hook invoked before adding a package reference to the package list,
+ * to ensure that it represents a member of the current package group.
+ */
+ return AppWindowMaker::IsPackageGroupAffiliate( this );
+}
+
+inline bool pkgXmlNode::IsVisibleClass(){ return true; }
+
static char *pkgGetTitle( pkgXmlNode *pkg, const pkgXmlNode *xml_root )
{
/* A private helper method, to retrieve the title attribute
@@ -421,7 +437,7 @@ void pkgListViewMaker::Dispatch( pkgXmlNode *package )
* dispatching the content of the directory to the display service,
* (which, in this case, populates the list view window pane).
*/
- if( package->IsElementOfType( package_key ) )
+ if( package->IsElementOfType( package_key ) && package->IsVisibleGroupMember() )
{
/* Assemble the package name into the list view record block.
*/
@@ -445,7 +461,7 @@ void pkgListViewMaker::Dispatch( pkgXmlNode *package )
*/
InsertItem( package, (char *)("") );
}
- else if( package->IsElementOfType( component_key ) )
+ else if( package->IsElementOfType( component_key ) && package->IsVisibleClass() )
{
/* Handle the recursive calls for the component sub-directory,
* inheriting the package name entry from the original package
diff --git a/src/pkgtree.cpp b/src/pkgtree.cpp
index b4285fe..4cfdc52 100644
--- a/src/pkgtree.cpp
+++ b/src/pkgtree.cpp
@@ -4,7 +4,7 @@
* $Id$
*
* Written by Keith Marshall <kei...@us...>
- * Copyright (C) 2012, MinGW.org Project
+ * Copyright (C) 2012, 2013, MinGW.org Project
*
*
* Implementation of the methods for the pkgTreeViewMaker class, and
@@ -26,6 +26,8 @@
* arising from the use of this software.
*
*/
+#define _WIN32_IE 0x0400
+
#include "guimain.h"
#include "pkgbase.h"
#include "pkgkeys.h"
@@ -36,9 +38,186 @@ static const char *package_group_all = "All Packages";
/* The following are candidates for inclusion in "pkgkeys";
* for now, we may keep them as local defines.
*/
+static const char *select_key = "select";
static const char *expand_key = "expand";
static const char *value_true = "true";
+static inline
+pkgXmlNode *is_existing_group( pkgXmlNode *dbase, const char *name )
+{
+ /* Helper to check for prior existence of a specified group name,
+ * at a specified level within the XML representation of the package
+ * group hierarchy, so we may avoid adding redundant duplicates.
+ */
+ while( dbase != NULL )
+ {
+ /* We haven't yet considered all XML database entries, at the
+ * requisite level; check the current reference entry...
+ */
+ if( safe_strcmp( strcasecmp, name, dbase->GetPropVal( name_key, NULL )) )
+ /*
+ * ...returning it immediately, if it is a named duplicate of
+ * the entry we are seeking to add.
+ */
+ return dbase;
+
+ /* When no duplicate found yet, move on to consider the next
+ * entry at the requisite XML database level, if any.
+ */
+ dbase = dbase->FindNextAssociate( package_group_key );
+ }
+ /* If we get to here, then no duplicate was found; the database
+ * reference must have become NULL, which we return.
+ */
+ return dbase;
+}
+
+static void
+map_package_group_hierarchy_recursive( pkgXmlNode *dbase, pkgXmlNode *group )
+{
+ /* Helper to recursively reconstruct an in-core image of the XML
+ * structure of the package list hierarchy, as it is specified in
+ * the package list read from external storage.
+ */
+ const char *name = group->GetPropVal( name_key, value_unknown );
+ pkgXmlNode *ref, *map = dbase->FindFirstAssociate( package_group_key );
+ if( (ref = is_existing_group( map, name )) == NULL )
+ {
+ /* The group name we are seeking to add doesn't yet appear at
+ * the requisite level within the in-core XML image; construct
+ * a new record, comprising the relevant data as represented
+ * in the external database...
+ */
+ ref = new pkgXmlNode( package_group_key );
+ ref->SetAttribute( name_key, name );
+ if( (name = group->GetPropVal( expand_key, NULL )) != NULL )
+ ref->SetAttribute( expand_key, name );
+
+ /* ...and attach it as the last sibling of any existing
+ * in-core records at the requisite level.
+ */
+ ref = (pkgXmlNode *)(dbase->LinkEndChild( ref ));
+ }
+ /* Recurse...
+ */
+ group = group->FindFirstAssociate( package_group_key );
+ while( group != NULL )
+ {
+ /* ...to capture any newly specified children of this group,
+ * regardless of whether the group already existed, or has
+ * just been added.
+ */
+ map_package_group_hierarchy_recursive( ref, group );
+ group = group->FindNextAssociate( package_group_key );
+ }
+}
+
+static void
+map_package_group_hierarchy( pkgXmlNode *dbase, pkgXmlNode *catalogue )
+{
+ /* Helper to kick-start the recursive mapping of external XML
+ * records into the in-core package group hierarchy image.
+ */
+ const char *group_hierarchy_key = "package-group-hierarchy";
+ if( (catalogue = catalogue->FindFirstAssociate( group_hierarchy_key )) != NULL )
+ {
+ /* We found a package group hierarchy specification...
+ */
+ dbase = dbase->FindFirstAssociate( package_group_key );
+ do { pkgXmlNode *group = catalogue->FindFirstAssociate( package_group_key );
+ while( group != NULL )
+ {
+ /* ...recursively map each top level package group
+ * which is specified within it...
+ */
+ map_package_group_hierarchy_recursive( dbase, group );
+ group = group->FindNextAssociate( package_group_key );
+ }
+ /* ...and repeat for any other package group hierarchy
+ * specifications we may encounter.
+ */
+ catalogue = catalogue->FindNextAssociate( group_hierarchy_key );
+ } while( catalogue != NULL );
+ }
+}
+
+static void
+load_package_group_hierarchy( HWND display, HTREEITEM parent, pkgXmlNode *group )
+{
+ /* Helper to load the package group hierarchy from it's in-core XML
+ * database representation, into a Windows tree view control.
+ */
+ TVINSERTSTRUCT ref;
+
+ /* Establish initial state for the tree view item insertion control.
+ */
+ ref.hParent = parent;
+ ref.item.mask = TVIF_TEXT | TVIF_CHILDREN;
+ ref.hInsertAfter = TVI_FIRST;
+
+ do { /* For each package group specified at the current level in the
+ * package group hierarchy, retrieve its name from the XML record...
+ */
+ pkgXmlNode *first_child = group->FindFirstAssociate( package_group_key );
+ ref.item.pszText = (char *)(group->GetPropVal( name_key, value_unknown ));
+ /*
+ * ...note whether any descendants are to be specified...
+ */
+ ref.item.cChildren = (first_child == NULL) ? 0 : 1;
+ /*
+ * ...and add a corresponding entry to the tree view.
+ */
+ ref.hInsertAfter = TreeView_InsertItem( display, &ref );
+
+ /* Check if the current group is to be made the initial selection,
+ * when the tree view is first displayed; the last entry so marked
+ * will become the actual initial selection. (Note that, to ensure
+ * that this setting cannot be abused by package maintainers, it is
+ * defined internally by mingw-get; it is not propagated from any
+ * external XML resource).
+ */
+ const char *option = group->GetPropVal( select_key, NULL );
+ if( (option != NULL) && (strcmp( option, value_true ) == 0) )
+ /*
+ * Make any group, which marked with the "select" attribute, the
+ * active selection; (note that this selection may be superseded,
+ * should another similarly marked group be encountered later).
+ */
+ TreeView_SelectItem( display, ref.hInsertAfter );
+
+ /* Any descendants specified, for the current group, must be
+ * processed recursively...
+ */
+ if( first_child != NULL )
+ {
+ /* There is at least one generation of children, of the current
+ * tree view entry; check if this entry should be expanded, so as
+ * to make its children visible in the initial view, recursively
+ * evaluate to identify further generations of descendants...
+ */
+ option = group->GetPropVal( expand_key, NULL );
+ load_package_group_hierarchy( display, ref.hInsertAfter, first_child );
+ if( (option != NULL) && (strcmp( option, value_true ) == 0) )
+ /*
+ * ...and expand to the requested level of visibility.
+ */
+ TreeView_Expand( display, ref.hInsertAfter, TVE_EXPAND );
+ }
+ /* Repeat for any other package groups which may be specified at
+ * the current level within the hierarchy.
+ */
+ group = group->FindNextAssociate( package_group_key );
+ } while( group != NULL );
+}
+
+inline void pkgXmlNode::SetPackageGroupHierarchyMapper()
+{
+ /* Method to assign the preceding helper, as the active handler
+ * for pkgXmlNode::MapPackageGroupHierarchy().
+ */
+ PackageGroupHierarchyMapper = map_package_group_hierarchy;
+}
+
EXTERN_C void pkgInitCategoryTreeGraft( pkgXmlNode *root )
{
/* Helper function to create the graft point, at which the
@@ -47,7 +226,10 @@ EXTERN_C void pkgInitCategoryTreeGraft( pkgXmlNode *root )
* of the XML database image.
*/
pkgXmlNode *pkgtree = new pkgXmlNode( package_group_key );
+
+ pkgtree->SetPackageGroupHierarchyMapper();
pkgtree->SetAttribute( name_key, package_group_all );
+ pkgtree->SetAttribute( select_key, value_true );
pkgtree->SetAttribute( expand_key, value_true );
root->LinkEndChild( pkgtree );
}
@@ -57,8 +239,8 @@ void AppWindowMaker::InitPackageTreeView()
/* Create and initialise a TreeView window, in which to present
* the package group hierarchy display...
*/
- PackageTreeView = CreateWindow( WC_TREEVIEW, NULL,
- WS_VISIBLE | WS_BORDER | WS_CHILD, 0, 0, 0, 0,
+ PackageTreeView = CreateWindow( WC_TREEVIEW, NULL, WS_VISIBLE |
+ WS_BORDER | WS_CHILD | TVS_FULLROWSELECT | TVS_SHOWSELALWAYS, 0, 0, 0, 0,
AppWindow, (HMENU)(ID_PACKAGE_TREEVIEW),
AppInstance, NULL
);
@@ -67,14 +249,7 @@ void AppWindowMaker::InitPackageTreeView()
* displaying the category headings within the tree view.
*/
SendMessage( PackageTreeView, WM_SETFONT, (WPARAM)(DefaultFont), TRUE );
-
- /* Initialise a tree view insertion structure, to the appropriate
- * state for assignment of the root entry in the tree view.
- */
- TVINSERTSTRUCT cat;
- cat.hParent = TVI_ROOT;
- cat.item.mask = TVIF_TEXT;
- cat.hInsertAfter = TVI_ROOT;
+ SendMessage( PackageTreeView, TVM_SETINDENT, 0, 0 );
/* Retrieve the root category entry, if any, as recorded in
* the package XML database, for assignment as the root entry
@@ -87,23 +262,181 @@ void AppWindowMaker::InitPackageTreeView()
* create an artificial root entry, (which will then become
* the sole entry in our tree view).
*/
- cat.item.pszText = (char *)(package_group_all);
- TreeView_InsertItem( PackageTreeView, &cat );
+ TVINSERTSTRUCT entry;
+ entry.hParent = TVI_ROOT;
+ entry.item.mask = TVIF_TEXT | TVIF_CHILDREN;
+ entry.item.pszText = (char *)(package_group_all);
+ entry.hInsertAfter = TVI_ROOT;
+ entry.item.cChildren = 0;
+
+ /* Map this sole entry into the tree view pane.
+ */
+ TreeView_InsertItem( PackageTreeView, &entry );
}
- else while( tree != NULL )
- {
+ else
/* The package group hierarchy has been incorporated into
* the in-core image of the XML database; create a windows
- * "tree view" representation of its structure.
- *
- * FIXME: this currently creates only the root of the tree;
- * we need to walk the XML hierarchy, and add an additional
- * tree view node for each element found.
+ * "tree view", into which we load a representation of the
+ * structure of this hierarchy.
+ */
+ load_package_group_hierarchy( PackageTreeView, TVI_ROOT, tree );
+}
+
+static bool is_child_affiliate( HWND tree, TVITEM *ref, const char *name )
+{
+ /* Helper method to recursively traverse a subtree of the
+ * package group hierarchy, to check if a specified package
+ * group name matches any descendant of the current group
+ * selection...
+ */
+ HTREEITEM mark = ref->hItem;
+ do { if( TreeView_GetItem( tree, ref )
+ && (strcasecmp( name, ref->pszText ) == 0) )
+ /*
+ * ...immediately promoting any such match as an
+ * affiliate of the current selection...
+ */
+ return true;
+
+ /* ...otherwise, recursively traverse each child
+ * subtree, at the current level...
+ */
+ if( ((ref->hItem = TreeView_GetChild( tree, mark )) != NULL)
+ && is_child_affiliate( tree, ref, name ) )
+ /*
+ * ...again, immediately promoting any match...
+ */
+ return true;
+
+ /* ...or otherwise, rewind to the marked match point,
+ * whence we repeat the search into its next immediate
+ * sibling subtree, (if any).
+ */
+ mark = ref->hItem = TreeView_GetNextSibling( tree, mark );
+ } while( mark != NULL );
+
+ /* If we get to here, the specified package group name is NOT
+ * an affiliate of any descendant, at the current match level,
+ * of the currently selected package group.
+ */
+ return false;
+}
+
+static inline bool is_affiliated( HWND tree, const char *name )
+{
+ /* Helper to initiate a determination if a specified package
+ * group name is an affiliate of the currently selected package
+ * group; i.e. if it matches the name of the selected group, or
+ * any of its descendants.
+ */
+ TVITEM ref;
+ if( ((ref.hItem = TreeView_GetSelection( tree )) == NULL)
+ || (ref.hItem == TreeView_GetRoot( tree )) )
+ /*
+ * Before proceeding further, we may note that ANY group name
+ * is considered to be IMPLICITLY matched, at the root of the
+ * package group tree.
+ */
+ return true;
+
+ /* At any level in the hierarchy, other than the root, the group
+ * name MUST be matched EXPLICITLY; note that...
+ */
+ if( name == NULL )
+ /* ...an unspecified name can never satisfy this criterion.
*/
- cat.item.pszText = (char *)(tree->GetPropVal( name_key, value_unknown ));
- HTREEITEM top = TreeView_InsertItem( PackageTreeView, &cat );
- tree = tree->FindNextAssociate( package_group_key );
+ return false;
+
+ /* As a basis for comparison, we must provide a working buffer
+ * into which we may retrieve names from the tree view...
+ */
+ char ref_text[ref.cchTextMax = 1 + strlen( name )];
+
+ /* ...beginning with the currently selected tree view item...
+ */
+ ref.mask = TVIF_TEXT;
+ ref.pszText = ref_text;
+ if( TreeView_GetItem( tree, &ref ) && (strcasecmp( name, ref_text ) == 0) )
+ /*
+ * ...and returning immediately, when it is found to match.
+ */
+ return true;
+
+ /* When the selected item doesn't match, we also look for a
+ * possible match among its descendants, if any...
+ */
+ if( (ref.hItem = TreeView_GetChild( tree, ref.hItem )) != NULL )
+ /*
+ * ...which we also promote as a match.
+ */
+ return is_child_affiliate( tree, &ref, name );
+
+ /* If we get to here, the selected tree item doesn't match;
+ * nor does it have any descendants among which a possible
+ * match might be found.
+ */
+ return false;
+}
+
+/* We use static methods to reference the tree view class object;
+ * thus, we must define a static reference pointer. (Note that its
+ * initial assignment to NULL will be updated, when the tree view
+ * class object is instantiated).
+ */
+HWND AppWindowMaker::PackageTreeView = NULL;
+bool AppWindowMaker::IsPackageGroupAffiliate( pkgXmlNode *package )
+{
+ /* Method to determine if a particular pkgXmlNode object is
+ * an affiliate of the currently selected package group, as
+ * specified in the tree view of the package group hierarchy.
+ * Note that this must be a static method, so that it may be
+ * invoked by methods of the pkgXmlNode object, without any
+ * requirement for that object to hold a reference to the
+ * AppWindowMaker object which owns the tree view.
+ */
+ static const char *group_key = "group";
+ static const char *affiliate_key = "affiliate";
+
+ /* An affiliation may be declared at any level, between the
+ * root of the XML document, and the pkgXmlNode specifications
+ * to which it applies; save an end-point reference, so that
+ * we may avoid overrunning the document root, as we walk
+ * back through the document...
+ */
+ pkgXmlNode *top = package->GetDocumentRoot();
+ while( package != top )
+ {
+ /* ...in search of applicable "affiliate" declarations.
+ */
+ pkgXmlNode *group = package->FindFirstAssociate( affiliate_key );
+ while( group != NULL )
+ {
+ /* For each declared affiliation, check if it matches the
+ * current selection in the package group hierarchy...
+ */
+ const char *group_name = group->GetPropVal( group_key, NULL );
+ if( is_affiliated( PackageTreeView, group_name ) )
+ /*
+ * ...immediately returning any successful match; (just one
+ * positive match is sufficient to determine affiliation).
+ */
+ return true;
+
+ /* When no affiliation has yet been identified, repeat the
+ * check for any further "affiliate" declarations at the
+ * current level within the XML document hierarchy...
+ */
+ group = group->FindNextAssociate( group_key );
+ }
+ /* ...and at enclosing levels, as may be necessary.
+ */
+ package = package->GetParent();
}
+ /* If we get to here, then we found no "affiliate" declarations to
+ * be evaluated; only a root match in the package group hierarchy
+ * is sufficient, to determine affiliation.
+ */
+ return is_affiliated( PackageTreeView, NULL );
}
/* $RCSfile$: end of file */
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 39 ++++++
src/guimain.h | 3 +-
src/pkgbase.h | 21 +++
src/pkgbind.cpp | 21 +++-
src/pkgdata.cpp | 60 +++++++++
src/pkglist.cpp | 20 +++-
src/pkgtree.cpp | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++----
7 files changed, 516 insertions(+), 27 deletions(-)
hooks/post-receive
--
Repository: mingw-get
|
|
From: Keith M. <no...@so...> - 2013-07-12 20:21:18
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 69409177957a7886b1137bbef9e93355cd8ec595 (commit)
via 09264441dc5be49866dfbc2e67fb010989da5657 (commit)
from 638c044daa55d3aa2dc6e18c91dee989223de8a9 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/69409177957a7886b1137bbef9e93355cd8ec595/
commit 69409177957a7886b1137bbef9e93355cd8ec595
Author: Keith Marshall <kei...@us...>
Date: Fri Jul 12 16:27:32 2013 +0100
Correct a static string buffer aliasing issue.
diff --git a/ChangeLog b/ChangeLog
index 6f61aa4..9146036 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2013-07-12 Keith Marshall <kei...@us...>
+ Correct a static string buffer aliasing issue.
+
+ * src/setup.cpp (SetupTool::setup_dll): New inline method; it ensures
+ that the buffer within approot_path() refers to the setup helper DLL.
+ (SetupTool::InitialiseSetupHookAPI): Use it, when loading the DLL.
+ (SetupTool::SetupTool): Use it again, when subsequently calling...
+ (_wunlink): ...this; it is now the preferred API, replacing...
+ (DeleteFileW): ...this; do not blindly assume that...
+ (SetupTool::dll_name): ...this remains unchanged between references;
+ it is an alias for the static buffer within approot_path().
+
+2013-07-12 Keith Marshall <kei...@us...>
+
Add a custom profile for use by the setup tool.
* xml/setup.xml: New file.
diff --git a/src/setup.cpp b/src/setup.cpp
index 9f6d1ab..4616be8 100644
--- a/src/setup.cpp
+++ b/src/setup.cpp
@@ -190,6 +190,13 @@ class SetupTool
static const wchar_t *gui_program;
int RunInstalledProgram( const wchar_t * );
+ inline wchar_t *setup_dll( void )
+ { /* Helper function to ensure that the static "approot_path" buffer
+ * specifies a reference path name for mingw-get-setup-0.dll
+ */
+ return approot_path( L"libexec\\mingw-get\\mingw-get-setup-0.dll" );
+ }
+
inline void CreateApplicationLauncher
( int, const wchar_t *, const char *, const char * );
};
@@ -449,8 +456,7 @@ bool SetupTool::InitialiseSetupHookAPI( void )
/* Having successfully loaded the main DLL, we perform a similar
* check for the setup tool's bridging DLL...
*/
- dll_name = approot_path( L"libexec\\mingw-get\\mingw-get-setup-0.dll" );
- if( (hook_dll = LoadLibraryW( dll_name )) == NULL )
+ if( (hook_dll = LoadLibraryW( dll_name = setup_dll() )) == NULL )
{
/* ...once again, abandoning the installation, if this is not
* available; in this case, since we've already successfully
@@ -1050,7 +1056,7 @@ base_dll( NULL ), hook_dll( NULL )
* then we must now unload them; we also have no further use for
* mingw-get-setup-0.dll, so we may delete it.
*/
- if( hook_dll != NULL ){ FreeLibrary( hook_dll ); DeleteFileW( dll_name ); }
+ if( hook_dll != NULL ){ FreeLibrary( hook_dll ); _wunlink( setup_dll() ); }
if( base_dll != NULL ){ FreeLibrary( base_dll ); }
/* We're done with the COM subsystem; release it.
https://sf.net/p/mingw/mingw-get/ci/09264441dc5be49866dfbc2e67fb010989da5657/
commit 09264441dc5be49866dfbc2e67fb010989da5657
Author: Keith Marshall <kei...@us...>
Date: Fri Jul 12 15:29:00 2013 +0100
Add a custom profile for use by the setup tool.
diff --git a/ChangeLog b/ChangeLog
index 7ef57ea..6f61aa4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-07-12 Keith Marshall <kei...@us...>
+
+ Add a custom profile for use by the setup tool.
+
+ * xml/setup.xml: New file.
+
2013-07-03 Keith Marshall <kei...@us...>
Improve handling of workspace clean-up requests.
diff --git a/xml/setup.xml b/xml/setup.xml
new file mode 100644
index 0000000..77ee0cc
--- /dev/null
+++ b/xml/setup.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<profile project="MinGW" application="mingw-get">
+ <!--
+ $Id$
+
+ Written by Keith Marshall <kei...@us...>
+ Copyright (C) 2013, MinGW.org Project
+
+
+ Initial configuration profile for mingw-get-setup.
+
+
+ This is free software. Permission is granted to copy, modify and
+ redistribute this software, under the provisions of the GNU General
+ Public License, Version 3, (or, at your option, any later version),
+ as published by the Free Software Foundation; see the file COPYING
+ for licensing details.
+
+ Note, in particular, that this software is provided "as is", in the
+ hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
+ even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
+ PARTICULAR PURPOSE. Under no circumstances will the author, or the
+ MinGW Project, accept liability for any damages, however caused,
+ arising from the use of this software.
+ -->
+
+ <repository uri="http://prdownloads.sourceforge.net/mingw/%F.xml.lzma?download">
+ <!--
+ The "repository" specification identifies the URI whence package
+ list catalogues may be downloaded; each catalogue download URI is
+ identified by substituting the catalogue name for the "%F" field
+ in the uri specification.
+
+ For the purpose of initial setup, we offer only a limited subset
+ of the packages which are available within the repository.
+ -->
+ <package-list catalogue="mingw32-mingw-get" />
+ </repository>
+
+ <system-map id="default">
+ <!--
+ The system map specifies the installation paths for each managed
+ subsystem. Multiple system maps are supported, provided each is
+ given a unique "id" attribute; each specifies an "installation",
+ comprising a collection of subsystems, each of which in turn is
+ associated with a specific "sysroot path".
+
+ In the case of the setup tool, we require only a single sysroot
+ specification, relating to the default installation path.
+ -->
+ <sysroot subsystem="mingw32" path="%R" />
+ </system-map>
+
+</profile>
+<!-- $RCSfile$: end of file -->
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 19 +++++++++++++++++++
src/setup.cpp | 12 +++++++++---
xml/setup.xml | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 83 insertions(+), 3 deletions(-)
create mode 100644 xml/setup.xml
hooks/post-receive
--
Repository: mingw-get
|
|
From: Keith M. <no...@so...> - 2013-07-03 21:22:34
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 638c044daa55d3aa2dc6e18c91dee989223de8a9 (commit)
via 9a7b78cabc85b4f00b79e966b07f2cd65be71d1f (commit)
via 4fff90c62f750fdcb6b59b356bcc823b9b0a7af0 (commit)
from 95b5e3418266f6f9c4fcb086a6b9570fb6216a5a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/638c044daa55d3aa2dc6e18c91dee989223de8a9/
commit 638c044daa55d3aa2dc6e18c91dee989223de8a9
Author: Keith Marshall <kei...@us...>
Date: Wed Jul 3 14:06:04 2013 +0100
Improve handling of workspace clean-up requests.
diff --git a/ChangeLog b/ChangeLog
index b16d134..7ef57ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2013-07-03 Keith Marshall <kei...@us...>
+ Improve handling of workspace clean-up requests.
+
+ * Makefile.in (mostlyclean): New rule; it replaces...
+ (clean): ...original intent delegated to 'mostlyclean'; retained and
+ augmented to remove all content specified by 'mostlyclean', plus...
+ (version.c, verinfo.h): ...these additional generated files.
+ (distclean): Modified; 'version.c' now removed by 'clean'.
+
+2013-07-03 Keith Marshall <kei...@us...>
+
Correct an omission from the source code distribution.
* Makefile.in (BUILD_AUX_FILES): Add makeopts.m4; this was omitted
diff --git a/Makefile.in b/Makefile.in
index 28ad640..9abc7af 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -530,11 +530,14 @@ readme.txt.in: README.in NEWS.in INSTALL.in
# Workspace clean-up...
#
-clean:
+mostlyclean:
rm -f *.$(OBJEXT) *.d *.dll $(BIN_PROGRAMS) $(LIBEXEC_PROGRAMS)
+clean: mostlyclean
+ rm -f version.c verinfo.h
+
distclean: clean
- rm -f config.* version.c build.tag build.time
+ rm -f config.* build.tag build.time
maintainer-clean: distclean
rm -f README NEWS INSTALL readme.txt Makefile pkginfo.c
https://sf.net/p/mingw/mingw-get/ci/9a7b78cabc85b4f00b79e966b07f2cd65be71d1f/
commit 9a7b78cabc85b4f00b79e966b07f2cd65be71d1f
Author: Keith Marshall <kei...@us...>
Date: Wed Jul 3 13:26:25 2013 +0100
Correct an omission from the source code distribution.
diff --git a/ChangeLog b/ChangeLog
index 18026e3..b16d134 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2013-07-03 Keith Marshall <kei...@us...>
+ Correct an omission from the source code distribution.
+
+ * Makefile.in (BUILD_AUX_FILES): Add makeopts.m4; this was omitted
+ from the 2013-04-10 modification to fix MinGW-Bug #1601.
+
+2013-07-03 Keith Marshall <kei...@us...>
+
Incorporate foundation for setup tool implementation.
* src/setup.cpp: New file; it implements the setup program.
diff --git a/Makefile.in b/Makefile.in
index 1073552..28ad640 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -363,7 +363,8 @@ SRCDIST_SUBDIRS = src src/pkginfo srcdist-doc icons \
# from the project's global build-aux repository...
#
BUILD_AUX_DIRS = build-aux build-aux/m4
-BUILD_AUX_FILES = config.guess config.sub install-sh missing.m4
+BUILD_AUX_FILES = config.guess config.sub install-sh \
+ makeopts.m4 missing.m4
# The names of distributed package archive files incorporate version
# information, derived from PACKAGE_VERSION; this is decomposed, so that
https://sf.net/p/mingw/mingw-get/ci/4fff90c62f750fdcb6b59b356bcc823b9b0a7af0/
commit 4fff90c62f750fdcb6b59b356bcc823b9b0a7af0
Author: Keith Marshall <kei...@us...>
Date: Wed Jul 3 13:07:47 2013 +0100
Incorporate foundation for setup tool implementation.
diff --git a/ChangeLog b/ChangeLog
index 83cc5a2..18026e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2013-07-03 Keith Marshall <kei...@us...>
+
+ Incorporate foundation for setup tool implementation.
+
+ * src/setup.cpp: New file; it implements the setup program.
+ * src/setup.rc: New file; it implements setup program resources.
+
+ * src/dllhook.cpp: New file; it implements a DLL bridging API to
+ facilitate invocation of mingw-get-0.dll functions from the setup
+ program, after both DLLs have been explicitly loaded at run time.
+
+ * src/setup.h: New file; it declares the interface between the
+ setup program and the preceding mingw-get bridging DLL.
+
+ * src/guimain.h: Add filter to exclude declarations specific to...
+ [IMPLEMENTATION_LEVEL == PACKAGE_BASE_COMPONENT]: ...this case, when
+ included by compilation units specific to the setup tool components.
+ (ID_MAIN_DIALOGUE_CAPTION, ID_DOWNLOAD_HOST_URI): New resource IDs.
+ (ID_PACKAGE_BASE_DISTNAME, ID_PACKAGE_DATA_DISTNAME): Likewise.
+ (ID_PACKAGE_GUI_DISTNAME): Likewise; define them.
+
+ * Makefile.in (all): Respecify it, in terms of...
+ (all-core, all-setup): ...these new rules; define them, and also...
+ (all-setup-exe, all-setup-dll): ...these, to force building of...
+ (mingw-get-setup.$EXEEXT, mingw-get-setup-0.dll): ...these binaries.
+ (setup.res.$OBJEXT): Specify prerequisites, as for guimain.res.$OBJEXT
+ (SETUP_TOOL_OBJECTS, SETUP_TOOL_LIBS): New macros; define them.
+ (SETUP_DLL_OBJECTS, SETUP_DLL_LIBS, SETUP_DISTNAME): Likewise.
+ (TAG_SCRIPT): Add resource script substitution definitions for...
+ (ID_PACKAGE_BASE_DISTNAME, ID_PACKAGE_DATA_DISTNAME): ...these...
+ (ID_PACKAGE_GUI_DISTNAME): ...and this.
+
2013-07-01 Keith Marshall <kei...@us...>
Add subprocess argument vector construction helpers.
diff --git a/Makefile.in b/Makefile.in
index 78a3133..1073552 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -132,6 +132,9 @@ TAG_SCRIPT = tag=$(BUILD_TAG); \
-e "s!%PACKAGE_NAME%!$(PACKAGE_TARNAME)!g" \
-e "s!%PACKAGE_VERSION%!$(PACKAGE_VERSION)$$tag!g" \
-e "s!%PACKAGE_VERINFO_PRODUCT_VERSION%!`$(PACKAGE_VERINFO_SCRIPT)`!g" \
+ -e "s!%PACKAGE_BASE_DISTNAME%!$(PACKAGE_DISTNAME)$$tag-bin.$(TAREXT)!g" \
+ -e "s!%PACKAGE_GUI_DISTNAME%!$(PACKAGE_DISTNAME)$$tag-gui.$(TAREXT)!g" \
+ -e "s!%PACKAGE_DATA_DISTNAME%!$(SETUP_DISTNAME)$$tag-%s.$(TAREXT)!g" \
-e "s!%COPYRIGHT_HOLDER%!@COPYRIGHT_HOLDER@!g" \
-e "s!%YEARS_OF_ISSUE%!@YEARS_OF_ISSUE@!g"
@@ -176,6 +179,12 @@ GUIMAIN_OBJECTS = \
GUIMAIN_LIBS = -lwtklite -lcomctl32
+SETUP_TOOL_OBJECTS = setup.$(OBJEXT) setup.res.$(OBJEXT) apihook.$(OBJEXT)
+SETUP_TOOL_LIBS = -lwtklite -lwininet -lcomctl32 -lole32 -Wl,-Bstatic -llzma
+
+SETUP_DLL_OBJECTS = dllhook.$(OBJEXT)
+SETUP_DLL_LIBS =
+
script_srcdir = ${srcdir}/scripts/libexec
BIN_PROGRAMS = pkginfo$(EXEEXT) mingw-get$(EXEEXT)
@@ -186,7 +195,16 @@ LIBEXEC_DATA = mingw-get-0.dll
# Primary build goals...
#
-all: $(BIN_PROGRAMS) $(LIBEXEC_PROGRAMS) $(LIBEXEC_DATA)
+all: all-core all-setup
+all-core: $(BIN_PROGRAMS) $(LIBEXEC_PROGRAMS) $(LIBEXEC_DATA)
+all-setup: all-setup-dll all-setup-exe
+all-setup-dll: mingw-get-setup-0.dll
+
+all-setup-exe:
+ @$(QUIET_MAKE) CXXFLAGS='$(CXXFLAGS) -Os' mingw-get-setup$(EXEEXT)
+
+mingw-get-setup$(EXEEXT): $(SETUP_TOOL_OBJECTS)
+ $(CXX) -o $@ $(CXXFLAGS) $(GUI_LDFLAGS) $+ $(SETUP_TOOL_LIBS)
pkginfo$(EXEEXT): driver.$(OBJEXT) pkginfo.$(OBJEXT)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $+
@@ -206,6 +224,9 @@ lastrites$(EXEEXT): rites.$(OBJEXT)
mingw-get-0.dll: $(CORE_DLL_OBJECTS)
$(CXX) -shared -o $@ $(CXXFLAGS) $(LDFLAGS) $+ $(LIBS)
+mingw-get-setup-0.dll: $(SETUP_DLL_OBJECTS) mingw-get-0.dll
+ $(CXX) -shared -o $@ $(CXXFLAGS) $(LDFLAGS) $+ $(SETUP_DLL_LIBS)
+
# The following recursive invocation hook provides a mechanism for
# accessing make's facility for reporting what it is doing, even when
# the command to be invoked is encapsulated within a more complex block,
@@ -272,7 +293,7 @@ time-stamp:
# The following dependencies must be explicitly declared.
#
-guimain.res.$(OBJEXT): Makefile build.time verinfo.h
+guimain.res.$(OBJEXT) setup.res.$(OBJEXT): Makefile build.time verinfo.h
verinfo.h version.c: Makefile build.time
# Installation tools and directory paths...
@@ -361,6 +382,8 @@ PACKAGE_DISTVERSION = `echo $(PACKAGE_VERSION)-$(PACKAGE_SUBSYSTEM) | sed \
-e 's,-$(PACKAGE_SUBSYSTEM),$(SNAPSHOT)&,'`
PACKAGE_DISTNAME = $(PACKAGE_TARNAME)-$(PACKAGE_DISTVERSION)
+SETUP_DISTNAME = $(PACKAGE_TARNAME)-setup-$(PACKAGE_DISTVERSION)
+
dist: srcdist bindist readme.txt.dist
# Specify where distributable files should be collected; by default,
diff --git a/src/dllhook.cpp b/src/dllhook.cpp
new file mode 100644
index 0000000..06394f9
--- /dev/null
+++ b/src/dllhook.cpp
@@ -0,0 +1,470 @@
+/*
+ * dllhook.cpp
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <kei...@us...>
+ * Copyright (C) 2013, MinGW.org Project
+ *
+ *
+ * Implementation of the processing redirector hook, to be provided
+ * in the form of a free-standing bridge DLL, through which the setup
+ * tool requests services from the main mingw-get DLL.
+ *
+ *
+ * This is free software. Permission is granted to copy, modify and
+ * redistribute this software, under the provisions of the GNU General
+ * Public License, Version 3, (or, at your option, any later version),
+ * as published by the Free Software Foundation; see the file COPYING
+ * for licensing details.
+ *
+ * Note, in particular, that this software is provided "as is", in the
+ * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
+ * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
+ * PARTICULAR PURPOSE. Under no circumstances will the author, or the
+ * MinGW Project, accept liability for any damages, however caused,
+ * arising from the use of this software.
+ *
+ */
+static const char *setup_key = "setup";
+
+#define WIN32_LEAN_AND_MEAN
+#define IMPLEMENTATION_LEVEL PACKAGE_BASE_COMPONENT
+
+#include "setup.h"
+#include "guimain.h"
+#include "pkgbase.h"
+#include "pkginfo.h"
+#include "pkgkeys.h"
+#include "pkgproc.h"
+#include "dmhcore.h"
+#include "mkpath.h"
+
+#include <stdlib.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static const char *internal_error = "internal error";
+#define MSG_INTERNAL_ERROR(MSG) "%s: "MSG_##MSG"\n", internal_error
+
+#define MSG_INVALID_REQUEST "invalid request code specified"
+#define MSG_NOTIFY_MAINTAINER "please report this to the mingw-get maintainer"
+
+#define PROGRESS_METER_CLASS setupProgressMeter
+
+class PROGRESS_METER_CLASS: public pkgProgressMeter
+{
+ /* Specialisation of the pkgProgressMeter class, through which
+ * the pkgXmlDocument::BindRepositories() method sends progress
+ * reports to the setup tool dialogue.
+ */
+ public:
+ PROGRESS_METER_CLASS( HWND, pkgXmlDocument & );
+ ~PROGRESS_METER_CLASS(){ dbase.DetachProgressMeter( this ); }
+
+ virtual int Annotate( const char *, ... );
+ virtual void SetRange( int, int );
+ virtual void SetValue( int );
+
+ private:
+ pkgXmlDocument &dbase;
+ HWND annotation, count, lim, frac, progress_bar;
+ void PutVal( HWND, const char *, ... );
+ int total;
+};
+
+/* This class requires a specialised constructor...
+ */
+#define IDD( DLG, ITEM ) GetDlgItem( DLG, IDD_PROGRESS_##ITEM )
+PROGRESS_METER_CLASS::PROGRESS_METER_CLASS( HWND owner, pkgXmlDocument &db ):
+dbase( db ), annotation( IDD( owner, MSG ) ), progress_bar( IDD( owner, BAR ) ),
+count( IDD( owner, VAL ) ), lim( IDD( owner, MAX ) ), frac( IDD( owner, PCT ) )
+{
+ /* ...which binds the progress repporter directly to the
+ * invoking pkgXmlDocument class object, before setting the
+ * initial item count to zero, from a minimal anticipated
+ * total of one.
+ */
+ dbase.AttachProgressMeter( this );
+ SetRange( 0, 1 ); SetValue( 0 );
+};
+
+/* The remaining methods of the class are abstracted from the
+ * generic progress metering implementation.
+ */
+#include "pmihook.cpp"
+
+static inline
+void initialise_profile( void )
+{
+ /* Helper function to ensure that profile.xml exists in the
+ * mingw-get database directory, either as a pre-existing file,
+ * or by creating it as a copy of defaults.xml
+ */
+ int copyin, copyout;
+ const char *profile = xmlfile( profile_key, NULL );
+ if( (profile != NULL) && (access( profile, F_OK ) != 0)
+ && ((copyout = set_output_stream( profile, 0644 )) >= 0) )
+ {
+ /* No profile.xml file currently exists, but we are able
+ * to create one...
+ */
+ const char *default_profile;
+ if( ((default_profile = xmlfile( defaults_key, NULL )) != NULL)
+ && ((copyin = open( default_profile, _O_RDONLY | _O_BINARY )) >= 0) )
+ {
+ /* ...whereas the defaults.xml DOES exist, and we are able
+ * to read it, so set up a transfer buffer, through which we
+ * may copy its content to profile.xml
+ */
+ char buf[BUFSIZ]; ssize_t count;
+ while( (count = read( copyin, buf, BUFSIZ )) > 0 )
+ write( copyout, buf, count );
+
+ /* When the entire content of defaults.xml has been copied,
+ * close both file streams, saving both files.
+ */
+ close( copyout );
+ close( copyin );
+ }
+ else
+ { /* We were unable to open defaults.xml for copying, but we
+ * already hold an open stream handle for profile.xml; close
+ * it, then unlink, to discard the resulting empty file.
+ */
+ close( copyout );
+ unlink( profile );
+ }
+ /* Attempting to open defaults.xml, whether successful or not,
+ * has left us with a heap memory allocation for its path name.
+ * We don't need it any more; free it so we don't leak memory.
+ */
+ free( (void *)(default_profile) );
+ }
+ /* Similarly, we have a heap memory allocation for the path name
+ * of profile.xml; we must also avoid leaking it.
+ */
+ free( (void *)(profile) );
+}
+
+static inline
+void update_database( pkgSetupAction *setup )
+{
+ /* Helper function to initiate an XML database update, based on
+ * a restricted (custom) profile, to ensure that the installation
+ * of mingw-get itself is properly recorded.
+ */
+ const char *dfile;
+ pkgXmlDocument dbase( dfile = xmlfile( setup_key ) );
+ if( dbase.IsOk() && (dbase.BindRepositories( false ) != NULL) )
+ {
+ /* Having successfully loaded the restricted profile, load the
+ * map of the installation it specifies, and update it to reflect
+ * the installation of the mingw-get packages we are currently
+ * installing.
+ */
+ dbase.LoadSystemMap();
+ setup->UpdateDatabase( dbase );
+ }
+ /* We're finished with the setup.xml profile; delete it, and free
+ * the memory which xmlfile() allocated to store its path name.
+ */
+ unlink( dfile );
+ free( (void *)(dfile) );
+}
+
+static inline
+void update_catalogue( HWND owner )
+{
+ /* Helper function to ensure that all locally installed catalogue
+ * files are synchronised with their latest versions, as hosted on
+ * their respective repository servers.
+ */
+ const char *dfile;
+ pkgXmlDocument dbase( dfile = xmlfile( profile_key ) );
+ if( dbase.IsOk() )
+ {
+ /* The XML package database has been successfully loaded;
+ * ensure that the local catalogue is synchronised with the
+ * with the up-to-date repository representation.
+ */
+ setupProgressMeter watch( owner, dbase );
+ dbase.BindRepositories( true );
+ watch.Annotate(
+ "Catalogue update completed; please check 'Details' pane for errors."
+ );
+ }
+ /* We're finished with the path name for the profile.xml file;
+ * release the memory which xmlfile() allocated to store it.
+ */
+ free( (void *)(dfile) );
+}
+
+EXTERN_C __declspec(dllexport)
+void setup_hook( unsigned int request, va_list argv )
+{
+ /* Single entry point API function, through which the setup tool
+ * directs all requests to its own delay-loaded DLL, and hence to
+ * mingw-get-0.dll itself.
+ */
+ switch( request )
+ { case SETUP_HOOK_DMH_BIND:
+ /* Initialisation hook, through which the setup tool makes its
+ * already initialised diagnostic message handler available to
+ * to DLL functions which it invokes.
+ */
+ dmh_bind( va_arg( argv, dmhTypeGeneric * ) );
+ break;
+
+ case SETUP_HOOK_POST_INSTALL:
+ /* This is the principal entry point, through which the setup
+ * tool hands off the final phases of mingw-get installation to
+ * the XML database management functions within the DLLs.
+ */
+ initialise_profile();
+ update_database( va_arg( argv, pkgSetupAction * ) );
+ update_catalogue( va_arg( argv, HWND ) );
+ break;
+
+ default:
+ /* We should never get to here; it's a programming error in
+ * the setup tool, if we do.
+ */
+ dmh_notify( DMH_ERROR, MSG_INTERNAL_ERROR( INVALID_REQUEST ) );
+ dmh_notify( DMH_ERROR, MSG_INTERNAL_ERROR( NOTIFY_MAINTAINER ) );
+ }
+}
+
+class pkgXmlNodeStack
+{
+ /* A convenience class for managing a list of pkgXmlNodes
+ * as a LIFO stack.
+ */
+ public:
+ inline pkgXmlNodeStack *push( pkgXmlNode * );
+ inline pkgXmlNodeStack *pop( pkgXmlNode ** );
+
+ private:
+ pkgXmlNodeStack *next;
+ pkgXmlNode *entry;
+};
+
+inline pkgXmlNodeStack *pkgXmlNodeStack::push( pkgXmlNode *node )
+{
+ /* Method to push a pkgXmlNode into a new frame, on the top of
+ * the stack, returning the new stack pointer.
+ */
+ pkgXmlNodeStack *rtn;
+ if( (rtn = new pkgXmlNodeStack) != NULL )
+ {
+ /* We successfully allocated storage space for the new stack
+ * entry; populate it with the specified pkgXmlNode date, and
+ * link it to the existing stack chain...
+ */
+ rtn->entry = node; rtn->next = this;
+
+ /* ...before returning the new top-of-stack pointer.
+ */
+ return rtn;
+ }
+ /* If we get to here, we were unable to expand the stack to
+ * accommodate any new entry; don't move the stack pointer.
+ */
+ return this;
+}
+
+inline pkgXmlNodeStack *pkgXmlNodeStack::pop( pkgXmlNode **node )
+{
+ /* Method to pop a pkgXmlNode from the top of the stack, while
+ * saving a reference pointer for it, and returning the updated
+ * stack pointer.
+ */
+ if( this == NULL )
+ /*
+ * The stack is empty; there's nothing more to do!
+ */
+ return NULL;
+
+ /* When the stack is NOT empty, capture the reference pointer
+ * for the SECOND entry (if any), store the top entry, delete
+ * its stack frame, and return the new stack pointer.
+ */
+ pkgXmlNodeStack *rtn = next; *node = entry;
+ delete this; return rtn;
+}
+
+void pkgSetupAction::UpdateDatabase( pkgXmlDocument &dbase )
+{
+ /* Method to ensure that the mingw-get package components which are
+ * specified in the setup actions list are recorded as "installed", in
+ * the installation database manifests.
+ */
+ if( this != NULL )
+ {
+ /* The setup actions list is not empty; ensure that we commence
+ * processing from its first entry...
+ */
+ pkgSetupAction *current = this;
+ while( current->prev != NULL ) current = current->prev;
+ dmh_notify( DMH_INFO, "%s: updating installation database\n", setup_key );
+ while( current != NULL )
+ {
+ /* ...then processing all entries sequentially, in turn,
+ * parse the package tarname specified in the current action
+ * entry, to identify the associated package name, component
+ * class and subsystem name.
+ */
+ const char *name_fmt = "%s-%s";
+ pkgSpecs lookup( current->package_name );
+ char lookup_name[1 + strlen( current->package_name )];
+ const char *component = lookup.GetComponentClass();
+ const char *subsystem = lookup.GetSubSystemName();
+ if( (component != NULL) && *component )
+ /*
+ * The package name is qualified by an explicit component
+ * name; form the composite package name string.
+ */
+ sprintf( lookup_name, name_fmt, lookup.GetPackageName(), component );
+ else
+ /* There is no explicit component name; just save a copy
+ * of the unqualified package name.
+ */
+ strcpy( lookup_name, lookup.GetPackageName() );
+
+ /* Locate the corresponding component package entry, if any,
+ * in the package catalogue.
+ */
+ if( dbase.FindPackageByName( lookup_name, subsystem ) != NULL )
+ {
+ /* Lookup was successful; now search the installation records,
+ * if any, for any matching package entry.
+ */
+ pkgXmlNodeStack *stack = NULL;
+ pkgXmlNode *sysroot = dbase.GetRoot()->GetSysRoot( subsystem );
+ pkgXmlNode *installed = sysroot->FindFirstAssociate( installed_key );
+ while( installed != NULL )
+ {
+ /* There is at least one installation record; walk the chain
+ * of all such records...
+ */
+ const char *tarname = installed->GetPropVal( tarname_key, NULL );
+ if( tarname != NULL )
+ {
+ /* ...extracting package and component names from the tarname
+ * specification within each...
+ */
+ pkgSpecs ref( tarname );
+ char ref_name[1 + strlen( tarname )];
+ if( ((component = ref.GetComponentClass()) != NULL) && *component )
+ /*
+ * ...once again forming the composite name, when applicable...
+ */
+ sprintf( ref_name, name_fmt, ref.GetPackageName(), component );
+ else
+ /* ...or simply storing the unqualified package name if not.
+ */
+ strcpy( ref_name, ref.GetPackageName() );
+
+ /* Check for a match between the installed package name, and
+ * the name we wish to record as newly installed...
+ */
+ if( (strcasecmp( ref_name, lookup_name ) == 0)
+ && (strcasecmp( tarname, current->package_name ) != 0) )
+ /*
+ * ...pushing the current installation record on to the
+ * update stack, in case of a match...
+ */
+ stack = stack->push( installed );
+ }
+ /* ...then move on to the next installation record, if any.
+ */
+ installed = installed->FindNextAssociate( installed_key );
+ }
+
+ /* Create a temporary package "release" descriptor...
+ */
+ pkgXmlNode *reference_hook = new pkgXmlNode( release_key );
+ if( reference_hook != NULL )
+ {
+ /* ...which we may conveniently attach to the root
+ * of the XML catalogue tree.
+ */
+ dbase.GetRoot()->AddChild( reference_hook );
+ reference_hook->SetAttribute( tarname_key, current->package_name );
+
+ /* Run the installer...
+ */
+ pkgTarArchiveInstaller registration_server( reference_hook );
+ if( registration_server.IsOk() )
+ {
+ /* ...reporting the installation as a "registration" of
+ * the specified package, but...
+ */
+ dmh_notify( DMH_INFO, "%s: register %s\n",
+ setup_key, current->package_name
+ );
+ /* ...noting that the package content has already been
+ * "installed" by the setup tool, but without recording
+ * any details, we run this without physically extracting
+ * any files, to capture the side effect of compiling an
+ * installation record.
+ */
+ registration_server.SaveExtractedFiles( false );
+ registration_server.Process();
+ }
+ /* With the installation record safely compiled, we may
+ * discard the temporary "release" descriptor from which
+ * we compiled it.
+ */
+ dbase.GetRoot()->DeleteChild( reference_hook );
+ }
+
+ /* When the update stack, constructed above, is not empty...
+ */
+ if( stack != NULL )
+ { while( stack != NULL )
+ {
+ /* ...pop each installation record, which is to be updated,
+ * off the update stack, in turn...
+ */
+ const char *tarname;
+ pkgXmlNode *installed;
+ stack = stack->pop( &installed );
+ if( (tarname = installed->GetPropVal( tarname_key, NULL )) != NULL )
+ {
+ /* ...identify its associated installed files manifest, and
+ * disassociate it from the sysroot of the current installation;
+ * (note that this automatically deletes the manifest itself, if
+ * it is associated with no other sysroots).
+ */
+ pkgManifest inventory( package_key, tarname );
+ inventory.DetachSysRoot( sysroot->GetPropVal( id_key, subsystem ) );
+ }
+ /* Delete the installation record from the current sysroot...
+ */
+ sysroot->DeleteChild( installed );
+ }
+ /* ...and mark the sysroot record as "modified", as a result of
+ * all preceding updates.
+ */
+ sysroot->SetAttribute( modified_key, value_yes );
+ }
+ }
+
+ /* Repeat for all packages with an associated setup action...
+ */
+ current = current->next;
+ }
+ /* ...and finally, report completion of all database updates, while also
+ * committing all recorded changes to disk storage.
+ */
+ dmh_notify( DMH_INFO, "%s: installation database updated\n", setup_key );
+ dbase.UpdateSystemMap();
+ }
+}
+
+/* $RCSfile$: end of file */
diff --git a/src/guimain.h b/src/guimain.h
index e70bf59..9c6b49d 100644
--- a/src/guimain.h
+++ b/src/guimain.h
@@ -41,6 +41,12 @@
#define SASH_BAR_THICKNESS 6
+#define ID_MAIN_DIALOGUE_CAPTION 122
+#define ID_DOWNLOAD_HOST_URI 130
+#define ID_PACKAGE_BASE_DISTNAME 131
+#define ID_PACKAGE_DATA_DISTNAME 132
+#define ID_PACKAGE_GUI_DISTNAME 133
+
#define ID_PACKAGE_TREEVIEW 201
#define ID_PACKAGE_LISTVIEW 202
#define ID_PACKAGE_TABCONTROL 203
@@ -127,6 +133,11 @@
#include <wtklite.h>
#include <commctrl.h>
+#if IMPLEMENTATION_LEVEL == PACKAGE_BASE_COMPONENT
+/*
+ * The remaining class declarations and function prototypes are
+ * required only by the main mingw-get GUI client application.
+ */
class pkgXmlNode;
class pkgXmlDocument;
class pkgProgressMeter;
@@ -229,5 +240,7 @@ inline long AppWindowMaker::DialogueResponse( int id, DLGPROC handler )
*/
EXTERN_C void pkgInitCategoryTreeGraft( pkgXmlNode* );
+#endif /* PACKAGE_BASE_COMPONENT */
+
#endif /* ! RC_INVOKED */
#endif /* GUIMAIN_H: $RCSfile$: end of file */
diff --git a/src/setup.cpp b/src/setup.cpp
new file mode 100644
index 0000000..9f6d1ab
--- /dev/null
+++ b/src/setup.cpp
@@ -0,0 +1,1656 @@
+/*
+ * setup.cpp
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <kei...@us...>
+ * Copyright (C) 2013, MinGW.org Project
+ *
+ *
+ * Implementation of the mingw-get setup tool's dialogue controller.
+ *
+ *
+ * This is free software. Permission is granted to copy, modify and
+ * redistribute this software, under the provisions of the GNU General
+ * Public License, Version 3, (or, at your option, any later version),
+ * as published by the Free Software Foundation; see the file COPYING
+ * for licensing details.
+ *
+ * Note, in particular, that this software is provided "as is", in the
+ * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
+ * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
+ * PARTICULAR PURPOSE. Under no circumstances will the author, or the
+ * MinGW Project, accept liability for any damages, however caused,
+ * arising from the use of this software.
+ *
+ */
+#define WIN32_LEAN_AND_MEAN
+#define _WIN32_WINNT 0x0500
+
+/* This component application does not support the DEBUGLEVEL feature
+ * of the main mingw-get application.
+ */
+#undef DEBUGLEVEL
+
+#include "setup.h"
+#include "guimain.h"
+#include "pkgtask.h"
+#include "dmh.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <process.h>
+#include <limits.h>
+#include <shlobj.h>
+#include <wctype.h>
+#include <wchar.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <wtkalign.h>
+#include <commctrl.h>
+
+static void ViewLicence( void * )
+{
+ /* Helper routine, dispatching requests via the MS-Windows shell,
+ * so that the user's choice of web browser is invoked to display
+ * the GNU General Public Licence, Version 3.
+ *
+ * Note that this function runs in its own thread, and requires
+ * COM services to be enabled...
+ */
+ CoInitialize( NULL );
+ /*
+ * ...so that the shell process may be invoked.
+ */
+ ShellExecute( NULL, NULL,
+ "http://www.gnu.org/licenses/gpl-3.0-standalone.html",
+ NULL, NULL, SW_SHOWNORMAL
+ );
+
+ /* The active thread terminates on return from this function;
+ * it no longer requires COM services.
+ */
+ CoUninitialize();
+}
+
+/* Embed procedures for creation of file system objects, and for
+ * constructing argument vectors for passing to child processes.
+ */
+#include "mkpath.c"
+#include "argwrap.c"
+
+static POINT offset = { 0, 0 };
+static int CALLBACK confirm( HWND dlg, unsigned msg, WPARAM request, LPARAM )
+{
+ /* A generic dialogue box procedure which positions the dialogue
+ * box at a specified offset, then waits for any supported button
+ * click, returning the associated button identifier; this is used
+ * by BrowseLicenceDocument() to confirm requests to invoke the
+ * web browser to display the product licence.
+ */
+ switch( msg )
+ { case WM_INITDIALOG:
+ /*
+ * When first displaying the confirmation dialogue...
+ */
+ if( (offset.x | offset.y) != 0 )
+ {
+ /* ...adjust its position as specified, and ensure that
+ * it is presented as foremost in the z-order...
+ */
+ RECT whence;
+ GetWindowRect( dlg, &whence );
+ OffsetRect( &whence, offset.x, offset.y );
+ SetWindowPos( dlg, HWND_TOP,
+ whence.left, whence.top, 0, 0, SWP_NOSIZE
+ );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ /* ...then close the dialogue, returning the identification
+ * of the button, as soon as any is clicked; (note that this
+ * assumes that the only active controls within the dialogue
+ * are presented as buttons).
+ */
+ EndDialog( dlg, LOWORD( request ) );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static inline void BrowseLicenceDocument( HWND dlg, long x = 0, long y = 0 )
+{
+ /* Routine to dispatch requests to display the product licence;
+ * it is invoked when the user clicks the "View Licence" button,
+ * and responds by requesting confirmation before launching the
+ * internet browser in a separate thread, to display an online
+ * copy of the licence document.
+ */
+ offset.x = x; offset.y = y;
+ if( DialogBox( NULL,
+ MAKEINTRESOURCE( IDD_SETUP_LICENCE ), dlg, confirm ) == IDOK
+ ) _beginthread( ViewLicence, 0, NULL );
+}
+
+/* The following string constants are abstracted from pkgkeys.c;
+ * we redefine this minimal subset here, to avoid the overhead of
+ * importing the entire content of the pkgkeys module.
+ */
+static const char *uri_key = "uri";
+static const char *mirror_key = "mirror";
+static const char *value_none = "none";
+
+class SetupTool
+{
+ /* Top level class, implementing the controlling features
+ * of the mingw-get setup tool.
+ */
+ public:
+ static int Status;
+
+ inline SetupTool( HINSTANCE );
+ static SetupTool *Invoke( void );
+ static unsigned int IsPref( unsigned int test ){ return test & prefs; }
+
+ bool InitialiseSetupHookAPI( void );
+ inline int DispatchSetupHookRequest( unsigned int, ... );
+
+ private:
+ const wchar_t *dll_name;
+ HMODULE base_dll, hook_dll;
+ typedef int (*dll_request_hook)( unsigned int, va_list );
+ dll_request_hook dll_request;
+
+ inline void DoFirstTimeSetup( HWND );
+ inline int SetInstallationPreferences( HWND );
+ inline HMODULE HaveWorkingInstallation( void );
+ inline wchar_t *UseDefaultInstallationDirectory( void );
+ inline void ShowInstallationDirectory( HWND );
+ inline int InstallationRequest( HWND );
+
+ static void EnablePrefs( HWND, int );
+ static inline void EnablePrefs( HWND, HWND );
+ static inline void StorePref( HWND, int, int );
+ static inline void ShowPref( HWND, int, int );
+
+ static SetupTool *setup_hook;
+ static const wchar_t *default_dirpath;
+ wchar_t *approot_path( const wchar_t * = NULL );
+ void ChangeInstallationDirectory( HWND );
+ static wchar_t *approot_tail;
+
+ static unsigned int prefs;
+ static int CALLBACK OpeningDialogue( HWND, unsigned, WPARAM, LPARAM );
+ static int CALLBACK ConfigureInstallationPreferences
+ ( HWND, unsigned, WPARAM, LPARAM );
+
+ static const wchar_t *gui_program;
+ int RunInstalledProgram( const wchar_t * );
+
+ inline void CreateApplicationLauncher
+ ( int, const wchar_t *, const char *, const char * );
+};
+
+/* We will never instantiate more than one object of the SetupTool
+ * class at any one time. Thus, we may record its status in a static
+ * member variable, which we must initialise; we assume the all setup
+ * operations will be completed successfully.
+ */
+int SetupTool::Status = EXIT_SUCCESS;
+
+/* We need an alternative status code, to indicate that the user has
+ * elected to run the standard installer immediately, on termination
+ * of the initial setup; the value is arbitrary, subject only to the
+ * requirement that it differs from EXIT_SUCCESS and EXIT_FAILURE.
+ */
+#define EXIT_CONTINUE 101
+
+/* Installation options are also recorded in a static member varaible;
+ * we initialise these to match a set of default preferences, which we
+ * believe will suit a majority of users.
+ */
+unsigned int SetupTool::prefs = SETUP_OPTION_DEFAULTS;
+
+/* We also provide a static hook, through which objects of any other
+ * class may invoke public methods of the SetupTool object, without
+ * requiring them to maintain their own reference to this object.
+ */
+SetupTool *SetupTool::setup_hook = NULL;
+SetupTool *SetupTool::Invoke( void ){ return setup_hook; }
+
+static void RefreshDialogueWindow( HWND AppWindow )
+{
+ /* A trivial helper routine, to force an immediate update
+ * of a dialogue window display.
+ */
+ InvalidateRect( AppWindow, NULL, FALSE );
+ UpdateWindow( AppWindow );
+}
+
+/* Embed an implementation of the diagnostic message handler,
+ * customised for deployment by the setup tool...
+ */
+#include "dmhcore.cpp"
+#include "dmhguix.cpp"
+
+/* ...and supported by this custom initialisation routine.
+ */
+EXTERN_C void dmh_init( const dmh_class subsystem, const char *progname )
+{
+ /* Public entry point for message handler initialisation...
+ *
+ * We only do it once, silently ignoring any attempt to
+ * establish a second handler.
+ */
+ if( (dmh == NULL) && (subsystem == DMH_SUBSYSTEM_GUI) )
+ dmh = new dmhTypeGUI( strdup( progname ) );
+}
+
+inline unsigned long pkgSetupAction::HasAttribute( unsigned long mask )
+{
+ /* Helper function to examine the flags within a setup action
+ * item, checking for the presence of a specified attribute.
+ */
+ return (this != NULL) ? mask & flags : 0UL;
+}
+
+void pkgSetupAction::ClearAllActions( void )
+{
+ /* Routine to clear an entire list of setup action items,
+ * releasing the memory allocated to each.
+ */
+ pkgSetupAction *current = this;
+ while( current != NULL )
+ {
+ /* Walk the list, deleting each item in turn.
+ */
+ pkgSetupAction *defunct = current;
+ current = current->next;
+ delete defunct;
+ }
+}
+
+/* Worker thread API for use with modal dialogue boxes; the worker thread
+ * is invoked by passing a function pointer, conforming to this prototype,
+ * to the _beginthread() API.
+ */
+typedef void SetupThreadProcedure( void * );
+
+class SetupDialogueThread
+{
+ /* Locally defined class to manage the binding of an arbitrary worker
+ * thread procedure to a modal dialogue, with a generic message loop.
+ */
+ public:
+ inline long ExitCode(){ return status; }
+ SetupDialogueThread( HWND, int, SetupThreadProcedure * );
+
+ private:
+ static int CALLBACK SetupDialogue( HWND, unsigned int, WPARAM, LPARAM );
+ static SetupThreadProcedure *WorkerThread;
+ long status;
+};
+
+/* We need to instantiate this static class member.
+ */
+SetupThreadProcedure *SetupDialogueThread::WorkerThread = NULL;
+
+int CALLBACK SetupDialogueThread::SetupDialogue
+( HWND window, unsigned int msg, WPARAM request, LPARAM )
+{
+ /* Generic handler for dialogue boxes which delegate an associated
+ * processing activity to a background thread.
+ */
+ switch( msg )
+ {
+ /* We need to handle only two classes of windows messages
+ * on behalf of such dialogue boxes...
+ */
+ case WM_INITDIALOG:
+ /* ...viz. on initial dialogue box creation, we delegate the
+ * designated activity to the background thread...
+ */
+ _beginthread( WorkerThread, 0, (void *)(window) );
+ return TRUE;
+
+ case WM_COMMAND:
+ switch( msg = LOWORD( request ) )
+ {
+ case IDOK:
+ case IDCANCEL:
+ /* ...then we wait for a notification that the dialogue may be
+ * closed, (which isn't permitted until the thread completes).
+ */
+ EndDialog( window, msg );
+ return TRUE;
+
+ case ID_SETUP_SHOW_LICENCE:
+ /* Any request to view the licence document is handled in situ,
+ * without closing the active dialogue box.
+ */
+ BrowseLicenceDocument( window, -4, -50 );
+ return TRUE;
+ }
+ }
+ /* Any other messages, which are directed to this dialogue box,
+ * may be safely ignored.
+ */
+ return FALSE;
+}
+
+SetupDialogueThread::SetupDialogueThread
+( HWND owner, int id, SetupThreadProcedure *setup_actions )
+{
+ /* Class constructor assigns the worker procedure for the thread,
+ * then opens the dialogue box which starts it, ultimately capturing
+ * the exit code when this dialogue is closed.
+ */
+ WorkerThread = setup_actions;
+ status = DialogBox( NULL, MAKEINTRESOURCE( id ), owner, SetupDialogue );
+}
+
+class SetupDownloadAgent
+{
+ /* A locally defined class to manage package download activities
+ * on behalf of the setup tool.
+ */
+ public:
+ static void Run( void * );
+ SetupDownloadAgent( pkgSetupAction *packages ){ PackageList = packages; }
+
+ private:
+ static pkgSetupAction *PackageList;
+};
+
+/* Initialise the list of packages for download, as an empty list;
+ * we will subsequently populate it, as required.
+ */
+pkgSetupAction *SetupDownloadAgent::PackageList = NULL;
+
+/* Embed the download agent implementation as a filtered subset of
+ * mingw-get's own download service implementation.
+ */
+#include "pkginet.cpp"
+#include "pkgnget.cpp"
+
+static inline int dll_load_failed( const wchar_t *dll_name )
+{
+ /* Helper to diagnose failure to load any supporting DLL.
+ */
+ return dmh_notify( DMH_ERROR,
+ "%S: DLL load failed; cannot run setup hooks\n", dll_name
+ );
+}
+
+void SetupDownloadAgent::Run( void *owner )
+{
+ /* Method to run the download agent; it fetches all packages
+ * which are specified in the setup tool's initial installation
+ * list, (using a metered download procedure)...
+ */
+ pkgDownloadMeterGUI metered( (HWND)(owner) );
+ PackageList->DownloadArchiveFiles();
+
+ /* ...then unpacks each into its ultimate installed location,
+ * before delegating finalisation of the installation to the
+ * installer DLLs, which should thus have been installed.
+ */
+ if( (PackageList->UnpackScheduledArchives() == IDOK)
+ && SetupTool::Invoke()->InitialiseSetupHookAPI() )
+ {
+ /* Only on successful initialisation of the DLL hooks, do
+ * we actually continue with the delegated installation.
+ */
+ SetupTool::Invoke()->DispatchSetupHookRequest(
+ SETUP_HOOK_POST_INSTALL, PackageList, owner
+ );
+
+ /* Successful DLL initialisation is also a prerequisite for
+ * allowing the user to run the main installer, to continue
+ * the installation with a more comprehensive package set;
+ * however, progression to such advanced installation...
+ */
+ if( SetupTool::IsPref( SETUP_OPTION_WITH_GUI ) )
+ /*
+ * ...is feasible, only if the user has elected to install
+ * the mingw-get GUI client.
+ */
+ EnableWindow( GetDlgItem( (HWND)(owner), IDOK ), TRUE );
+ }
+ else
+ /* DLL initialisation was unsuccessful; tell the user that
+ * we are unable to continue this installation.
+ */
+ dmh_notify( DMH_ERROR, "setup: unable to continue\n" );
+
+ /* In any event, always offer the option to quit, without
+ * proceeding to advanced installation.
+ */
+ EnableWindow( GetDlgItem( (HWND)(owner), IDCANCEL ), TRUE );
+}
+
+bool SetupTool::InitialiseSetupHookAPI( void )
+{
+ /* Helper method, invoked by SetupDownloadAgent::Run(), to confirm
+ * that the requisite installer DLLs have been successfully unpacked,
+ * and if so, to initialise them for continuation of installation.
+ *
+ * First, we must confirm that mingw-get's main DLL is available...
+ */
+ if( (base_dll = HaveWorkingInstallation()) == NULL )
+ /*
+ * ...immediately abandoning the installation, if not.
+ */
+ return (dll_load_failed( dll_name ) == 0);
+
+ /* Having successfully loaded the main DLL, we perform a similar
+ * check for the setup tool's bridging DLL...
+ */
+ dll_name = approot_path( L"libexec\\mingw-get\\mingw-get-setup-0.dll" );
+ if( (hook_dll = LoadLibraryW( dll_name )) == NULL )
+ {
+ /* ...once again, abandoning the installation, if this is not
+ * available; in this case, since we've already successfully
+ * loaded mingw-get's main DLL, we also unload it.
+ */
+ FreeLibrary( base_dll ); base_dll = NULL;
+ return (dll_load_failed( dll_name ) == 0);
+ }
+ /* With both DLLs successfully loaded, we may establish the
+ * conduit, through which the setup tool invokes procedures in
+ * either of these DLLs...
+ */
+ dll_request = (dll_request_hook)(GetProcAddress( hook_dll, "setup_hook" ));
+ if( dll_request != NULL )
+ {
+ /* ...and, on success, complete the DLL initialisation by
+ * granting the DLLs shared access to the diagnostic message
+ * handler provided by the setup tool's main program.
+ */
+ DispatchSetupHookRequest( SETUP_HOOK_DMH_BIND, dmh );
+ return true;
+ }
+ /* If we get to here, DLL initialisation was unsuccessful;
+ * diagnose, and bail out.
+ */
+ dmh_notify( DMH_ERROR, "setup_hook: DLL entry point not found\n" );
+ return false;
+}
+
+inline int SetupTool::DispatchSetupHookRequest( unsigned int request, ... )
+{
+ /* Helper method, providing a variant argument API to the
+ * request hook within the setup tool's bridging DLL; it
+ * collects the argument vector, to pass into the DLL.
+ */
+ va_list argv;
+ va_start( argv, request );
+ int retval = dll_request( request, argv );
+ va_end( argv );
+ return retval;
+}
+
+static inline
+long InitiatePackageInstallation( HWND owner, pkgSetupAction *pkglist )
+{
+ /* Helper routine, invoked by SetupTool::DoFirstTimeSetup(), to
+ * install mingw-get, and proceed to further package selection.
+ */
+ SetupDownloadAgent agent( pkglist );
+ SetupDialogueThread run( owner, IDD_SETUP_DOWNLOAD, SetupDownloadAgent::Run );
+ RefreshDialogueWindow( owner );
+ return run.ExitCode();
+}
+
+/* Embed a selected subset of the package stream extractor methods,
+ * sufficient to support unpacking of the .tar.xz archives which are
+ * used as the delivery medium for mingw-get.
+ */
+#include "pkgstrm.cpp"
+
+/* The standard archive extractor expects to use the pkgOpenArchiveStream()
+ * function to gain access to archive files; however, the generalised version
+ * of this is excluded from the subset embedded from pkgstrm.cpp, so we must
+ * provide a replacement...
+ */
+pkgArchiveStream *pkgOpenArchiveStream( const char *archive_path_name )
+{
+ /* ...function to prepare an archive file for extraction; (this specialised
+ * version is specific to extraction of xz compressed archives).
+ */
+ return new pkgXzArchiveStream( archive_path_name );
+}
+
+/* The archive extractor classes incorporate reference pointers to pkgXmlNode
+ * and pkgManifest class objects, but these are not actually used within the
+ * context required here; to placate the compiler, declare these as opaque
+ * data types.
+ */
+class pkgXmlNode;
+class pkgManifest;
+
+/* Embed the minimal subset of required extractor classes and methods...
+ */
+#include "tarproc.cpp"
+
+/* ...noting that the formal implementation of this required constructor
+ * has been excluded; (it implements a level of complexity, not required
+ * here); hence, we provide a minimal, do nothing, substitute.
+ */
+pkgTarArchiveProcessor::pkgTarArchiveProcessor( pkgXmlNode * ){}
+
+/* Similarly, we need a simplified implementation of the destructor
+ * for this same class...
+ */
+pkgTarArchiveProcessor::~pkgTarArchiveProcessor()
+{
+ /* ...but it this case, we still use it to clean up the memory
+ * allocated by the pkgTarArchiveExtractor class constructor.
+ */
+ free( (void *)(sysroot_path) );
+ delete stream;
+}
+
+static
+int CALLBACK unwise( HWND owner, unsigned msg, WPARAM request, LPARAM data )
+{
+ /* Handler for the dialogue box which is presented when the user
+ * makes an unwise choice of installation directory (specifically
+ * a choice with white space in the path name).
+ */
+ switch( msg )
+ {
+ case WM_INITDIALOG:
+ /* There are no particular initialisation requirements, for
+ * this dialogue box; just accept the defaults.
+ */
+ return TRUE;
+
+ case WM_COMMAND:
+ /* User has selected one of the continuation options...
+ */
+ switch( msg = LOWORD( request ) )
+ {
+ /* When it is...
+ */
+ case IDIGNORE:
+ /* Ignore advice to choose a more appropriate location:
+ * this requires additional confirmation that the user has
+ * understood the implications of this choice; do no more
+ * than enable the button which provides such confirmation.
+ */
+ if( HIWORD( request ) == BN_CLICKED )
+ EnableWindow( GetDlgItem( owner, IDYES ),
+ SendMessage( (HWND)(data), BM_GETCHECK, 0, 0 ) == BST_CHECKED
+ );
+ return TRUE;
+
+ case IDNO:
+ /* Accept advice; go back to make a new choice of location
+ * for this installation, or...
+ */
+ case IDYES:
+ /* ...confirm understanding of, and intent to ignore, advice;
+ * in either case close the dialogue, returning appropriate
+ * selection code.
+ */
+ EndDialog( owner, msg );
+ return TRUE;
+ }
+ }
+ /* No other conditions are handled explicitly, within this dialogue.
+ */
+ return FALSE;
+}
+
+static bool UnconfirmedDirectorySelection( HWND owner, const wchar_t *choice )
+{
+ /* Helper function to ratify user's selection of installation directory;
+ * given an absolute path name retrieved from SHBrowsForFolder(), it checks
+ * for the presence of embedded white space, and reiterates the appropriate
+ * warning when any is found, before allowing the user to choose again, or
+ * to ignore the advice, and shoot himself/herself in the foot.
+ */
+ const wchar_t *path;
+ RefreshDialogueWindow( owner );
+ if( choice && *(path = choice) )
+ {
+ /* We have a non-empty path name selection to ratify...
+ */
+ while( *path )
+ if( iswspace( *path++ ) )
+ {
+ /* ...and we DID find embedded white space; castigate the user
+ * for his/her folly in ignoring advice...
+ */
+ return DialogBox( NULL, MAKEINTRESOURCE( IDD_SETUP_UNWISE ),
+ owner, unwise ) != IDYES;
+ }
+ /* If we get to here, then the user appears to have made a sane choice;
+ * caller need not repeat the request for a directory selection...
+ */
+ return false;
+ }
+ /* ...but when we were asked to ratify no selection at all, then caller
+ * must repeat this request.
+ */
+ return true;
+}
+
+static
+int CALLBACK BrowserInit( HWND owner, unsigned msg, LPARAM, LPARAM dirname )
+{
+ /* Helper function to set the default installation directory path name,
+ * and to assign a more appropriate dialogue box description...
+ */
+ if( msg == BFFM_INITIALIZED )
+ {
+ /* ...when initialising the SHBrowseForFolder() dialogue to elicit
+ * the user's choice of installation directory.
+ */
+ SendMessage( owner, WM_SETTEXT, 0, (LPARAM)("Select Installation Directory") );
+ SendMessage( owner, BFFM_SETSELECTIONW, TRUE, dirname );
+ }
+ return 0;
+}
+
+static inline
+bool mkdir_default( wchar_t *dirpath )
+{
+ /* Helper function to create the default installation directory;
+ * this must exist before we call SHBrowseForFolder(), so that we
+ * may offer as the default choice, even if the user subsequently
+ * declines to accept it.
+ */
+ bool retval = false; struct _stat chkdir;
+ if( ! ((_wstat( dirpath, &chkdir ) == 0) && S_ISDIR( chkdir.st_mode )) )
+ {
+ /* The recommended default directory doesn't yet exist; try to
+ * create it...
+ */
+ if( ! (retval = (_wmkdir( dirpath ) == 0)) )
+ /*
+ * ...but if unsuccessful, fall back to offering the root
+ * directory of the default device, as a starting point for
+ * the user's selection.
+ */
+ dirpath[3] = L'\0';
+ }
+ /* In any event, this will return "true" if we created the
+ * directory, or "false" if it either already existed, or if
+ * our attempt to create it failed.
+ */
+ return retval;
+}
+
+static inline
+void rmdir_default( const wchar_t *offer, const wchar_t *selected )
+{
+ /* Helper function, called if we created the default installation
+ * directory; it will remove it if the user rejected this default
+ * selection, and any descendant thereof.
+ */
+ const wchar_t *chk = offer;
+ while( *chk && *selected && (*chk++ == *selected++) ) ;
+ if( (*chk != L'\0') || ((*selected != L'\0') && (*selected != L'\\')) )
+ _wrmdir( offer );
+}
+
+static
+int setup_putenv( const char *varname, const wchar_t *value )
+{
+ /* Helper function to assign a specified value to a named
+ * environment variable.
+ */
+ const char *fmt = "%s=%S";
+ char assignment[1 + snprintf( NULL, 0, fmt, varname, value )];
+ snprintf( assignment, sizeof( assignment ), fmt, varname, value );
+ return putenv( assignment );
+}
+
+wchar_t *SetupTool::approot_tail = NULL;
+wchar_t *SetupTool::approot_path( const wchar_t *relative_path )
+{
+ /* Helper method to resolve a relative path name to its absolute
+ * equivalent, within the directory hierarchy of the user's chosen
+ * installation directory.
+ *
+ * The resolved absolute path name is returned in this static
+ * buffer, initially defined to be empty.
+ */
+ static wchar_t dirpath[PATH_MAX] = L"\0";
+
+ /* When a previous call has left a "tail" buffer,
+ * (which may or may not be populated)...
+ */
+ if( approot_tail != NULL )
+ /*
+ * ...then clear it...
+ */
+ *approot_tail = L'\0';
+
+ else if( *dirpath != L'\0' )
+ /*
+ * ...otherwise, establish the "tail" buffer, following
+ * the "approot" string within the "dirpath" buffer.
+ */
+ for( approot_tail = dirpath; *approot_tail != L'\0'; approot_tail++ )
+ ;
+
+ /* When a relative path argument is specified...
+ */
+ if( relative_path != NULL )
+ {
+ /* ...then we must resolve it as an absolute path, interpreting
+ * it as relative to "approot", by copying it into the "tail"
+ * buffer within "dirpath".
+ *
+ * We perform the copy character by character, storing at the
+ * advancing "caret" position, while ensuring we do not overrun
+ * the "endstop" location, which we set initially to mark the
+ * end of the "dirpath" buffer.
+ */
+ wchar_t *caret = approot_tail - 1;
+ wchar_t *endstop = dirpath + PATH_MAX - 1;
+
+ /* We initially set "caret" to point to the final character
+ * in "approot", so that we may check for the presence of a
+ * directory separator; if there ISN'T one there already...
+ */
+ if( (*caret != L'\\') && (*caret != L'/') )
+ /*
+ * ...then we advance it to the start of the "tail"
+ * buffer, where we will insert one.
+ */
+ ++caret;
+
+ /* When the first character of the specified relative path
+ * is NOT itself a directory separator, (which is expected
+ * in the normal case)...
+ */
+ if( (*relative_path != L'\\') && (*relative_path != L'/') )
+ /*
+ * ...then we explicitly insert one; (we may note that this
+ * will either overwrite an existing separator at the end of
+ * "approot", or it will occupy the first "caret" position
+ * within the "tail" buffer).
+ */
+ *caret++ = L'\\';
+
+ /* Now, we copy the relative path to the "caret" location...
+ */
+ do { /* ...ensuring that we do NOT overrun the "endstop"...
+ */
+ if( caret < endstop )
+ {
+ /* ...and normalising directory separators, favouring
+ * Microsoft's '\\' preference, as we go...
+ */
+ if( (*caret = *relative_path++) == L'/' )
+ *caret = L'\\';
+ }
+ else
+ /* ...but, if we hit the "endstop", we immediately
+ * truncate and terminate the copy...
+ */
+ *caret = L'\0';
+
+ /* ...continuing until we've copied the terminating NUL
+ * from the relative path argument itself, or we hit the
+ * "endstop", forcing early termination.
+ */
+ } while( *caret++ != L'\0' );
+ }
+ /* However we completed the operation, we return a pointer to the
+ * entire content of the "dirpath" static buffer.
+ */
+ return dirpath;
+};
+
+inline int pkgSetupAction::UnpackScheduledArchives( void )
+{
+ /* Helper to unpack each of the package archives, specified in the
+ * setup actions list, extracting content to its ultimate installed
+ * location within the user specified installation directory tree.
+ */
+ int status = IDCANCEL;
+ pkgSetupAction *install;
+
+ /* When the action list is not empty...
+ */
+ if( (install = this) != NULL )
+ {
+ /* ...ensure that we process it from its first entry.
+ */
+ status = IDOK;
+ while( install->prev != NULL ) install = install->prev;
+ while( install != NULL )
+ {
+ /* For each list entry, locate the downloaded copy of the
+ * archive, in the installer's package cache directory.
+ */
+ const char *cache = "%R" "var\\cache\\mingw-get\\packages\\%F";
+ char archive_name[mkpath( NULL, cache, install->ArchiveName(), NULL )];
+ mkpath( archive_name, cache, install->ArchiveName(), NULL );
+
+ /* Report activity, and provided download has made the
+ * cached copy of the archive available...
+ */
+ dmh_notify( DMH_INFO, "setup: unpacking %s\n", install->ArchiveName() );
+ if( install->HasAttribute( ACTION_DOWNLOAD ) == 0 )
+ /*
+ * ...extract its content.
+ */
+ pkgTarArchiveExtractor( archive_name, "%R" );
+
+ else
+ { /* The package is not available; assume that download was
+ * unsuccessful, and diagnose accordingly...
+ */
+ dmh_notify( DMH_ERROR, "unpack: required archive file is not available\n" );
+ dmh_notify( DMH_ERROR, "unpack: aborted due to previous download failure\n" );
+
+ /* ...then cancel further installation activities.
+ */
+ status = IDCANCEL;
+ }
+
+ /* Repeat for any other scheduled action items.
+ */
+ install = install->next;
+ }
+ }
+ /* Ultimately return the status code, indicating either complete
+ * success, or requesting cancellation of further installation.
+ */
+ return status;
+}
+
+static
+char *arg_append( char *caret, const char *argtext, const char *endstop )
+{
+ /* Command line construction helper function; append specified "argtext"
+ * into the constructed command line, with appropriate quoting to keep it
+ * as a single argument, and preceded by a space, at the position marked
+ * by "caret", and ensuring that the text does not overrun "endstop".
+ */
+ if( (endstop > caret) && ((endstop - caret) > 1)
+ && (argwrap( caret + 1, argtext, endstop - caret - 1) != NULL) )
+ {
+ /* The specified argument can be accommodated; insert the separating
+ * space, and update the caret to mark the position at which the next
+ * argument, if any, should be appended.
+ */
+ *caret = '\040';
+ return caret + strlen( caret );
+ }
+ /* If we get to here, the argument could not be accommodated, return the
+ * caret position, unchanged.
+ */
+ return caret;
+}
+
+static
+char *arg_append( char *caret, const wchar_t *argtext, const char *endstop )
+{
+ /* Overloaded variant of the preceding command line construction helper;
+ * this variant appends an argument, specified as a wide character string,
+ * to the constructed command line.
+ */
+ if( (endstop > caret) && ((endstop - caret) > 1) )
+ {
+ /* There is at least some remaining space in the command line buffer;
+ * convert the specified argument to a regular string...
+ */
+ const char *conv_fmt = "%S";
+ char conv_buf[1 + snprintf( NULL, 0, conv_fmt, argtext )];
+ snprintf( conv_buf, sizeof( conv_buf ), conv_fmt, argtext );
+ /*
+ * ...then delegate the actual append operation to the regular string
+ * handling variant of the helper function.
+ */
+ return arg_append( caret, conv_buf, endstop );
+ }
+ /* If we get to here, the command line buffer space has been completely
+ * exhausted; return the caret position, unchanged.
+ */
+ return caret;
+}
+
+#ifndef ARG_MAX
+/* POSIX specifies this as the maximum number of characters allowed in the
+ * aggregate of all arguments passed to a child process in an exec() function
+ * call. It isn't typically defined on MS-Windows, although limits do apply
+ * in the case of exec(), spawn(), or system() function calls. MSDN tells
+ * us that the maximum length of a command line is 8191 characters on WinXP
+ * and later, but only 2047 characters on earlier versions; allowing one
+ * additional character for a terminating NUL, we will adopt the lower
+ * of these, as a conservative choice.
+ */
+# define ARG_MAX 2048
+#endif
+
+inline void SetupTool::CreateApplicationLauncher
+( int opt, const wchar_t *appname, const char *desc, const char *linkname )
+{
+ /* Construct a command line to invoke the shlink.js script, (which is
+ * provided by the mingw-get package), via the system provided wscript
+ * interpreter, to install a desktop or start-menu application link.
+ */
+ static const char *cmd = "wscript";
+ static const char *location[] = { "--start-menu", "--desktop" };
+
+ /* Initialise the argument list, setting the wscript option to suppress
+ * its normal verbose behaviour, and set a buffer endstop reference, so
+ * that we may detect, and avoid overrun.
+ */
+ char cmdline[ARG_MAX] = "-nologo";
+ const char *endstop = cmdline + sizeof( cmdline );
+
+ /* Add the full path name reference for the shlink.js script which is to
+ * be executed; (note that we resolve this relative to the user's choice
+ * of installation directory, where the script will have been installed,
+ * during prior unpacking of the mingw-get-bin package tarball).
+ */
+ char *caret = arg_append( cmdline + strlen( cmdline ),
+ approot_path( L"libexec\\mingw-get\\shlink.js" ), endstop
+ );
+
+ /* Add options to select placement of the application links, and to specify
+ * whether they should be available to current user ot to all users.
+ */
+ caret = arg_append( ((opt & SETUP_OPTION_ALL_USERS) != 0)
+ ? arg_append( caret, "--all-users", endstop )
+ : caret, location[opt >> 2], endstop
+ );
+
+ /* Add a description for the application link.
+ */
+ caret = arg_append( arg_append( caret, "--description", endstop ),
+ desc, endstop
+ );
+
+ /* Specify the path name for the application to be invoked, (again noting
+ * that this must be resolved relative to the installation directory), and
+ * the name to be given to the link file itself.
+ */
+ arg_append( arg_append( caret, approot_path( appname ), endstop ),
+ linkname, endstop
+ );
+
+ /* Finally, invoke the script interpreter to process the specified command.
+ * (We use a spawn() call here, in preference to system(), to avoid opening
+ * any unwanted console windows).
+ */
+ spawnlp( P_WAIT, cmd, cmd, cmdline, NULL );
+}
+
+inline SetupTool::SetupTool( HINSTANCE Instance ):
+base_dll( NULL ), hook_dll( NULL )
+{
+ /* Constructor for the SetupTool object. Note that there should be only
+ * one such object instantiated; this is intended as a one time only call,
+ * and any attempted subsequent call will be ignored, as a consequence of...
[truncated message content] |
|
From: Keith M. <no...@so...> - 2013-07-01 20:05:09
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-get".
The branch, master has been updated
via 95b5e3418266f6f9c4fcb086a6b9570fb6216a5a (commit)
from 3b4940a9b9c272fb76e32c22eb6909d1ba949ba5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-get/ci/95b5e3418266f6f9c4fcb086a6b9570fb6216a5a/
commit 95b5e3418266f6f9c4fcb086a6b9570fb6216a5a
Author: Keith Marshall <kei...@us...>
Date: Mon Jul 1 16:57:41 2013 +0100
Add subprocess argument vector construction helpers.
diff --git a/ChangeLog b/ChangeLog
index 09c85c4..83cc5a2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2013-07-01 Keith Marshall <kei...@us...>
+
+ Add subprocess argument vector construction helpers.
+
+ * src/argwrap.c src/argwrap.h: New files; they implement an API for
+ construction of argument vectors, with appropriate quoting, to be
+ passed to MS-Windows exec'd subprocesses. Rewritten from scratch,
+ without reference to any prior GPL licensed implementation, with MIT
+ style licence, these provide the foundation for a possible future
+ libmingwex.a implementation; they are included here, since no such
+ implementation is currently available.
+
2013-06-28 Keith Marshall <kei...@us...>
Avoid inadvertent overwrite of existing files.
diff --git a/src/argwrap.c b/src/argwrap.c
new file mode 100644
index 0000000..47ad7c8
--- /dev/null
+++ b/src/argwrap.c
@@ -0,0 +1,251 @@
+/*
+ * argwrap.c
+ *
+ * $Id$
+ *
+ * Provides the implementation of the helper function, argwrap(), which
+ * may be used to prepare arguments for passing to any child process, via
+ * the Microsoft implementations of the spawn() or exec() functions; it
+ * ensures that each argument passed is appropriately quoted, such that
+ * it will be correctly read by the MSVCRT argv parsing code, without
+ * fear of unintended word splitting.
+ *
+ *
+ * Written by Keith Marshall <kei...@us...>
+ * Copyright (C) 2013, MinGW.org Project <http://mingw.org>
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders and contributors shall not be used in advertising or otherwise
+ * to promote the sale, use or other dealings in this Software without
+ * prior written authorization.
+ *
+ */
+#include "argwrap.h"
+
+#include <ctype.h>
+#include <string.h>
+
+const char *argwrap( char *rtnbuf, const char *argtext, size_t len )
+{
+ /* Helper function to immunise a single argument string against word
+ * splitting by the MSVCRT argv parsing code; it returns its original
+ * argument intact, if already immune, otherwise it returns a copy of
+ * this argument, in dynamically allocated memory, with appropriate
+ * quoting added to provide immunity.
+ */
+ const char *rtntext;
+ if( (rtntext = argtext) != NULL )
+ {
+ /* When the original argument is not NULL, we have already set up
+ * the return state for an already immune string; now perform a scan
+ * to verify immunity, accumulating counters for original length and
+ * required length for a fully immunised copy.
+ */
+ //char *argp;
+ int ect = 0, ict = 0, rct;
+
+ if( *argtext == '\0' )
+ /*
+ * The input argument is an empty string. To ensure that this is
+ * preserved in the argument vector passed to a child process, we
+ * must wrap it in double quotes; thus its length, excluding the
+ * terminating NUL, may be deterministically set to two.
+ */
+ rct = 2;
+
+ else
+ { /* The input argument is not an empty string; we must scan it, to
+ * determine whether or not it requires wrapping in double quotes.
+ */
+ const char *argp = argtext; rct = 0;
+ do { if( *argp == '\\' )
+ /*
+ * Microsoft's interpretation of a backslash is ambiguous.
+ * In any unquoted context, it is interpreted literally, but
+ * when it is used in a double quoted context, it represents
+ * an escape if, and only if, it appears within a contiguous
+ * run of backslashes which is immediately followed either
+ * by a literal double quote character, or by the double
+ * quote character which terminates the quoted context.
+ *
+ * This apparently bizarre behaviour is necessary to provide
+ * the most natural practical interpretation of user input,
+ * given the ambiguous requirement for backslashes to serve
+ * as both directory name separators and escape characters;
+ * to accommodate this ambiguity, at this point we simply
+ * count the length of each contiguous run of backslashes
+ * which we encounter.
+ */
+ ++ect;
+
+ else
+ { /* The current character may be unambiguously processed,
+ * as a literal representation of itself...
+ */
+ if( (*argp == '\"') || isspace( *argp ) || iscntrl( *argp ) )
+ {
+ /* Here, we have identified an embedded character which
+ * imposes a requirement that the entire argument should
+ * be wrapped in double quotes...
+ */
+ if( ict == rct )
+ /*
+ * This is the first such character encountered, so
+ * we must reserve additional space to accommodate the
+ * enclosing double quote characters.
+ */
+ rct += 2;
+
+ if( *argp == '\"' )
+ /*
+ * A literal double quote character must be escaped,
+ * by prefixing a backslash; furthermore, any literal
+ * backslashes which immediately precede it must also
+ * be individually escaped. We have already accounted
+ * for the space to accommodate any contiguous run of
+ * such preceding literal backslashes; now we account
+ * for an additional escape for each of them, plus
+ * one more for the literal double quote.
+ */
+ rct += ect + 1;
+ }
+ /* Since the current character is known not to be a literal
+ * backslash, we can guarantee that there are zero contiguous
+ * backslashes immediately preceding the next character.
+ */
+ ect = 0;
+ }
+ /* Irrespective of quoting adjustments, we must also account
+ * for one input character being copied to the output...
+ */
+ ++ict; ++rct;
+
+ /* ...then, we loop back until all available input characters
+ * have been scanned.
+ */
+ } while( *++argp );
+ }
+ /* We've now completed a scan of the input argument, and have assessed
+ * the size required for the returned argument string; if this exceeds
+ * the original input character count, the the returned argument needs
+ * to be wrapped in double quotes, and we must allocate a new buffer,
+ * in which to return it...
+ */
+ if( rct > ict )
+ {
+ /* We need to rewrite the specified argument, adding quoting and
+ * any escape codes, as identified above; when the caller has not
+ * provided a return buffer...
+ */
+ char *argp;
+ if( (rtnbuf == NULL) && (len == 0) )
+ /*
+ * ...then we allocate one of suitable size...
+ */
+ argp = (char *)(malloc( 1 + rct + ect ));
+
+ else
+ argp = ( len > (rct + ect)) ? rtnbuf : NULL;
+
+ if( argp != NULL )
+ {
+ /* We have successfully allocated a return buffer, with sufficient
+ * space to accommodate the wrapped argument, together with embedded
+ * escapes to be inserted, as already accounted for in the preceding
+ * scan, plus any further escapes required to identify any trailing
+ * literal backslashes, and also a terminating NUL.
+ *
+ * We may now assign this buffer as the argument to return, and
+ * insert the opening double quote, prior to copying the text of
+ * the input argument, with insertion of necessary escapes...
+ */
+ rtntext = argp;
+ *argp++ = '\"'; ect = 0;
+ while( *argtext )
+ {
+ /* Scan the input argument a second time...
+ */
+ if( *argtext == '\\' )
+ /*
+ * ...again counting literal backslashes, in case they
+ * need to be escaped on copying out.
+ */
+ ++ect;
+
+ else
+ { /* The input character is not a literal backslash; if it is
+ * a literal double quote...
+ */
+ if( *argtext == '\"' )
+ /*
+ * ...then it, and each immediately preceding contiguous
+ * backslash, (if any)...
+ */
+ for( ++ect; ect > 0; ect-- )
+ /*
+ * ...must be escaped, by insertion of an extra
+ * backslash character.
+ */
+ *argp++ = '\\';
+
+ /* Irrespective of the need for escaping this character, we
+ * can be certain that the next character has zero immediately
+ * preceding contiguous backslashes.
+ */
+ ect = 0;
+ }
+
+ /* After the above insertion of any necessary escape characters,
+ * each input character is copied verbatim, to the return buffer.
+ */
+ *argp++ = *argtext++;
+ }
+
+ /* After copying all input characters, if it is identified that the
+ * input string ended with a run of one or more contiguous backslash
+ * characters...
+ */
+ while( ect-- > 0 )
+ /*
+ * ...then one escape character must be inserted for each...
+ */
+ *argp++ = '\\';
+
+ /* ...before we ultimately add the closing double quote character,
+ * and the terminating NUL.
+ */
+ *argp++ = '\"';
+ *argp = '\0';
+ }
+ }
+ else if( rtnbuf != NULL )
+ rtntext = (len > strlen( argtext )) ? strcpy( rtnbuf, argtext ) : NULL;
+ }
+ /* Finally, whether we needed to create a double-quote-wrapped copy of the
+ * input argument, or we can simply return a direct reference to the input
+ * argument itself, "rtntext" provides the appropriate reference, which we
+ * must return.
+ */
+ return rtntext;
+}
+
+/* $RCSfile$: end of file */
diff --git a/src/argwrap.h b/src/argwrap.h
new file mode 100644
index 0000000..388cba2
--- /dev/null
+++ b/src/argwrap.h
@@ -0,0 +1,75 @@
+#ifndef ARGWRAP_H
+/*
+ * argwrap.h
+ *
+ * $Id$
+ *
+ * This private header provides declarations which are to be shared by
+ * the argwrap.c and argvwrap.c implementations.
+ *
+ *
+ * Written by Keith Marshall <kei...@us...>
+ * Copyright (C) 2013, MinGW.org Project <http://mingw.org>
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders and contributors shall not be used in advertising or otherwise
+ * to promote the sale, use or other dealings in this Software without
+ * prior written authorization.
+ *
+ */
+#define ARGWRAP_H 1
+
+#include <stdlib.h>
+#include <errno.h>
+
+#undef BEGIN_C_DECLS
+#undef END_C_DECLS
+
+#ifdef __cplusplus
+# define BEGIN_C_DECLS extern "C" {
+# define END_C_DECLS }
+#else
+# define BEGIN_C_DECLS
+# define END_C_DECLS
+#endif
+
+BEGIN_C_DECLS
+
+static __inline__
+void __attribute__((__always_inline__)) *inline_malloc( size_t request )
+{
+ /* In some, if not all versions of MSVCRT, Microsoft's implementation of
+ * malloc() neglects to set errno appropriately on failure; this locally
+ * implemented wrapper works around this deficiency.
+ */
+ void *allotted;
+ if( (allotted = malloc( request )) == NULL )
+ errno = ENOMEM;
+ return allotted;
+}
+#define malloc( request ) inline_malloc( request )
+
+extern const char *argwrap( char *, const char *, size_t );
+
+END_C_DECLS
+
+#endif /* !defined ARGWRAP_H: $RCSfile$: end of file */
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 12 +++
src/argwrap.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/argwrap.h | 75 +++++++++++++++++
3 files changed, 338 insertions(+), 0 deletions(-)
create mode 100644 src/argwrap.c
create mode 100644 src/argwrap.h
hooks/post-receive
--
Repository: mingw-get
|
|
From: Earnie B. <no...@so...> - 2013-07-01 12:35:39
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-dist".
The branch, master has been updated
via 95d09656467e0a9cd45745645af93a6bd5c8f507 (commit)
from a1406a3200b691e10bceaa8e704798c32c1537bd (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-dist/ci/95d09656467e0a9cd45745645af93a6bd5c8f507/
commit 95d09656467e0a9cd45745645af93a6bd5c8f507
Author: Earnie Boyd <ea...@us...>
Date: Mon Jul 1 08:35:17 2013 -0400
Add mingw32-wsl release candidate 4.
diff --git a/ChangeLog b/ChangeLog
index 520ebce..0205a65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-07-01 Earnie Boyd <ea...@us...>
+
+ * mingw32/mingw32-wsl-candidate.xml: Add wsl_rc-4.0-1-mingw32-rc-4.
+ * package-list.xml.lzma mingw32-package-list.xml.lzma: Regenerated.
+ * common/issue.log mingw32/issue.log: Update accordingly.
+
2013-06-19 Earnie Boyd <ea...@us...>
* mingw32/mingw32-wsl-candidate.xml: Add wsl_rc-4.0-1-mingw32-rc-3.
diff --git a/common/issue.log b/common/issue.log
index c25830e..44254f7 100644
--- a/common/issue.log
+++ b/common/issue.log
@@ -23,6 +23,6 @@
# MinGW Project, accept liability for any damages, however caused,
# arising from the use of this software.
#
- 75fc52dde8d408d798c0be51070d5d02f4c63085 2013061800 package-list.xml
+ 75fc52dde8d408d798c0be51070d5d02f4c63085 2013070100 package-list.xml
#
# $RCSfile$: end of file
diff --git a/mingw32/issue.log b/mingw32/issue.log
index f80eaf1..263cd02 100644
--- a/mingw32/issue.log
+++ b/mingw32/issue.log
@@ -50,12 +50,12 @@
cd33ad74b608bce33ea297801253e6efbafce27c 2012073100 mingw32-mingw-utils.xml
d31c39c6584fde6d4b9ddafbca913509b32a1dfc 2012073100 mingw32-mpc.xml
99995a8e17659b6514f71ae2b17bbbcd8eb4c0a9 2012073100 mingw32-mpfr.xml
- 983af8ad24a6f97da867784dfeeecc6661d54d88 2013061800 mingw32-package-list.xml
+ 983af8ad24a6f97da867784dfeeecc6661d54d88 2013070100 mingw32-package-list.xml
bad22da9b9ec9bcea1d539e29ee2976cc88d9fc2 2013053000 mingw32-pexports.xml
cdb2a4dbedfc9f2cdfc92340f6f9b12da061c0d9 2012073100 mingw32-popt.xml
9399cb6c2efd8fd907c42a278a6f41bbde9e440c 2011091400 mingw32-pthreads-w32.xml
428964289b3509293a13c9394199b5e2d4887c3e 2012063001 mingw32-runtime.xml
- 8111d853ffb3cfd3f4ec62324b17d9a9403ff0fe 2013061800 mingw32-wsl-candidate.xml
+ 12acb32f80e49c893167cfae82e448dd766d49bb 2013070100 mingw32-wsl-candidate.xml
247a02890f109a5fe4996fde4af9d576dca3cd1e 2012073100 mingw32-xz.xml
4a2e1515655331483b8ddc898b2405fb89401d73 2012073100 mingw32-zlib.xml
#
diff --git a/mingw32/mingw32-wsl-candidate.xml b/mingw32/mingw32-wsl-candidate.xml
index 42a7a4c..fbe48fc 100644
--- a/mingw32/mingw32-wsl-candidate.xml
+++ b/mingw32/mingw32-wsl-candidate.xml
@@ -63,6 +63,7 @@
<package name="mingw32-wsl_rc">
<component class="meta">
+ <release tarname="wsl_rc-4.0-1-mingw32-rc-4-meta.tar.lzma" />
<release tarname="wsl_rc-4.0-1-mingw32-rc-3-meta.tar.lzma" />
<release tarname="wsl_rc-4.0-1-mingw32-rc-2-meta.tar.lzma" />
<release tarname="wsl_rc-4.0-1-mingw32-rc-1-meta.tar.lzma" />
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 6 ++++++
common/issue.log | 2 +-
mingw32/issue.log | 4 ++--
mingw32/mingw32-wsl-candidate.xml | 1 +
4 files changed, 10 insertions(+), 3 deletions(-)
hooks/post-receive
--
Repository: mingw-dist
|