lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi, folks,

What is bug, what is feature ?

When userdata is  garbage collected if I  call Lua from C ?  I call it
this way:

------------------8<----------------------------
static void my_core(MyData *my)
{
  printf("my %s: <my_core>\n",my->name);
  lua_getglobal(L,"myPrint");
  lua_pushusertag(L,my,my_tag);
  lua_call(L,1,0);
  lua_setgcthreshold(L,0);
  printf("my %s: </my_core>\n",my->name);
}
------------------8<----------------------------

Please note that I want  garbage collection quite often as my userdata
potentially are huge. The problem now is, that on linux (Linux neumann
2.4.16-64GB-SMP),  'my'  is garbage  collected  even  if  it had  been
created in C, while on  Tru64 alpha (OSF1 weyl.wias-berlin.de V5.1 732
alpha),  'my'  is  _not_  garbage  collected.  I  believe,  the  later
behaviour is right, but I am not sure. 

If it  is the  other way round,  do I  have to wrap  the core  call by
lua_ref/lua_unref (and after it is unrefed, what is with GC then ?)
 
But what is most puzzeling me is the different behaviour on
Linux and alpha (64 bit BTW).

I included a  shar with this file and all the  files necessary to test
this with plain lua-4.0.1. I stick  with that as I am relying on tolua
(which I  beloved now). But don't  get confused by the  tolua stuff in
the names of the test code: I derived it by tweaking tolua output.

Juergen


PS: Here is the commented output of the test code on alpha
------------------8<----------------------------
gcconfusion.alpha -c gcconfusion.lua
my test: created       -- by Lua call                                  
myPrint:        test                                                   
my test2: created      -- by Lua call                                  
my mycall: created     -- in C                                         
my mycall: <my_core>                                                   
myPrint:        mycall -- Core call to Lua output with C created data  
my mycall: </my_core>                                                  
my mycall: destroyed   -- release in C                                 
my test2: <my_core>                                                    
myPrint:        test2  -- Core call to Lua output with Lua created data
my test2: </my_core>                                                   
my test: destroyed     -- Lua GC                                       
my test2: destroyed    -- Lua GC                                       
------------------8<----------------------------



PS: Here is the commented output of the test code on linux
------------------8<----------------------------
gcconfusion.linux -c gcconfusion.lua
my test: created         -- by Lua call                                  
myPrint:        test	                                                 
my test2: created	 -- by Lua call                                  
my mycall: created	 -- in C                                         
my mycall: <my_core>	                                                 
myPrint:        mycall	 -- Core call to Lua output with C created data  
my mycall: destroyed	 -- Lua GC: why??                                              
my mycall: </my_core>	 -- release in C  not performed (ptr messed up)                                
my test2: <my_core>	                                                 
myPrint:        test2	 -- Core call to Lua output with Lua created data
my test2: </my_core>	                                                 
my test2: destroyed	 -- Lua GC                                       
my test: destroyed	 -- Lua GC                                       
make: *** [linux] Speicherzugriffsfehler -- Access violation
------------------8<----------------------------
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2c).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2003-02-19 12:25 CET by <fuhrmann@neumann>.
# Source directory was `/home/unix/3dbe/fuhrmann/sandboxes/gcconfusion'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#    981 -rw-rw-r-- Makefile
#   3712 -rw-rw-r-- README
#  11234 -rw-rw-r-- gcconfusion.c
#    156 -rw-rw-r-- gcconfusion.lua
#   3169 -rw-r--r-- lua_config
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
    shar_n= shar_c='
'
  else
    shar_n=-n shar_c=
  fi
else
  shar_n= shar_c='\c'
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
$echo $shar_n 'x -' 'lock directory' "\`_sh13321': "$shar_c
if mkdir _sh13321; then
  $echo 'created'
else
  $echo 'failed to create'
  exit 1
fi
# ============= Makefile ==============
if test -f 'Makefile' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Makefile' '(file already exists)'
else
  $echo 'x -' extracting 'Makefile' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
