/*
 * The olsr.org Optimized Link-State Routing daemon (olsrd)
 *
 * Copyright (c) 2004, Thomas Lopatic (thomas@olsr.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 *
 * * Redistributions of source code must retain the above copyright 
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright 
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the 
 *   distribution.
 * * Neither the name of olsr.org, olsrd nor the names of its 
 *   contributors may be used to endorse or promote products derived 
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Visit http://www.olsr.org for more information.
 *
 * If you find this software useful feel free to make a donation
 * to the project. For more information see the website or contact
 * the copyright holders.
 *
 * $Id: glua.c,v 1.4 2007/04/20 13:46:03 bernd67 Exp $
 */

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

#include "link.h"
#include "plugin.h"
#include "lib.h"
#include "os_unix.h"
#include "http.h"
#include "glua.h"
#include "glua_ext.h"

#include <stdio.h>
#include <string.h>

static const char infoKey;
static const char keepFlagKey;
static const char argListKey;
    
int lspToLua(const char *rootDir, const char *lspFileName,
             const char *workDir, const char *luaFileName)
{
  FILE *file;
  int lspLen;
  unsigned char *buff;
  int start, code, i, k;
  char *lspPath = fullPath(rootDir, lspFileName);
  char *luaPath = fullPath(workDir, luaFileName);

  if (fileIsNewer(lspPath, luaPath) == 0)
  {
    freeMem(lspPath);
    freeMem(luaPath);
    return 0;
  }

  file = fopen(lspPath, "r");

  if (file == NULL)
  {
    error("cannot open %s\n", lspPath);
    freeMem(lspPath);
    freeMem(luaPath);
    return -1;
  }

  if (fseek(file, 0, SEEK_END) < 0)
  {
    error("cannot seek to end of %s\n", lspPath);
    fclose(file);
    freeMem(lspPath);
    freeMem(luaPath);
    return -1;
  }

  lspLen = ftell(file);

  if (lspLen < 0)
  {
    error("cannot determine length of %s\n", lspPath);
    fclose(file);
    freeMem(lspPath);
    freeMem(luaPath);
    return -1;
  }

  if (fseek(file, 0, SEEK_SET) < 0)
  {
    error("cannot seek to beginning of %s\n", lspPath);
    fclose(file);
    freeMem(lspPath);
    freeMem(luaPath);
    return -1;
  }

  buff = allocMem(lspLen);

  if (fread(buff, lspLen, 1, file) != 1)
  {
    error("cannot read %s\n", lspPath);
    fclose(file);
    freeMem(lspPath);
    freeMem(luaPath);
    freeMem(buff);
    return -1;
  }

  fclose(file);

  if (createAllDirs(luaPath) < 0)
  {
    error("cannot create required directories for %s\n",
          luaPath);
    freeMem(lspPath);
    freeMem(luaPath);
    freeMem(buff);
    return -1;
  }

  file = fopen(luaPath, "w");

  if (file == NULL)
  {
    error("cannot open %s\n", luaPath);
    freeMem(lspPath);
    freeMem(luaPath);
    freeMem(buff);
    return -1;
  }

  start = 0;
  code = 0;

  i = 0;

  for (;;)
  {
    if (code == 0 && (i == lspLen || strncmp((char *)(buff + i), "<?lua", 5) == 0))
    {
      fprintf(file, "tas.write(\"");

      for (k = start; k < i; k++)
      {
        if (buff[k] == 13)
          continue;

        if (buff[k] == '\\' || buff[k] == '"' || buff[k] == 10)
          fputc('\\', file);

        fputc(buff[k], file);
      }

      fprintf(file, "\")\n");

      if (i == lspLen)
        break;

      if (buff[i + 5] == '=')
      {
        i += 6;
        code = 2;
      }

      else
      {
        i += 5;
        code = 1;
      }

      start = i;

      continue;
    }

    if (code > 0 && (i == lspLen || strncmp((char *)(buff + i), "?>", 2) == 0))
    {
      if (code > 1)
        fprintf(file, "tas.write(");

      for (k = start; k < i; k++)
        if (buff[k] != 13)
          fputc(buff[k], file);

      if (code > 1)
        fputc(')', file);

      fputc('\n', file);

      if (i == lspLen)
        break;

      i += 2;
      start = i;

      code = 0;

      continue;
    }

    i++;
  }

  fclose(file);
  freeMem(lspPath);
  freeMem(luaPath);
  freeMem(buff);
  return 0;
}

static int luaWriter(lua_State *lua __attribute__((unused)), const void *buff, int len, FILE *file)
{
  return fwrite(buff, len, 1, file) == 1;
}

int luaToLex(char **errMsg, const char *workDir, const char *luaFileName,
             const char *lexFileName)
{
  lua_State *lua;
  int res;
  FILE *file;
  char *luaPath = fullPath(workDir, luaFileName);
  char *lexPath = fullPath(workDir, lexFileName);

  *errMsg = NULL;

  if (fileIsNewer(luaPath, lexPath) == 0)
  {
    freeMem(luaPath);
    freeMem(lexPath);
    return 0;
  }

  lua = lua_open();

  res = luaL_loadfile(lua, luaPath);

  if (res != 0)
  {
    *errMsg = myStrdup(lua_tostring(lua, -1));
    error("cannot load %s: %s\n", luaPath, *errMsg);
    lua_close(lua);
    freeMem(luaPath);
    freeMem(lexPath);
    return -1;
  }

  file = fopen(lexPath, "wb");

  if (file == NULL)
  {
    error("cannot open %s\n", lexPath);
    lua_close(lua);
    freeMem(luaPath);
    freeMem(lexPath);
    return -1;
  }

  lua_dump(lua, (lua_Chunkwriter)luaWriter, file);

  fclose(file);

  lua_close(lua);
  freeMem(luaPath);
  freeMem(lexPath);
  return 0;
}

