#include <lua.h>
#include <lualib.h>
+#include <unistd.h> /* For ssize_t */
#ifdef __WIN32__
#include <windows.h>
#endif
lua_settable(L,-3); \
} while(0)
+struct whelk_string {
+ size_t len,alloc;
+ char *buffer;
+};
+
+#ifdef __WIN32__
+struct whelk_wait {
+ int no_objects;
+ HANDLE *objects;
+};
+#endif
+
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);
+int whelk_spawn(lua_State *L);
+
+char *whelk_string_prealloc(struct whelk_string *string,size_t len);
+void whelk_string_seek(struct whelk_string *string,ssize_t offset);
+char *whelk_string_finalize(struct whelk_string *string);
+void whelk_string_free(struct whelk_string *string);
#ifdef __WIN32__
char *whelk_utf16_to_utf8(const WCHAR *ucs2,int len);
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);
+
+int whelk_wait_add_object(struct whelk_wait *wait,HANDLE object);
+void whelk_wait_remove_object(struct whelk_wait *wait,HANDLE object);
+HANDLE whelk_wait_poll(struct whelk_wait *wait);
+void whelk_wait_free(struct whelk_wait *wait);
#endif
--- /dev/null
+#include <stdlib.h>
+#include <errno.h>
+#include <windows.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "_whelk.h"
+
+static void whelk_close_pipe(HANDLE pipe[2])
+{
+ CloseHandle(pipe[0]);
+ CloseHandle(pipe[1]);
+}
+
+/* Create a pipe with one end inheritable */
+
+static BOOL whelk_child_pipe(HANDLE pipe[2],BOOL to_child)
+{
+ SECURITY_ATTRIBUTES sa={0};
+ HANDLE h;
+ sa.nLength=sizeof(sa);
+ sa.bInheritHandle=TRUE;
+ if (!CreatePipe(pipe+0,pipe+1,&sa,0))
+ return FALSE;
+ if (!DuplicateHandle(GetCurrentProcess(),pipe[to_child?0:1],
+ GetCurrentProcess(),&h,0,TRUE,DUPLICATE_SAME_ACCESS))
+ {
+ whelk_close_pipe(pipe);
+ return FALSE;
+ }
+ CloseHandle(pipe[to_child?0:1]);
+ pipe[to_child?0:1]=h;
+ return TRUE;
+}
+
+/*
+ * spawn(application_name,command-line,working-directory,standard-input)
+ *
+ * Returns two strings (the data written to standard output and standard error
+ * respectively) and the exit code.
+ */
+
+int whelk_spawn(lua_State *L)
+{
+ STARTUPINFOW si={0};
+ PROCESS_INFORMATION pi={0};
+ WCHAR *application_name=whelk_utf8_to_utf16(luaL_checkstring(L,1),-1);
+ WCHAR *command_line=whelk_utf8_to_utf16(luaL_checkstring(L,2),-1);
+ WCHAR *working_directory=whelk_utf8_to_utf16(luaL_checkstring(L,3),-1);
+ size_t stdin_len;
+ const char *standard_input=luaL_checklstring(L,4,&stdin_len);
+ struct whelk_string standard_output={0};
+ struct whelk_string standard_error={0};
+ char *buffer;
+ HANDLE stdin_pipe[2],stdout_pipe[2],stderr_pipe[2],h;
+ struct whelk_wait wait={0};
+ DWORD nb;
+ int exitcode;
+ if (!whelk_child_pipe(stdin_pipe,TRUE))
+ {
+ free(application_name);
+ free(command_line);
+ free(working_directory);
+ errno=EMFILE;
+ return whelk_perror(L,NULL);
+ }
+ if (!whelk_child_pipe(stdout_pipe,FALSE))
+ {
+ free(application_name);
+ free(command_line);
+ free(working_directory);
+ whelk_close_pipe(stdin_pipe);
+ errno=EMFILE;
+ return whelk_perror(L,NULL);
+ }
+ if (!whelk_child_pipe(stderr_pipe,FALSE))
+ {
+ free(application_name);
+ free(command_line);
+ free(working_directory);
+ whelk_close_pipe(stdin_pipe);
+ whelk_close_pipe(stdout_pipe);
+ errno=EMFILE;
+ return whelk_perror(L,NULL);
+ }
+ si.cb=sizeof(si);
+ si.dwFlags=STARTF_USESTDHANDLES;
+ si.hStdInput=stdin_pipe[0];
+ si.hStdOutput=stdout_pipe[1];
+ si.hStdError=stderr_pipe[1];
+ if (!CreateProcessW(application_name,command_line,NULL,NULL,TRUE,
+ CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS,NULL,working_directory,
+ &si,&pi))
+ {
+ free(application_name);
+ free(command_line);
+ free(working_directory);
+ whelk_close_pipe(stdin_pipe);
+ whelk_close_pipe(stdout_pipe);
+ whelk_close_pipe(stderr_pipe);
+ errno=EACCES;
+ return whelk_perror(L,NULL);
+ }
+ free(application_name);
+ free(command_line);
+ free(working_directory);
+ CloseHandle(stdout_pipe[1]);
+ CloseHandle(stderr_pipe[1]);
+ whelk_wait_add_object(&wait,stdout_pipe[0]);
+ whelk_wait_add_object(&wait,stderr_pipe[0]);
+ whelk_wait_add_object(&wait,pi.hProcess);
+ if (standard_input)
+ whelk_wait_add_object(&wait,stdin_pipe[1]);
+ else
+ {
+ whelk_close_pipe(stdin_pipe);
+ stdin_pipe[1]=INVALID_HANDLE_VALUE;
+ }
+ for(;;)
+ {
+ h=whelk_wait_poll(&wait);
+ if (h==INVALID_HANDLE_VALUE)
+ break;
+ else if (h==stdout_pipe[0])
+ {
+ buffer=whelk_string_prealloc(&standard_output,1024);
+ if (ReadFile(stdout_pipe[0],buffer,1024,&nb,NULL))
+ whelk_string_seek(&standard_output,nb);
+ else
+ whelk_wait_remove_object(&wait,stdout_pipe[0]);
+ }
+ else if (h==stderr_pipe[0])
+ {
+ buffer=whelk_string_prealloc(&standard_error,1024);
+ if (ReadFile(stderr_pipe[0],buffer,1024,&nb,NULL))
+ whelk_string_seek(&standard_error,nb);
+ else
+ whelk_wait_remove_object(&wait,stderr_pipe[0]);
+ }
+ else if (h==pi.hProcess)
+ break;
+ else if (h==stdin_pipe[1])
+ {
+ nb=max(stdin_len,512);
+ WriteFile(stdin_pipe[1],standard_input,nb,NULL,NULL);
+ standard_input+=nb;
+ stdin_len-=nb;
+ if (!stdin_len)
+ {
+ whelk_wait_remove_object(&wait,stdin_pipe[1]);
+ whelk_close_pipe(stdin_pipe);
+ standard_input=NULL;
+ }
+ }
+ }
+ whelk_wait_free(&wait);
+ if (standard_input)
+ whelk_close_pipe(stdin_pipe);
+ if (GetExitCodeProcess(pi.hProcess,&nb))
+ exitcode=(int)nb;
+ else
+ exitcode=-1;
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ CloseHandle(stdout_pipe[0]);
+ CloseHandle(stderr_pipe[0]);
+ whelk_string_finalize(&standard_output);
+ whelk_string_finalize(&standard_error);
+ lua_pushlstring(L,standard_output.buffer,standard_output.len);
+ lua_pushlstring(L,standard_error.buffer,standard_error.len);
+ whelk_string_free(&standard_output);
+ whelk_string_free(&standard_error);
+ lua_pushnumber(L,exitcode);
+ return 3;
+}