include lua_config
LUA=lua-4.0.1
LUATAR=/home/unix/3dbe/fuhrmann/pdelib2/3rdparty/lua-4.0.1.tar.gz
X
default:
X	echo On alpha, issue 'make alpha'
X	echo On linux, issue 'make linux'
X	echo 'make clean' cleans up the whole mess
X
$(LUA): 
X	gunzip -c  $(LUATAR) | tar -xf - 
X	cp lua_config $(LUA)/config
X
liblinux/liblua.a: $(LUA)
X	cd $(LUA); make
X	-mkdir liblinux
X	mv $(LUA)/lib/*.a liblinux
X	cd $(LUA); make clean
X
libalpha/liblua.a: $(LUA)
X	cd $(LUA); make
X	-mkdir libalpha
X	mv $(LUA)/lib/*.a libalpha
X	cd $(LUA); make clean
X
X
gcconfusion.alpha: libalpha/liblua.a gcconfusion.c
X	$(CC) $(CFLAGS) -o gcconfusion.alpha gcconfusion.c -Llibalpha -llua -llualib -lm
X
gcconfusion.linux: liblinux/liblua.a gcconfusion.c
X	$(CC) $(CFLAGS) -o gcconfusion.linux gcconfusion.c -Lliblinux -llua -llualib -lm
X
linux: gcconfusion.linux
X	gcconfusion.linux -c gcconfusion.lua
X
alpha: gcconfusion.alpha
X	gcconfusion.alpha -c gcconfusion.lua
X
X
clean: 
X	chmod -R +w $(LUA)
X	-rm -r *linux* *alpha* $(LUA)
X 
SHAR_EOF
  (set 20 03 02 19 11 56 16 'Makefile'; eval "$shar_touch") &&
  chmod 0664 'Makefile' ||
  $echo 'restore of' 'Makefile' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Makefile:' 'MD5 check failed'
a32efbbc79604e67d83aa0bfa9168160  Makefile
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'Makefile'`"
    test 981 -eq "$shar_count" ||
    $echo 'Makefile:' 'original size' '981,' 'current size' "$shar_count!"
  fi
fi
# ============= README ==============
if test -f 'README' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'README' '(file already exists)'
else
  $echo 'x -' extracting 'README' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
What is bug, what is feature ?
X
When userdata is  garbage collected if I  call Lua from C ?  I call it
this way:
X
------------------8<----------------------------
static void my_core(MyData *my)
{
X  printf("my %s: <my_core>\n",my->name);
X  lua_getglobal(L,"myPrint");
X  lua_pushusertag(L,my,my_tag);
X  lua_call(L,1,0);
X  lua_setgcthreshold(L,0);
X  printf("my %s: </my_core>\n",my->name);
}
------------------8<----------------------------
X
Please note that I want  garbage collection quite often as my userdata
potentially are huge. The problem now is, that on linux (Linux neumann
2.4.16-64GB-SMP),  'my'  is garbage  collected  even  if  it had  been
created in C, while on  Tru64 alpha (OSF1 weyl.wias-berlin.de V5.1 732
alpha),  'my'  is  _not_  garbage  collected.  I  believe,  the  later
behaviour is right, but I am not sure. 
X
If it  is the  other way round,  do I  have to wrap  the core  call by
lua_ref/lua_unref (and after it is unrefed, what is with GC then ?)
X 
But what is most puzzeling me is the different behaviour on
Linux and alpha (64 bit BTW).
X
I included a  shar with this file and all the  files necessary to test
this with plain lua-4.0.1. I stick  with that as I am relying on tolua
(which I  beloved now). But don't  get confused by the  tolua stuff in
the names of the test code: I derived it by tweaking tolua output.
X
Juergen
X
X
PS: Here is the commented output of the test code on alpha
------------------8<----------------------------
gcconfusion.alpha -c gcconfusion.lua
my test: created       -- by Lua call                                  
myPrint:        test                                                   
my test2: created      -- by Lua call                                  
my mycall: created     -- in C                                         
my mycall: <my_core>                                                   
myPrint:        mycall -- Core call to Lua output with C created data  
my mycall: </my_core>                                                  
my mycall: destroyed   -- release in C                                 
my test2: <my_core>                                                    
myPrint:        test2  -- Core call to Lua output with Lua created data
my test2: </my_core>                                                   
my test: destroyed     -- Lua GC                                       
my test2: destroyed    -- Lua GC                                       
------------------8<----------------------------
X
X
X
PS: Here is the commented output of the test code on linux
------------------8<----------------------------
gcconfusion.linux -c gcconfusion.lua
my test: created         -- by Lua call                                  
myPrint:        test	                                                 
my test2: created	 -- by Lua call                                  
my mycall: created	 -- in C                                         
my mycall: <my_core>	                                                 
myPrint:        mycall	 -- Core call to Lua output with C created data  
my mycall: destroyed	 -- Lua GC: why??                                              
my mycall: </my_core>	 -- release in C  not performed (ptr messed up)                                
my test2: <my_core>	                                                 
myPrint:        test2	 -- Core call to Lua output with Lua created data
my test2: </my_core>	                                                 
my test2: destroyed	 -- Lua GC                                       
my test: destroyed	 -- Lua GC                                       
make: *** [linux] Speicherzugriffsfehler -- Access violation
------------------8<----------------------------
SHAR_EOF
  (set 20 03 02 19 12 25 06 'README'; eval "$shar_touch") &&
  chmod 0664 'README' ||
  $echo 'restore of' 'README' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'README:' 'MD5 check failed'
ce5172d725c3b49079570d0331244162  README
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'README'`"
    test 3712 -eq "$shar_count" ||
    $echo 'README:' 'original size' '3712,' 'current size' "$shar_count!"
  fi
fi
# ============= gcconfusion.c ==============
if test -f 'gcconfusion.c' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'gcconfusion.c' '(file already exists)'
else
  $echo 'x -' extracting 'gcconfusion.c' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'gcconfusion.c' &&
/*
** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
X
X
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
X
#include "lua.h"
X
#include "luadebug.h"
#include "lualib.h"
X
static lua_State *L = NULL;
X
/*-------------------------------------------------------*/
/* BEGIN GCCONFUSION STUFF */
X
#include <assert.h>
X
X
#define PROMPT "gcconfusion>"
#define addref(p) (p->refcount++, p)
#define release(p) (p->refcount--, p->refcount>0?0:(p->destroy(p),1))
X
X
typedef struct MyDataStruct{
X  int refcount;
X  void (*destroy)(struct MyDataStruct *MyData);
X  char name[20];
} MyData; 
X
X char *myName(MyData *my);
X MyData *myCreate(char *name);
X void myCall(MyData *my);
X void myCall2(MyData *my,MyData *my2);
X void myRelease(MyData *my);
X
#define myRelease(my) release(my)
X
X
X
X
static int my_tag;
X
/* function: myName */
static int toluaI_gcconfusion_myName00(lua_State* L)
{
X
X  MyData* my = ((MyData*)  lua_touserdata(L,1));
X {
X  char* toluaI_ret = (char*)  myName(my);
X  lua_pushstring(L,(const char*)toluaI_ret);
X }
X return 1;
}
X
/* function: myCreate */
static int toluaI_gcconfusion_myCreate00(lua_State* L)
{
X  char* name = ((char*)  lua_tostring(L,1));
X  {
X    MyData* toluaI_ret = (MyData*)  myCreate(name);
X    lua_pushusertag(L,(void*)toluaI_ret,my_tag);
X  }
X return 1;
}
X
/* function: myCall */
static int toluaI_gcconfusion_myCall00(lua_State* L)
{
X  MyData* my = ((MyData*)  lua_touserdata(L,1));
X {
X  myCall(my);
X }
X return 1;
}
X
/* function: myCall2 */
static int toluaI_gcconfusion_myCall200(lua_State* L)
{
X
X  MyData* my = ((MyData*)  lua_touserdata(L,1));
X  MyData* my2 = ((MyData*)  lua_touserdata(L,2));
X {
X  myCall2(my,my2);
X }
X return 1;
}
X
/* function: myRelease */
static int toluaI_gcconfusion_myRelease00(lua_State* L)
{
X  MyData* my = ((MyData*)  lua_touserdata(L,1));
X {
X  myRelease(my);
X }
X return 1;
}
static void register_function (lua_State* L,char* name, lua_CFunction func)
{
X
X  lua_pushcfunction(L,func);
X  lua_setglobal(L,name);
}
X
/* Open function */
int tolua_gcconfusion_open (lua_State* L)
{
X  my_tag=lua_newtag(L);
X  register_function(L,"myName",toluaI_gcconfusion_myName00);
X  register_function(L,"myCreate",toluaI_gcconfusion_myCreate00);
X  register_function(L,"myCall",toluaI_gcconfusion_myCall00);
X  register_function(L,"myCall2",toluaI_gcconfusion_myCall200);
X  register_function(L,"myRelease",toluaI_gcconfusion_myRelease00);
X  {  
X    lua_getglobal(L,"myRelease");
X    lua_settagmethod(L,my_tag,"gc");
X  }
X  return 1;
}
X
/* Close function */
void tolua_gcconfusion_close (lua_State* L)
{
X lua_pushnil(L); lua_setglobal(L,"MyData");
X lua_pushnil(L); lua_setglobal(L,"myName");
X lua_pushnil(L); lua_setglobal(L,"myCreate");
X lua_pushnil(L); lua_setglobal(L,"myCall");
X lua_pushnil(L); lua_setglobal(L,"myCall2");
X lua_pushnil(L); lua_setglobal(L,"myRelease");
}
X
X
static void myDestroy(MyData*my)
{
X  assert(my->refcount==0);
X  printf("my %s: destroyed\n",my->name);
X  free(my);
}
X
X
MyData *myCreate(char *name)
{
X  MyData *my=malloc(sizeof(MyData));
X  strncpy(my->name,name,20);
X  my->refcount=0;
X  my->destroy=myDestroy;
X  printf("my %s: created\n",my->name);
X  return addref(my);
}
X
static void my_core(MyData *my)
{
X  printf("my %s: <my_core>\n",my->name);
X  lua_getglobal(L,"myPrint");
X  lua_pushusertag(L,my,my_tag);
X  lua_call(L,1,0);
X  lua_setgcthreshold(L,0);
X  printf("my %s: </my_core>\n",my->name);
}
void myCall(MyData *my)
{
X  MyData *my2=myCreate("mycall");
X  my_core(my2);
X  release(my2);
}
void myCall2(MyData *my,MyData *my2)
{
X  my_core(my2);
}
X
char *myName(MyData *my)
{
X  return my->name;
}
X
static void userinit (void) {
X  extern int tolua_gcconfusion_open (lua_State* L);
X  lua_baselibopen(L);
X  lua_iolibopen(L);
X  lua_strlibopen(L);
X  lua_mathlibopen(L);
X  lua_dblibopen(L);
X  /* add your libraries here */
X  tolua_gcconfusion_open(L);
}
X
/* END GCCONFUSION STUFF */
/* Everything els is plain Lua4.01, except userinit which
X   moved here */
/*-------------------------------------------------------*/
X
X
X
X
X
#ifndef PROMPT
#define PROMPT		"> "
#endif
X
#ifdef _POSIX_SOURCE
#include <unistd.h>
#else
static int isatty (int x) { return x==0; }  /* assume stdin is a tty */
#endif
X
X
/*
** global options
*/
struct Options {
X  int toclose;
X  int stacksize;
};
X
X
typedef void (*handler)(int);  /* type for signal actions */
X
static void laction (int i);
X
X
static lua_Hook old_linehook = NULL;
static lua_Hook old_callhook = NULL;
X
X
/* USERINIT TAKEN OUT */
X
static handler lreset (void) {
X  return signal(SIGINT, laction);
}
X
X
static void lstop (void) {
X  lua_setlinehook(L, old_linehook);
X  lua_setcallhook(L, old_callhook);
X  lreset();
X  lua_error(L, "interrupted!");
}
X
X
static void laction (int i) {
X  (void)i;  /* to avoid warnings */
X  signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop,
X                              terminate process (default action) */
X  old_linehook = lua_setlinehook(L, (lua_Hook)lstop);
X  old_callhook = lua_setcallhook(L, (lua_Hook)lstop);
}
X
X
static int ldo (int (*f)(lua_State *l, const char *), const char *name) {
X  int res;
X  handler h = lreset();
X  int top = lua_gettop(L);
X  res = f(L, name);  /* dostring | dofile */
X  lua_settop(L, top);  /* remove eventual results */
X  signal(SIGINT, h);  /* restore old action */
X  /* Lua gives no message in such cases, so lua.c provides one */
X  if (res == LUA_ERRMEM) {
X    fprintf(stderr, "lua: memory allocation error\n");
X  }
X  else if (res == LUA_ERRERR)
X    fprintf(stderr, "lua: error in error message\n");
X  return res;
}
X
X
static void print_message (void) {
X  fprintf(stderr,
X  "usage: lua [options].  Available options are:\n"
X  "  -        execute stdin as a file\n"
X  "  -c       close Lua when exiting\n"
X  "  -e stat  execute string `stat'\n"
X  "  -f name  execute file `name' with remaining arguments in table `arg'\n"
X  "  -i       enter interactive mode with prompt\n"
X  "  -q       enter interactive mode without prompt\n"
X  "  -sNUM    set stack size to NUM (must be the first option)\n"
X  "  -v       print version information\n"
X  "  a=b      set global `a' to string `b'\n"
X  "  name     execute file `name'\n"
);
}
X
X
static void print_version (void) {
X  printf("%.80s  %.80s\n", LUA_VERSION, LUA_COPYRIGHT);
}
X
X
static void assign (char *arg) {
X  char *eq = strchr(arg, '=');
X  *eq = '\0';  /* spilt `arg' in two strings (name & value) */
X  lua_pushstring(L, eq+1);
X  lua_setglobal(L, arg);
}
X
X
static void getargs (char *argv[]) {
X  int i;
X  lua_newtable(L);
X  for (i=0; argv[i]; i++) {
X    /* arg[i] = argv[i] */
X    lua_pushnumber(L, i);
X    lua_pushstring(L, argv[i]);
X    lua_settable(L, -3);
X  }
X  /* arg.n = maximum index in table `arg' */
X  lua_pushstring(L, "n");
X  lua_pushnumber(L, i-1);
X  lua_settable(L, -3);
}
X
X
static int l_getargs (lua_State *l) {
X  char **argv = (char **)lua_touserdata(l, -1);
X  getargs(argv);
X  return 1;
}
X
X
static int file_input (const char *argv) {
X  int result = ldo(lua_dofile, argv);
X  if (result) {
X    if (result == LUA_ERRFILE) {
X      fprintf(stderr, "lua: cannot execute file ");
X      perror(argv);
X    }
X    return EXIT_FAILURE;
X  }
X  else
X    return EXIT_SUCCESS;
}
X
X
/* maximum length of an input string */
#ifndef MAXINPUT
#define MAXINPUT	BUFSIZ
#endif
X
static void manual_input (int version, int prompt) {
X  int cont = 1;
X  if (version) print_version();
X  while (cont) {
X    char buffer[MAXINPUT];
X    int i = 0;
X    if (prompt) {
X      const char *s;
X      lua_getglobal(L, "_PROMPT");
X      s = lua_tostring(L, -1);
X      if (!s) s = PROMPT;
X      fputs(s, stdout);
X      lua_pop(L, 1);  /* remove global */
X    }
X    for(;;) {
X      int c = getchar();
X      if (c == EOF) {
X        cont = 0;
X        break;
X      }
X      else if (c == '\n') {
X        if (i>0 && buffer[i-1] == '\\')
X          buffer[i-1] = '\n';
X        else break;
X      }
X      else if (i >= MAXINPUT-1) {
X        fprintf(stderr, "lua: input line too long\n");
X        break;
X      }
X      else buffer[i++] = (char)c;
X    }
X    buffer[i] = '\0';
X    ldo(lua_dostring, buffer);
X    lua_settop(L, 0);  /* remove eventual results */
X  }
X  printf("\n");
}
X
X
static int handle_argv (char *argv[], struct Options *opt) {
X  if (opt->stacksize > 0) argv++;  /* skip option `-s' (if present) */
X  if (*argv == NULL) {  /* no more arguments? */
X    if (isatty(0)) {
X      manual_input(1, 1);
X    }
X    else
X      ldo(lua_dofile, NULL);  /* executes stdin as a file */
X  }
X  else {  /* other arguments; loop over them */
X    int i;
X    for (i = 0; argv[i] != NULL; i++) {
X      if (argv[i][0] != '-') {  /* not an option? */
X        if (strchr(argv[i], '='))
X          assign(argv[i]);
X        else
X          if (file_input(argv[i]) != EXIT_SUCCESS)
X            return EXIT_FAILURE;  /* stop if file fails */
X        }
X        else switch (argv[i][1]) {  /* option */
X          case 0: {
X            ldo(lua_dofile, NULL);  /* executes stdin as a file */
X            break;
X          }
X          case 'i': {
X            manual_input(0, 1);
X            break;
X          }
X          case 'q': {
X            manual_input(0, 0);
X            break;
X          }
X          case 'c': {
X            opt->toclose = 1;
X            break;
X          }
X          case 'v': {
X            print_version();
X            break;
X          }
X          case 'e': {
X            i++;
X            if (argv[i] == NULL) {
X              print_message();
X              return EXIT_FAILURE;
X            }
X            if (ldo(lua_dostring, argv[i]) != 0) {
X              fprintf(stderr, "lua: error running argument `%.99s'\n", argv[i]);
X              return EXIT_FAILURE;
X            }
X            break;
X          }
X          case 'f': {
X            i++;
X            if (argv[i] == NULL) {
X              print_message();
X              return EXIT_FAILURE;
X            }
X            getargs(argv+i);  /* collect remaining arguments */
X            lua_setglobal(L, "arg");
X            return file_input(argv[i]);  /* stop scanning arguments */
X          }
X          case 's': {
X            fprintf(stderr, "lua: stack size (`-s') must be the first option\n");
X            return EXIT_FAILURE;
X          }
X          default: {
X            print_message();
X            return EXIT_FAILURE;
X          }
X        }
X    }
X  }
X  return EXIT_SUCCESS;
}
X
X
static void getstacksize (int argc, char *argv[], struct Options *opt) {
X  if (argc >= 2 && argv[1][0] == '-' && argv[1][1] == 's') {
X    int stacksize = atoi(&argv[1][2]);
X    if (stacksize <= 0) {
X      fprintf(stderr, "lua: invalid stack size ('%.20s')\n", &argv[1][2]);
X      exit(EXIT_FAILURE);
X    }
X    opt->stacksize = stacksize;
X  }
X  else
X    opt->stacksize = 0;  /* no stack size */
}
X
X
static void register_getargs (char *argv[]) {
X  lua_pushuserdata(L, argv);
X  lua_pushcclosure(L, l_getargs, 1);
X  lua_setglobal(L, "getargs");
}
X
X
int main (int argc, char *argv[]) {
X  struct Options opt;
X  int status;
X  opt.toclose = 0;
X  getstacksize(argc, argv, &opt);  /* handle option `-s' */
X  L = lua_open(opt.stacksize);  /* create state */
X  userinit();  /* open libraries */
X  register_getargs(argv);  /* create `getargs' function */
X  status = handle_argv(argv+1, &opt);
X  if (opt.toclose)
X    lua_close(L);
X  return status;
}
X
SHAR_EOF
  (set 20 03 02 19 12 16 11 'gcconfusion.c'; eval "$shar_touch") &&
  chmod 0664 'gcconfusion.c' ||
  $echo 'restore of' 'gcconfusion.c' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'gcconfusion.c:' 'MD5 check failed'