static int tasWrite(lua_State *lua)
{
  int numArg = lua_gettop(lua);
  const char *strConv;
  int i;
  struct connInfo *info;

  lua_pushlightuserdata(lua, (void *)&infoKey);
  lua_gettable(lua, LUA_REGISTRYINDEX);

  info = lua_touserdata(lua, -1);

  lua_getglobal(lua, "tostring");

  for (i = 1; i <= numArg; i++)
  {
    lua_pushvalue(lua, -1);
    lua_pushvalue(lua, i);

    lua_call(lua, 1, 1);

    strConv = lua_tostring(lua, -1);

    if (strConv == NULL)
      return luaL_error(lua, "cannot convert value to string");

    writeBuff(&info->write[2], (unsigned char *)strConv, strlen(strConv));

    lua_pop(lua, 1);
  }

  return 0;
}

static int tasAddHeaderLine(lua_State *lua)
{
  struct connInfo *info;
  char *line;

  lua_pushlightuserdata(lua, (void *)&infoKey);
  lua_gettable(lua, LUA_REGISTRYINDEX);

  info = lua_touserdata(lua, -1);

  line = myStrdup(luaL_checkstring(lua, 1));

  chomp(line, strlen(line));

  writeBuff(&info->write[1], (unsigned char *)line, strlen(line));
  writeBuff(&info->write[1], (unsigned char *)"\r\n", 2);

  freeMem(line);

  return 0;
}

static int tasSetContentType(lua_State *lua)
{
  struct connInfo *info;
  const char *contType;

  lua_pushlightuserdata(lua, (void *)&infoKey);
  lua_gettable(lua, LUA_REGISTRYINDEX);

  info = lua_touserdata(lua, -1);

  contType = luaL_checkstring(lua, 1);

  info->contType = allocBuff(info, strlen(contType) + 1);
  strcpy(info->contType, contType);

  return 0;
}

static int tasKeepState(lua_State *lua)
{
  int *keepFlag;

  lua_pushlightuserdata(lua, (void *)&keepFlagKey);
  lua_gettable(lua, LUA_REGISTRYINDEX);

  keepFlag = lua_touserdata(lua, -1);

  *keepFlag = 1;

  return 0;
}

static int tasGetParameters(lua_State *lua)
{
  int i;
  char **argList;

  lua_pushlightuserdata(lua, (void *)&argListKey);
  lua_gettable(lua, LUA_REGISTRYINDEX);

  argList = lua_touserdata(lua, -1);

  lua_newtable(lua);

  if (argList == NULL)
    return 1;
  
  for (i = 0; argList[i] != NULL; i += 2)
  {
    lua_pushstring(lua, argList[i]);
    lua_pushstring(lua, argList[i + 1]);
    lua_settable(lua, -3);
  }

  return 1;
}

static const struct luaL_reg tasLib[] =
{
  { "write", tasWrite },
  { "set_content_type", tasSetContentType },
  { "add_header_line", tasAddHeaderLine },
  { "keep_state", tasKeepState },
  { "get_parameters", tasGetParameters },
#ifdef TAS_EXTRA_FUNCTIONS
  TAS_EXTRA_FUNCTIONS
#endif
  { NULL, NULL }
};

static int luaopen_tas(lua_State *lua)
{
  luaL_openlib(lua, "tas", tasLib, 0);
  return 1;
}

int runLua(char **errMsg, struct connInfo *info, const char *workDir,
           const char *lexFileName, char **argList, void **session)
{
  lua_State *lua;
  int res;
  char *lexPath = fullPath(workDir, lexFileName);
  int keepFlag = 0;

  *errMsg = NULL;

  if (*session == NULL)
  {
    lua = lua_open();

    luaopen_base(lua);
    luaopen_table(lua);
    luaopen_io(lua);
    luaopen_string(lua);
    luaopen_math(lua);
    luaopen_debug(lua);
    luaopen_loadlib(lua);

    luaopen_tas(lua);
  }

  else
    lua = *session;

  lua_pushlightuserdata(lua, (void *)&infoKey);
  lua_pushlightuserdata(lua, (void *)info);
  lua_settable(lua, LUA_REGISTRYINDEX);
    
  lua_pushlightuserdata(lua, (void *)&argListKey);
  lua_pushlightuserdata(lua, (void *)argList);
  lua_settable(lua, LUA_REGISTRYINDEX);
    
  lua_pushlightuserdata(lua, (void *)&keepFlagKey);
  lua_pushlightuserdata(lua, (void *)&keepFlag);
  lua_settable(lua, LUA_REGISTRYINDEX);

  res = luaL_loadfile(lua, lexPath);

  if (res != 0)
  {
    *errMsg = myStrdup(lua_tostring(lua, -1));
    error("cannot load %s: %s\n", lexPath, *errMsg);
    lua_close(lua);
    freeMem(lexPath);
    return -1;
  }

  res = lua_pcall(lua, 0, 0, 0);

  if (res != 0)
  {
    *errMsg = myStrdup(lua_tostring(lua, -1));
    error("cannot run %s: %s\n", lexPath, *errMsg);
    lua_close(lua);
    freeMem(lexPath);
    return -1;
  }

  if (keepFlag == 0)
  {
    lua_close(lua);
    *session = NULL;
  }

  else
    *session = lua;


  freeMem(lexPath);
  return 0;
}

void freeLuaSession(void *session)
{
  lua_close(session);
}


syntax highlighted by Code2HTML, v. 0.9.1