Initial checkin 0.1
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 9 Jul 2009 07:52:03 +0000 (08:52 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 9 Jul 2009 07:52:03 +0000 (08:52 +0100)
14 files changed:
.gitignore [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
bootstrap.sh [new file with mode: 0644]
configure.ac [new file with mode: 0644]
whelk.pc.in [new file with mode: 0644]
whelk/Makefile.am [new file with mode: 0644]
whelk/_whelk.h [new file with mode: 0644]
whelk/get_folder_path.c [new file with mode: 0644]
whelk/reg_keys.c [new file with mode: 0644]
whelk/registry.c [new file with mode: 0644]
whelk/shelllink.c [new file with mode: 0644]
whelk/unicode.c [new file with mode: 0644]
whelk/whelk.c [new file with mode: 0644]
whelk/whelk.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e8a2590
--- /dev/null
@@ -0,0 +1,16 @@
+Makefile
+Makefile.in
+aclocal.m4
+config.*
+config/
+autom4te.cache/
+configure
+libtool
+whelk-*.tar.gz
+stamp-h1
+.deps/
+.libs/
+*.o
+*.lo
+*.la
+whelk.pc
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..6bef9ed
--- /dev/null
@@ -0,0 +1,4 @@
+SUBDIRS=whelk
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA=whelk.pc
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100644 (file)
index 0000000..69c3355
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+mkdir -p config
+autoheader
+aclocal
+libtoolize
+automake --foreign --add-missing
+autoconf
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..c7ade1c
--- /dev/null
@@ -0,0 +1,75 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_INIT([whelk],[0.1],[ali@juiblex.co.uk])
+AC_PREREQ(2.59)
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_SRCDIR([whelk/whelk.c])
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([Makefile
+whelk.pc
+whelk/Makefile
+])
+AM_INIT_AUTOMAKE(no-define)
+AC_CANONICAL_HOST
+case $host_os in
+    mingw*)
+        host_mingw="yes"
+        ;;
+    *)
+        host_mingw=""
+        ;;
+esac
+AM_CONDITIONAL(WHELK_MINGW,[test -n "$host_mingw"])
+
+##################################################
+# Checks for programs.
+##################################################
+AC_PROG_CC
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG
+
+##################################################
+# Checks for header files.
+##################################################
+AC_HEADER_STDC
+
+##################################################
+# Checks for typedefs, structures, and compiler characteristics.
+##################################################
+
+##################################################
+# Checks for libraries.
+##################################################
+case $host_os in
+    mingw*)
+       EXTRA_LIBS="-lole32"
+       EXTRA_BUILD_LIBS="-Wl,-luuid"
+       EXTRA_PRIVATE_LIBS="-luuid"
+        ;;
+    *)
+       EXTRA_LIBS=""
+       EXTRA_BUILD_LIBS=""
+       EXTRA_PRIVATE_LIBS=""
+        ;;
+esac
+AC_SUBST(EXTRA_LIBS)
+AC_SUBST(EXTRA_BUILD_LIBS)
+AC_SUBST(EXTRA_PRIVATE_LIBS)
+PKG_CHECK_MODULES(LUA,[lua])
+lua_binary_version=`$PKG_CONFIG --variable V lua`
+AC_SUBST([LUA_BINARY_VERSION],[$lua_binary_version])
+
+##################################################
+# Checks for library functions.
+##################################################
+
+##################################################
+# Checks for processor independent files.
+##################################################
+
+##################################################
+# Generate the various configured files
+##################################################
+AC_OUTPUT
diff --git a/whelk.pc.in b/whelk.pc.in
new file mode 100644 (file)
index 0000000..3dca0a6
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: whelk
+Description: A lua library for use with rpm scripts
+Version: @VERSION@
+Requires: lua
+Libs: -L${libdir} -lwhelk @EXTRA_LIBS@
+Libs.private: @EXTRA_PRIVATE_LIBS@
+Cflags: -I${includedir}
diff --git a/whelk/Makefile.am b/whelk/Makefile.am
new file mode 100644 (file)
index 0000000..c643597
--- /dev/null
@@ -0,0 +1,25 @@
+AM_CFLAGS=$(LUA_CFLAGS)
+LIBS=$(LUA_LIBS) $(EXTRA_LIBS) $(EXTRA_BUILD_LIBS)
+LDFLAGS=-no-undefined
+
+INCLUDES=-I$(top_srcdir)
+
+lib_LTLIBRARIES=libwhelk.la
+
+libwhelk_la_SOURCES=whelk.c whelk.h _whelk.h
+if WHELK_MINGW
+libwhelk_la_SOURCES+=unicode.c get_folder_path.c registry.c reg_keys.c \
+       shelllink.c
+endif
+
+pkginclude_HEADERS=whelk.h
+
+luaexecdir=$(libdir)/lua/$(LUA_BINARY_VERSION)
+luaexec_LTLIBRARIES=whelk.la
+whelk_la_SOURCES=$(libwhelk_la_SOURCES)
+whelk_la_LDFLAGS=-avoid-version -module
+
+if WHELK_MINGW
+install-exec-hook:
+       rm -f $(DESTDIR)$(luaexecdir)/whelk.dll.a
+endif
diff --git a/whelk/_whelk.h b/whelk/_whelk.h
new file mode 100644 (file)
index 0000000..9d0e503
--- /dev/null
@@ -0,0 +1,32 @@
+#include <lua.h>
+#include <lualib.h>
+#ifdef __WIN32__
+#include <windows.h>
+#endif
+#include <whelk/whelk.h>
+
+#define whelk_reg_const(L,name) \
+    do { \
+       lua_pushliteral(L,#name); \
+       lua_pushnumber(L,name); \
+       lua_settable(L,-3); \
+    } while(0)
+
+int whelk_perror(lua_State *L,const char *s);
+int whelk_get_folder_path(lua_State *L);
+void whelk_open_get_folder_path(lua_State *L);
+void whelk_open_reg_keys(lua_State *L);
+int whelk_create_short_cut(lua_State *L);
+
+#ifdef __WIN32__
+char *whelk_utf16_to_utf8(const WCHAR *ucs2,int len);
+WCHAR *whelk_utf8_to_utf16(const char *utf8,int len);
+
+HRESULT whelk_reg_close_key(HKEY key);
+HRESULT whelk_reg_open_key(HKEY key,const char *subkey,HKEY *out);
+HRESULT whelk_reg_get_value(HKEY key,const char *subkey,const char *value,
+  DWORD *type,void **data,DWORD *nb);
+HRESULT whelk_reg_set_value(HKEY key,const char *subkey,const char *value,
+  DWORD type,const void *data,int nb);
+HRESULT whelk_reg_delete_key(HKEY key,const char *subkey);
+#endif
diff --git a/whelk/get_folder_path.c b/whelk/get_folder_path.c
new file mode 100644 (file)
index 0000000..a4d7784
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <windows.h>
+#define _WIN32_IE 0x500
+#include <shlobj.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "_whelk.h"
+
+int whelk_get_folder_path(lua_State *L)
+{
+    WCHAR path[MAX_PATH];
+    char *utf8;
+    int folder=luaL_checkint(L,1);
+    HRESULT result;
+    result=SHGetFolderPathW(NULL,folder,NULL,SHGFP_TYPE_CURRENT,path);
+    if (result!=S_OK)
+    {
+       if (result==E_FAIL)
+           errno=ENOENT;
+       else
+           errno=EINVAL;
+       return whelk_perror(L,NULL);
+    }
+    utf8=whelk_utf16_to_utf8(path,-1);
+    lua_pushstring(L,utf8);
+    free(utf8);
+    return 1;
+}
+
+void whelk_open_get_folder_path(lua_State *L)
+{
+    whelk_reg_const(L,CSIDL_ADMINTOOLS);
+    whelk_reg_const(L,CSIDL_APPDATA);
+    whelk_reg_const(L,CSIDL_COMMON_ADMINTOOLS);
+    whelk_reg_const(L,CSIDL_COMMON_APPDATA);
+    whelk_reg_const(L,CSIDL_COMMON_DOCUMENTS);
+    whelk_reg_const(L,CSIDL_COMMON_PROGRAMS);
+    whelk_reg_const(L,CSIDL_COMMON_DESKTOPDIRECTORY);
+    whelk_reg_const(L,CSIDL_COOKIES);
+    whelk_reg_const(L,CSIDL_FLAG_CREATE);
+    whelk_reg_const(L,CSIDL_FLAG_DONT_VERIFY);
+    whelk_reg_const(L,CSIDL_HISTORY);
+    whelk_reg_const(L,CSIDL_INTERNET_CACHE);
+    whelk_reg_const(L,CSIDL_LOCAL_APPDATA);
+    whelk_reg_const(L,CSIDL_MYPICTURES);
+    whelk_reg_const(L,CSIDL_PERSONAL);
+    whelk_reg_const(L,CSIDL_PROGRAM_FILES);
+    whelk_reg_const(L,CSIDL_PROGRAM_FILES_COMMON);
+    whelk_reg_const(L,CSIDL_SYSTEM);
+    whelk_reg_const(L,CSIDL_WINDOWS);
+}
diff --git a/whelk/reg_keys.c b/whelk/reg_keys.c
new file mode 100644 (file)
index 0000000..3a2fa47
--- /dev/null
@@ -0,0 +1,168 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <windows.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "_whelk.h"
+
+#define WHELK_KEYHANDLE                "HKEY"
+#define whelk_checkkeyptr(L,n) ((HKEY *)luaL_checkudata(L,n,WHELK_KEYHANDLE))
+
+static HKEY whelk_checkkey(lua_State *L,int n)
+{
+    HKEY *key=whelk_checkkeyptr(L,n);
+    if (*key==INVALID_HANDLE_VALUE)
+       luaL_error(L,"attempt to use a closed WIN32 registry key");
+    return *key;
+}
+
+static HKEY *newkey(lua_State *L)
+{
+    HKEY *key=(HKEY *)lua_newuserdata(L,sizeof(HKEY));
+    *key=INVALID_HANDLE_VALUE;
+    luaL_getmetatable(L,WHELK_KEYHANDLE);
+    lua_setmetatable(L,-2);
+    return key;
+}
+
+static int get_value(lua_State *L)
+{
+    DWORD type,nb;
+    HRESULT result;
+    int retval=1;
+    void *data;
+    HKEY key=whelk_checkkey(L,1);
+    const char *subkey=luaL_checkstring(L,2);
+    const char *value=luaL_checkstring(L,3);
+    result=whelk_reg_get_value(key,subkey,value,&type,&data,&nb);
+    if (result!=ERROR_SUCCESS)
+    {
+       lua_pushnil(L);
+       lua_pushfstring(L,"%s: Failed to get value",value);
+       lua_pushinteger(L,result);
+       retval=3;
+    }
+    else
+       switch(type)
+       {
+           case REG_SZ:
+           case REG_EXPAND_SZ:
+               lua_pushstring(L,(char *)data);
+               break;
+           case REG_DWORD:
+               lua_pushnumber(L,*(DWORD *)data);
+               break;
+           default:
+               lua_pushnil(L);
+               lua_pushfstring(L,"%s: Data is not a string or number",value);
+               lua_pushinteger(L,ERROR_INVALID_PARAMETER);
+               retval=3;
+       }
+    free(data);
+    return retval;
+}
+
+static int set_value(lua_State *L)
+{
+    DWORD type;
+    int nb;
+    HRESULT result;
+    lua_Number number;
+    DWORD d;
+    const void *data;
+    HKEY key=whelk_checkkey(L,1);
+    const char *subkey=luaL_checkstring(L,2);
+    const char *value=luaL_checkstring(L,3);
+    switch(lua_type(L,4))
+    {
+       case LUA_TSTRING:
+           data=lua_tostring(L,4);
+           type=REG_SZ;
+           nb=-1;
+           break;
+       case LUA_TNUMBER:
+           number=lua_tonumber(L,4);
+           d=(DWORD)number;
+           if ((lua_Number)d!=number)
+           {
+               lua_pushnil(L);
+               lua_pushfstring(L,"%s: Data is not storable as DWORD",value);
+               lua_pushinteger(L,ERROR_INVALID_PARAMETER);
+           }
+           data=&d;
+           type=REG_DWORD;
+           nb=sizeof(d);
+           break;
+       case LUA_TNIL:
+           data=NULL;
+           type=REG_NONE;
+           nb=0;
+           break;
+       default:
+           lua_pushnil(L);
+           lua_pushfstring(L,"%s: Data is not a string or number",value);
+           lua_pushinteger(L,ERROR_INVALID_PARAMETER);
+           return 3;
+    }
+    result=whelk_reg_set_value(key,subkey,value,type,data,nb);
+    if (result!=ERROR_SUCCESS)
+    {
+       lua_pushnil(L);
+       lua_pushfstring(L,"%s: Failed to set value",value);
+       lua_pushinteger(L,result);
+       return 3;
+    }
+    return 1;
+}
+
+static int delete_key(lua_State *L)
+{
+    HRESULT result;
+    HKEY key=whelk_checkkey(L,1);
+    const char *subkey=luaL_checkstring(L,2);
+    result=whelk_reg_delete_key(key,subkey);
+    if (result!=ERROR_SUCCESS)
+    {
+       lua_pushnil(L);
+       lua_pushfstring(L,"%s: Failed to delete key",subkey);
+       lua_pushinteger(L,result);
+       return 3;
+    }
+    return 1;
+}
+
+static int reg_gc(lua_State *L)
+{
+    HKEY key=*whelk_checkkeyptr(L,1);
+    if (key!=INVALID_HANDLE_VALUE)
+       (void)whelk_reg_close_key(key);
+    return 0;
+}
+
+static const luaL_Reg reg_methods[]={
+    { "GetValue",get_value },
+    { "SetValue",set_value },
+    { "DeleteKey",delete_key },
+    { "__gc",reg_gc },
+    { NULL }
+};
+
+static void create_predefined_key(lua_State *L,HKEY key,const char *name)
+{
+    *newkey(L)=key;
+    lua_setfield(L,-3,name);
+}
+
+void whelk_open_reg_keys(lua_State *L)
+{
+    luaL_newmetatable(L,WHELK_KEYHANDLE);
+    lua_pushvalue(L,-1);
+    lua_setfield(L,-2,"__index");
+    luaL_register(L,NULL,reg_methods);
+    create_predefined_key(L,HKEY_CLASSES_ROOT,"KEY_CLASSES_ROOT");
+    create_predefined_key(L,HKEY_CURRENT_CONFIG,"KEY_CURRENT_CONFIG");
+    create_predefined_key(L,HKEY_CURRENT_USER,"KEY_CURRENT_USER");
+    create_predefined_key(L,HKEY_LOCAL_MACHINE,"KEY_LOCAL_MACHINE");
+    create_predefined_key(L,HKEY_USERS,"KEY_USERS");
+}
diff --git a/whelk/registry.c b/whelk/registry.c
new file mode 100644 (file)
index 0000000..b15ab60
--- /dev/null
@@ -0,0 +1,175 @@
+#include <stdlib.h>
+#include <windows.h>
+#include "_whelk.h"
+
+HRESULT whelk_reg_close_key(HKEY key)
+{
+    return RegCloseKey(key);
+}
+
+HRESULT whelk_reg_open_key(HKEY key,const char *subkey,HKEY *out)
+{
+    int i;
+    WCHAR *subkey2;
+    HRESULT result;
+    subkey2=whelk_utf8_to_utf16(subkey,-1);
+    for(i=0;subkey2[i];i++)
+       if (subkey2[i]=='/')
+           subkey2[i]='\\';
+    result=RegOpenKeyExW(key,subkey2,0,KEY_READ|KEY_WRITE,out);
+    free(subkey2);
+    return result;
+    
+}
+
+HRESULT whelk_reg_create_key(HKEY key,const char *subkey,HKEY *out)
+{
+    int i;
+    WCHAR *subkey2;
+    HRESULT result;
+    subkey2=whelk_utf8_to_utf16(subkey,-1);
+    for(i=0;subkey2[i];i++)
+       if (subkey2[i]=='/')
+           subkey2[i]='\\';
+    result=RegCreateKeyExW(key,subkey2,0,NULL,REG_OPTION_NON_VOLATILE,
+      KEY_READ|KEY_WRITE,NULL,out,NULL);
+    free(subkey2);
+    return result;
+    
+}
+
+HRESULT whelk_reg_get_value(HKEY key,const char *subkey,const char *value,
+  DWORD *type,void **data,DWORD *nb)
+{
+    HRESULT result;
+    WCHAR *value2,*str2;
+    DWORD len;
+    if (subkey && *subkey)
+    {
+       result=whelk_reg_open_key(key,subkey,&key);
+       if (result!=ERROR_SUCCESS)
+           return result;
+    }
+    value2=whelk_utf8_to_utf16(value,-1);
+    *nb=0;
+    *data=NULL;
+    result=RegQueryValueExW(key,value2,0,type,*data,nb);
+    if (result==ERROR_MORE_DATA)
+    {
+       *data=malloc(*nb);
+       result=RegQueryValueExW(key,value2,0,type,*data,nb);
+    }
+    free(value2);
+    if (subkey && *subkey)
+       (void)whelk_reg_close_key(key);
+    if (result!=ERROR_SUCCESS)
+    {
+       free(*data);
+       *data=NULL;
+    }
+    else if (*type==REG_SZ || *type==REG_EXPAND_SZ)
+    {
+       str2=*data;
+       len=*nb/2;
+       if (!str2[len-1])       /* Cope with unterminated strings */
+           len--;
+       *data=whelk_utf16_to_utf8(str2,len);
+       *nb=strlen(*data)+1;
+       free(str2);
+    }
+    return result;
+}
+
+/*
+ * To delete a value, set data to NULL.
+ */
+
+HRESULT whelk_reg_set_value(HKEY key,const char *subkey,const char *value,
+  DWORD type,const void *data,int nb)
+{
+    HRESULT result;
+    WCHAR *value2,*str2;
+    if (subkey && *subkey)
+    {
+       if (data)
+           result=whelk_reg_create_key(key,subkey,&key);
+       else
+       {
+           result=whelk_reg_open_key(key,subkey,&key);
+           if (result==ERROR_FILE_NOT_FOUND || result==ERROR_PATH_NOT_FOUND)
+               return ERROR_SUCCESS;
+       }
+       if (result!=ERROR_SUCCESS)
+           return result;
+    }
+    value2=whelk_utf8_to_utf16(value,-1);
+    if (data)
+    {
+       /* FIXME: Support REG_MULTI_SZ */
+       if (type==REG_SZ || type==REG_EXPAND_SZ)
+       {
+           str2=whelk_utf8_to_utf16(data,nb);
+           nb=(lstrlenW(str2)+1)*sizeof(WCHAR);
+           data=str2;
+       }
+       result=RegSetValueExW(key,value2,0,type,data,nb);
+       if (type==REG_SZ || type==REG_EXPAND_SZ)
+           free(str2);
+    }
+    else
+       result=RegDeleteValueW(key,value2);
+    free(value2);
+    if (subkey && *subkey)
+       (void)whelk_reg_close_key(key);
+    return result;
+}
+
+static HRESULT whelk_reg_delete_key_wide(HKEY key,WCHAR *subkey)
+{
+    HRESULT result,r;
+    HKEY skey;
+    int i;
+    DWORD nsubkeys;
+    DWORD name_len,max_name_len;       /* In WCHARs */
+    WCHAR *name;
+    result=RegOpenKeyExW(key,subkey,0,KEY_READ|KEY_WRITE,&skey);
+    if (result==ERROR_FILE_NOT_FOUND || result==ERROR_PATH_NOT_FOUND)
+       return ERROR_SUCCESS;
+    else if (result!=ERROR_SUCCESS)
+       return result;
+    result=RegQueryInfoKeyW(skey,NULL,NULL,NULL,&nsubkeys,&max_name_len,NULL,
+      NULL,NULL,NULL,NULL,NULL);
+    if (result!=ERROR_SUCCESS)
+    {
+       RegCloseKey(skey);
+       return result;
+    }
+    max_name_len++;                    /* For terminator */
+    name=malloc(max_name_len*sizeof(WCHAR));
+    for(i=nsubkeys-1;i>=0;i--)
+    {
+       name_len=max_name_len;
+       r=RegEnumKeyExW(skey,i,name,&name_len,NULL,NULL,NULL,NULL);
+       if (r==ERROR_SUCCESS)
+           r=whelk_reg_delete_key_wide(skey,name);
+       if (r!=ERROR_SUCCESS)
+           result=r;
+    }
+    free(name);
+    RegCloseKey(skey);
+    if (result==ERROR_SUCCESS)
+       result=RegDeleteKeyW(key,subkey);
+    return result;
+}
+
+HRESULT whelk_reg_delete_key(HKEY key,const char *subkey)
+{
+    HRESULT result;
+    WCHAR *subkey2;
+    if (!subkey || !*subkey)
+       return ERROR_INVALID_PARAMETER;
+    subkey2=whelk_utf8_to_utf16(subkey,-1);
+    result=whelk_reg_delete_key_wide(key,subkey2);
+    free(subkey2);
+    return result;
+}
diff --git a/whelk/shelllink.c b/whelk/shelllink.c
new file mode 100644 (file)
index 0000000..8492e08
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdlib.h>
+#define INITGUID
+#define COBJMACROS
+#include <windows.h>
+#include <objbase.h>
+#include <objidl.h>
+#include <shlobj.h>
+#include <shlguid.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "_whelk.h"
+
+int whelk_create_short_cut(lua_State *L)
+{
+    int i;
+    const char *link_path=luaL_checkstring(L,1);
+    const char *target_path=luaL_checkstring(L,2);
+    const char *description=luaL_checkstring(L,3);
+    WCHAR *utf16;
+    IShellLinkW *sl;
+    IPersistFile *pf;
+    HRESULT result,co_initialized;
+    co_initialized=CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);
+    result=CoCreateInstance(&CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,
+      &IID_IShellLinkW,(void **)&sl);
+    if (FAILED(result))
+    {
+       lua_pushnil(L);
+       lua_pushfstring(L,"Failed to create shortcut");
+       lua_pushinteger(L,result);
+       if (co_initialized==S_OK || co_initialized==S_FALSE)
+           CoUninitialize();
+       return 3;
+    }
+    utf16=whelk_utf8_to_utf16(target_path,-1);
+    for(i=0;utf16[i];i++)
+       if (utf16[i]=='/')
+           utf16[i]='\\';
+    IShellLinkW_SetPath(sl,utf16);
+    free(utf16);
+    if (*description)
+    {
+       utf16=whelk_utf8_to_utf16(description,-1);
+       IShellLinkW_SetDescription(sl,utf16);
+       free(utf16);
+    }
+    result=IShellLinkW_QueryInterface(sl,&IID_IPersistFile,(void **)&pf);
+    if (FAILED(result))
+    {
+       IShellLinkW_Release(sl);
+       lua_pushnil(L);
+       lua_pushfstring(L,"Failed to create shortcut");
+       lua_pushinteger(L,result);
+       if (co_initialized==S_OK || co_initialized==S_FALSE)
+           CoUninitialize();
+       return 3;
+    }
+    utf16=whelk_utf8_to_utf16(link_path,-1);
+    result=IPersistFile_Save(pf,utf16,0);
+    free(utf16);
+    IPersistFile_Release(pf);
+    IShellLinkW_Release(sl);
+    if (co_initialized==S_OK || co_initialized==S_FALSE)
+       CoUninitialize();
+    if (FAILED(result))
+    {
+       lua_pushnil(L);
+       lua_pushfstring(L,"Failed to create shortcut");
+       lua_pushinteger(L,result);
+       return 3;
+    }
+    else
+       return 0;
+}
diff --git a/whelk/unicode.c b/whelk/unicode.c
new file mode 100644 (file)
index 0000000..763f978
--- /dev/null
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <windows.h>
+#include <winnls.h>
+#include "_whelk.h"
+
+char *whelk_utf16_to_utf8(const WCHAR *utf16,int len)
+{
+    int n;
+    char *utf8;
+    n=WideCharToMultiByte(CP_UTF8,0,utf16,len,NULL,0,NULL,NULL);
+    if (n)
+    {
+       utf8=malloc(n);
+       if (utf8)
+           WideCharToMultiByte(CP_UTF8,0,utf16,len,utf8,n,NULL,NULL);
+    }
+    else
+       utf8=NULL;
+    return utf8;
+}
+
+WCHAR *whelk_utf8_to_utf16(const char *utf8,int len)
+{
+    int n;
+    WCHAR *utf16;
+    n=MultiByteToWideChar(CP_UTF8,0,utf8,len,NULL,0);
+    if (n)
+    {
+       utf16=malloc(n*sizeof(WCHAR));
+       if (utf16)
+           MultiByteToWideChar(CP_UTF8,0,utf8,len,utf16,n);
+    }
+    else
+       utf16=NULL;
+    return utf16;
+}
diff --git a/whelk/whelk.c b/whelk/whelk.c
new file mode 100644 (file)
index 0000000..dc3c155
--- /dev/null
@@ -0,0 +1,50 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "config.h"
+#include "_whelk.h"
+
+int whelk_perror(lua_State *L,const char *s)
+{
+    lua_pushnil(L);
+    if (s)
+       lua_pushfstring(L,"%s: %s",s,strerror(errno));
+    else
+       lua_pushstring(L,strerror(errno));
+    lua_pushinteger(L,errno);
+    return 3;
+}
+
+static int whelk_unsupported(lua_State *L)
+{
+    errno=ENOSYS;
+    return whelk_perror(L,NULL);
+}
+
+#ifdef __WIN32__
+#define WIN32_ONLY(func)       func
+#else
+#define WIN32_ONLY(func)       whelk_unsupported
+#endif
+
+static const luaL_reg whelk_functions[]={
+    { "GetFolderPath",WIN32_ONLY(whelk_get_folder_path) },
+    { "CreateShortCut",WIN32_ONLY(whelk_create_short_cut) },
+    { NULL }
+};
+
+LUALIB_API int luaopen_whelk(lua_State *L)
+{
+    luaL_register(L,"whelk",whelk_functions);
+    lua_pushliteral(L,"version");
+    lua_pushliteral(L,PACKAGE_STRING);
+    lua_settable(L,-3);
+#ifdef __WIN32__
+    whelk_open_get_folder_path(L);
+    whelk_open_reg_keys(L);
+#endif
+    return 1;
+}
diff --git a/whelk/whelk.h b/whelk/whelk.h
new file mode 100644 (file)
index 0000000..7f7025d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __WHELK_H__
+#define __WHELK_H__
+
+#include <lua.h>
+#include <lualib.h>
+
+LUALIB_API int luaopen_whelk(lua_State *L);
+
+#endif  /* __WHELK_H__ */