19e7a701bc4b5db14b1ab5dbd7891205  gcconfusion.c
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'gcconfusion.c'`"
    test 11234 -eq "$shar_count" ||
    $echo 'gcconfusion.c:' 'original size' '11234,' 'current size' "$shar_count!"
  fi
fi
# ============= gcconfusion.lua ==============
if test -f 'gcconfusion.lua' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'gcconfusion.lua' '(file already exists)'
else
  $echo 'x -' extracting 'gcconfusion.lua' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'gcconfusion.lua' &&
function myPrint(my)
X   print("myPrint: ",myName(my))
end
X
X
test=myCreate("test");
myPrint(test)
test2=myCreate("test2");
X
myCall(test)
myCall2(test,test2)
SHAR_EOF
  (set 20 03 02 19 11 46 30 'gcconfusion.lua'; eval "$shar_touch") &&
  chmod 0664 'gcconfusion.lua' ||
  $echo 'restore of' 'gcconfusion.lua' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'gcconfusion.lua:' 'MD5 check failed'
07ddb3a1e56cc9151b450ae91b76bd9c  gcconfusion.lua
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'gcconfusion.lua'`"
    test 156 -eq "$shar_count" ||
    $echo 'gcconfusion.lua:' 'original size' '156,' 'current size' "$shar_count!"
  fi
