[Home] [Downloads] [Search] [Help/forum]

Gammon Software Solutions forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  Programming
. -> [Folder]  General
. . -> [Subject]  Imbedding Lua in your own applications
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Imbedding Lua in your own applications

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page


Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Fri 24 Mar 2006 03:46 AM (UTC)  quote  ]

Amended on Fri 24 Mar 2006 03:47 AM (UTC) by Nick Gammon

Message
This material is covered in the Lua documentation, but I will do my own version here to help people who are relying on this site for Lua information. :)

Let's start with a simple C program that creates a Lua "script space" and runs a simple literal script:


#include "lua.h"

const char * myscript = 
  " print ('Hello, world. Lua version is', _VERSION)";

int main (void)
  {
  
  lua_State * L = lua_open();   /* opens Lua */
  luaopen_base(L);              /* opens the basic library */
  
  luaL_loadbuffer (L, myscript, strlen (myscript), "example");  /* compile */

  lua_pcall (L, 0, 0, 0);  /* execute */
          
  lua_close (L);  /* close Lua */
  return 0;
}  /* end of main */



This has the absolute basics. It:


  • Creates a script space (in the variable L)
  • Adds to it the basic library functions (such as 'print')
  • Compiles the script (with luaL_loadbuffer)
  • Executes the script (with lua_pcall)
  • Closes the script space
  • Exits


I needed the lua.h file from the Lua distribution, and the lua50.lib file from the Windows binary distribution. The file lua50.dll also needs to be somewhere in your path.

I compiled it like this (under Cygwin):


gcc test.c lua50.lib -o test.exe


This compiled test.c (the above file) and linked in the lua50.lib library. Then running it gives the expected results:


Hello, world. Lua version is Lua 5.0.2


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #1 on Fri 24 Mar 2006 03:56 AM (UTC)  quote  ]
Message
One major problem with the above example is that there is no error handling. If the script has errors you won't know about them, it will silently fail. This more elaborate example will detect and display any compile or runtime error:


#include <stdio.h>
#include "lua.h"


const char * myscript = " print ('Hello, world. Lua version is', _VERSION)";

int main (void)
  {
  int error;
  
  lua_State * L = lua_open();   /* opens Lua */
  luaopen_base(L);              /* opens the basic library */
  
  error = 
     luaL_loadbuffer (L, myscript, strlen (myscript), "example") ||
     lua_pcall (L, 0, 0, 0);
          
  if (error)
    {
    fprintf (stderr, "%s", lua_tostring (L, -1));
    lua_pop (L, 1);
    }  

  lua_close (L);
  return 0;
}  /* end of main */



If either the call to compile, or execute, fails it returns a non-zero value, and the error message is left on top of the Lua stack, which can be obtained by calling lua_tostring.

This example simply displays the message, although obviously you could put it into a dialog box, echo it to your user, or whatever is appropriate.

Let's test that with different scripts. If the script is:


const char * myscript = " print (2 'nick') ";


Then I see:


[string "example"]:1: `)' expected near `'nick''


That was a compile-time error. However if I make a runtime error (adding a number to a string, then you get a different message:


const char * myscript = " print (2 + 'nick') ";


This gives:


[string "example"]:1: attempt to perform arithmetic on a string value

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #2 on Fri 24 Mar 2006 04:22 AM (UTC)  quote  ]
Message
Now let's try a more elaborate example. This one will read in a file (an obvious example here is to read a configuration file for a program). The file is loaded and compiled, then executed, effectively putting any assignments it does into the Lua script space.

My example Lua file is this:


a = 22
b = 33
c = "nick"

-- do tests if wanted

if a < b then
  a = 99
end -- if



The advantage of using Lua is that you can do tests or arithmetic inside the configuration file (and put comments).

Here is the code to read it in. We also extract a couple of values from the Lua script space back into C space:


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "lua.h"

void error (lua_State *L, const char *fmt, ...) 
  {
  va_list argp;
  va_start (argp, fmt);
  vfprintf (stderr, fmt, argp);
  va_end (argp);
  lua_close (L);
  exit (1);
  }  /* end of error function */
  
int main (void)
  {
    
  int a, b;
  const char * c;
  
  lua_State * L = lua_open();   /* opens Lua */
  luaopen_base(L);              /* opens the basic library */
  
  if (luaL_loadfile(L, "myconfig.lua") ||
      lua_pcall (L, 0, 0, 0))
    error (L, "Error loading file: %s", lua_tostring (L, -1));

  /* get value of "a" */
  
  lua_getglobal (L, "a");
  if (!lua_isnumber (L, -1))
    error (L, "'a' should be a number\n");
  a = (int) lua_tonumber (L, -1);
  printf ("Found value of 'a' to be %i\n", a);
  lua_pop (L, 1);
  
  /* get value of "c" */
  
  lua_getglobal (L, "c");
  if (!lua_isstring (L, -1))
    error (L, "'c' should be a string\n");
  c = lua_tostring (L, -1);
  printf ("Found value of 'c' to be %s\n", c);
  lua_pop (L, 1);

  
  lua_close (L);
  return 0;
}  /* end of main */



This example also uses a more elaborate error function (suggested from the Lua book). This error function reports the error and terminates the application, however you may find it more useful to report the error to the user and continue processing.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Fri 24 Mar 2006 04:24 AM (UTC)  quote  ]
Message
The above example uses the Lua API functions to extract numbers and strings from the global address space. An obvious enhancement for a bigger application would be to make that extraction into a small function (one for numbers, one for strings, and so on). You might also handle defaults by testing for nil, and if so substituting some default value.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #4 on Fri 24 Mar 2006 04:29 AM (UTC)  quote  ]
Message
Now let's look at adding in the normal Lua libraries. This simply involves a few more lines of initialization code:


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "lua.h"

