[svn commit] r438 - in trunk: . gc gc/tests include/minor

jimb at red-bean.com jimb at red-bean.com
Wed Apr 27 01:25:00 CDT 2005


Author: jimb
Date: Wed Apr 27 01:24:59 2005
New Revision: 438

Added:
   trunk/gc/ports.c
   trunk/gc/ports.h
   trunk/gc/tests/c-api-ports.c
Modified:
   trunk/TODO
   trunk/gc/Makefile.am
   trunk/gc/init.c
   trunk/gc/strings.c
   trunk/gc/tests/   (props changed)
   trunk/gc/tests/Makefile.am
   trunk/gc/tests/c-api-characters.c
   trunk/gc/tests/c-api-strings.c
   trunk/gc/tests/svnignore
   trunk/include/minor/minor.h
   trunk/include/minor/unicode.h
Log:
Add I/O ports and tests --- for everything but s-expression parsing
and printing.


Modified: trunk/TODO
==============================================================================
--- trunk/TODO	(original)
+++ trunk/TODO	Wed Apr 27 01:24:59 2005
@@ -1,8 +1,3 @@
-* implement and test simple input port functions:
-  - Unicode
-  - C execution character set
-
-* imp/test trivial functions
 * imp/test read
   - test parsing every possible sort of token directly concatenated
     with every other possible sort
@@ -16,11 +11,19 @@
 
 * Fix all unsigned / signed comparisons in gen-ints.sh
 
+* Move all forms of basic character execution set to test-lib.c,
+  along with a 'char_name' function; use in c-api-ports, c-api-characters,
+  and c-api-strings.
+
 
 ==== prd.txt item 3 (simple <minor/minor.h> C interfaces) finished
 
 * Re-prioritize to-do items.
 
+* For tests that don't actually communicate between threads, add
+  "torture test" that runs them in many threads over and over.  Then let
+  the regression tests run single-threaded (and faster!) by default.
+
 * Why use 'assert' when we have 'check'?
 
 * tests for unicode-case.c
@@ -80,7 +83,9 @@
 - TYPE_to_TYPE for all conversion functions, TYPE_is_TYPE for functions 
   that test whether the conversion would abort
 
-- QUALITY_p for all predicates, or is_QUALITY for all predicates
+- is_QUALITY for all predicates.  (QUALITY_p is quaint, but the Scheme
+  functions themselves don't use it, and the non-historical
+  explanation "p stands for 'predicate', see?" is obscure.)
 
 - ad_FOO for linear accessors
 

Modified: trunk/gc/Makefile.am
==============================================================================
--- trunk/gc/Makefile.am	(original)
+++ trunk/gc/Makefile.am	Wed Apr 27 01:24:59 2005
@@ -41,6 +41,8 @@
 	numbers.c \
 	pairs.c \
 	pause.h \
+	ports.c \
+	ports.h \
 	procedures.c \
 	procedures.h \
 	refapi.c \

Modified: trunk/gc/init.c
==============================================================================
--- trunk/gc/init.c	(original)
+++ trunk/gc/init.c	Wed Apr 27 01:24:59 2005
@@ -19,6 +19,7 @@
 #include "vectors.h"
 #include "procedures.h"
 #include "numbers.h"
+#include "ports.h"
 
 void
 mn__init (void)
@@ -41,6 +42,7 @@
     mn__gc_symbols_init (c);
     mn__gc_procedures_init (c);
     mn__gc_numbers_init (c);
+    mn__gc_ports_init (c);
   }
   mn__end_incoherent (c);
 }

Modified: trunk/gc/strings.c
==============================================================================
--- trunk/gc/strings.c	(original)
+++ trunk/gc/strings.c	Wed Apr 27 01:24:59 2005
@@ -304,12 +304,6 @@
 
   /* Build an exception object to return when conversion to Unicode
      fails.  */
-  {
-    static const char message[] = "C / Unicode conversion failed";
-    tagged_t ex = mn__string_from_mem (c, message, sizeof (message) - 1);
-
-    check (ex != mn__unique_false ());
-    
-    mn__conversion_exception = mn__make_global_ref (ex);
-  }
+  mn__conversion_exception
+    = mn__build_exception (c, "C / Unicode conversion failed");
 }

