XML includes

Posted by Tsunami on Mon 24 Jul 2006 09:12 PM — 13 posts, 51,423 views.

USA #0
Within the XML of my plugin, I have an include statement, basically:

<include name="path/filename.xml" />

Now, unless I use an absolute path, MUSHclient uses the plugins directory as the working directory for the include. I can't use an absolute path I have no control over where user's put my plugin. Right now, if the plugin isn't directly inside the default plugins directory, the includes won't work. My question, why isn't the working directory the directory the plugin is in? This seems to make more sense to me. Anyways, if this isn't possible, is there some fix so that the user doesn't have to place my plugin in a specific location, ie right inside the default plugin directory?

Thanks, Tsunami
Australia Forum Administrator #1
How could that work? Say you have 5 plugins, all in different directories. There is only one current directory, and all 5 plugins scripts can run at any time (eg. when a trigger fires). Thus, there can't be 5 current directories. I suppose MUSHclient could change the current directory every time it calls a plugin script, but this sounds like needless overhead to me.

I suggest you use:


GetPluginInfo (GetPluginID (), 6)


Example output when I tested that was:


C:\Program Files\MUSHclient\worlds\plugins\MXP_Tag_Fixer.xml


Use a bit of mucking around with regexps to convert that into directory\filename, and you have the plugin directory.


See:

http://www.gammon.com.au/scripts/doc.php?function=GetPluginInfo
Australia Forum Administrator #2
When I read your post again I see my solution won't really work as that is for plugin load time. :)

If you are coding in Lua you can use my suggestion and use dofile to load shared stuff, rather than the include method.

What version of MUSHclient are you using? I seem to recall this issue came up a couple of months ago. See:

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=6316
Amended on Mon 24 Jul 2006 09:54 PM by Nick Gammon
USA #3
Aye, it does load them at runtime of course, so I was thinking as it loads each plugin, simply setting the working dir for each.

I can't use Lua includes because the included files contain XML themselves (triggers/aliases and all that jazz). For all the pure Lua files, that would certainly work, and in fact that's about how I do it (I'm just using pcall instead), using a regex to parse that and find the plugin directory. That won't work with XML of course, so if it's placed in the wrong directory, the plugin spits out all kinds of nasty error messages which people bug me about ;)

-Tsunami
Australia Forum Administrator #4
OK, how about this? Rather than using the XML include, do it in Lua? You can include an XML file like this (eg. if it contains triggers etc.):


f = assert (io.open ("my_includes.lua", "r"))
s = f:read ("*a") 
f:close ()  -- close it
ImportXML (s)  -- import triggers, aliases etc.


Now if you make that into a general function, you can pass down the pathname to it, and it can include as many files as you want, similarly to what you are doing for including the pure Lua. Like this:


function include_stuff (name)
  local f = assert (io.open (name, "r"))
  local s = f:read ("*a") 
  f:close ()  -- close it
  ImportXML (s)
end -- include_stuff 

include_stuff ("my_includes.lua")
Amended on Thu 27 Jul 2006 05:58 AM by Nick Gammon
USA #5
That is indeed possible, but, correct me if I'm wrong, the default Lua sandbox sets io to nil, disallowing any file io. Therefore I'd have to tell the user to edit their Lua sandbox, and I've essentially exchanged one set of instructions to the user for another. Both of which they can (will) screw up, heh. Thanks, Tsunami
Australia Forum Administrator #6
Yes, you are right, io is set to nil as default. However:

Quote:

For all the pure Lua files, that would certainly work, and in fact that's about how I do it ...


Won't you have the same problem here then?
USA #7
Pure lua files I use the require function, which isn't dependant on io.
#8
How exactly would I use pcall to include straight lua files into my system? I'd love to be able to seperate my script files from my xml files..

edit: Sorry I did a little research and saw that you can do:

require"filename"


but is there anyway to require a file that isn't in my Mushclient\lua directory, and is in my mushclient\scripts directory instead?
Amended on Fri 09 Feb 2007 12:24 PM by Gore
USA #9
First you have to set the Lua package path variable. I do it like this:


_,_,PATH = string.find(world.GetPluginInfo(world.GetPluginID(),6),'^(.+\)')
package.path = package.path .. ';' ..PATH .. 'modules\scripts\?.lua' .. ';' .. PATH .. 'modules\plugins\?.lua'


This adds the listed directories to the path variable. Then, for simplicity's sake, I created a function:


function load_module(module)
	result,error = pcall(require,module)
	
	if(not result) then
		world.Note('[WARNING]: ' .. string.upper(module) .. ' MODULE LOAD ERROR: ' .. error)
		return false
	elseif(CTRL_DEBUG) then
		world.Note('[DEBUG]: ' .. string.upper(module) .. ' MODULE LOADED.')
	end

	return true
end


Calling load_module('scripts') then will look for a file called scripts.lua in any of the directories in the package.path variable, and attempt to load it.
USA #10
To keep with the semantics of require, your load_module function should return nil when the require fails, and the module table itself when the require succeeds.

This lets you do things like:


util = load_module("long.nested.module.hierarchy.util")
if not util then
  -- die one way or another
end

util.do_something(foo)


If you don't return the module table like that, then you have to refer to things by their entire package name, unless you subsequently manually set an alias.
Australia Forum Administrator #11
Just a reminder that "dofile" will load an arbitrary file name of Lua code, and execute it, effectively including it.

So, you could do something like:


dofile ("mushclient/scripts/myfile.lua")


The difference is that, unlike "require", dofile does not check to see if the module is already loaded. However if this is part of the startup code for a plugin, that might not matter much.

However if you prefer to use require, because of its integration with the package system, see this post:

http://www.gammon.com.au/forum/bbshowpost.php?id=7336

That discusses how you can use MUSHclient to find its executable directory, and then build up a path variable, suitable for your needs, from that.
USA #12
Re: David Haley

In my case it isn't an issue, because I don't particularly care what was loaded, it's up to the writer of that piece of code to check that it functions with my code as intended. Still, your point is a good one, and I hadn't thought of it.