rev 737 - in trunk: . include/prothon modules/OS src

SVN User <[email protected]> Thu, 15 Jul 2004 01:46:53 -0400
Newsgroups gmane.comp.lang.prothon.cvs
Message-ID <[email protected]>
Author: mark
Date: 2004-07-15 01:46:48 -0400 (Thu, 15 Jul 2004)
New Revision: 737

Modified:
   trunk/STATUS.txt
   trunk/include/prothon/prothon.h
   trunk/include/prothon/prothon_dll.h
   trunk/modules/OS/OS.c
   trunk/src/builtins-file.c
   trunk/src/object.c
Log:
added process object with methods, untested

Modified: trunk/STATUS.txt
===================================================================
--- trunk/STATUS.txt	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/STATUS.txt	2004-07-15 05:46:48 UTC (rev 737)
@@ -1,15 +1,16 @@
 
 ----------------------- TO-DO (highest priority first) ------------------------
 
---- add pOpen, pOpen2, pOpen3, & pOpen4 to os module
+--- add Process object to os module
 --- write regression app in Prothon
 
+--- check all PEPs
+--- revisit all methods to change list returns into generators
+
 --- bug in simple instantiation in the console in 710
 
---- revisit all methods to change list returns into generators
+--- getAttr, delAttr, getAttrNoProp, setAttrNoProp, & delAttrNoProp
 
---- check all PEPs
-
 --- check into tcl and twisted about async io
 
 --- -o optimize cmd-line option to remove asserts

Modified: trunk/include/prothon/prothon.h
===================================================================
--- trunk/include/prothon/prothon.h	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/include/prothon/prothon.h	2004-07-15 05:46:48 UTC (rev 737)
@@ -340,6 +340,8 @@
 	MUTEX_PROTO,		//   Mutex
 	PARMPTR_PROTO,		//
 	PROP_PROTO,			//
+	FILE_PROTO,         //
+	TEXTFILE_PROTO,     //
   
 // Exceptions
 	EXCEPTION,			//    Exception
@@ -558,6 +560,10 @@
 // Clobbers binary data in dest object (copy)
 void copy_object_data(isp ist, obj_p copy, obj_p obj);
 
+// SET_FILE_OBJ_DATA: low-level routine to create a file object
+void set_file_obj_data(isp ist, obj_p file_obj, obj_p filename, obj_p mode,
+						  	    apr_file_t *fp, int bufsize, apr_int32_t flags);
+
 // SET_TYPE_IF_EXC: Set data type and owner, throw exception if already set
 #define SET_TYPE_IF_EXC(owner, obj, type)				\
 	if ((obj)->data_type != DATA_TYPE_NONE)				\
@@ -1096,13 +1102,16 @@
 
 
 #define SEQ_OR_PARAM(index, var)	/* obj_p var; */						\
-	if ( has_proto(ist, ITEM, OBJ(STRING_PROTO)) ||					        \
-		!has_proto(ist, ITEM, OBJ(SEQ_PROTO))) {						    \
+do { obj_p list, item = index > 0 ? parms[((index)-1)*2+1] :                \
+                              list_item(ist, parms[1], -index);             \
+	if ( has_proto(ist, item, OBJ(STRING_PROTO)) ||					        \
+		!has_proto(ist, item, OBJ(SEQ_PROTO))) {						    \
 		list = NEW_LIST(1);													\
-		list_append(ist, list, ITEM);										\
+		list_append(ist, list, item);										\
 		(var) = list;														\
 	} else																	\
-		(var) = ITEM
+		(var) = item;														\
+} while (FALSE)
 
 // FORM_RPARAM: convenience macro for single formal right parameter
 // Defines a formal label/default-value list that matches  func(rparam).

Modified: trunk/include/prothon/prothon_dll.h
===================================================================
--- trunk/include/prothon/prothon_dll.h	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/include/prothon/prothon_dll.h	2004-07-15 05:46:48 UTC (rev 737)
@@ -135,7 +135,10 @@
 	i32_t		(*int2i32t)(isp ist, obj_p self);
 	i64_t		(*int2i64t)(isp ist, obj_p self);
 	char*		(*pr2c_strptr)(isp ist, obj_p str_obj);
+	void		(*set_file_obj_data)(isp ist, obj_p file_obj, obj_p filename, obj_p mode,
+						  	         apr_file_t *fp, int bufsize, apr_int32_t flags);
 
+
 	void*		(*pr_malloc)(size_t nbytes);
 	void*		(*pr_realloc)(void *p, size_t nbytes);
 	void		(*pr_free)(void *p);
@@ -372,6 +375,7 @@
 #define int2i64t		 	(*services->int2i64t)
 #define int2i32t	 		(*services->int2i32t)
 #define pr2c_strptr	 		(*services->pr2c_strptr)
+#define set_file_obj_data	(*services->set_file_obj_data)
 
 #endif // OBJECT_H
 

Modified: trunk/modules/OS/OS.c
===================================================================
--- trunk/modules/OS/OS.c	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/modules/OS/OS.c	2004-07-15 05:46:48 UTC (rev 737)
@@ -58,15 +58,48 @@
 // note: to build this in windows, define NO_APR
 
 MODULE_DECLARE(os);
+MODULE_DECLARE(Process);
 
+#define PROC_STDIN			1
+#define PROC_STDOUT			2
+#define PROC_STDERR			4
+#define PROC_WAIT			8
+#define PROC_SHELLCMD		16
+#define PROC_COPYENV		32
+#define PROC_COPYENVPATH	64
+#define PROC_DAEMON			128
+
+MODULE_CONSTANT_DECLARE(os, STDIN		); 
+MODULE_CONSTANT_DECLARE(os, STDOUT		); 
+MODULE_CONSTANT_DECLARE(os, STDERR		); 
+MODULE_CONSTANT_DECLARE(os, WAIT		); 
+MODULE_CONSTANT_DECLARE(os, SHELLCMD	); 
+MODULE_CONSTANT_DECLARE(os, COPYENV		); 
+MODULE_CONSTANT_DECLARE(os, COPYENVPATH	); 
+MODULE_CONSTANT_DECLARE(os, DAEMON	    ); 
+
 MODULE_START(os)
 {
 	os_OBJ = NEW_OBJ(NULL);
 	MODULE_SET_DOC(os, "Operating System specific routines");
 	set_obj_id(os_OBJ, *, os);
 	MODULE_ADD_TO_BASE(os);
+
+	Process_OBJ = NEW_OBJ(NULL);
+	MODULE_SET_DOC(Process, "Operating System Process Object Prototype");
+	MODULE_ADD_TO_BASE(Process);
+
+	MODULE_CONSTANT_INT(os, STDIN		,   PROC_STDIN			); 
+	MODULE_CONSTANT_INT(os, STDOUT		,   PROC_STDOUT			); 
+	MODULE_CONSTANT_INT(os, STDERR		,   PROC_STDERR			); 
+	MODULE_CONSTANT_INT(os, WAIT		,   PROC_WAIT			); 
+	MODULE_CONSTANT_INT(os, SHELLCMD	,   PROC_SHELLCMD		); 
+	MODULE_CONSTANT_INT(os, COPYENV		,   PROC_COPYENV		); 
+	MODULE_CONSTANT_INT(os, COPYENVPATH	,   PROC_COPYENVPATH	); 
+	MODULE_CONSTANT_INT(os, DAEMON	    ,   PROC_DAEMON			); 
 }
 
+//****************************  os  *******************************************
 DEF(os, system, FPARM1(cmd, NULL)) {
 	if (!has_proto(ist, parms[1], OBJ(STRING_PROTO))) {
 		ist->exception_obj = NEW_OBJ(OBJ(TYPE_EXC));
@@ -77,10 +110,213 @@
 	return NEW_INT(system(pr2c_strptr(ist, parms[1])));
 }
 
+//****************************  Process ***************************************
+typedef struct {
+	data_size_t	size;
+	apr_pool_t* pool;
+	apr_proc_t  proc;
+} proc_t;
+
+typedef proc_t* proc_p;
+
+#define MAX_ARGV_ARGS 128
+#define MAX_ENV_VARS  512
+
+#define SIGKILL 11   // stolen from APR private.h, is this right???
+
+DEF(Process, init_, FPARM4(argV, OBJ(NODEF), flags, NEW_INT(0), dir, OBJ(NONE), env, OBJ(NONE))) {
+	apr_status_t aprerr;
+	apr_procattr_t* attr;
+	apr_pool_t* pool;
+	obj_p argv_list, env_list=NULL, dir;
+	int i, arg_len, env_len, flags;
+	int stdin_flg=APR_NO_PIPE, stdout_flg=APR_NO_PIPE, stderr_flg=APR_NO_PIPE;
+	apr_cmdtype_e cmd_type = 0;
+	proc_p procp;
+	char *argv_arr[MAX_ARGV_ARGS], *env_arr[MAX_ENV_VARS];
+
+	BIN_EMPTY_CHK();
+	SEQ_OR_PARAM(1, argv_list);
+	arg_len = (int) list_len(ist, argv_list);
+	if (arg_len >= MAX_ARGV_ARGS) {
+		raise_exception(ist, OBJ(VALUE_EXC), "%d args is more than the max of %d", arg_len, MAX_ARGV_ARGS-1);
+		return NULL;
+	}
+	for (i=0; i < arg_len; i++) {
+		obj_p str_obj = list_item(ist, argv_list, i);
+		CHECK_TYPE_EXC(str_obj, OBJ(STRING_PROTO), String);
+		argv_arr[i] = pr2c_strptr(ist, str_obj);
+	}
+	argv_arr[i] = NULL;
+	INT_32_PARAM(2, flags);
+	if ((flags & (PROC_STDIN|PROC_STDOUT|PROC_STDERR)) && (flags & PROC_WAIT)) {
+		raise_exception(ist, OBJ(VALUE_EXC), "flags argument cannot specify pipes and WAIT");
+		return NULL;
+	}
+	i = 0;
+	if (flags & PROC_SHELLCMD   ) { cmd_type = APR_SHELLCMD;     i++; }
+	if (flags & PROC_COPYENV	) { cmd_type = APR_PROGRAM_ENV;  i++; }
+	if (flags & PROC_COPYENVPATH) { cmd_type = APR_PROGRAM_PATH; i++; }
+	if (i > 1) {
+		raise_exception(ist, OBJ(VALUE_EXC), "flags can only have one of SHELLCMD, COPYENV, & COPYENVPATH");
+		return NULL;
+	}
+	dir = parms[5]; 
+	if (dir == OBJ(NONE)) dir = NULL;
+	if (parms[7] != OBJ(NONE)) {
+		SEQ_OR_PARAM(4, env_list);
+		env_len = (int) list_len(ist, env_list);
+		if (env_len >= MAX_ENV_VARS) {
+			raise_exception(ist, OBJ(VALUE_EXC), "%d env vars is more than the max of %d", env_len, MAX_ENV_VARS-1);
+			return NULL;
+		}
+		for (i=0; i < env_len; i++) {
+			obj_p str_obj = list_item(ist, argv_list, i);
+			CHECK_TYPE_EXC(str_obj, OBJ(STRING_PROTO), String);
+			env_arr[i] = pr2c_strptr(ist, str_obj);
+		}
+		env_arr[i] = NULL;
+	}
+	aprerr = apr_pool_create(&pool, get_pr_head_pool());
+	IF_APR_ERR("out of memory in Process init_") return NULL;
+	
+	aprerr = apr_procattr_create(&attr, pool);
+	IF_APR_ERR("error in apr_procattr_create") return NULL;
+
+	if (flags & PROC_STDIN)  stdin_flg  = APR_FULL_BLOCK;
+	if (flags & PROC_STDOUT) stdout_flg = APR_FULL_BLOCK;
+	if (flags & PROC_STDERR) stderr_flg = APR_FULL_BLOCK;
+    aprerr = apr_procattr_io_set(attr, stdin_flg, stdout_flg, stderr_flg);
+	IF_APR_ERR("error in apr_procattr_io_set") return NULL;
+
+	if (dir) {
+		char* path = pr2c_strptr(ist, get_attr(ist, dir, sym(ist, "path")));
+		aprerr = apr_procattr_dir_set(attr, path);
+		IF_APR_ERR("error in apr_procattr_dir_set") return NULL;
+	}
+	if (cmd_type) {
+		aprerr = apr_procattr_cmdtype_set(attr, cmd_type);
+		IF_APR_ERR("error in apr_procattr_cmdtype_set") return NULL;
+	}
+	if (flags & PROC_DAEMON) {
+		aprerr = apr_procattr_detach_set(attr, APR_PROC_DETACH_DAEMONIZE); 
+		IF_APR_ERR("error in apr_procattr_detach_set") return NULL;
+	}
+	procp = self->data.ptr = pr_malloc(sizeof(proc_t));
+	DATA_SIZE(self) = (data_size_t) sizeof(proc_t);
+	procp->pool = pool;
+
+	aprerr = apr_proc_create(&procp->proc, argv_arr[0], argv_arr, env_arr, attr, pool);
+	IF_APR_ERR("error in apr_proc_create") return NULL;
+
+	set_attr(ist, self, SYM(NAME_), NEW_STRING(argv_arr[0]));
+	set_attr(ist, self, sym(ist, "pid"), NEW_INT(procp->proc.pid));
+
+	if (flags & PROC_STDIN) {
+		obj_p file_obj = NEW_OBJ(OBJ(TEXTFILE_PROTO));
+		SET_TYPE_IF_EXC(OBJ(TEXTFILE_PROTO), file_obj, DATA_TYPE_DATAPTR) return NULL;
+		set_file_obj_data( ist, file_obj, NEW_STRING("stdInPipe"), NEW_STRING("w"), 
+							    procp->proc.in, 0, APR_WRITE );
+		set_attr(ist, file_obj, sym(ist, "encoding"), NEW_STRING("ASCII"));
+		file_obj->unclonable = TRUE;
+		set_attr(ist, self, sym(ist, "stdInPipe"), file_obj);
+	}
+	if (flags & PROC_STDOUT) {
+		obj_p file_obj = NEW_OBJ(OBJ(TEXTFILE_PROTO));
+		SET_TYPE_IF_EXC(OBJ(TEXTFILE_PROTO), file_obj, DATA_TYPE_DATAPTR) return NULL;
+		set_file_obj_data( ist, file_obj, NEW_STRING("stdOutPipe"), NEW_STRING("r"), 
+							    procp->proc.out, 0, APR_READ );
+		set_attr(ist, file_obj, sym(ist, "encoding"), NEW_STRING("ASCII"));
+		file_obj->unclonable = TRUE;
+		set_attr(ist, self, sym(ist, "stdOutPipe"), file_obj);
+	}
+	if (flags & PROC_STDERR) {
+		obj_p file_obj = NEW_OBJ(OBJ(TEXTFILE_PROTO));
+		SET_TYPE_IF_EXC(OBJ(TEXTFILE_PROTO), file_obj, DATA_TYPE_DATAPTR) return NULL;
+		set_file_obj_data( ist, file_obj, NEW_STRING("stdErrPipe"), NEW_STRING("r"), 
+							    procp->proc.err, 0, APR_READ );
+		set_attr(ist, file_obj, sym(ist, "encoding"), NEW_STRING("ASCII"));
+		file_obj->unclonable = TRUE;
+		set_attr(ist, self, sym(ist, "stdErrPipe"), file_obj);
+	}
+}
+
+DEF(Process, str_, NULL) {
+	char *name, buf[300];
+	if (self == Process_OBJ) return NEW_STRING("<Process:prototype>");
+	BIN_STR_CHK(Process);
+    name = pr2c_strptr(ist, get_attr(ist, self, SYM(NAME_)));
+	apr_snprintf(buf, sizeof(buf), "<Process:%s>", name);
+	return NEW_STRING(buf);
+}
+
+DEF(Process, running_QUES, FPARM1(retCodes, OBJ(PR_FALSE))) {
+	apr_status_t aprerr;
+	proc_p procp;
+	int exitcode;
+	obj_p res = NULL;
+	apr_exit_why_e exit_why;
+	BIN_CONTENT_CHK(Process);
+	procp = self->data.ptr;
+	aprerr = apr_proc_wait(&procp->proc, &exitcode, &exit_why, APR_NOWAIT);
+	IF_APR_ERR("error in apr_proc_wait") return NULL;
+	if (aprerr & APR_CHILD_DONE)    res = OBJ(PR_FALSE);
+	if (aprerr & APR_CHILD_NOTDONE) res = OBJ(PR_TRUE);
+	if (res && parms[1] == OBJ(PR_TRUE)) {
+		obj_p tuple = NEW_TUPLE(3);
+		list_append(ist, tuple, res);
+		list_append(ist, tuple, NEW_INT(exitcode));
+		list_append(ist, tuple, NEW_INT(exit_why));
+		return tuple;
+	} else if (res)
+		return res;
+	raise_exception(ist, OBJ(INTERNAL_EXC), "invalid return status from apr_proc_wait: %d", aprerr);
+	return NULL;
+}
+
+DEF(Process, wait, FPARM1(retCodes, OBJ(PR_FALSE))) {
+	apr_status_t aprerr;
+	proc_p procp;
+	int exitcode;
+	apr_exit_why_e exit_why;
+
+	BIN_CONTENT_CHK(Process);
+	procp = self->data.ptr;
+	aprerr = apr_proc_wait(&procp->proc, &exitcode, &exit_why, APR_WAIT);
+	IF_APR_ERR("error in apr_proc_wait") return NULL;
+	if (parms[1] == OBJ(PR_TRUE)) {
+		obj_p tuple = NEW_TUPLE(2);
+		list_append(ist, tuple, NEW_INT(exitcode));
+		list_append(ist, tuple, NEW_INT(exit_why));
+		return tuple;
+	} else
+		NEW_INT(exitcode);
+}
+
+DEF(Process, kill, FPARM1(sig, NEW_INT(SIGKILL))) {
+	apr_status_t aprerr;
+	proc_p procp;
+	int sig;
+
+	BIN_CONTENT_CHK(Process);
+	INT_32_PARAM(1, sig);
+	procp = self->data.ptr;
+	aprerr = apr_proc_kill(&procp->proc, sig); 
+	IF_APR_ERR("error in apr_proc_kill") return NULL;
+	return self;
+}
+
+//****************************  MODULE INIT  **********************************
 MAIN_MODULE_INIT(os)
 {
 	MODULE_SUB_INIT(os);
 	MODULE_ADD_SYM(os, system);
 
+	MODULE_ADD_SYM(Process, init_);
+	MODULE_ADD_SYM(Process, str_);
+	MODULE_ADD_SYM(Process, running_QUES);
+	MODULE_ADD_SYM(Process, wait);
+	MODULE_ADD_SYM(Process, kill);
+
 	check_exceptions(ist);
 }

Modified: trunk/src/builtins-file.c
===================================================================
--- trunk/src/builtins-file.c	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/src/builtins-file.c	2004-07-15 05:46:48 UTC (rev 737)
@@ -65,6 +65,7 @@
 #define MIN_BUFSIZE  65536
 
 typedef struct {
+	data_size_t	 size;
 	apr_file_t	*stream;	/* APR file reference */
 	int			 bufsize;	/* Size of our buffer */
 	apr_pool_t	*pool;		/* Pool associated with this file */
@@ -91,7 +92,7 @@
 MODULE_DECLARE(StdErr);
 
 //*************************** set_file_obj_data *******************************
-static void set_file_obj_data( isp ist, obj_p file_obj, obj_p filename, obj_p mode,
+void set_file_obj_data( isp ist, obj_p file_obj, obj_p filename, obj_p mode,
 						  	   apr_file_t *fp, int bufsize, apr_int32_t flags) {
     apr_status_t aprerr;
 	apr_pool_t *subpool = NULL;
@@ -136,11 +137,11 @@
 
 	if (bufsize < MIN_BUFSIZE)
 		bufsize = MIN_BUFSIZE;
-
-	filep->bufsize = bufsize;
-	filep->stream  = fp;
-	filep->pool = subpool;
-	filep->flags = flags;
+    filep->size         = sizeof(file_t);
+	filep->bufsize      = bufsize;
+	filep->stream       = fp;
+	filep->pool         = subpool;
+	filep->flags        = flags;
 	file_obj->data.ptr  = filep;
 	file_obj->rd_access = ACC_USER1;
 	file_obj->wr_access = ACC_USER1;
@@ -624,7 +625,7 @@
 
 MODULE_START(File)
 {
-	File_OBJ = NEW_OBJ(NULL);
+	File_OBJ = OBJ(FILE_PROTO);
 	set_obj_doc(File_OBJ, "File object prototype");
 
 	MODULE_ADD_TO_BASE(File);
@@ -1250,7 +1251,7 @@
 
 MODULE_START(TextFile)
 {
-	TextFile_OBJ = NEW_OBJ(File_OBJ);
+	TextFile_OBJ = OBJ(TEXTFILE_PROTO);
 	set_obj_doc(TextFile_OBJ, "TextFile object prototype");
 
 	MODULE_ADD_TO_BASE(TextFile);
Modified: trunk/src/object.c
===================================================================
--- trunk/src/object.c	2004-07-14 22:26:33 UTC (rev 736)
+++ trunk/src/object.c	2004-07-15 05:46:48 UTC (rev 737)
@@ -210,6 +210,7 @@
 	dll_services.pr2c_strptr	   = pr2c_strptr;		 
 	dll_services.proto_owns_binary = proto_owns_binary;		 
 	dll_services.obj_set_data_owner	= obj_set_data_owner;		 
+	dll_services.set_file_obj_data = set_file_obj_data;
 
 	/* Setup the core objects. Order counts here */
 	OBJ(OBJECT)             = NEW_OBJ(NULL);
@@ -231,11 +232,13 @@
 	OBJ(SLICE_PROTO)        = NEW_OBJ(NULL);
 	OBJ(LOCAL_PROTO)        = NEW_OBJ(NULL);
 	OBJ(OUTER_PROTO)        = NEW_OBJ(NULL);
-	OBJ(SUPER_PROTO)         = NEW_OBJ(NULL);
+	OBJ(SUPER_PROTO)        = NEW_OBJ(NULL);
 	OBJ(THREAD_PROTO)       = NEW_OBJ(NULL);
 	OBJ(MUTEX_PROTO)        = NEW_OBJ(NULL);
 	OBJ(PARMPTR_PROTO)      = NEW_OBJ(NULL);
 	OBJ(PROP_PROTO)         = NEW_OBJ(NULL);
+	OBJ(FILE_PROTO)         = NEW_OBJ(NULL);
+	OBJ(TEXTFILE_PROTO)     = NEW_OBJ(NULL);
 	OBJ(ROOT_GLOBALS)       = NEW_OBJ(NULL);
 	OBJ(MODULES)            = NEW_OBJ(NULL);
 	OBJ(SYS)				= NEW_OBJ(NULL);