void error (lua_State *L, const char *fmt, ...) 
  {
  va_list argp;
  va_start (argp, fmt);
  vfprintf (stderr, fmt, argp);
  va_end (argp);
  lua_close (L);
  exit (1);
  }  /* end of error function */
  
int main (void)
  {
  
  lua_State * L = lua_open();   /* opens Lua */
  luaopen_base(L);              /* opens the basic library */
  luaopen_table(L);             /* opens the table library */
  luaopen_io(L);                /* opens the I/O library */
  luaopen_string(L);            /* opens the string lib. */
  luaopen_math(L);              /* opens the math lib. */
  luaopen_loadlib(L);           /* loadlib function */
  luaopen_debug(L);             /* debug library  */
  
  if (luaL_loadfile(L, "myconfig.lua") ||
      lua_pcall (L, 0, 0, 0))
    error (L, "Error loading file: %s", lua_tostring (L, -1));

  lua_close (L);
  return 0;
}  /* end of main */



Running this on this file:


for i = 1, 10 do
  print (i, math.sqrt (i))
end -- if


... gives:


1       1
2       1.4142135623731
3       1.7320508075689
4       2
5       2.2360679774998
6       2.4494897427832
7       2.6457513110646
8       2.8284271247462
9       3
10      3.1622776601684


Note in this example we have used a function in the math library.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Fri 24 Mar 2006 05:00 AM (UTC)  quote  ]
Message
If you decide to use Lua 5.1 (rather than 5.0.2) then opening the libraries is simpler, and indeed required to be done this simpler way or it crashes:


#define _WIN32

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

void error (lua_State *L, const char *fmt, ...) 
  {
  va_list argp;
  va_start (argp, fmt);
  vfprintf (stderr, fmt, argp);
  va_end (argp);
  lua_close (L);
  exit (1);
  }  /* end of error function */
  
int main (void)
  {
 
  lua_State * L = luaL_newstate ();   /* opens Lua */
  luaL_openlibs (L);                  /* new way of opening all libraries */
  
  if (luaL_loadfile(L, "myconfig.lua") ||
      lua_pcall (L, 0, 0, 0))
    error (L, "Error loading file: %s", lua_tostring (L, -1));

  lua_close (L);
  return 0;
}  /* end of main */



The main change is that the multiple lines which opened the libraries are replaced by a single line (luaL_openlibs) which opens all of the standard libraries for you.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Dralnu   USA  (277 posts)  [Biography] bio
Date Reply #6 on Fri 24 Mar 2006 08:35 AM (UTC)  quote  ]
Message
Great timing Nick. I needed something to use for a guide, and I think this may help get me on my way, plus I know alot of others will love to have the info
[Go to top] top

Posted by Zeno   USA  (2,871 posts)  [Biography] bio   Moderator
Date Reply #7 on Fri 24 Mar 2006 11:01 AM (UTC)  quote  ]

Amended on Fri 24 Mar 2006 11:19 AM (UTC) by Zeno

Message
This is odd.

Nick, in your latest post (the one before Dralnu's) the time of the post is not shown. A bug?

Anyways. I am considering imbedding Lua into Project CR, but I don't see where I would use it. Hm.

Zeno McDohl,
Owner of Bleached InuYasha Galaxy
http://www.biyg.org
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio   Moderator
Date Reply #8 on Fri 24 Mar 2006 12:49 PM (UTC)  quote  ]
Message
The time shows up for me. It's at 10:00 PM. Maybe if you're in Central Time, or whatever is Pacific+2, it's exactly midnight, which confuses something?

For your project, I'd consider using Lua as a data storage mechanism. And then you can use it as a replacement for mudprog. Lua would excel in both areas.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Zeno   USA  (2,871 posts)  [Biography] bio   Moderator
Date Reply #9 on Fri 24 Mar 2006 02:30 PM (UTC)  quote  ]
Message
You're right, it's my time zone. It shows up when I'm not logged in. I guess it has issues displaying if it's 0?

Well I won't have any mudprogs. Data storage? As in maybe player files, game options etc?

Zeno McDohl,
Owner of Bleached InuYasha Galaxy
http://www.biyg.org
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio   Moderator
Date Reply #10 on Fri 24 Mar 2006 04:38 PM (UTC)  quote  ]
Message
Quote:
As in maybe player files, game options etc?
Precisely. These are really just key-value pairs, i.e. "min_level_avatar" = 51 in SMAUG.

In Lua, you can set up your settings as a table, and then use serialization classes (Nick wrote an example around here somewhere) to output the table to a Lua script. Then the next time you need to load the data, you just load the script, and in doing so you will have loaded up tables to say what exactly has been done. :)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Nick Gammon   Australia  (19,473 posts)  [Biography] bio   Forum Administrator
Date Reply #11 on Fri 24 Mar 2006 09:49 PM (UTC)  quote  ]
Message
Yes, Lua would really lend itself to reading in those sorts of things. Examples would be:


  • MUD configuration (eg. name, port number, welcome message)

  • Player files

  • Classes, races, spells

  • Areas


The beauty of Lua is that you basically load in the entire file in one line of code. If you decide to change the files later the loading code doesn't have to be changed. Also the files can be complex (eg. spells might contain multiple effects, which can be in a table, players might have inventory which contain bags which contain potions - these can be tables of tables).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


12,373 views.

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Web site powered by FutureQuest.Net]