/* llfslibext.c

  Copyright 2010-2011 Taco Hoekwater <[email protected]>

  This file is part of LuaTeX.

  LuaTeX is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
  Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  LuaTeX is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.

  You should have received a copy of the GNU General Public License along
  with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */

#include "lua/luatex-api.h"
#include "ptexlib.h"

#include <kpathsea/c-stat.h>
#include <kpathsea/c-dir.h>
#include <time.h>

static const char _svn_version[] =
   "$Id: llfslibext.c 4164 2011-04-16 09:00:09Z taco $ $URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.70.1/source/texk/web2c/luatexdir/lua/llfslibext.c $";

#ifdef _WIN32
#  include <windows.h>
#else
#endif

#ifdef _WIN32

static int get_short_name(lua_State * L)
{
   long length = 0;
   TCHAR *buffer = NULL;
   const char *lpszPath = luaL_checkstring(L, 1);
   length = GetShortPathName(lpszPath, NULL, 0);
   if (length == 0) {
       lua_pushnil(L);
       lua_pushfstring(L, "operating system error: %d", (int) GetLastError());
       return 2;
   }
   buffer = (TCHAR *) xmalloc(length * sizeof(TCHAR));
   length = GetShortPathName(lpszPath, buffer, length);
   if (length == 0) {
       lua_pushnil(L);
       lua_pushfstring(L, "operating system error: %d", (int) GetLastError());
       return 2;
   }
   lua_pushlstring(L, (const char *) buffer, (size_t) length);
   return 1;
}

static int read_link(lua_State * L)
{
   lua_pushboolean(L, 0);
   lua_pushliteral(L, "readlink not supported on this platform");
   return 2;
}

#else

static int pusherror(lua_State * L, const char *info)
{
   lua_pushnil(L);
   if (info == NULL)
       lua_pushstring(L, strerror(errno));
   else
       lua_pushfstring(L, "%s: %s", info, strerror(errno));
   lua_pushinteger(L, errno);
   return 3;
}

static int Preadlink(lua_State * L)
{
/** readlink(path) */
   const char *path = luaL_checkstring(L, 1);
   char *b = NULL;
   int allocated = 128;
   int n;
   while (1) {
       b = malloc(allocated);
       if (!b)
           return pusherror(L, path);
       n = readlink(path, b, allocated);
       if (n == -1) {
           free(b);
           return pusherror(L, path);
       }
       if (n < allocated)
           break;
       /* Not enough room, try bigger */
       allocated *= 2;
       free(b);
   }
   lua_pushlstring(L, b, n);
   free(b);
   return 1;
}


static int read_link(lua_State * L)
{
   return Preadlink(L);
}

static int get_short_name(lua_State * L __attribute__ ((unused)))
{
   /* simply do nothing */
   return 1;
}
#endif


/*
** Get file information
*/
static int file_is_directory(lua_State * L)
{
   struct stat info;
   const char *file = luaL_checkstring(L, 1);

   if (stat(file, &info)) {
       lua_pushnil(L);
       lua_pushfstring(L, "cannot obtain information from file `%s'", file);
       return 2;
   }
   if (S_ISDIR(info.st_mode))
       lua_pushboolean(L, 1);
   else
       lua_pushboolean(L, 0);

   return 1;
}

static int file_is_file(lua_State * L)
{
   struct stat info;
   const char *file = luaL_checkstring(L, 1);

   if (stat(file, &info)) {
       lua_pushnil(L);
       lua_pushfstring(L, "cannot obtain information from file `%s'", file);
       return 2;
   }
   if (S_ISREG(info.st_mode))
       lua_pushboolean(L, 1);
   else
       lua_pushboolean(L, 0);

   return 1;
}


void open_lfslibext(lua_State * L)
{

   lua_getglobal(L, "lfs");
   lua_pushcfunction(L, file_is_directory);
   lua_setfield(L, -2, "isdir");
   lua_pushcfunction(L, file_is_file);
   lua_setfield(L, -2, "isfile");
   lua_pushcfunction(L, read_link);
   lua_setfield(L, -2, "readlink");
   lua_pushcfunction(L, get_short_name);
   lua_setfield(L, -2, "shortname");
   lua_pop(L, 1);              /* pop the table */
}