OSDN Git Service

Implement GUI hooks in "rites of passage" internal API.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Fri, 14 Sep 2012 21:12:58 +0000 (22:12 +0100)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Fri, 14 Sep 2012 21:12:58 +0000 (22:12 +0100)
ChangeLog
src/pkglock.h [new file with mode: 0644]
src/rites.c

index d8cfc0c..79f5f42 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
 2012-09-14  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
+       Implement GUI hooks in "rites of passage" internal API.
+
+       * src/pkglock.h: New file; it adds the pkgLock() and pkgRelease()
+       inline wrapper functions, through which the GUI application acquires
+       and manages an exclusive access lock for the XML catalogue.
+
+       * src/rites.c (lockfile_name): Explicitly cast memory allocated for
+       the returned name to (char *), so this may be embedded in C++ code.
+       (pkgInitRites): Factor out lock acquisition failure diagnostics...
+       (pkgLockFail): ...to this inline helper function; conditionally...
+       [ifdef GUIMAIN_H]: ...provide one implementation for GUI use...
+       [ifndef GUIMAIN_H]: ...and an alternative for CLI use.
+
+2012-09-14  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
        Be case agnostic when matching shortcut targets.
 
        * scripts/libexec/unlink.js [ref.TargetPath == chklink]: Apply
diff --git a/src/pkglock.h b/src/pkglock.h
new file mode 100644 (file)
index 0000000..2a7235d
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef PKGLOCK_H
+/*
+ * pkglock.h
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2012, MinGW Project
+ *
+ *
+ * Implementation of inline wrapper functions, for use by the GUI
+ * application, to manage the process lock on the XML catalogue.
+ *
+ *
+ * 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 PKGLOCK_H  1
+
+/* We need to import the phase one initiation rites definitions
+ * from "rites.c"...
+ */
+#define IMPLEMENT_INITIATION_RITES  PHASE_ONE_RITES
+
+#ifndef EXIT_FATAL
+ /* ...and we need this to be defined, before we do so.
+  */
+# define EXIT_FATAL  (EXIT_FAILURE + 1)
+#endif
+
+#include "rites.c"
+#include "approot.h"
+
+RITES_INLINE int pkgLock( const char *caption )
+{
+  /* Wrapper function for pkgInitRites(), called exclusively when
+   * starting in GUI mode, to establish the required process lock
+   * for access to the local installation catalogue.
+   *
+   * Before proceeding, we ensure that the APPROOT environment
+   * variable has been initialised, so that pkgInitRites() may
+   * correctly define the path for the lock file...
+   */
+  const char *varname = "APPROOT";
+  if( getenv( varname ) == NULL )
+  {
+    /* ...and we initialise it, if necessary.
+     */
+    const char *fmt = "%s=%S\\";
+    const wchar_t *approot = AppPathNameW( NULL );
+    size_t len = 1 + snprintf( NULL, 0, fmt, varname, approot );
+    char var[len]; snprintf( var, len, fmt, varname, approot );
+    putenv( var );
+  }
+
+  /* Now, we invoke pkgInitRites(), attempting to acquire the
+   * lock; a CLI process may already own this, in which case we
+   * will allow the user to wait and subsequently retry.
+   */
+  int lock, retry;
+  do { if( (lock = pkgInitRites( caption )) >= 0 )
+        /*
+         * We've acquired the lock; return it immediately.
+         */
+        return lock;
+
+       /* This attempt to acquire the lock was unsuccessful;
+       * if the lock file path is invalid, there is no point
+       * in retrying, but otherwise we grant the user the
+       * opportunity to do so...
+       */
+       retry = (errno == ENOENT) ? IDCANCEL : MessageBox( NULL,
+          "Cannot acquire lock for exclusive access to mingw-get catalogue.\n"
+          "Another mingw-get process may be running, (in a CLI session); if\n"
+          "this is the case, you may wait for this process to complete, and\n"
+          "then RETRY this operation; otherwise select CANCEL to quit.",
+          caption, MB_ICONWARNING | MB_RETRYCANCEL
+        );
+       /* ...repeating until we either acquire the lock, or
+       * the user decides to give up.
+       */
+     } while( retry == IDRETRY );
+
+  /* If we get to here, then lock acquisition was unsuccessful;
+   * return the unacquired lock status, accordingly.
+   */
+  return lock;
+}
+
+RITES_INLINE int pkgRelease( int lock, const char *caption, int status )
+{
+  /* A thin wrapper around the pkgLastRites() function; it's primary
+   * purpose is to pass the exit code from the main window message loop,
+   * (as the default program exit code), back to the operating system,
+   * after last rites processing, (in the event of failure to exec()
+   * the external last rites handler process).
+   */
+  (void)(pkgLastRites( lock, caption ));
+  return status;
+}
+
+#endif /* ! PKGLOCK_H: $RCSfile$: end of file */
index 97e3e51..153f9c8 100644 (file)
@@ -266,7 +266,7 @@ RITES_INLINE const char *lockfile_name( void )
     const char *lockpath = approot_path();
     const wchar_t *lockname = MINGW_GET_LCK;
     size_t wanted = 1 + snprintf( NULL, 0, "%s%S", lockpath, lockname );
