#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define luac_c
#define LUA_CORE
#include "lua.h"
#include "lauxlib.h"
#include "ldo.h"
#include "lfunc.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstring.h"
#include "lundump.h"
#define PROGNAME "luac" /* default program name */
#define OUTPUT PROGNAME ".out" /* default output file */
static
int
listing=0;
static
int
dumping=1;
static
int
stripping=0;
static
char
Output[]={ OUTPUT };
static
const
char
* output=Output;
static
const
char
* progname=PROGNAME;
static
void
fatal(
const
char
* message)
{
fprintf
(stderr,
"%s: %s\n"
,progname,message);
exit
(EXIT_FAILURE);
}
static
void
cannot(
const
char
* what)
{
fprintf
(stderr,
"%s: cannot %s %s: %s\n"
,progname,what,output,
strerror
(
errno
));
exit
(EXIT_FAILURE);
}
static
void
usage(
const
char
* message)
{
if
(*message==
'-'
)
fprintf
(stderr,
"%s: unrecognized option "
LUA_QS
"\n"
,progname,message);
else
fprintf
(stderr,
"%s: %s\n"
,progname,message);
fprintf
(stderr,
"usage: %s [options] [filenames].\n"
"Available options are:\n"
" - process stdin\n"
" -l list\n"
" -o name output to file "
LUA_QL(
"name"
)
" (default is \"%s\")\n"
" -p parse only\n"
" -s strip debug information\n"
" -v show version information\n"
" -- stop handling options\n"
,
progname,Output);
exit
(EXIT_FAILURE);
}
#define IS(s) (strcmp(argv[i],s)==0)
static
int
doargs(
int
argc,
char
* argv[])
{
int
i;
int
version=0;
if
(argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
for
(i=1; i<argc; i++)
{
if
(*argv[i]!=
'-'
)
break
;
else
if
(IS(
"--"
))
{
++i;
if
(version) ++version;
break
;
}
else
if
(IS(
"-"
))
break
;
else
if
(IS(
"-l"
))
++listing;
else
if
(IS(
"-o"
))
{
output=argv[++i];
if
(output==NULL || *output==0) usage(LUA_QL(
"-o"
)
" needs argument"
);
if
(IS(
"-"
)) output=NULL;
}
else
if
(IS(
"-p"
))
dumping=0;
else
if
(IS(
"-s"
))
stripping=1;
else
if
(IS(
"-v"
))
++version;
else
usage(argv[i]);
}
if
(i==argc && (listing || !dumping))
{
dumping=0;
argv[--i]=Output;
}
if
(version)
{
printf
(
"%s %s\n"
,LUA_RELEASE,LUA_COPYRIGHT);
if
(version==argc-1)
exit
(EXIT_SUCCESS);
}
return
i;
}
#define toproto(L,i) (clvalue(L->top+(i))->l.p)
static
const
Proto* combine(lua_State* L,
int
n)
{
if
(n==1)
return
toproto(L,-1);
else
{
int
i,pc;
Proto* f=luaF_newproto(L);
setptvalue2s(L,L->top,f); incr_top(L);
f->source=luaS_newliteral(L,
"=("
PROGNAME
")"
);
f->maxstacksize=1;
pc=2*n+1;
f->code=luaM_newvector(L,pc,Instruction);
f->sizecode=pc;
f->p=luaM_newvector(L,n,Proto*);
f->sizep=n;
pc=0;
for
(i=0; i<n; i++)
{
f->p[i]=toproto(L,i-n-1);
f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
}
f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
return
f;
}
}
static
int
writer(lua_State* L,
const
void
* p,
size_t
size,
void
* u)
{
UNUSED(L);
return
(
fwrite
(p,size,1,(
FILE
*)u)!=1) && (size!=0);
}
struct
Smain {
int
argc;
char
** argv;
};
static
int
pmain(lua_State* L)
{
struct
Smain* s = (
struct
Smain*)marpa_lua_touserdata(L, 1);
int
argc=s->argc;
char
** argv=s->argv;
const
Proto* f;
int
i;
if
(!marpa_lua_checkstack(L,argc)) fatal(
"too many input files"
);
for
(i=0; i<argc; i++)
{
const
char
* filename=IS(
"-"
) ? NULL : argv[i];
if
(marpa_luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
}
f=combine(L,argc);
if
(listing) luaU_print(f,listing>1);
if
(dumping)
{
FILE
* D= (output==NULL) ? stdout :
fopen
(output,
"wb"
);
if
(D==NULL) cannot(
"open"
);
lua_lock(L);
luaU_dump(L,f,writer,D,stripping);
lua_unlock(L);
if
(
ferror
(D)) cannot(
"write"
);
if
(
fclose
(D)) cannot(
"close"
);
}
return
0;
}
int
main(
int
argc,
char
* argv[])
{
lua_State* L;
struct
Smain s;
int
i=doargs(argc,argv);
argc-=i; argv+=i;
if
(argc<=0) usage(
"no input files given"
);
L=lua_open();
if
(L==NULL) fatal(
"not enough memory for state"
);
s.argc=argc;
s.argv=argv;
if
(marpa_lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
marpa_lua_close(L);
return
EXIT_SUCCESS;
}