Modified: trunk/gc/tests/Makefile.am
==============================================================================
--- trunk/gc/tests/Makefile.am	(original)
+++ trunk/gc/tests/Makefile.am	Wed Apr 27 01:24:59 2005
@@ -5,6 +5,7 @@
 	c-api-lists \
 	c-api-numbers \
 	c-api-pairs \
+	c-api-ports \
 	c-api-procedures \
 	c-api-refs \
 	c-api-strings \
@@ -28,6 +29,7 @@
 c_api_lists_SOURCES = c-api-lists.c test-lib.c
 c_api_numbers_SOURCES = c-api-numbers.c test-lib.c
 c_api_pairs_SOURCES = c-api-pairs.c test-lib.c
+c_api_ports_SOURCES = c-api-ports.c test-lib.c
 c_api_procedures_SOURCES = c-api-procedures.c test-lib.c
 c_api_refs_SOURCES = c-api-refs.c test-lib.c
 c_api_strings_SOURCES = c-api-strings.c test-lib.c

Modified: trunk/gc/tests/c-api-characters.c
==============================================================================
--- trunk/gc/tests/c-api-characters.c	(original)
+++ trunk/gc/tests/c-api-characters.c	Wed Apr 27 01:24:59 2005
@@ -15,12 +15,16 @@
 char basic[] = ("abcdefghijklmnopqrstuvwxyz"
 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 		"0123456789"
-		"!\"#%&'()*+,-./:;<=>?[\\]^_{|}~");
+		"!\"#%&'()*+,-./:;<=>?[\\]^_{|}~"
+		" \t\v\f"
+		"\a\b\r\n");
 
 wchar_t wide[] = (L"abcdefghijklmnopqrstuvwxyz"
 		  L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 		  L"0123456789"
-		  L"!\"#%&'()*+,-./:;<=>?[\\]^_{|}~");
+		  L"!\"#%&'()*+,-./:;<=>?[\\]^_{|}~"
+		  L" \t\v\f"
+		  L"\a\b\r\n");
 
 
 /* The ISO C basic character set, expressed in unicode.  This
@@ -49,6 +53,12 @@
   0x003c, 0x003d, 0x003e, 0x003f, 0x005b, 0x005c, 0x005d, 0x005e,
   0x005f, 0x007b, 0x007c, 0x007d, 0x007e,
 
+  /* Whitespace.  */
+  0x0020, 0x0009, 0x000b, 0x000c,
+
+  /* Control characters.  */
+  0x0007, 0x0008, 0x000d, 0x000a,
+
   /* The null character.  */
   0x0000
 };

Modified: trunk/gc/tests/c-api-strings.c
==============================================================================
--- trunk/gc/tests/c-api-strings.c	(original)
+++ trunk/gc/tests/c-api-strings.c	Wed Apr 27 01:24:59 2005
@@ -18,7 +18,8 @@
 			"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 			"0123456789"
 			"!\"#%&'()*+,-./:;<=>?[\\]^_{|}~"
-			" \t\v\f");
+			" \t\v\f"
+			"\a\b\r\n");
 
 /* An array containing all the characters in the ISO C basic character
    set, in UTF-8.  */
@@ -48,6 +49,9 @@
   /* Whitespace.  */
   0x20, 0x09, 0x0b, 0x0c,
 
+  /* Control characters.  */
+  0x07, 0x08, 0x0d, 0x0a,
+
   /* The null character.  */
   0x00
 };

Modified: trunk/gc/tests/svnignore
==============================================================================
--- trunk/gc/tests/svnignore	(original)
+++ trunk/gc/tests/svnignore	Wed Apr 27 01:24:59 2005
@@ -9,6 +9,7 @@
 c-api-lists
 c-api-numbers
 c-api-pairs
+c-api-ports
 c-api-procedures
 c-api-refs
 c-api-strings

Modified: trunk/include/minor/minor.h
==============================================================================
--- trunk/include/minor/minor.h	(original)
+++ trunk/include/minor/minor.h	Wed Apr 27 01:24:59 2005
@@ -268,7 +268,7 @@
    An interface which handles these sorts of errors by returning
    exceptions doesn't work well:
 
-   - Users will often not check for exceptional return values in these
+   - Users will often not check for exception return values in these
      cases, since they "know" the errors cannot occur.  If the API
      reports them as exceptions which the user's code ignores, then
      the program behaves unpredictably, instead of failing in a
