6 * Written by Keith Marshall <keith@users.osdn.me>
7 * Copyright (C) 2009-2013, 2020, MinGW.org Project
10 * Implementation of package management task scheduler and executive.
13 * This is free software. Permission is granted to copy, modify and
14 * redistribute this software, under the provisions of the GNU General
15 * Public License, Version 3, (or, at your option, any later version),
16 * as published by the Free Software Foundation; see the file COPYING
17 * for licensing details.
19 * Note, in particular, that this software is provided "as is", in the
20 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
21 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
22 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
23 * MinGW Project, accept liability for any damages, however caused,
24 * arising from the use of this software.
38 /* The following static member of the pkgSpinWait class provides
39 * the access hook through which the static core implementation of
40 * the base class methods may pass reports back to any derivative
41 * class object, while retaining the capability to issue reports
42 * even when no such object exists.
44 pkgSpinWait *pkgSpinWait::referrer = NULL;
46 int pkgSpinWait::Report( const char *fmt, ... )
48 /* Also declared as static, this directs printf() style reports
49 * to any existing derivative class object, while behaving as a
50 * no-op in the absence of any such object.
53 if( referrer != NULL )
56 va_start( argv, fmt );
57 count = referrer->DispatchReport( fmt, argv );
63 int pkgSpinWait::Indicator( void )
65 /* Once again, declared as static, this method provides a
66 * mechanism for spin-wait animation of any "%c" formatted
67 * field within a progress reporting message.
69 static const char *marker = "|/-\\";
70 return marker[ referrer->UpdateIndex() ];
73 EXTERN_C const char *action_name( unsigned long index )
75 /* Define the keywords used on the mingw-get command line,
76 * to specify the package management actions to be performed,
77 * mapping each to a unique action code index.
79 static const char* action_id[] =
81 "no change", /* unused; zero cannot test true in a bitwise test */
82 "remove", /* remove a previously installed package */
83 "install", /* install a new package */
84 "upgrade", /* upgrade previously installed packages */
86 "list", /* list packages and display related information */
87 "show", /* a synonym for "list" */
89 "update", /* update local copy of repository catalogues */
90 "licence", /* retrieve licence sources from repository */
91 "source" /* retrieve package sources from repository */
94 /* For specified "index", return a pointer to the associated keyword,
95 * or NULL, if "index" is outside the defined action code range.
97 return ((index >= 0) && (index < end_of_actions))
102 EXTERN_C int action_code( const char* request )
104 /* Match an action keyword specified on the command line
105 * to an entry from the above list...
107 if( request != NULL )
109 int lencode = strlen( request );
111 int index, retval, matched;
112 for( index = matched = 0; index < end_of_actions; index++ )
114 /* Try all defined keywords in turn, until we run out
117 if( (strncmp( request, action_name( index ), lencode ) == 0)
119 * When we find a match, and it is the first...
121 && (++matched == 1) )
123 * ...then we record as the probable index to return.
129 * We matched more than one valid keyword; reject them all.
131 dmh_notify( DMH_ERROR, "%s: action keyword is ambiguous\n", request );
133 else if( matched == 1 )
135 * We matched exactly one keyword; return its index value.
139 /* If we get to here, the specified keyword was not uniquely matched;
140 * signal this, by returning -1.
145 /* To circumvent MS-Windows restrictions on deletion and/or overwriting
146 * executable and shared object files, while their respective code is in
147 * use by a running application, and to facilitate upgrade of mingw-get
148 * itself, while it is the running application performing the upgrade,
149 * we introduce a "rites of passage" work around. The first phase of
150 * this is invoked immediately on process start up, but the second
151 * phase is deferred...
153 #define IMPLEMENT_INITIATION_RITES PHASE_TWO_RITES
156 * ...until we know for sure that a self-upgrade has been scheduled...
158 RITES_INLINE bool self_upgrade_rites( const char *name )
160 /* ...as determined by inspection of package names, and deferring
161 * the rite as "pending" until a request to process "mingw-get-bin"
162 * is actually received...
164 pkgSpecs pkg( name );
165 bool pending = ((name = pkg.GetComponentClass()) == NULL)
166 || (strcmp( name, "bin" ) != 0) || ((name = pkg.GetPackageName()) == NULL)
167 || (strcmp( name, "mingw-get" ) != 0);
171 * We've just identified a request to process "mingw-get-bin";
172 * thus the requirement to invoke the "self upgrade rites" has
173 * now become immediate, so do it...
177 /* Finally, return the requirement state as it now is, whether it
178 * remains "pending" or not, so that the caller may avoid checking
179 * the requirement for invoking the "self upgrade rites" process,
180 * after it has already been requested.
185 pkgActionItem::pkgActionItem( pkgActionItem *after, pkgActionItem *before )
187 /* Construct an appropriately initialised non-specific pkgActionItem...
189 flags = 0; /* no specific action yet assigned */
191 min_wanted = NULL; /* no minimum package version constraint... */
192 max_wanted = NULL; /* nor any maximum version */
194 /* Initialise package selection to NONE, for this action... */
195 selection[to_remove] = selection[to_install] = NULL;
197 /* Insert this item at a specified location in the actions list.
204 pkgActionItem::Append( pkgActionItem *item )
206 /* Add an "item" to an ActionItems list, attaching it immediately
207 * after the item referenced by the "this" pointer; nominally "this"
208 * refers to the last entry in the list, resulting in a new item
209 * being appended to the list, but the implementation preserves
210 * integrity of any following list items, thus also fulfilling
211 * an "insert after this" function.
215 * No list exists yet;
216 * return "item" as first and only entry in new list.
220 /* Ensure "item" physically exists, or if not, create a generic
221 * placeholder in which to construct it...
223 if( (item == NULL) && ((item = new pkgActionItem()) == NULL) )
225 * ...bailing out if no such placeholder can be created.
229 /* Maintain list integrity...
231 if( (item->next = next) != NULL )
233 * ...moving any existing items which already follow the insertion
234 * point in the list structure, to follow the newly added "item".
238 /* Set the new item's own reference pointer, to establish its list
239 * attachment point...
243 /* ...and attach it immediately after that point.
249 pkgActionItem::Insert( pkgActionItem *item )
251 /* Add an "item" to an ActionItems list, inserting it immediately
252 * before the item referenced by the "this" pointer.
256 * No list exists yet;
257 * return "item" as first and only entry in new list.
261 /* Ensure "item" physically exists, or if not, create a generic
262 * placeholder in which to construct it...
264 if( (item == NULL) && ((item = new pkgActionItem()) == NULL) )
266 * ...bailing out if no such placeholder can be created.
270 /* Maintain list integrity...
272 if( (item->prev = prev) != NULL )
274 * ...moving any existing items which already precede the insertion
275 * point in the list structure, to precede the newly added "item".
279 /* Set the new item's own reference pointer, to establish the item
280 * currently at the attachment point, as its immediate successor...
284 /* ...and attach it, immediately preceding that point.
290 pkgActionItem::Schedule( unsigned long action, pkgActionItem& item )
292 /* Make a copy of an action item template (which may exist in
293 * a volatile scope) on the heap, assign the requested action,
294 * and return it for inclusion in the task schedule.
296 pkgActionItem *rtn = new pkgActionItem(); *rtn = item;
297 if( pkgOptions()->Test( OPTION_REINSTALL ) == OPTION_REINSTALL )
299 * When the user specified the "--reinstall" option, either
300 * explicitly, or implied by "--download-only", (or even as a
301 * side effect of "--print-uris"), we MUST enable a download
302 * action, in case it is required to complete the request.
304 action |= ACTION_DOWNLOAD;
305 rtn->flags = action | (item.flags & ~ACTION_MASK);
307 /* The min_wanted and max_wanted properties, if defined, refer
308 * to dynamically allocated memory blocks, (on the heap); these
309 * must have only one action item owner; currently, the original
310 * item and the copy we've just made are both effective owners,
311 * and we want only the copy to retain this ownership, we must
312 * detach them from the original item.
314 item.min_wanted = item.max_wanted = NULL;
316 /* Similarly, we must transfer any linkage into the schedule of
317 * actions from the original item to the copy.
319 if( item.prev != NULL ) (item.prev)->next = rtn;
320 if( item.next != NULL ) (item.next)->prev = rtn;
321 item.prev = item.next = NULL;
323 /* Finally, we return the copy, leaving the ultimate disposal
324 * of the original to the caller's discretion.
329 void pkgActionItem::Assert
330 ( unsigned long set, unsigned long mask, pkgActionItem *schedule )
332 /* A method to manipulate the control, error trapping, and state
333 * flags for all items in the specified schedule of actions.
335 * Starting at the specified item, or the invoking class object
336 * item if no starting point is specified...
338 if( (schedule != NULL) || ((schedule = this) != NULL) )
340 /* ...and provided this starting point is not NULL, walk back
341 * to the first item in the associated task schedule...
343 while( schedule->prev != NULL ) schedule = schedule->prev;
344 while( schedule != NULL )
346 /* ...then, processing each scheduled task item in sequence,
347 * update the flags according to the specified mask and new
350 schedule->flags = (schedule->flags & mask) | set;
352 * ...before moving on to the next item in the sequence.
354 schedule = schedule->next;
360 pkgActionItem::GetReference( pkgActionItem& item )
362 /* Check for a prior reference, within the task schedule,
363 * for the package specified for processing by "item".
366 if( (pkg = item.Selection()->GetParent()) != NULL )
368 /* We have a pointer to the XML database entry which identifies
369 * the package containing the release specified as the selection
370 * associated with "item"; walk the chain of prior entries in
373 for( pkgActionItem* item = this; item != NULL; item = item->prev )
375 /* ...and if we find another item holding an identical pointer,
376 * (i.e. to the same package), we return it...
378 if( item->Selection()->GetParent() == pkg )
383 /* If we get to here, there is no prior action scheduled for the
384 * specified package, so we return a NULL pointer...
389 pkgXmlNode *pkgActionItem::SelectIfMostRecentFit( pkgXmlNode *package )
391 /* Assign "package" as the "selection" for the referring action item,
392 * provided it matches the specified selection criteria and it represents
393 * a more recent release than any current selection.
395 pkgSpecs test( package );
397 /* Establish the selection criteria...
399 pkgSpecs min_fit( min_wanted );
400 pkgSpecs max_fit( max_wanted );
402 /* Choose one of the above, as a basis for identification of
403 * a correct package-component match...
405 pkgSpecs& fit = min_wanted ? min_fit : max_fit;
407 /* Initially assuming that it may not...
409 flags &= ~ACTION_MAY_SELECT;
411 /* ...verify that "package" fulfills the selection criteria...
413 if( match_if_explicit( test.GetComponentClass(), fit.GetComponentClass() )
414 && match_if_explicit( test.GetComponentVersion(), fit.GetComponentVersion() )
415 && ((max_wanted == NULL) || ((flags & STRICTLY_LT) ? (test < max_fit) : (test <= max_fit)))
416 && ((min_wanted == NULL) || ((flags & STRICTLY_GT) ? (test > min_fit) : (test >= min_fit))) )
418 /* We have the correct package component, and it fits within
419 * the allowed range of release versions...
421 pkgSpecs last( Selection() );
424 * It is also more recent than the current selection,
425 * so we now replace that...
427 selection[to_install] = package;
429 /* Regardless of whether we selected it, or not,
430 * mark "package" as a viable selection.
432 flags |= ACTION_MAY_SELECT;
435 /* Whatever choice we make, we return the resultant selection...
440 inline void pkgActionItem::SetPrimary( pkgActionItem* ref )
443 selection[ to_install ] = ref->selection[ to_install ];
444 selection[ to_remove ] = ref->selection[ to_remove ];
447 pkgActionItem* pkgXmlDocument::Schedule
448 ( unsigned long action, pkgActionItem& item, pkgActionItem* rank )
450 /* Schedule an action item with a specified ranking order in
451 * the action list, (or at the end of the list if no ranking
452 * position is specified)...
454 pkgActionItem *ref = rank ? rank : actions;
456 /* If we already have a prior matching item...
458 pkgActionItem *prior;
459 if( (prior = actions->GetReference( item )) != NULL )
461 /* ...then, when the current request refers to a primary action,
462 * we update the already scheduled request to reflect this...
464 if( (action & ACTION_PRIMARY) == ACTION_PRIMARY )
465 prior->SetPrimary( rank = ref->Schedule( action /* & ACTION_MASK */, item ) );
467 dmh_printf( "Schedule(0x%08x):%s(prior)\n",
468 prior->HasAttribute((unsigned long)(-1)),
469 prior->Selection()->ArchiveName()
474 /* ...otherwise, when this request produces a valid package reference,
475 * we raise a new scheduling request...
477 else if( ((ref = ref->Schedule( action, item )) != NULL)
478 && ((ref->Selection() != NULL) || (ref->Selection( to_remove ) != NULL)) )
481 dmh_printf( "Schedule(0x%08x):%s(new)\n",
482 ref->HasAttribute((unsigned long)(-1)),
483 ref->Selection()->ArchiveName()
486 /* ...and, when successfully raised, add it to the task list...
490 * ...at the specified ranking position, if any...
492 return rank->Insert( ref );
495 /* ...otherwise, at the end of the list.
497 return actions = actions->Append( ref );
500 /* If we get to here, then no new action was scheduled; we simply
501 * return the current insertion point in the task list.
506 static __inline__ __attribute__((__always_inline__))
507 int reinstall_action_scheduled( pkgActionItem *package )
509 /* Helper function to identify scheduled actions which will
510 * result in reinstallation of the associated package.
513 ( pkgOptions()->Test( OPTION_REINSTALL )
514 && (package->Selection() == package->Selection( to_remove ))
518 void pkgActionItem::Execute( bool with_download )
521 { pkgActionItem *current = this;
522 bool init_rites_pending = true;
523 while( current->prev != NULL ) current = current->prev;
525 /* Unless normal operations have been suppressed by the
526 * --print-uris option, (in order to obtain a list of all
527 * package URIs which the operation would access)...
529 if( pkgOptions()->Test( OPTION_PRINT_URIS ) < OPTION_PRINT_URIS )
531 /* ...we initiate any download requests which may
532 * be necessary to fetch all required archives into
533 * the local package cache.
536 DownloadArchiveFiles( current );
537 } while( SetAuthorities( current ) > 0 );
539 else while( current != NULL )
541 /* The --print-uris option is in effect: we simply loop
542 * over all packages with an assigned action, printing
543 * the associated download URI for each; (note that this
544 * will print the URI regardless of prior existence of
545 * the associated package in the local cache).
547 current->PrintURI( current->Selection()->ArchiveName() );
548 current = current->next;
551 /* If the --download-only option is in effect, then we have
552 * nothing more to do...
554 if( pkgOptions()->Test( OPTION_DOWNLOAD_ONLY ) != OPTION_DOWNLOAD_ONLY )
558 while( current != NULL )
560 /* ...processing only those packages with assigned actions...
562 if( (current->flags & ACTION_MASK) != 0 )
564 /* ...print a notification of the installation process to
565 * be performed, identifying the package to be processed.
568 pkgXmlNode *ref = current->Selection();
569 if( (tarname = ref->GetPropVal( tarname_key, NULL )) == NULL )
571 ref = current->Selection( to_remove );
572 tarname = ref->GetPropVal( tarname_key, value_unknown );
574 dmh_printf( "%s: %s\n", reinstall_action_scheduled( current )
575 ? "reinstall" : action_name( current->flags & ACTION_MASK ),
579 /* Package pre/post processing scripts may need to
580 * refer to the sysroot path for the package; place
581 * a copy in the environment, to facilitate this.
583 pkgSpecs lookup( tarname );
584 ref = ref->GetSysRoot( lookup.GetSubSystemName() );
585 const char *path = ref->GetPropVal( pathname_key, NULL );
588 /* Format the sysroot path into an environment variable
589 * assignment specification; note that the recorded path
590 * name is likely to include macros such as "%R", so we
591 * filter it through mkpath(), to expand them.
593 const char *nothing = "";
594 char varspec_template[9 + strlen( path )];
595 sprintf( varspec_template, "SYSROOT=%s", path );
596 char varspec[mkpath( NULL, varspec_template, nothing, NULL )];
597 mkpath( varspec, varspec_template, nothing, NULL );
598 pkgPutEnv( PKG_PUTENV_DIRSEP_MSW, varspec );
601 /* Check for any outstanding requirement to invoke the
602 * "self upgrade rites" process, so that we may install an
603 * upgrade for mingw-get itself...
605 if( init_rites_pending )
607 * ...discontinuing the check once this has been completed,
608 * since it need not be performed more than once.
610 init_rites_pending = self_upgrade_rites( tarname );
612 /* If we are performing an upgrade...
614 if( ((current->flags & ACTION_MASK) == ACTION_UPGRADE)
616 * ...and the latest version of the package is already installed...
618 && (current->Selection() == current->Selection( to_remove ))
620 * ...and the `--reinstall' option hasn't been specified...
622 && (pkgOptions()->Test( OPTION_REINSTALL ) == 0) )
624 * ...then simply report the up-to-date status...
626 dmh_notify( DMH_INFO, "package %s is up to date\n", tarname );
629 { /* ...otherwise, proceed to perform remove and install
630 * operations, as appropriate.
632 if( reinstall_action_scheduled( current )
633 || ((current->flags & ACTION_REMOVE) == ACTION_REMOVE) )
635 /* The selected package has been marked for removal, either
636 * explicitly, or as an implicit prerequisite for upgrade, or
637 * in preparation for reinstallation.
639 pkgRemove( current );
642 if( (current->flags & ACTION_INSTALL) == ACTION_INSTALL )
644 /* The selected package has been marked for installation,
645 * either explicitly, or implicitly to complete a package upgrade.
647 pkgXmlNode *tmp = current->Selection( to_remove );
648 if( reinstall_action_scheduled( current )
649 || ((current->flags & ACTION_MASK) == ACTION_UPGRADE) )
650 current->selection[ to_remove ] = NULL;
651 pkgInstall( current );
652 current->selection[ to_remove ] = tmp;
656 /* Proceed to the next package, if any, with scheduled actions.
658 pkgSpinWait::Report( "Processing... (%c)", pkgSpinWait::Indicator() );
659 current = current->next;
665 pkgActionItem *pkgActionItem::Clear( pkgActionItem *schedule, unsigned long mask )
667 /* Method to remove those action items which have no attribute flags in common
668 * with the specified mask, from the schedule; return the residual schedule of
669 * items, if any, which were not removed. (Note that specifying a mask with a
670 * value of 0UL, which is the default, results in removal of all items).
672 pkgActionItem *residual = NULL;
674 /* Starting at the specified item, or the invoking class object item
675 * if no starting point is specified...
677 if( (schedule != NULL) || ((schedule = this) != NULL) )
679 /* ...and provided this starting point is not NULL, walk back to
680 * the first item in the associated task schedule...
682 while( schedule->prev != NULL ) schedule = schedule->prev;
683 while( schedule != NULL )
685 /* ...then, processing each scheduled task item in sequence, and
686 * keeping track of the next to be processed...
688 pkgActionItem *nextptr = schedule->next;
689 if( (schedule->flags & mask) == 0 )
691 * ...delete each which doesn't match any masked attribute...
696 /* ...otherwise add it to the residual schedule.
700 /* In either event, move on to the next item in sequence, if any.
705 /* Ultimately, return a pointer to the last item added to the residual
706 * schedule, or NULL if all items were deleted.
711 pkgActionItem::~pkgActionItem()
714 * The package version range selectors, "min_wanted" and "max_wanted",
715 * are always allocated storage space on the heap; we need to free that,
716 * before we destroy the reference pointers.
718 if( (max_wanted != NULL) && (max_wanted != min_wanted) )
720 * "max_wanted" is non-NULL, and is distinct, (i.e. it doesn't
721 * represent an equality constraint which shares a reference with
722 * "min_wanted"); we need to free it independently.
724 free( (void *)(max_wanted) );
726 if( min_wanted != NULL )
728 * "min_wanted" is non-NULL; we don't care if it is distinct,
729 * because if not, freeing it is required anyway, to also free
730 * the same memory referenced by "max_wanted".
732 free( (void *)(min_wanted) );
734 /* Also ensure that we preserve the integrity of any linked list of
735 * action items in which this item participates, by detaching this
736 * item from the pointer chain.
738 if( prev != NULL ) prev->next = next;
739 if( next != NULL ) next->prev = prev;
745 * Implementation of processing hooks, for handling pre/post-install
746 * and pre/post-remove scripts.
752 static const char *action_key = "action";
753 static const char *normal_key = "normal";
755 #define LUA_INLINE static inline __attribute__((__always_inline__))
757 LUA_INLINE bool init_lua_path()
758 # define LUA_LIBEXEC_PATH "\\libexec\\mingw-get\\?.lua"
760 /* A one time initialisation hook, to ensure that the built-in Lua script
761 * interpreter will load scripts from the libexec directory associated with
762 * the running mingw-get.exe instance.
764 putenv( "LUA_PATH=!\\?.lua;!" LUA_LIBEXEC_PATH ";!\\.." LUA_LIBEXEC_PATH );
768 LUA_INLINE bool lua_isstringarg( lua_State *interpreter, int arg_index )
770 /* Convenience function to check if a particular argument was passed
771 * from Lua, and if so, if it has a valid string representation.
773 return lua_isnoneornil( interpreter, arg_index ) ? false
774 : lua_isstring( interpreter, arg_index );
777 static int lua_wsh_libexec_path( lua_State *interpreter )
779 /* Implementation for the Lua wsh.libexec_path function; it supports
780 * usage conforming to either of the function prototypes:
782 * wsh.libexec_path( script )
783 * wsh.libexec_path( script, subsystem )
785 * returning the absolute file system path to "script", within the
786 * libexec tree for the applicable subsystem, (or for the system in
787 * general, if no "subsystem" argument is specified).
789 const char *approot = approot_path();
790 const char *script = lua_tostring( interpreter, 1 );
792 if( lua_isstringarg( interpreter, 2 ) )
794 /* This is the case where a "subsystem" is specified, so we encode
795 * the applicable subsystem inclusive path name...
797 const char *path = "%slibexec\\%s\\%s";
798 const char *subsystem = lua_tostring( interpreter, 2 );
799 char ref[1 + snprintf( NULL, 0, path, approot, subsystem, script )];
800 snprintf( ref, sizeof( ref ), path, approot, subsystem, script );
802 /* ...which we then pass back to the Lua caller.
804 lua_pushstring( interpreter, ref );
807 { /* This is the case where no subsystem has been specified,
808 * so we encode the general system libexec path name...
810 const char *path = "%slibexec\\%s";
811 char ref[1 + snprintf( NULL, 0, path, approot, script )];
812 snprintf( ref, sizeof( ref ), path, approot, script );
814 /* ...again passing it back to the Lua caller.
816 lua_pushstring( interpreter, ref );
818 /* In either case, we have one result to pass back.
823 static int lua_wsh_execute( lua_State *interpreter )
825 /* Implementation for the Lua wsh.execute function; it conforms to
826 * an effective function prototype equivalent to:
828 * wsh.execute( command )
830 * delivering a capability similar to os.execute, but using wscript
831 * as the command interpreter, rather than the system shell.
833 if( lua_isstringarg( interpreter, 1 ) )
835 /* If no "command" is specified, we silently process this as a no-op;
836 * when a command IS specified, we hand it off to the interpreter.
838 const char *wsh = "wscript", *mode = "-nologo";
839 spawnlp( _P_WAIT, wsh, wsh, mode, lua_tostring( interpreter, 1 ), NULL );
841 /* Either way, we have nothing to return to the Lua caller.
846 static int luaload_wsh( lua_State *interpreter )
848 /* Declare the functions provided by our Windows Script Host
849 * interface, wrapping them into the Lua "wsh" module...
851 static struct luaL_Reg wsh_function_registry[] =
853 /* Lua Name Handler Function */
854 /* -------------- -------------------- */
855 { "execute", lua_wsh_execute },
856 { "libexec_path", lua_wsh_libexec_path },
860 /* ...and register the module within the active interpreter.
862 luaL_newlib( interpreter, wsh_function_registry );
866 int pkgXmlNode::DispatchScript
867 ( int status, const char *context, const char *priority, pkgXmlNode *action )
869 /* Private method, called by InvokeScript(), to hand-off each script
870 * fragment from the requesting XML node, with class attribute matching
871 * the requested context and precedence matching the requested priority,
872 * for execution by the embedded lua interpreter.
874 lua_State *interpreter = NULL;
875 static const char *priority_key = "precedence";
876 static bool lua_path_setup = false;
878 if( ! lua_path_setup )
880 * The Lua script path hasn't been initialised yet; do it now!
882 lua_path_setup = init_lua_path();
884 while( action != NULL )
886 /* We have at least one remaining script fragment, attached to the
887 * current XML node, which is a potential candidate for execution...
889 if( (strcmp( context, action->GetPropVal( class_key, value_none )) == 0)
890 && (strcmp( priority, action->GetPropVal( priority_key, normal_key )) == 0) )
892 /* ...and it does fit the current context and precedence; if we
893 * have not yet attached an interpreter to this node, then...
895 if( (interpreter == NULL) && ((interpreter = luaL_newstate()) != NULL) )
897 /* ...start one now, initialise it by loading the standard
900 luaL_openlibs( interpreter );
902 /* ...and register our Windows Script Host interface...
904 luaL_requiref( interpreter, "wsh", luaload_wsh, 1 );
906 /* ...then hand off the current script fragment to this active
909 if( (status = luaL_dostring( interpreter, action->GetText() )) != 0 )
911 * ...reporting any errors through mingw-get's standard
912 * diagnostic message handler.
914 dmh_printf( "lua error in %s script:\n%s\n", context,
915 lua_tostring( interpreter, -1 )
919 /* Check for any further script fragments attached to the current node.
921 action = action->FindNextAssociate( action_key );
924 /* Before leaving this node...
926 if( interpreter != NULL )
928 * ...close any active lua interpreter which we may have attached.
930 lua_close( interpreter );
932 /* Finally, return the execution status reported by lua, from the last
933 * script fragment executed within the scope of the current node.
938 int pkgXmlNode::InvokeScript( int status, const char *context )
940 /* Private component of the implementation for the public
941 * InvokeScript() method; it checks for the existence of at
942 * least one script attached to the invoking XML node, then
943 * hands off processing of the entire script collection...
945 pkgXmlNode *action = FindFirstAssociate( action_key );
947 /* ...first processing any, in the requested context, which are
948 * designated as having "immediate" precedence...
950 status = DispatchScript( status, context, "immediate", action );
952 * ...then, traversing the XML hierarchy towards the root...
954 if( this != GetDocumentRoot() )
956 * ...processing any script fragments, in the requested context,
957 * which are attached to any container nodes...
959 status = GetParent()->InvokeScript( status, context );
961 /* ...and finally, process any others attached to the current node,
962 * in the requested context, having "normal" precedence.
964 return DispatchScript( status, context, normal_key, action );
967 /* $RCSfile$: end of file */