Add new function to spawn child 0.2
authorJ. Ali Harlow <ali@juiblex.co.uk>
Tue Aug 18 14:11:42 2009 +0100 (2009-08-18)
changeset 347fa028d40b3
parent 2 14482ca89223
child 4 034b16d9eebb
child 5 0ea90868d987
Add new function to spawn child
configure.ac
whelk/Makefile.am
whelk/_whelk.h
whelk/spawn.c
whelk/string.c
whelk/wait.c
whelk/whelk.c
     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