1.1 --- a/configure.ac Fri Aug 14 14:54:39 2009 +0100
1.2 +++ b/configure.ac Tue Aug 18 14:11:42 2009 +0100
1.3 @@ -22,6 +22,17 @@
1.4 esac
1.5 AM_CONDITIONAL(WHELK_MINGW,[test -n "$host_mingw"])
1.6
1.7 +# libtool versioning - this applies to all libraries in this package
1.8 +#
1.9 +# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
1.10 +#
1.11 +LT_CURRENT=1
1.12 +LT_REVISION=0
1.13 +LT_AGE=1
1.14 +AC_SUBST(LT_CURRENT)
1.15 +AC_SUBST(LT_REVISION)
1.16 +AC_SUBST(LT_AGE)
1.17 +
1.18 ##################################################
1.19 # Checks for programs.
1.20 ##################################################
2.1 --- a/whelk/Makefile.am Fri Aug 14 14:54:39 2009 +0100
2.2 +++ b/whelk/Makefile.am Tue Aug 18 14:11:42 2009 +0100
2.3 @@ -6,11 +6,12 @@
2.4
2.5 lib_LTLIBRARIES=libwhelk.la
2.6
2.7 -libwhelk_la_SOURCES=whelk.c whelk.h _whelk.h
2.8 +libwhelk_la_SOURCES=whelk.c whelk.h _whelk.h string.c
2.9 if WHELK_MINGW
2.10 libwhelk_la_SOURCES+=unicode.c get_folder_path.c registry.c reg_keys.c \
2.11 - shelllink.c
2.12 + shelllink.c spawn.c wait.c
2.13 endif
2.14 +libwhelk_la_LDFLAGS=-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
2.15
2.16 pkginclude_HEADERS=whelk.h
2.17
3.1 --- a/whelk/_whelk.h Fri Aug 14 14:54:39 2009 +0100
3.2 +++ b/whelk/_whelk.h Tue Aug 18 14:11:42 2009 +0100
3.3 @@ -1,5 +1,6 @@
3.4 #include <lua.h>
3.5 #include <lualib.h>
3.6 +#include <unistd.h> /* For ssize_t */
3.7 #ifdef __WIN32__
3.8 #include <windows.h>
3.9 #endif
3.10 @@ -12,11 +13,29 @@
3.11 lua_settable(L,-3); \
3.12 } while(0)
3.13
3.14 +struct whelk_string {
3.15 + size_t len,alloc;
3.16 + char *buffer;
3.17 +};
3.18 +
3.19 +#ifdef __WIN32__
3.20 +struct whelk_wait {
3.21 + int no_objects;
3.22 + HANDLE *objects;
3.23 +};
3.24 +#endif
3.25 +
3.26 int whelk_perror(lua_State *L,const char *s);
3.27 int whelk_get_folder_path(lua_State *L);
3.28 void whelk_open_get_folder_path(lua_State *L);
3.29 void whelk_open_reg_keys(lua_State *L);
3.30 int whelk_create_short_cut(lua_State *L);
3.31 +int whelk_spawn(lua_State *L);
3.32 +
3.33 +char *whelk_string_prealloc(struct whelk_string *string,size_t len);
3.34 +void whelk_string_seek(struct whelk_string *string,ssize_t offset);
3.35 +char *whelk_string_finalize(struct whelk_string *string);
3.36 +void whelk_string_free(struct whelk_string *string);
3.37
3.38 #ifdef __WIN32__
3.39 char *whelk_utf16_to_utf8(const WCHAR *ucs2,int len);
3.40 @@ -29,4 +48,9 @@
3.41 HRESULT whelk_reg_set_value(HKEY key,const char *subkey,const char *value,
3.42 DWORD type,const void *data,int nb);
3.43 HRESULT whelk_reg_delete_key(HKEY key,const char *subkey);
3.44 +
3.45 +int whelk_wait_add_object(struct whelk_wait *wait,HANDLE object);
3.46 +void whelk_wait_remove_object(struct whelk_wait *wait,HANDLE object);
3.47 +HANDLE whelk_wait_poll(struct whelk_wait *wait);
3.48 +void whelk_wait_free(struct whelk_wait *wait);
3.49 #endif
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/whelk/spawn.c Tue Aug 18 14:11:42 2009 +0100
4.3 @@ -0,0 +1,175 @@
4.4 +#include <stdlib.h>
4.5 +#include <errno.h>
4.6 +#include <windows.h>
4.7 +#include <lua.h>
4.8 +#include <lualib.h>
4.9 +#include <lauxlib.h>
4.10 +#include "_whelk.h"
4.11 +
4.12 +static void whelk_close_pipe(HANDLE pipe[2])
4.13 +{
4.14 + CloseHandle(pipe[0]);
4.15 + CloseHandle(pipe[1]);
4.16 +}
4.17 +
4.18 +/* Create a pipe with one end inheritable */
4.19 +
4.20 +static BOOL whelk_child_pipe(HANDLE pipe[2],BOOL to_child)
4.21 +{
4.22 + SECURITY_ATTRIBUTES sa={0};
4.23 + HANDLE h;
4.24 + sa.nLength=sizeof(sa);
4.25 + sa.bInheritHandle=TRUE;
4.26 + if (!CreatePipe(pipe+0,pipe+1,&sa,0))
4.27 + return FALSE;
4.28 + if (!DuplicateHandle(GetCurrentProcess(),pipe[to_child?0:1],
4.29 + GetCurrentProcess(),&h,0,TRUE,DUPLICATE_SAME_ACCESS))
4.30 + {
4.31 + whelk_close_pipe(pipe);
4.32 + return FALSE;
4.33 + }
4.34 + CloseHandle(pipe[to_child?0:1]);
4.35 + pipe[to_child?0:1]=h;
4.36 + return TRUE;
4.37 +}
4.38 +
4.39 +/*
4.40 + * spawn(application_name,command-line,working-directory,standard-input)
4.41 + *
4.42 + * Returns two strings (the data written to standard output and standard error
4.43 + * respectively) and the exit code.
4.44 + */
4.45 +
4.46 +int whelk_spawn(lua_State *L)
4.47 +{
4.48 + STARTUPINFOW si={0};
4.49 + PROCESS_INFORMATION pi={0};
4.50 + WCHAR *application_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1);
4.51 + WCHAR *command_line=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1);
4.52 + WCHAR *working_directory=whelk_utf8_to_utf16(luaL_checkstring(L,3),-1);
4.53 + size_t stdin_len;
4.54 + const char *standard_input=luaL_checklstring(L,4,&stdin_len);
4.55 + struct whelk_string standard_output={0};
4.56 + struct whelk_string standard_error={0};
4.57 + char *buffer;
4.58 + HANDLE stdin_pipe[2],stdout_pipe[2],stderr_pipe[2],h;
4.59 + struct whelk_wait wait={0};
4.60 + DWORD nb;
4.61 + int exitcode;
4.62 + if (!whelk_child_pipe(stdin_pipe,TRUE))
4.63 + {
4.64 + free(application_name);
4.65 + free(command_line);
4.66 + free(working_directory);
4.67 + errno=EMFILE;
4.68 + return whelk_perror(L,NULL);
4.69 + }
4.70 + if (!whelk_child_pipe(stdout_pipe,FALSE))
4.71 + {
4.72 + free(application_name);
4.73 + free(command_line);
4.74 + free(working_directory);
4.75 + whelk_close_pipe(stdin_pipe);
4.76 + errno=EMFILE;
4.77 + return whelk_perror(L,NULL);
4.78 + }
4.79 + if (!whelk_child_pipe(stderr_pipe,FALSE))
4.80 + {
4.81 + free(application_name);
4.82 + free(command_line);
4.83 + free(working_directory);
4.84 + whelk_close_pipe(stdin_pipe);
4.85 + whelk_close_pipe(stdout_pipe);
4.86 + errno=EMFILE;
4.87 + return whelk_perror(L,NULL);
4.88 + }
4.89 + si.cb=sizeof(si);
4.90 + si.dwFlags=STARTF_USESTDHANDLES;
4.91 + si.hStdInput=stdin_pipe[0];
4.92 + si.hStdOutput=stdout_pipe[1];
4.93 + si.hStdError=stderr_pipe[1];
4.94 + if (!CreateProcessW(application_name,command_line,NULL,NULL,TRUE,
4.95 + CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS,NULL,working_directory,
4.96 + &si,&pi))
4.97 + {
4.98 + free(application_name);
4.99 + free(command_line);
4.100 + free(working_directory);
4.101 + whelk_close_pipe(stdin_pipe);
4.102 + whelk_close_pipe(stdout_pipe);
4.103 + whelk_close_pipe(stderr_pipe);
4.104 + errno=EACCES;
4.105 + return whelk_perror(L,NULL);
4.106 + }
4.107 + free(application_name);
4.108 + free(command_line);
4.109 + free(working_directory);
4.110 + CloseHandle(stdout_pipe[1]);
4.111 + CloseHandle(stderr_pipe[1]);
4.112 + whelk_wait_add_object(&wait,stdout_pipe[0]);
4.113 + whelk_wait_add_object(&wait,stderr_pipe[0]);
4.114 + whelk_wait_add_object(&wait,pi.hProcess);
4.115 + if (standard_input)
4.116 + whelk_wait_add_object(&wait,stdin_pipe[1]);
4.117 + else
4.118 + {
4.119 + whelk_close_pipe(stdin_pipe);
4.120 + stdin_pipe[1]=INVALID_HANDLE_VALUE;
4.121 + }
4.122 + for(;;)
4.123 + {
4.124 + h=whelk_wait_poll(&wait);
4.125 + if (h==INVALID_HANDLE_VALUE)
4.126 + break;
4.127 + else if (h==stdout_pipe[0])
4.128 + {
4.129 + buffer=whelk_string_prealloc(&standard_output,1024);
4.130 + if (ReadFile(stdout_pipe[0],buffer,1024,&nb,NULL))
4.131 + whelk_string_seek(&standard_output,nb);
4.132 + else
4.133 + whelk_wait_remove_object(&wait,stdout_pipe[0]);
4.134 + }
4.135 + else if (h==stderr_pipe[0])
4.136 + {
4.137 + buffer=whelk_string_prealloc(&standard_error,1024);
4.138 + if (ReadFile(stderr_pipe[0],buffer,1024,&nb,NULL))
4.139 + whelk_string_seek(&standard_error,nb);
4.140 + else
4.141 + whelk_wait_remove_object(&wait,stderr_pipe[0]);
4.142 + }
4.143 + else if (h==pi.hProcess)
4.144 + break;
4.145 + else if (h==stdin_pipe[1])
4.146 + {
4.147 + nb=max(stdin_len,512);
4.148 + WriteFile(stdin_pipe[1],standard_input,nb,NULL,NULL);
4.149 + standard_input+=nb;
4.150 + stdin_len-=nb;
4.151 + if (!stdin_len)
4.152 + {
4.153 + whelk_wait_remove_object(&wait,stdin_pipe[1]);
4.154 + whelk_close_pipe(stdin_pipe);
4.155 + standard_input=NULL;
4.156 + }
4.157 + }
4.158 + }
4.159 + whelk_wait_free(&wait);
4.160 + if (standard_input)
4.161 + whelk_close_pipe(stdin_pipe);
4.162 + if (GetExitCodeProcess(pi.hProcess,&nb))
4.163 + exitcode=(int)nb;
4.164 + else
4.165 + exitcode=-1;
4.166 + CloseHandle(pi.hThread);
4.167 + CloseHandle(pi.hProcess);
4.168 + CloseHandle(stdout_pipe[0]);
4.169 + CloseHandle(stderr_pipe[0]);
4.170 + whelk_string_finalize(&standard_output);
4.171 + whelk_string_finalize(&standard_error);
4.172 + lua_pushlstring(L,standard_output.buffer,standard_output.len);
4.173 + lua_pushlstring(L,standard_error.buffer,standard_error.len);
4.174 + whelk_string_free(&standard_output);
4.175 + whelk_string_free(&standard_error);
4.176 + lua_pushnumber(L,exitcode);
4.177 + return 3;
4.178 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/whelk/string.c Tue Aug 18 14:11:42 2009 +0100
5.3 @@ -0,0 +1,37 @@
5.4 +#include <stdlib.h>
5.5 +#include "_whelk.h"
5.6 +
5.7 +char *whelk_string_prealloc(struct whelk_string *string,size_t len)
5.8 +{
5.9 + char *new;
5.10 + if (string->alloc<string->len+len)
5.11 + {
5.12 + new=realloc(string->buffer,string->len+len);
5.13 + if (!new)
5.14 + return NULL;
5.15 + string->buffer=new;
5.16 + string->alloc=string->len+len;
5.17 + }
5.18 + return string->buffer+string->len;
5.19 +}
5.20 +
5.21 +void whelk_string_seek(struct whelk_string *string,ssize_t offset)
5.22 +{
5.23 + if (offset>=0 || string->len>=(size_t)-offset)
5.24 + string->len+=offset;
5.25 + else
5.26 + string->len=0;
5.27 +}
5.28 +
5.29 +char *whelk_string_finalize(struct whelk_string *string)
5.30 +{
5.31 + whelk_string_prealloc(string,1);
5.32 + string->buffer[string->len]='\0';
5.33 + return string->buffer;
5.34 +}
5.35 +
5.36 +void whelk_string_free(struct whelk_string *string)
5.37 +{
5.38 + free(string->buffer);
5.39 + memset(string,0,sizeof(*string));
5.40 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/whelk/wait.c Tue Aug 18 14:11:42 2009 +0100
6.3 @@ -0,0 +1,47 @@
6.4 +#include <stdlib.h>
6.5 +#include <windows.h>
6.6 +#include "_whelk.h"
6.7 +
6.8 +int whelk_wait_add_object(struct whelk_wait *wait,HANDLE object)
6.9 +{
6.10 + HANDLE *new;
6.11 + new=realloc(wait->objects,wait->no_objects+1);
6.12 + if (!new)
6.13 + return -1;
6.14 + wait->objects=new;
6.15 + wait->objects[wait->no_objects++]=object;
6.16 + return 0;
6.17 +}
6.18 +
6.19 +void whelk_wait_remove_object(struct whelk_wait *wait,HANDLE object)
6.20 +{
6.21 + int i;
6.22 + for(i=0;i<wait->no_objects;i++)
6.23 + if (wait->objects[i]==object)
6.24 + break;
6.25 + if (i!=wait->no_objects-1)
6.26 + memcpy(wait->objects+i,wait->objects+i+1,
6.27 + (wait->no_objects-i-1)*sizeof(*wait->objects));
6.28 + wait->no_objects--;
6.29 +}
6.30 +
6.31 +/*
6.32 + * Where two or more objects are ready,
6.33 + * the object added first is returned.
6.34 + */
6.35 +
6.36 +HANDLE whelk_wait_poll(struct whelk_wait *wait)
6.37 +{
6.38 + DWORD retval;
6.39 + retval=WaitForMultipleObjects(wait->no_objects,wait->objects,FALSE,
6.40 + INFINITE);
6.41 + if (retval>=WAIT_OBJECT_0 && retval-WAIT_OBJECT_0<wait->no_objects)
6.42 + return wait->objects[retval-WAIT_OBJECT_0];
6.43 + else
6.44 + return INVALID_HANDLE_VALUE;
6.45 +}
6.46 +
6.47 +void whelk_wait_free(struct whelk_wait *wait)
6.48 +{
6.49 + free(wait->objects);
6.50 +}
7.1 --- a/whelk/whelk.c Fri Aug 14 14:54:39 2009 +0100
7.2 +++ b/whelk/whelk.c Tue Aug 18 14:11:42 2009 +0100
7.3 @@ -33,6 +33,7 @@
7.4 static const luaL_reg whelk_functions[]={
7.5 { "GetFolderPath",WIN32_ONLY(whelk_get_folder_path) },
7.6 { "CreateShortCut",WIN32_ONLY(whelk_create_short_cut) },
7.7 + { "Spawn",WIN32_ONLY(whelk_spawn) },
7.8 { NULL }
7.9 };
7.10