Click here to Skip to main content
15,885,278 members
Articles / Containers / Virtual Machine

Integrating Lua into C++

Rate me:
Please Sign up or sign in to vote.
4.82/5 (42 votes)
2 Sep 2005CPOL8 min read 332.9K   8.6K   127  
An article about embedding the Lua scripting language with C++ objects.
/*
** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $
** load pre-compiled Lua chunks
** See Copyright Notice in lua.h
*/

#define lundump_c

#include "lua.h"

#include "ldebug.h"
#include "lfunc.h"
#include "lmem.h"
#include "lopcodes.h"
#include "lstring.h"
#include "lundump.h"
#include "lzio.h"

#define	LoadByte	(lu_byte) ezgetc

typedef struct {
 lua_State* L;
 ZIO* Z;
 Mbuffer* b;
 int swap;
 const char* name;
} LoadState;

static void unexpectedEOZ (LoadState* S)
{
 luaG_runerror(S->L,"unexpected end of file in %s",S->name);
}

static int ezgetc (LoadState* S)
{
 int c=zgetc(S->Z);
 if (c==EOZ) unexpectedEOZ(S);
 return c;
}

static void ezread (LoadState* S, void* b, int n)
{
 int r=luaZ_read(S->Z,b,n);
 if (r!=0) unexpectedEOZ(S);
}

static void LoadBlock (LoadState* S, void* b, size_t size)
{
 if (S->swap)
 {
  char* p=(char*) b+size-1;
  int n=size;
  while (n--) *p--=(char)ezgetc(S);
 }
 else
  ezread(S,b,size);
}

static void LoadVector (LoadState* S, void* b, int m, size_t size)
{
 if (S->swap)
 {
  char* q=(char*) b;
  while (m--)
  {
   char* p=q+size-1;
   int n=size;
   while (n--) *p--=(char)ezgetc(S);
   q+=size;
  }
 }
 else
  ezread(S,b,m*size);
}

static int LoadInt (LoadState* S)
{
 int x;
 LoadBlock(S,&x,sizeof(x));
 if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name);
 return x;
}

static size_t LoadSize (LoadState* S)
{
 size_t x;
 LoadBlock(S,&x,sizeof(x));
 return x;
}

static lua_Number LoadNumber (LoadState* S)
{
 lua_Number x;
 LoadBlock(S,&x,sizeof(x));
 return x;
}

static TString* LoadString (LoadState* S)
{
 size_t size=LoadSize(S);
 if (size==0)
  return NULL;
 else
 {
  char* s=luaZ_openspace(S->L,S->b,size);
  ezread(S,s,size);
  return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */
 }
}

static void LoadCode (LoadState* S, Proto* f)
{
 int size=LoadInt(S);
 f->code=luaM_newvector(S->L,size,Instruction);
 f->sizecode=size;
 LoadVector(S,f->code,size,sizeof(*f->code));
}

static void LoadLocals (LoadState* S, Proto* f)
{
 int i,n;
 n=LoadInt(S);
 f->locvars=luaM_newvector(S->L,n,LocVar);
 f->sizelocvars=n;
 for (i=0; i<n; i++)
 {
  f->locvars[i].varname=LoadString(S);
  f->locvars[i].startpc=LoadInt(S);
  f->locvars[i].endpc=LoadInt(S);
 }
}

static void LoadLines (LoadState* S, Proto* f)
{
 int size=LoadInt(S);
 f->lineinfo=luaM_newvector(S->L,size,int);
 f->sizelineinfo=size;
 LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo));
}

static void LoadUpvalues (LoadState* S, Proto* f)
{
 int i,n;
 n=LoadInt(S);
 if (n!=0 && n!=f->nups) 
  luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d",
		S->name,n,f->nups);
 f->upvalues=luaM_newvector(S->L,n,TString*);
 f->sizeupvalues=n;
 for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
}

static Proto* LoadFunction (LoadState* S, TString* p);