@@ -889,7 +889,7 @@
 
 /* Like mn_make_procedure, except that FUNC's return value is a Scheme
    list of values, to be returned as the values of the function.
-   Exceptional returns are handled the same way.  */
+   Exception returns are handled the same way.  */
 mn_ref *mn_make_multi_valued_procedure (mn_call *,
                                         mn_func_t *func,
                                         int nargs, _Bool rest,
@@ -951,57 +951,211 @@
 
 /* Input/Output ports.  */
 
-/* Return true if REF refers to a port; otherwise, return false.  */
-_Bool mn_port_p (mn_call *, mn_ref *ref);
+/* Returning Exceptions:
 
-/* Create a new input or output port which gets characters by reading
-   from the Standard I/O file object FILE.
+   Like the C <stdio.h> functions, the functions in this section use
+   EOF or WEOF as their exception return value, and the input
+   functions also return EOF or WEOF to indicate that they have
+   reached end-of-file.  So EOF / WEOF is both a normal return value
+   and an exception return value.
+
+   To distinguish these two cases, when an input function reaches
+   end-of-file, it will always set its end-of-file indicator.  If it
+   encounters an error, it will always set the current exception
+   (obviously).  Thus, when a function returns EOF or WEOF, the caller
+   should always check the end-of-file indicator, and if it is clear,
+   check the current exception.  For example:
+
+     if ((ch = mn_getc (c, port)) == EOF)
+       {
+	 if (mn_eof (c, port))
+	   ... handle EOF ...
+         else
+           ... handle exception mn_get_exception (c) ...
+       }
+
+   The End-of-File Indicator:
+
+   On POSIX systems, it is possible for an input stream to reach end-
+   of-file more than once.  For example, when a user types control-D
+   at a terminal, a process reading from that terminal receives an
+   end-of-file indication --- the 'read' system call returns zero,
+   indicating that no bytes were read.  However, the user may then
+   continue to enter characters at the terminal, which can include
+   more EOF characters.  So from the reading process's point of view,
+   even after receiving an end-of-file, there may be more data left to
+   read.
+
+   For consistency with the C <stdio.h> input functions, Minor input
+   ports include an end-of-file indicator, which records whether
+   end-of-file has been reached.  See the individual functions'
+   descriptions for the details of house the end-of-file indicator
+   works.
+
+   (Note that only the C functions defined in this interface respect a
+   port's end-of-file indicator.  Scheme input functions operating on
+   the same port may consume new input even if the end-of-file
+   indicator is set.  The end-of-file indicator is just a convenience
+   for C programmers, making Minor ports behave more like C <stdio.h>
+   streams.)
+
+   See the comments at the start of the section on "Characters" for
+   Minor's general conventions for processing text.  */
+
+/* Return true if REF refers to a port, input port, or output port;
+   otherwise, return false.  */
+_Bool mn_port_p        (mn_call *, mn_ref *ref);
+_Bool mn_input_port_p  (mn_call *, mn_ref *ref);
+_Bool mn_output_port_p (mn_call *, mn_ref *ref);
+
+/* Return true if REF refers to an open port; otherwise, return
+   false.  */
+_Bool mn_open_port_p (mn_call *, mn_ref *ref);
+
+/* Create a new input or output port based on the Standard I/O file
+   object FILE.  The returned port's end-of-file indicator is always
+   equal to that of FILE.
+
+   Each port returned by these functions may be used either with the
+   byte input/output routines (mn_putc; mn_getc; etc.) or the wide
+   character input/output routines (mn_putwc; mn_getwc; etc.), but not
+   both: you may not mix byte and wide character operations on a given
+   port.  The first operation performed determines the port's
+   orientation (byte or wide character), and from that point on only
+   operations of the same orientation may be performed.
 
    There is currently no way to arrange for FILE to be freed if the
    port object becomes garbage.  We will eventually fix this, once we
    implement guardians.  */
-mn_ref *mn_create_stdio_input_port (mn_call *, 
-				    FILE *file);
-mn_ref *mn_create_stdio_output_port (mn_call *, 
-				     FILE *file);
+mn_ref *mn_make_stdio_input_port  (mn_call *, FILE *file);
+mn_ref *mn_make_stdio_output_port (mn_call *, FILE *file);
 
-/* If PORT was created using mn_create_stdio_input_port or
-   mn_create_stdio_output_port, return the underyling FILE object.  */
+/* If PORT was created using mn_make_stdio_input_port or
+   mn_make_stdio_output_port, return the underlying FILE object.
+   If PORT is not a port at all, abort.  Otherwise, return NULL.  */
 FILE *mn_stdio_port_file (mn_call *, mn_ref *port);
 
-/* Return the current input/output port.  */
-mn_ref *mn_current_input_port (mn_call *);
-mn_ref *mn_current_output_port (mn_call *);
-
-/* Set the current input/output port to PORT, and return true.  If
-   PORT is not a port, return false and set the pending exception.  */
-_Bool mn_set_current_input_port (mn_call *, mn_ref *port);
-_Bool mn_set_current_output_port (mn_call *, mn_ref *port);
-
-/* Print the null-terminated string STRING on PORT, and return true.
-   STRING is assumed to be in the current C execution character set.
-   If PORT is not a port, return false and set the pending
-   exception.  */
-_Bool mn_display_str (mn_call *, mn_ref *port, const char *string);
+/* Close PORT.  If PORT is an output port with buffered unwritten
+   data, write it out.  If all goes well, return true; if an error
+   occurs while doing the output, set the pending exception and return
+   false.
+
+   If PORT is already closed, this function has no effect.
+
+   If PORT is not a port, abort.  */
+_Bool mn_close_port (mn_call *, mn_ref *port);
+
+/* Print the byte or wide character CH on PORT, and return CH.  (For
+   mn_putc, CH is first converted to an unsigned character.)
+
+   If an error occurs while doing the output, return EOF / WEOF and
+   set the pending exception.  
+
+   If PORT is not an open output port, abort.  */
+int    mn_putc  (mn_call *, mn_ref *port, int     ch);
+wint_t mn_putwc (mn_call *, mn_ref *port, wchar_t ch);
+
+/* Print OBJECT on PORT the way `write' does, and return true.
+
+   This is a 'wide character' operation.
+
+   If an error occurs while doing the output, return false and set the
+   pending exception.
 
-/* Print OBJECT on PORT the way `write' does, and return true.  If
-   PORT is not a port, return false and set the pending exception.  */
+   If PORT is not an open output port, abort.  */
 _Bool mn_write (mn_call *, mn_ref *object, mn_ref *port);
 
-/* Print OBJECT on PORT the way `display' does, and return true.  If
-   PORT is not a port, return false and set the pending exception.  */
+/* Print OBJECT on PORT the way `display' does, and return true.
+
+   This is a 'wide character' operation.
+
+   If an error occurs while doing the output, return false and set the
+   pending exception.
+
+   If PORT is not an open output port, abort.  */
 _Bool mn_display (mn_call *, mn_ref *object, mn_ref *port);
 
-/* Read a datum from PORT the way 'read' does, and return it.  If PORT
-   is not a port, or if there is not a well-formed datum on PORT,
-   return false and set the pending exception.  */
+/* Print the null-terminated string / wide string STRING on PORT, and
+   return true.
+
+   If an error occurs while doing the output, return false and set the
+   pending exception.
+
+   If PORT is not an open output port, abort.  */
+_Bool mn_display_str (mn_call *, mn_ref *port, const char    *string);
+_Bool mn_display_wcs (mn_call *, mn_ref *port, const wchar_t *string);
+
+/* If PORT's end-of-file indicator is set, return EOF / WEOF.
+   Otherwise, read a single byte / multibyte character from PORT, and
+   return it.  If end-of-file is reached, set PORT's end-of-file
+   indicator and return EOF / WEOF.
+
+   If an error occurs while doing the input, return false and set the
+   pending exception.
+
+   If PORT is not an open input port, abort.  */
+int    mn_getc  (mn_call *, mn_ref *port);
+wint_t mn_getwc (mn_call *, mn_ref *port);
+
+/* Push back the character / wide character CH onto PORT.  If the call
+   is successful, clear PORT's end-of-file indicator and return CH.
+   (For mn_ungetc, CH is first converted to an unsigned character.)
+
+   Only one character of pushback is guaranteed.  If too many calls to
+   mn_ungetc / mn_ungetwc are made without intervening calls to
+   consume the pushed-back characters, they return EOF / WEOF and set
+   the pending exception.
+
+   If PORT is not an open input port, abort.  */
+int    mn_ungetc  (mn_call *, mn_ref *port, int     ch);
+wint_t mn_ungetwc (mn_call *, mn_ref *port, wchar_t ch);
+
+/* If PORT's end-of-file indicator is set, return the end-of-file
+   object.  Otherwise, read a datum from PORT the way 'read' does, and
+   return it.  If no datum, complete or partial, is found on PORT
+   before end-of-file is reached, set the end-of-file indicator, and
+   return the end-of-file object.
+
+   This is a 'wide character' operation.
+
+   If there is an incomplete or ill-formed datum on PORT, or if an
+   error occurs while doing the input, return NULL and set the pending
+   exception.
+
+   If PORT is not an open input port, abort.  */
 mn_ref *mn_read (mn_call *, mn_ref *port);
 
-/* Eventually, I'd like to replace this with something that lets you
-   do arbitrary computation to provide the stream's contents.  It
+/* Return true if PORT's end-of-file indicator is set, or false
+   otherwise.
+
+   NOTE: this just tests the end-of-file indicator; it doesn't go and
+   check whether PORT is actually at end-of-file.  That is, you must
+   get an EOF / WEOF from some input function before this will return
+   true.
+
+   If PORT is not an open input port, abort.  */
+_Bool mn_port_eof_p (mn_call *, mn_ref *port);
+
+/* Clear PORT's end-of-file indicator.
+   If PORT is not an open input port, abort.  */
+void mn_port_clear_eof (mn_call *, mn_ref *port);
+
+/* Return true if OBJ is the Scheme end-of-file object.  */
+_Bool mn_eof_object_p (mn_call *, mn_ref *obj);
+
+/* Return a reference to the end-of-file object.  */
+mn_ref *mn_eof_object (mn_call *);
+
+/* Eventually, I'd like to provide something that lets you do
+   arbitrary computation to provide the stream's contents.  It
    shouldn't require a function call for every character passed, and
    it should support some sort of buffering.  We'll use it for
-   character set conversion, compression, and so on.  */
+   character set conversion, compression, and so on.
+
+   The C++ arrangement is probably good.
+
+   MzScheme's custom ports meet all those criteria, but they're
+   awfully complicated; is all that really necessary?  */
 
 
 /* Top-Level Environments.  */

Modified: trunk/include/minor/unicode.h
==============================================================================
--- trunk/include/minor/unicode.h	(original)
+++ trunk/include/minor/unicode.h	Wed Apr 27 01:24:59 2005
@@ -484,4 +484,43 @@
 };
 
 
+
+/* Input/output functions that operate on Unicode code points.  */
+
+/* As far as port orientation is concerned, these functions are all
+   'wide character' operations.  (See the documentation for
+   mn_make_stdio_input_port and mn_make_stdio_output_port for details
+   about port orientation.)  */
+
+/* Print the Unicode character U on PORT, and return U.
+
+   If an error occurs while doing the output, return MN_UNICODE_EOF
+   and set the pending exception.
+
+   If PORT is not an output port, abort.  */
+mn_unicode_int_t mn_put_unicode (mn_call *, mn_ref *port, mn_unicode_t u);
+
+/* If PORT's end-of-file indicator is set, return MN_UNICODE_EOF.
+   Otherwise, read a single multibyte character from PORT, and return
+   it as a Unicode code point.  If end-of-file is reached, set PORT's
+   end-of-file indicator and return MN_UNICODE_EOF.
+
+   If an error occurs while doing the input, return MN_UNICODE_EOF and
+   set the pending exception.
+
+   If PORT is not an input port, abort.  */
+mn_unicode_int_t mn_get_unicode (mn_call *, mn_ref *port);
+
+/* Push back the Unicode character U onto PORT.  If the call is
+   successful, clear PORT's end-of-file indicator and return CH.
+
+   Only one character of pushback is guaranteed.  If too many calls to
+   mn_ungetc / mn_ungetwc are made without intervening calls to
+   consume the pushed-back characters, they return EOF / WEOF and set
+   the pending exception.
+
+   If PORT is not an input port, abort.  */
+mn_unicode_int_t mn_unget_unicode (mn_call *, mn_ref *port, mn_unicode_t u);
+
+
 #endif /* MN_UNICODE_H */




More information about the Minor mailing list