-    if( (lockfile = malloc( wanted )) != NULL )
+    if( (lockfile = (char *)(malloc( wanted ))) != NULL )
       snprintf( lockfile, wanted, "%s%S", lockpath, lockname );
   }
   /* In any case, we return the pointer as resolved on first call.
@@ -286,6 +286,47 @@ RITES_INLINE const char *lockfile_name( void )
  */
 #define unlink_if_stale  mingw_get_unlink
 
+#ifdef GUIMAIN_H
+ /*
+  * When guimain.h has been included, we infer that we are compiling
+  * inline components for the mingw-get GUI application; we implement
+  * custom variants of some sub-components which are GUI specific.
+  */
+  RITES_INLINE void pkgLockFail( const char *progname, const char *lockfile )
+  {
+    /* Helper function to diagnose failure to acquire the package lock.
+     * This implementation is for use in the GUI application, where there
+     * may be no stderr stream attached; construct a suitable message to
+     * be displayed in a windows message box.
+     */
+    const char *fmt = "*** ERROR *** cannot acquire catalogue lock\n%s: %s";
+    char msg[1 + snprintf( NULL, 0, fmt, lockfile, strerror( errno ) )];
+    snprintf( msg, sizeof( msg ), fmt, lockfile, strerror( errno ) );
+    MessageBox( NULL, msg, progname, MB_ICONERROR );
+  }
+
+#else
+ /* When guimain.h has NOT been included, and we are compiling inline,
+  * we fall back to implementing CLI specific sub-component variants.
+  */
+  RITES_INLINE void pkgLockFail( const char *progname, const char *lockfile )
+  {
+    /* Helper function to diagnose failure to acquire the package lock.
+     * This implementation is for use in the CLI application, which should
+     * always have a stderr stream attached; emit a suitable sequence of
+     * messages by simply writing to this stream.
+     */
+    fprintf( stderr,
+       "%s: cannot acquire lock for exclusive execution\n", progname
+      );
+    fprintf( stderr, "%s: ", progname ); perror( lockfile );
+    if( errno == EEXIST )
+      fprintf( stderr, "%s: another mingw-get process appears to be running\n",
+         progname
+       );
+  }
+#endif
+
 RITES_INLINE int pkgInitRites( const char *progname )
 {
   /* Helper to acquire an exclusive execution lock, and if sucessful,
@@ -304,14 +345,7 @@ RITES_INLINE int pkgInitRites( const char *progname )
   {
     /* We failed to acquire the lock; diagnose failure...
      */
-    fprintf( stderr, "%s: cannot acquire lock for exclusive execution\n",
-       progname
-      );
-    fprintf( stderr, "%s: ", progname ); perror( lockfile );
-    if( errno == EEXIST )
-      fprintf( stderr, "%s: another mingw-get process appears to be running\n",
-         progname
-       );
+    pkgLockFail( progname, lockfile );
   }
 
   /* Return the lock, indicating success or failure as appropriate.