static void LoadConstants (LoadState* S, Proto* f)
{
 int i,n;
 n=LoadInt(S);
 f->k=luaM_newvector(S->L,n,TObject);
 f->sizek=n;
 for (i=0; i<n; i++)
 {
  TObject* o=&f->k[i];
  int t=LoadByte(S);
  switch (t)
  {
   case LUA_TNUMBER:
	setnvalue(o,LoadNumber(S));
	break;
   case LUA_TSTRING:
	setsvalue2n(o,LoadString(S));
	break;
   case LUA_TNIL:
   	setnilvalue(o);
	break;
   default:
	luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name);
	break;
  }
 }
 n=LoadInt(S);
 f->p=luaM_newvector(S->L,n,Proto*);
 f->sizep=n;
 for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
}

static Proto* LoadFunction (LoadState* S, TString* p)
{
 Proto* f=luaF_newproto(S->L);
 f->source=LoadString(S); if (f->source==NULL) f->source=p;
 f->lineDefined=LoadInt(S);
 f->nups=LoadByte(S);
 f->numparams=LoadByte(S);
 f->is_vararg=LoadByte(S);
 f->maxstacksize=LoadByte(S);
 LoadLines(S,f);
 LoadLocals(S,f);
 LoadUpvalues(S,f);
 LoadConstants(S,f);
 LoadCode(S,f);
#ifndef TRUST_BINARIES
 if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name);
#endif
 return f;
}

static void LoadSignature (LoadState* S)
{
 const char* s=LUA_SIGNATURE;
 while (*s!=0 && ezgetc(S)==*s)
  ++s;
 if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name);
}

static void TestSize (LoadState* S, int s, const char* what)
{
 int r=LoadByte(S);
 if (r!=s)
  luaG_runerror(S->L,"virtual machine mismatch in %s: "
	"size of %s is %d but read %d",S->name,what,s,r);
}

#define TESTSIZE(s,w)	TestSize(S,s,w)
#define V(v)		v/16,v%16

static void LoadHeader (LoadState* S)
{
 int version;
 lua_Number x,tx=TEST_NUMBER;
 LoadSignature(S);
 version=LoadByte(S);
 if (version>VERSION)
  luaG_runerror(S->L,"%s too new: "
	"read version %d.%d; expected at most %d.%d",
	S->name,V(version),V(VERSION));
 if (version<VERSION0)				/* check last major change */
  luaG_runerror(S->L,"%s too old: "
	"read version %d.%d; expected at least %d.%d",
	S->name,V(version),V(VERSION0));
 S->swap=(luaU_endianness()!=LoadByte(S));	/* need to swap bytes? */
 TESTSIZE(sizeof(int),"int");
 TESTSIZE(sizeof(size_t), "size_t");
 TESTSIZE(sizeof(Instruction), "Instruction");
 TESTSIZE(SIZE_OP, "OP");
 TESTSIZE(SIZE_A, "A");
 TESTSIZE(SIZE_B, "B");
 TESTSIZE(SIZE_C, "C");
 TESTSIZE(sizeof(lua_Number), "number");
 x=LoadNumber(S);
 if ((long)x!=(long)tx)		/* disregard errors in last bits of fraction */
  luaG_runerror(S->L,"unknown number format in %s",S->name);
}

static Proto* LoadChunk (LoadState* S)
{
 LoadHeader(S);
 return LoadFunction(S,NULL);
}

/*
** load precompiled chunk
*/
Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff)
{
 LoadState S;
 const char* s=zname(Z);
 if (*s=='@' || *s=='=')
  S.name=s+1;
 else if (*s==LUA_SIGNATURE[0])
  S.name="binary string";
 else
  S.name=s;
 S.L=L;
 S.Z=Z;
 S.b=buff;
 return LoadChunk(&S);
}

/*
** find byte order
*/
int luaU_endianness (void)
{
 int x=1;
 return *(char*)&x;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions