[gs-cvs] rev 6912 - trunk/gs/src

ray at ghostscript.com ray at ghostscript.com
Wed Jul 12 14:30:01 PDT 2006


Author: ray
Date: 2006-07-12 14:30:00 -0700 (Wed, 12 Jul 2006)
New Revision: 6912

Modified:
   trunk/gs/src/files.h
   trunk/gs/src/ierrors.h
   trunk/gs/src/imain.c
   trunk/gs/src/iminst.h
   trunk/gs/src/interp.c
   trunk/gs/src/zfileio.c
   trunk/gs/src/zfproc.c
   trunk/gs/src/ziodevs.c
   trunk/gs/src/ziodevsc.c
Log:
Change stdio callback mechanism to call directly from the stream processing
function, not requiring a CALLC callout all the way back through the interp
to 'imain.c' This simplifies some of the calling and is more efficient.

DETAILS:

gsapi_ and/or gsdll_ clients will see no difference.



Modified: trunk/gs/src/files.h
===================================================================
--- trunk/gs/src/files.h	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/files.h	2006-07-12 21:30:00 UTC (rev 6912)
@@ -46,9 +46,6 @@
 extern stream *const invalid_file_entry;
 /* Make an invalid file object. */
 void make_invalid_file(ref *);
-/* create a stream for a file object */
-int file_prepare_stream(const char *, uint, const char *,
-		 uint, stream **, char[4], gs_memory_t *);
 
 /*
  * Macros for checking file validity.
@@ -168,8 +165,4 @@
 	/* for zfile.c */
 int zfilelineedit(i_ctx_t *i_ctx_p);
 
-	/* for zfproc.c */
-int zneedstdin(i_ctx_t *i_ctx_p);
-int zneedstdout(i_ctx_t *i_ctx_p);
-int zneedstderr(i_ctx_t *i_ctx_p);
 #endif /* files_INCLUDED */

Modified: trunk/gs/src/ierrors.h
===================================================================
--- trunk/gs/src/ierrors.h	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/ierrors.h	2006-07-12 21:30:00 UTC (rev 6912)
@@ -135,21 +135,6 @@
 #define e_NeedInput (-106)
 
 /*
- * Internal code for stdin callout.
- */
-#define e_NeedStdin (-107)
-
-/*
- * Internal code for stdout callout.
- */
-#define e_NeedStdout (-108)
-
-/*
- * Internal code for stderr callout.
- */
-#define e_NeedStderr (-109)
-
-/*
  * Internal code for a normal exit when usage info is displayed.
  * This allows Window versions of Ghostscript to pause until
  * the message can be read.

Modified: trunk/gs/src/imain.c
===================================================================
--- trunk/gs/src/imain.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/imain.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -199,10 +199,8 @@
 }
 
 /*
- * Invoke the interpreter, handling stdio callouts
- * e_NeedStdin, e_NeedStdout and e_NeedStderr.
- * We don't yet pass callouts all the way out because they
- * occur within gs_main_init2() and swproc().
+ * Invoke the interpreter. This layer doesn't do much (previously stdio
+ * callouts were handled here instead of in the stream processing.
  */
 private int
 gs_main_interpret(gs_main_instance *minst, ref * pref, int user_errors, 
@@ -218,96 +216,6 @@
 
     code = gs_interpret(&minst->i_ctx_p, pref, 
 		user_errors, pexit_code, perror_object);
-    while ((code == e_NeedStdin) || (code == e_NeedStdout) || 
-	(code == e_NeedStderr)) {
-        i_ctx_p = minst->i_ctx_p;
-	if (code == e_NeedStdout) {
-	    /*
-	     * On entry:
-	     *  esp[0]  = string, data to write to stdout
-	     *  esp[-1] = bool, EOF (ignored)
-	     *  esp[-2] = array, procedure (ignored)
-	     *  esp[-3] = file, stdout stream
-	     * We print the string then pop these 4 items.
-	     */
-	    if (r_type(&esp[0]) == t_string) {
-		const char *str = (const char *)(esp[0].value.const_bytes); 
-		int count = esp[0].tas.rsize;
-		int rcode = 0;
-		if (str != NULL)
-		    rcode = outwrite(imemory, str, count);
-		if (rcode < 0)
-		    return_error(e_ioerror);
-	    }
-
-	    /* On return, we need to set 
-	     *  osp[-1] = string buffer, 
-	     *  osp[0] = file
-	     */
-	    gs_push_string(minst, (byte *)minst->stdout_buf, 
-		sizeof(minst->stdout_buf), false);
-	    gs_push_integer(minst, 0);	/* push integer */
-	    osp[0] = esp[-3];		/* then replace with file */
-	    /* remove items from execution stack */
-	    esp -= 4;
-	}
-	else if (code == e_NeedStderr) {
-	    if (r_type(&esp[0]) == t_string) {
-		const char *str = (const char *)(esp[0].value.const_bytes); 
-		int count = esp[0].tas.rsize;
-		int rcode = 0;
-		if (str != NULL)
-		    rcode = errwrite(str, count);
-		if (rcode < 0)
-		    return_error(e_ioerror);
-	    }
-	    gs_push_string(minst, (byte *)minst->stderr_buf, 
-		sizeof(minst->stderr_buf), false);
-	    gs_push_integer(minst, 0);
-	    osp[0] = esp[-3];
-	    esp -= 4;
-	}
-	else if (code == e_NeedStdin) {
-	    int count = sizeof(minst->stdin_buf);
-	    /*
-	     * On entry:
-	     *  esp[0]  = array, procedure (ignored)
-	     *  esp[-1] = file, stdin stream
-	     * We read from stdin then pop these 2 items.
-	     */
-	    if (minst->heap->gs_lib_ctx->stdin_fn)
-		count = (*minst->heap->gs_lib_ctx->stdin_fn)
-		    (minst->heap->gs_lib_ctx->caller_handle, 
-		     minst->stdin_buf, count);
-	    else
-		count = gp_stdin_read(minst->stdin_buf, count, 
-				      minst->heap->gs_lib_ctx->stdin_is_interactive,
-				      minst->heap->gs_lib_ctx->fstdin);
-	    if (count < 0)
-	        return_error(e_ioerror);
-
-	    /* On return, we need to set 
-	     *  osp[-1] = string buffer, 
-	     *  osp[0] = file
-	     */
-	    gs_push_string(minst, (byte *)minst->stdin_buf, count, false);
-	    gs_push_integer(minst, 0);	/* push integer */
-	    osp[0] = esp[-1];		/* then replace with file */
-	    /* remove items from execution stack */
-	    esp -= 2;
-	}
-	/*
-	 * To resume the interpreter, we call gs_interpret with a null ref.
-	 * This copies the literal null onto the operand stack.
-	 * To remove this we push a zpop onto the execution stack.
-	 */
-	make_null(&refnul);
-	make_oper(&refpop, 0, zpop); 
-	esp += 1;
-	*esp = refpop;
-	code = gs_interpret(&minst->i_ctx_p, &refnul, 
-		    user_errors, pexit_code, perror_object);
-    }
     return code;
 }
 

Modified: trunk/gs/src/iminst.h
===================================================================
--- trunk/gs/src/iminst.h	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/iminst.h	2006-07-12 21:30:00 UTC (rev 6912)
@@ -72,7 +72,6 @@
     gs_file_path lib_path;	/* library search list (GS_LIB) */
     long base_time[2];		/* starting usertime */
     void *readline_data;	/* data for gp_readline */
-    char stdin_buf[STDIN_BUF_SIZE];	/* for e_NeedStdin callout */
     char stdout_buf[STDOUT_BUF_SIZE];	/* for e_NeedStdout callout */
     char stderr_buf[STDERR_BUF_SIZE];	/* for e_NeedStderr callout */
     ref error_object;		/* Use by gsapi_*() */

Modified: trunk/gs/src/interp.c
===================================================================
--- trunk/gs/src/interp.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/interp.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -520,9 +520,6 @@
 	    epref = &doref;
 	    goto again;
 	case e_NeedInput:
-	case e_NeedStdin:
-	case e_NeedStdout:
-	case e_NeedStderr:
 	    return code;
     }
     /* Adjust osp in case of operand stack underflow */

Modified: trunk/gs/src/zfileio.c
===================================================================
--- trunk/gs/src/zfileio.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/zfileio.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -816,32 +816,7 @@
     return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
 }
 
-/* Callout for stdin */
-/* - .needstdin - */
-int
-zneedstdin(i_ctx_t *i_ctx_p)
-{
-    return e_NeedStdin;		/* Interpreter will exit to caller. */
-}
 
-/* Callout for stdout */
-/* - .needstdout - */
-int
-zneedstdout(i_ctx_t *i_ctx_p)
-{
-    return e_NeedStdout;	/* Interpreter will exit to caller. */
-}
-
-/* Callout for stderr */
-/* - .needstderr - */
-int
-zneedstderr(i_ctx_t *i_ctx_p)
-{
-    return e_NeedStderr;	/* Interpreter will exit to caller. */
-}
-
-
-
 /* ------ Initialization procedure ------ */
 
 /* We need to split the table because of the 16-element limit. */
@@ -878,9 +853,6 @@
     {"3%zreadstring_continue", zreadstring_continue},
     {"4%zwritecvp_continue", zwritecvp_continue},
     {"3%zwritehexstring_continue", zwritehexstring_continue},
-    {"0.needstdin", zneedstdin},
-    {"0.needstdout", zneedstdout},
-    {"0.needstderr", zneedstderr},
     op_def_end(0)
 };
 

Modified: trunk/gs/src/zfproc.c
===================================================================
--- trunk/gs/src/zfproc.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/zfproc.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -205,14 +205,6 @@
     esp[-1] = *fop;
     r_clear_attrs(esp - 1, a_executable);
     *esp = ((stream_proc_state *) ps->state)->proc;
-
-    /* If stream is stdin, ask for callout. */
-    zget_stdin(i_ctx_p, &psstdin);
-    if (ps == psstdin) {
-	check_estack(1);
-	esp += 1;
-	make_op_estack(esp, zneedstdin);
-    }
     return o_push_estack;
 }
 /* Continue a read operation after returning from a procedure callout. */
@@ -345,15 +337,6 @@
     esp[-2] = psst->proc;
     *esp = psst->data;
     r_set_size(esp, psst->index);
-
-    /* If stream is stdout/err, ask for callout. */
-    zget_stdout(i_ctx_p, &psstdout);
-    zget_stderr(i_ctx_p, &psstderr);
-    if ((ps == psstderr) || (ps == psstdout)) {
-	check_estack(1);
-	esp += 1;
-	make_op_estack(esp, (ps == psstderr) ? zneedstderr : zneedstdout);
-    }
     return o_push_estack;
 }
 /* Continue a write operation after returning from a procedure callout. */

Modified: trunk/gs/src/ziodevs.c
===================================================================
--- trunk/gs/src/ziodevs.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/ziodevs.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -157,6 +157,27 @@
 }
 
 private int
+    s_stdout_swrite_process(stream_state *, stream_cursor_read *,
+			 stream_cursor_write *, bool);
+
+/* Write a buffer to stdout, potentially writing to callback */
+private int
+s_stdout_write_process(stream_state * st, stream_cursor_read * ignore_pr,
+		     stream_cursor_write * pw, bool last)
+{
+    uint count = pr->limit - pr->ptr;
+    int written;
+
+    if (count == 0) 
+	return 0;
+    written = outwrite(st->memory, pr->ptr + 1, count);
+    if (written < count) {
+	return ERRC;
+    pr->ptr += written;
+    return 0;
+}
+
+private int
 stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
 	    gs_memory_t * mem)
 {
@@ -176,6 +197,7 @@
 	swrite_file(s, gs_stdout, buf, STDOUT_BUF_SIZE);
 	s->save_close = s->procs.flush;
 	s->procs.close = file_close_file;
+	s->procs.process = s_stdout_write_process;
 	make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
 	*ps = s;
 	return 1;

Modified: trunk/gs/src/ziodevsc.c
===================================================================
--- trunk/gs/src/ziodevsc.c	2006-07-12 21:24:01 UTC (rev 6911)
+++ trunk/gs/src/ziodevsc.c	2006-07-12 21:30:00 UTC (rev 6912)
@@ -81,52 +81,78 @@
 }
 
 private int
+    s_stdin_read_process(stream_state *, stream_cursor_read *,
+			 stream_cursor_write *, bool);
+
+private int
 stdin_init(gx_io_device * iodev, gs_memory_t * mem)
 {
     mem->gs_lib_ctx->stdin_is_interactive = true;
     return 0;
 }
 
-/* stdin stream implemented as procedure */
+/* Read from stdin into the buffer. */
+/* If interactive, only read one character. */
 private int
+s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
+		     stream_cursor_write * pw, bool last)
+{
+    int wcount = (int)(pw->limit - pw->ptr);
+    int count;
+    gs_memory_t *mem = st->memory;
+
+    if (wcount <= 0)
+	return 0;
+
+    /* do the callout */
+    if (mem->gs_lib_ctx->stdin_fn)
+	count = (*mem->gs_lib_ctx->stdin_fn)
+	    (mem->gs_lib_ctx->caller_handle, (char *)pw->ptr + 1,
+	     mem->gs_lib_ctx->stdin_is_interactive ? 1 : wcount);
+    else
+	count = gp_stdin_read(pw->ptr + 1, wcount,
+		      mem->gs_lib_ctx->stdin_is_interactive,
+		      mem->gs_lib_ctx->fstdin);
+
+    pw->ptr += (count < 0) ? 0 : count;
+    return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
+}
+
+private int
 stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
-	    gs_memory_t * mem)
+	   gs_memory_t * mem)
 {
     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
     stream *s;
-    int code;
 
     if (!streq1(access, 'r'))
 	return_error(e_invalidfileaccess);
     if (file_is_invalid(s, &ref_stdin)) {
-	/* procedure source */
-	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
-	ref rint;
+	/****** stdin SHOULD NOT LINE-BUFFER ******/
+	gs_memory_t *mem = imemory_system;
+	byte *buf;
+	static const stream_procs p = {
+	    s_std_noavailable, s_std_noseek, s_std_read_reset,
+	    s_std_read_flush, file_close_file, s_stdin_read_process
+	};
 
-	/* The procedure isn't used. */
-	/* Set it to literal 0 to recognised stdin. */
-	make_int(&rint, 0);
+	s = file_alloc_stream(mem, "stdin_open(stream)");
 
-	/* implement stdin as a procedure */
-	code = sread_proc(&rint, &s, imem);
-	if (code < 0)
-	    return code;
+	/* We want stdin to read only one character at a time, */
+	/* but it must have a substantial buffer, in case it is used */
+	/* by a stream that requires more than one input byte */
+	/* to make progress. */
+	buf = gs_alloc_bytes(mem, STDIN_BUF_SIZE, "stdin_open(buffer)");
+	if (s == 0 || buf == 0)
+	    return_error(e_VMerror);
+
+	s_std_init(s, buf, STDIN_BUF_SIZE, &p, s_mode_read);
+	s->file = 0;
+	s->file_modes = s->modes;
+	s->file_offset = 0;
+	s->file_limit = max_long;
 	s->save_close = s_std_null;
-	s->procs.close = stdio_close;
-	/* allocate buffer */
-	if (s->cbuf == 0) {
-	    int len = STDIN_BUF_SIZE;
-	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
-	    		len, "stdin_open");
-	    if (buf == 0)
-		return_error(e_VMerror);
-	    s->cbuf = buf;
-	    s->srptr = s->srlimit = s->swptr = buf - 1;
-	    s->swlimit = buf - 1 + len;
-	    s->bsize = s->cbsize = len;
-	}
-	s->state->min_left = 0;
-	make_file(&ref_stdin, a_read | avm_system, s->read_id, s);
+	make_file(&ref_stdin, a_readonly | avm_system, s->read_id, s);
 	*ps = s;
 	return 1;
     }
@@ -151,60 +177,62 @@
     iodev->state = NULL;
     return min(code, 0);
 }
+
 /* Test whether a stream is stdin. */
 bool
 zis_stdin(const stream *s)
 {
-    /* Only stdin should be a procedure based stream, opened for
-     * reading and with a literal 0 as the procedure.
-     */
-    if (s_is_valid(s) && s_is_reading(s) && s_is_proc(s)) {
-        stream_proc_state *state = (stream_proc_state *)s->state;
-	if ((r_type(&(state->proc)) == t_integer) &&
-		(state->proc.value.intval == 0))
-	    return true;
-    }
-    return false;
+    return (s_is_valid(s) && s->procs.process == s_stdin_read_process);
 }
 
-/* stdout stream implemented as procedure */
 private int
+    s_stdout_swrite_process(stream_state *, stream_cursor_read *,
+			 stream_cursor_write *, bool);
+
+/* Write a buffer to stdout, potentially writing to callback */
+private int
+s_stdout_write_process(stream_state * st, stream_cursor_read *pr,
+		     stream_cursor_write *ignore_pw, bool last)
+{
+    uint count = pr->limit - pr->ptr;
+    int written;
+
+    if (count == 0) 
+	return 0;
+    written = outwrite(st->memory, pr->ptr + 1, count);
+    if (written < count)
+	return ERRC;
+    pr->ptr += written;
+    return 0;
+}
+
+private int
 stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
 	    gs_memory_t * mem)
 {
     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
     stream *s;
-    int code;
 
     if (!streq1(access, 'w'))
 	return_error(e_invalidfileaccess);
     if (file_is_invalid(s, &ref_stdout)) {
-	/* procedure source */
-	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
-	ref rint;
+	gs_memory_t *mem = imemory_system;
+	byte *buf;
+	static const stream_procs p = {
+	    s_std_noavailable, s_std_noseek, s_std_write_reset,
+	    s_std_write_flush, file_close_file, s_stdout_write_process
+	};
 
-	/* The procedure isn't used. */
-	/* Set it to literal 1 to recognised stdout. */
-	make_int(&rint, 1);
-
-	/* implement stdout as a procedure */
-	code = swrite_proc(&rint, &s, imem);
-	if (code < 0)
-	    return code;
+	s = file_alloc_stream(mem, "stdout_open(stream)");
+	buf = gs_alloc_bytes(mem, STDOUT_BUF_SIZE, "stdout_open(buffer)");
+	if (s == 0 || buf == 0)
+	    return_error(e_VMerror);
+	s_std_init(s, buf, STDOUT_BUF_SIZE, &p, s_mode_write);
+	s->file = 0;
+	s->file_modes = s->modes;
+	s->file_offset = 0;		/* in case we switch to reading later */
+	s->file_limit = max_long;	/* ibid. */
 	s->save_close = s->procs.flush;
-	s->procs.close = stdio_close;
-	/* allocate buffer */
-	if (s->cbuf == 0) {
-	    int len = STDOUT_BUF_SIZE;
-	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
-	    		len, "stdout_open");
-	    if (buf == 0)
-		return_error(e_VMerror);
-	    s->cbuf = buf;
-	    s->srptr = s->srlimit = s->swptr = buf - 1;
-	    s->swlimit = buf - 1 + len;
-	    s->bsize = s->cbsize = len;
-	}
 	make_file(&ref_stdout, a_write | avm_system, s->write_id, s);
 	*ps = s;
 	return 1;
@@ -212,6 +240,7 @@
     *ps = s;
     return 0;
 }
+
 /* This is the public routine for getting the stdout stream. */
 int
 zget_stdout(i_ctx_t *i_ctx_p, stream ** ps)
@@ -231,44 +260,54 @@
     return min(code, 0);
 }
 
-/* stderr stream implemented as procedure */
 private int
+    s_stderr_swrite_process(stream_state *, stream_cursor_read *,
+			 stream_cursor_write *, bool);
+
+/* Write a buffer to stderr, potentially writing to callback */
+private int
+s_stderr_write_process(stream_state * st, stream_cursor_read *pr,
+		     stream_cursor_write *ignore_pw, bool last)
+{
+    uint count = pr->limit - pr->ptr;
+    int written;
+
+    if (count == 0) 
+	return 0;
+    written = errwrite((const char *)(pr->ptr + 1), count);
+    if (written < count) 
+	return ERRC;
+    pr->ptr += written;
+    return 0;
+}
+
+private int
 stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
 	    gs_memory_t * mem)
 {
     i_ctx_t *i_ctx_p = (i_ctx_t *)iodev->state;	/* see above */
     stream *s;
-    int code;
 
     if (!streq1(access, 'w'))
 	return_error(e_invalidfileaccess);
     if (file_is_invalid(s, &ref_stderr)) {
-	/* procedure source */
-	gs_ref_memory_t *imem = (gs_ref_memory_t *)imemory_system;
-	ref rint;
+	gs_memory_t *mem = imemory_system;
+	byte *buf;
+	static const stream_procs p = {
+	    s_std_noavailable, s_std_noseek, s_std_write_reset,
+	    s_std_write_flush, file_close_file, s_stderr_write_process
+	};
 
-	/* The procedure isn't used. */
-	/* Set it to literal 2 to recognised stderr. */
-	make_int(&rint, 2);
-
-	/* implement stderr as a procedure */
-	code = swrite_proc(&rint, &s, imem);
-	if (code < 0)
-	    return code;
+	s = file_alloc_stream(mem, "stderr_open(stream)");
+	buf = gs_alloc_bytes(mem, STDERR_BUF_SIZE, "stderr_open(buffer)");
+	if (s == 0 || buf == 0)
+	    return_error(e_VMerror);
+	s_std_init(s, buf, STDERR_BUF_SIZE, &p, s_mode_write);
+	s->file = 0;
+	s->file_modes = s->modes;
+	s->file_offset = 0;		/* in case we switch to reading later */
+	s->file_limit = max_long;	/* ibid. */
 	s->save_close = s->procs.flush;
-	s->procs.close = stdio_close;
-	/* allocate buffer */
-	if (s->cbuf == 0) {
-	    int len = STDERR_BUF_SIZE;
-	    byte *buf = gs_alloc_bytes((gs_memory_t *)imemory_system,
-	    		len, "stderr_open");
-	    if (buf == 0)
-		return_error(e_VMerror);
-	    s->cbuf = buf;
-	    s->srptr = s->srlimit = s->swptr = buf - 1;
-	    s->swlimit = buf - 1 + len;
-	    s->bsize = s->cbsize = len;
-	}
 	make_file(&ref_stderr, a_write | avm_system, s->write_id, s);
 	*ps = s;
 	return 1;
@@ -276,6 +315,7 @@
     *ps = s;
     return 0;
 }
+
 /* This is the public routine for getting the stderr stream. */
 int
 zget_stderr(i_ctx_t *i_ctx_p, stream ** ps)



More information about the gs-cvs mailing list