Lua helper functions for PDB conversion

Interface

quote writes a string that Lua can read back, or nil for a null pointer. If emptyAsNil is nonzero, it also writes the empty string as nil.

<header>= (U->) [D->]
#include <stdio.h>
#include <lua.h>
extern char *quote(char *s, int emptyAsNil);
#define QUOTE(s) quote(s, 0)
Defines QUOTE (links are to index).

comma helps put commas between list elements without having them at the ends of lists. bitstring converts a single bit to a string representing a suitable Lua value.

<header>+= (U->) [<-D->]
#define comma(P) ((P) ? ", " : "")
#define bitstring(B) ((B) ? "1" : "nil")
Defines bitstring, comma (links are to index).

write_docs prints out indented comments. It takes care of the initial -- and trailing newline.

<header>+= (U->) [<-D->]
extern void write_docs(FILE *fp, int indent, char **lines);

This group of macros is useful for ``packing'' Lua values into internal form. They are all macros so that S can be a literal string combined with "return ". This means if you want to use a non-literal char * value, you have to use the function (*f) forms.

<header>+= (U->) [<-D->]
#define objectval(S) myref(objectvalf("return " S, S))
#define objectvalxx(S) objectvalf("return " S, S)
#define bitval(S) (!lua_isnil(objectvalxx(S)))
#define numberval(S) numbervalf(objectvalxx(S), S)
#define numberopt(S,N) numberoptf(objectvalxx(S),N, S)
#define intval(S) intvalf(objectvalxx(S), S)
#define intopt(S,N) intoptf(objectvalxx(S),N, S)
#define stringval(S) stringvalf(objectvalxx(S), S)
#define stringopt(S,N) stringoptf(objectvalxx(S),N, S)
#define setstring(L, S, SIZE) setstringf(L, objectvalxx(S), SIZE, NULL, S)
#define setstringopt(L, S, OPT, SIZE) setstringf(L, objectvalxx(S), SIZE, OPT, S)
#define setblock(L, S) setstring(L, S, sizeof(L))
#define setblockopt(L, S, OPT) setstringopt(L, S, OPT, sizeof(L))
Defines bitval, intopt, intval, numberopt, numberval, objectval, objectvalxx, setblock, setblockopt, setstring, setstringopt, stringopt, stringval (links are to index).

Macros with opt suffixes allow a value to be missing (i.e., nil), and they take an extra argument that is the value to be returned in that case. setstring is used to get string values of limited size, and setblock is a special case that makes it easy to pack fixed-size arrays.

Here are the function versions of these macros. Don't call them unless you know what you're doing.

<header>+= (U->) [<-D->]
extern lua_Object objectvalf(char *stmt, char *expression);
  /* never call this without wrapping in a ref */
extern float numbervalf(lua_Object o, char *expression);
extern float numberoptf(lua_Object o, float x, char *expression);
extern int intvalf(lua_Object o, char *expression);
extern int intoptf(lua_Object o, int n, char *expression);
extern char *stringvalf(lua_Object o, char *expression);
extern char *stringoptf(lua_Object o, char *s, char *expression);
extern void setstringf(void *dst, lua_Object o, int n, char *optional, char *exp);

dbcheck complains with an error message unless the Lua expression E is true.

<header>+= (U->) [<-D->]
#define dbcheck(E, MSG) dbcheckf("return " E, MSG)
extern void dbcheckf(char *lua_boolean, char *errmsg);
Defines dbcheck (links are to index).

These macros track the locations of Lua ``begin blocks,'' so if you forget to close a block, you can find out where the unclosed block was opened.

<header>+= (U->) [<-D->]
extern char **blockfiles;
extern int *blocklines;
#define lua_beginblock() (*blockfiles++ = __FILE__, *blocklines++ = __LINE__, \
                          lua_beginblock())
#define lua_endblock() (--blockfiles, --blocklines, lua_endblock())
extern void showall(void);
Defines lua_beginblock, lua_endblock (links are to index).

Implementation

Refs hacking

This was an unnecessary hack used when debugging. I was trying to see if objects got lost, so I made ``refs'' to them. Don't define USEREFS.