fi
# ============= lua_config ==============
if test -f 'lua_config' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'lua_config' '(file already exists)'
else
  $echo 'x -' extracting 'lua_config' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'lua_config' &&
# configuration file for making Lua
# see INSTALL for installation instructions
X
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
X
# ------------------------------------------------------------------ Lua
X
# Lua uses double for numbers. To change this, uncomment one of the lines below.
#NUMBER= -DLUA_NUM_TYPE=double
#NUMBER= -DLUA_NUM_TYPE=float
#NUMBER= -DLUA_NUM_TYPE=long
# Optionally, you may also want change how numbers are converted to strings,
# and vice-versa. Look for LUA_NUMBER in llimits.h and in the rest of the code.
X
# If you want support for pipes, uncomment the following line.
# You need popen in your C library.
#POPEN= -DPOPEN
X
# If you need compatibility with previous versions, edit and uncomment the
# definition of COMPAT below.
# Use -DLUA_COMPAT_READPATTERN if you need complex read patterns.
# Use -DLUA_COMPAT_ARGRET if you need the old semantics that used only the
# first value returned by a function when it is called as the last parameter.
# Use -DLUA_DEPRECATEDFUNCS if you need the obsolete functions in the standard 
# Lua library (not recommended).
#COMPAT= -DLUA_COMPAT_READPATTERN -DLUA_COMPAT_ARGRET -DLUA_DEPRECATEDFUNCS
X
# ------------------------------------------------------------------ C compiler
X
# You need an ANSI C compiler. gcc is a popular one.
CC= cc
X
# ------------------------------------------------------------------ C library
X
# If your C library is not POSIX compliant, comment the following line.
POSIX= -D_POSIX_SOURCE
X
# If your C library does not have the newer ANSI functions strerror, strcoll,
# and locale support, uncomment the following line. SunOs 4.1.x is one example.
#OLD_ANSI= -DOLD_ANSI
X
# In SunOs 4.1.x, standard headers in /usr/include are not ANSI,
# so uncomment the following line to avoid prototypes warnings.
#EXTRA_INCS= -I/usr/5include
X
# The stand-alone Lua interpreter needs the math functions, which are usually
# in libm.a (-lm).  If your C library already includes the math functions,
# or if you are using a modified interpreter that does not need them,
# then comment the following line.
EXTRA_LIBS= -lm
X
# ------------------------------------------------------------------ librarian
X
# This should work in all Unix systems.
AR= ar rcu
X
# If your system doesn't have (or need) ranlib, use RANLIB=true.
# On some systems, "ar s" does what ranlib would do.
RANLIB= ranlib
#RANLIB= ar s
#RANLIB= true
X
# ------------------------------------------------------------------ install
X
# Locations for "make install". You may need to be root do "make install".
INSTALL_ROOT= /usr/local
INSTALL_BIN= $(INSTALL_ROOT)/bin
INSTALL_INC= $(INSTALL_ROOT)/include
INSTALL_LIB= $(INSTALL_ROOT)/lib
INSTALL_MAN= $(INSTALL_ROOT)/man/man1
X
# You might prefer to use "install" if you have it.
INSTALL_EXEC= cp
INSTALL_DATA= cp
#INSTALL_EXEC= install -m 0755
#INSTALL_DATA= install -m 0644
X
# == END OF USER SETTINGS. DO NOT CHANGE ANYTHING BELOW THIS LINE =============
X
BIN= $(LUA)/bin
INC= $(LUA)/include
LIB= $(LUA)/lib
X
INCS= -I$(INC) $(EXTRA_INCS)
DEFS= $(COMPAT) $(NUMBER) $(OLD_ANSI) $(EXTRA_DEFS)
X
CFLAGS= -O2 $(WARN) $(INCS) $(DEFS)
X
V=4.0
X
# (end of config)
SHAR_EOF
  (set 20 03 02 19 11 37 46 'lua_config'; eval "$shar_touch") &&
  chmod 0644 'lua_config' ||
  $echo 'restore of' 'lua_config' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'lua_config:' 'MD5 check failed'
33809b8fb4f54c9e5cb32e96678c151f  lua_config
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'lua_config'`"
    test 3169 -eq "$shar_count" ||
    $echo 'lua_config:' 'original size' '3169,' 'current size' "$shar_count!"
  fi
fi
$echo $shar_n 'x -' 'lock directory' "\`_sh13321': " $shar_c
if rm -fr _sh13321; then
  $echo 'removed'
else
  $echo 'failed to remove'
fi
exit 0