<header>+= (U->) [<-D]
#ifdef USEREFS
typedef struct myref { int ref; } Ref;
extern Ref myref(lua_Object o);
#define deref(R) lua_getref((R).ref)
#else
typedef lua_Object Ref;
#define myref(_) (_)
#define deref(_) (_)
#define my_unref(_) ((void)(_))
#endif
Defines deref, lua_Object, myref, my_unref (links are to index).

<functions>= (U->) [D->]
#ifdef USEREFS
Ref myref(lua_Object o) {
  Ref answer;
  lua_pushobject(o);
  answer.ref = lua_ref(0);
  return answer;
}
#endif
Defines myref (links are to index).

Tracking block locations

<*>=
#include <stdlib.h>
#include <string.h>
<header>
<functions>
static char *bfiles[1024];
static int blines[1024];
char **blockfiles = bfiles;
int *blocklines = blines;
void showall(void) {
  while (blockfiles > bfiles)
    fprintf(stderr, "Open block at %s:%d\n", *--blockfiles, *--blocklines);
}
Defines bfiles, blines, blockfiles, blocklines, showall (links are to index).

Grabbing Lua values

<functions>+= (<-U) [<-D->]
extern lua_Object objectvalf(char *stmt, char *expression) {
  if (lua_dostring(stmt)) {
     fprintf(stderr, "Error -- evaluation of `%s' failed\n", expression);
     exit(1);
  } 
  if (lua_getresult(1) != LUA_NOOBJECT) 
    return lua_getresult(1);
  fprintf(stderr, "Error -- evaluation of `%s' produced no result\n", expression);
  exit(1);
  return 0;
}
<functions>+= (<-U) [<-D->]
extern float numbervalf(lua_Object o, char *exp) {
  if (lua_isnumber(o)) return lua_getnumber(o);
  else {
    fprintf(stderr, "`%s' is not a number\n", exp);
    exit(1);
  }
}
extern float numberoptf(lua_Object o, float x, char *expression) {
  if (lua_isnil(o)) return x;
  else return numbervalf(o, expression);
}

<functions>+= (<-U) [<-D->]
extern int intvalf(lua_Object o, char *exp) {
  return (int) numbervalf(o, exp);
}
extern int intoptf(lua_Object o, int x, char *expression) {
  if (lua_isnil(o)) return x;
  else return intvalf(o, expression);
}

<functions>+= (<-U) [<-D->]
extern char *stringvalf(lua_Object o, char *exp) {
  if (lua_isstring(o)) return lua_getstring(o);
  else {
    fprintf(stderr, "`%s' is not a string\n", exp);
    exit(1);
  }
}
extern char *stringoptf(lua_Object o, char *s, char *expression) {
  if (lua_isnil(o)) return s;
  else return stringvalf(o, expression);
}

<functions>+= (<-U) [<-D->]
extern void setstringf(void *dst, lua_Object o, int n, char *optional, char *exp) {
  char *s;
  memset(dst, 0, n);
  if (lua_isnil(o) && optional)
    s = optional;
  else if (lua_isstring(o))
    s = lua_getstring(o);
  else {
    fprintf(stderr, "`%s' is not a string\n", exp);
    exit(1);
  }
  strncpy(dst, s, n);
}

Other functions

<functions>+= (<-U) [<-D->]
void dbcheckf(char *lua_exp, char *errmsg) {
  if (lua_isnil(objectvalf(lua_exp, lua_exp))) {
    fprintf(stderr, "Malformed Lua database: %s\n", errmsg);
    exit(1);
  }
}
Defines dbcheckf (links are to index).

<functions>+= (<-U) [<-D->]
extern char *quote(char *s, int emptyAsNil) {
  if (!s || (emptyAsNil && !*s))
    return "nil";
  else {
    lua_pushstring("%q");
    lua_pushstring(s);
    lua_call("format");
    return lua_getstring(lua_getresult(1));
  }
}

<functions>+= (<-U) [<-D]
extern void write_docs(FILE *fp, int indent, char **lines) {
  int i;
  for (; *lines; lines++) {
    for (i = 0; i < indent; i++)
      putc(' ', fp);
    fprintf(fp, "-- %s\n", *lines);
  }
}