From 32136ecee22a3870c333781750d0231cee48e49e Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 28 Jul 2026 15:42:45 -0700 Subject: [PATCH 1/6] add documenting comments to the sdTerminal routines --- csrc/pf_io.c | 2 +- csrc/pf_io.h | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/csrc/pf_io.c b/csrc/pf_io.c index 8491771..1245cc7 100644 --- a/csrc/pf_io.c +++ b/csrc/pf_io.c @@ -90,7 +90,7 @@ cell_t ioKey( void ) /************************************************************** ** Receive line from keyboard. -** Return number of characters enterred. +** Return number of characters entered. */ #define SPACE (0x20) #define BACKSPACE (0x08) diff --git a/csrc/pf_io.h b/csrc/pf_io.h index 242e9e6..2126523 100644 --- a/csrc/pf_io.h +++ b/csrc/pf_io.h @@ -30,13 +30,54 @@ #ifdef __cplusplus extern "C" { #endif + +/** Send a character to an output device so it can be + * seen by the user. + * + * On posix systems, this could be implemented using putchar(c). + */ int sdTerminalOut( char c ); + +/** Echo a character to an output device if sdTerminalIn does NOT + * already automatically echo characters. + * If sdTerminalIn() echos characters then this could be a NOOP. + */ int sdTerminalEcho( char c ); + +/** + * Flush any characters that may be sitting in an output buffer. + * If sdTerminalFlush() is not called then output characters may be held + * indefinitely. + */ int sdTerminalFlush( void ); + +/** Return immediately with a character from the terminal if is is available. + * If not available then wait for the user to press a key. + * + * On posix systems, this could be implemented using getchar(). + */ int sdTerminalIn( void ); + +/** + * Return 1 if a character is available to be read using sdTerminalIn(). + */ int sdQueryTerminal( void ); + +/** + * Initialize the terminal IO system. + */ void sdTerminalInit( void ); + +/** + * Cleanup the terminal IO system. + * If you call sdTerminalInit() twice and sdTerminalTerm() once then + * the input system will be terminated. + */ void sdTerminalTerm( void ); + +/** + * Sleep for msec milliseconds. + */ cell_t sdSleepMillis( cell_t msec ); #ifdef __cplusplus } From 834e342c6723faba2e1ea8d285ab9d4e4cf890e5 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 28 Jul 2026 16:06:36 -0700 Subject: [PATCH 2/6] add pfqaterm binary to test terminal IO --- csrc/pfqaterm.c | 149 ++++++++++++++++++++++++++++++++++++++++ platforms/unix/Makefile | 13 ++++ platforms/unix/pfqaterm | Bin 0 -> 36680 bytes 3 files changed, 162 insertions(+) create mode 100644 csrc/pfqaterm.c create mode 100755 platforms/unix/pfqaterm diff --git a/csrc/pfqaterm.c b/csrc/pfqaterm.c new file mode 100644 index 0000000..22c6a8a --- /dev/null +++ b/csrc/pfqaterm.c @@ -0,0 +1,149 @@ +/* @(#) pfqaterm.c 26/07/28 1.0 */ +/*************************************************************** +** Interactive test for the pForth terminal I/O subsystem. +** +** The terminal API is defined in "pf_io.h". A developer who +** implements that API for a new platform can run this program +** to check that the character I/O behaves as pForth expects. +** +** This test is interactive. It must be run from a terminal +** because it asks the user to press a key. +** +** Author: Phil Burk +** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom +** +** Permission to use, copy, modify, and/or distribute this +** software for any purpose with or without fee is hereby granted. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +** +***************************************************************/ + +#include +#include +#include +#include + +#include "pf_all.h" +#include "paging/unittest.h" + +PFQA_INSTANTIATE_GLOBALS; + +/* How long to nap between calls to sdQueryTerminal(). */ +#define POLL_PERIOD_MSEC (50) +/* How long to wait for the user before giving up. */ +#define TIMEOUT_MSEC (10000) +#define MAX_POLLS (TIMEOUT_MSEC / POLL_PERIOD_MSEC) + +/* sdTerminalIn() should not block because a character is already +** available. time() only has one second of resolution so allow for +** the second to tick over while we are calling it. */ +#define MAX_READ_SECONDS (1) + +/*************************************************************** +** Print a message using the terminal API under test. +*/ +static void TermPrint( const char *msg ) +{ + const char *s = msg; + while( *s ) + { + sdTerminalOut( *s++ ); + } + sdTerminalFlush(); +} + +/*************************************************************** +** Throw away any characters that are already waiting so that +** stale input cannot satisfy the test. +** The loop is bounded because sdQueryTerminal() stays true forever +** if stdin is at the end of a file or a closed pipe. +*/ +#define MAX_DRAIN (100) +static void DrainTerminal( void ) +{ + int i; + for( i = 0; i < MAX_DRAIN; i++ ) + { + if( sdQueryTerminal() == FFALSE ) break; + if( sdTerminalIn() == EOF ) break; + } +} + +/*************************************************************** +** Test sdQueryTerminal(), sdTerminalIn() and sdSleepMillis(). +*/ +static void pfQaTerminalIO( void ) +{ + int numPolls; + int query; + int c; + time_t startTime; + time_t stopTime; + + DrainTerminal(); + + TermPrint( "Terminal QA for pForth\n" ); + +/* Nothing has been typed yet so the terminal should be quiet. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + + ASSERT_EQ( 0, sdSleepMillis( POLL_PERIOD_MSEC ) ); + + TermPrint( "Please press a letter key.\n" ); + +/* Poll until a character arrives or we run out of patience. */ + for( numPolls = 0; numPolls < MAX_POLLS; numPolls++ ) + { + query = sdQueryTerminal(); + if( query != FFALSE ) break; + sdSleepMillis( POLL_PERIOD_MSEC ); + } + + if( numPolls >= MAX_POLLS ) + { + TermPrint( "TIMED OUT! No key was pressed.\n" ); + ASSERT_LT( numPolls, MAX_POLLS ); + } + +/* sdQueryTerminal() must not consume the character. */ + ASSERT_NE( FFALSE, sdQueryTerminal() ); + ASSERT_NE( FFALSE, sdQueryTerminal() ); + +/* A character is waiting so this should return immediately. */ + startTime = time( NULL ); + c = sdTerminalIn(); + stopTime = time( NULL ); + ASSERT_LE( stopTime - startTime, MAX_READ_SECONDS ); + +/* Did we get the key that the user pressed? */ + ASSERT_NE( EOF, c ); + EXPECT_TRUE( isalpha( c ) ); + TermPrint( "You pressed '" ); + sdTerminalEcho( (char) c ); + TermPrint( "'\n" ); + +/* The character was consumed so the terminal should be quiet again. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + +error: + return; +} + +/***************************************************************/ +int main( void ) +{ + sdTerminalInit(); + pfQaTerminalIO(); + sdTerminalTerm(); + + PFQA_PRINT_RESULT; + return PFQA_EXIT_RESULT; +} diff --git a/platforms/unix/Makefile b/platforms/unix/Makefile index 67f9131..fb43709 100644 --- a/platforms/unix/Makefile +++ b/platforms/unix/Makefile @@ -42,6 +42,7 @@ FTHDIR = $(PFORTHDIR)/fth BUILDDIR = $(shell pwd) PFDICAPP = pforth +PFQATERMAPP = pfqaterm PFORTHDIC = pforth.dic PFDICDAT = pfdicdat.h PFORTHAPP = pforth_standalone @@ -98,6 +99,9 @@ PFBASESOURCE = pf_cglue.c pf_clib.c pf_core.c pf_inner.c \ paging/pagedmem.c paging/lockpage.c paging/qadmpage.c PFSOURCE = pf_main.c $(PFBASESOURCE) $(IO_SOURCE) +# Interactive QA test for the terminal I/O API defined in "pf_io.h". +PFQATERMSOURCE = pfqaterm.c $(IO_SOURCE) + VPATH = .:$(CSRCDIR):$(CSRCDIR)/posix:$(CSRCDIR)/stdio:$(CSRCDIR)/win32_console:$(CSRCDIR)/win32 XCFLAGS = $(CCOPTS) @@ -114,6 +118,7 @@ LINK = $(CC) $(LDFLAGS) $(ASANOPTS) .SUFFIXES: .c .o .eo PFOBJS = $(PFSOURCE:.c=.o) +PFQATERMOBJS = $(PFQATERMSOURCE:.c=.o) PFEMBOBJS = $(PFSOURCE:.c=.eo) %.o: %.c $(PFINCLUDES) @@ -141,6 +146,12 @@ pffiles: $(PFDICAPP): $(PFINCLUDES) $(PFOBJS) $(LINK) -o $@ $(PFOBJS) $(LDADD) -lm +# Build the interactive terminal I/O test. +$(PFQATERMAPP): $(PFINCLUDES) $(PFQATERMOBJS) + $(LINK) -o $@ $(PFQATERMOBJS) $(LDADD) + @echo "" + @echo "Run './$(PFQATERMAPP)' from a terminal to test the pForth I/O subsystem." + # Build basic dictionary image by running newly built pforth and including "system.fth". $(PFORTHDIC): $(PFDICAPP) wd=$$(pwd); (cd $(FTHDIR); "$${wd}/$(PFDICAPP)" -i system.fth) @@ -173,6 +184,7 @@ help: @echo " pforthdic = executable pforth plus pforth.dic file" @echo " pfdicdat = header image of full dictionary build by compiling Forth code." @echo " pforthapp = executable with embedded dictionary image. DEFAULT 'all' target." + @echo " pfqaterm = interactive test for the terminal I/O API in 'pf_io.h'." @echo "" @echo " The file 'fth/pfdicdat.h' is generated by pForth. It contains a binary image of the Forth dictionary." @echo " It allows pForth to work as a standalone image that does not need to load a dictionary file." @@ -197,3 +209,4 @@ clean: rm -f $(PFDICDAT) $(FTHDIR)/$(PFDICDAT) $(CSRCDIR)/$(PFDICDAT) rm -f $(PFORTHDIC) $(FTHDIR)/$(PFORTHDIC) rm -f $(PFDICAPP) + rm -f $(PFQATERMOBJS) $(PFQATERMAPP) diff --git a/platforms/unix/pfqaterm b/platforms/unix/pfqaterm new file mode 100755 index 0000000000000000000000000000000000000000..389f254ab523f7fdf430c17bfad8d424288ae9d1 GIT binary patch literal 36680 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 Date: Tue, 28 Jul 2026 16:28:10 -0700 Subject: [PATCH 3/6] add test for character buffering --- csrc/pfqaterm.c | 55 +++++++++++++++++++++++++++++++++++++++ csrc/posix/pf_io_posix.c | 9 +++++++ platforms/unix/pfqaterm | Bin 36680 -> 36712 bytes 3 files changed, 64 insertions(+) diff --git a/csrc/pfqaterm.c b/csrc/pfqaterm.c index 22c6a8a..79026f0 100644 --- a/csrc/pfqaterm.c +++ b/csrc/pfqaterm.c @@ -47,6 +47,11 @@ PFQA_INSTANTIATE_GLOBALS; ** the second to tick over while we are calling it. */ #define MAX_READ_SECONDS (1) +/* How many characters must be buffered while the program is asleep. */ +#define NUM_BUFFERED_CHARS (5) +/* How long the user has to type them. */ +#define TYPING_TIME_MSEC (5000) + /*************************************************************** ** Print a message using the terminal API under test. */ @@ -137,11 +142,61 @@ static void pfQaTerminalIO( void ) return; } +/*************************************************************** +** Test that characters typed while the program is not looking +** are buffered by the terminal instead of being dropped. +*/ +static void pfQaTerminalBuffering( void ) +{ + int i; + int c; + char typed[NUM_BUFFERED_CHARS + 1]; + time_t startTime; + time_t stopTime; + + DrainTerminal(); + +/* Nothing has been typed yet so the terminal should be quiet. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + + TermPrint( "Please type 5 letters within the next 5 seconds.\n" ); + +/* Ignore the terminal completely while the user types. */ + ASSERT_EQ( 0, sdSleepMillis( TYPING_TIME_MSEC ) ); + +/* All 5 characters should have been buffered while we were asleep. */ + startTime = time( NULL ); + for( i = 0; i < NUM_BUFFERED_CHARS; i++ ) + { + ASSERT_NE( FFALSE, sdQueryTerminal() ); + c = sdTerminalIn(); + ASSERT_NE( EOF, c ); + EXPECT_TRUE( isalpha( c ) ); + typed[i] = (char) c; + } + typed[NUM_BUFFERED_CHARS] = '\0'; + +/* The characters were already waiting so none of the reads should block. */ + stopTime = time( NULL ); + ASSERT_LE( stopTime - startTime, MAX_READ_SECONDS ); + + TermPrint( "You typed '" ); + TermPrint( typed ); + TermPrint( "'\n" ); + +/* We read every character so the terminal should be quiet again. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + +error: + return; +} + /***************************************************************/ int main( void ) { sdTerminalInit(); pfQaTerminalIO(); + pfQaTerminalBuffering(); sdTerminalTerm(); PFQA_PRINT_RESULT; diff --git a/csrc/posix/pf_io_posix.c b/csrc/posix/pf_io_posix.c index b4c518d..1fb96e2 100644 --- a/csrc/posix/pf_io_posix.c +++ b/csrc/posix/pf_io_posix.c @@ -135,6 +135,15 @@ void sdTerminalInit(void) { perror("sdTerminalInit: setvbuf"); } +/* Do not let stdio buffer input. sdTerminalIn() uses getchar(), which would + * read a whole block of characters into the stdio buffer, but sdQueryTerminal() + * asks the file descriptor. Characters sitting in the stdio buffer would then + * be invisible to sdQueryTerminal(). + */ + if (setvbuf(stdin, NULL, _IONBF, (size_t) 0) != 0) + { + perror("sdTerminalInit: setvbuf"); + } } } diff --git a/platforms/unix/pfqaterm b/platforms/unix/pfqaterm index 389f254ab523f7fdf430c17bfad8d424288ae9d1..8eb7cbc2cddc1a81b5f968064a47e3f72999654a 100755 GIT binary patch delta 4341 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 TbLA(){d+2ZI&GZ!_i*h$r0*-9 delta 3674 zcmb7HeNa@_6+idA-OVoFxQmEb!GOX-L=zTbVgg(I2&hSPA%0|>peYidrW4fZkmBSm zP*Sk!@OtS-nvNf-sVs5YO-b64+LYRKYHBCdOqysWrkF8~nAjnS<3Kue`#W!U@$sgA zw0Ah~p5Hn5eB5)-efzk2NI88-={v8ax%Br}&)S?qB#0=N9~hfc4i|RJ$WI)g|;QLH$ih!N3=)b8t5J5h7nI<{TT{ zxs9l<$w3=RBat$eJwnvySIFnw>z6L@-UF5Tn5KjbzN1o4fNV``rGBkIg#MBk3?u@7 zJ*!gxq?kfTp^vnt3Vke34Lwif8BqMgPCKO!C^YPM1Oq!bxS&^@Sm=batEw7xe9;u- z@8I)9$XEl%E+pP<@#Rbi21+Ry@L_aJm< z1p^l_kEm3}NvuQ?Skub-9Gk>c64V-~jYrU}jk=WKQy& z$#KzV33jSuKQ2@?gsN%|x--{7bxv2b%G$p*(Hcsix>40VC~|{=H?Z4{NW#eQIb^8C zN^U+^oTs_u%_+fv_y4r%h0Q$Jcr~1hQJP7Vroadm_6h|7Vr6;}Nfh5Y-6 z7Z{62@7IrGVH0FIf?9cv?SlVXqnU^2PPMPbtyvYixoKr6@<*YMsP*s4iNsuQa;y{y zAw@?S`<&>?HxYg8B??_tX%ddZbcdqvlO2hfa($A0%Lj@+8yReyPww0Kpm~8u)$zXQ zM_v1a;(xne`_h7e>_{Y&x8)S1pNz;KB$Y3IT##p~{r90MmGpXS20ap(YX8FkC%g{2 zLSCNXpCsX*ER~Zpd{Xks3}@DcJu zM+ilbNCV9Sm4NO8tpPm>+6meV+7J2(=mh9>&|9EU&`nU1LShc6NWLEYhAi(G;@!$C z9lnwgH+DXriO0ljJo*`i`El8U#|gJ+-a|Di^|9!k*|NH`b7{ZRXPaY7J0`|Oej9y+ zpY{~cR=lh*(RIeR5jlfV{4XKD?3`cZLLnQVj*t5+_yOQXI4CcbRb3?k)X^C1@gY38 z`ph$-0MpT)hFQJ|vpyf>1My(Y_FG-@R9Ct7ZA;YOS@4-y7R#43x5UjkTwiQ+$06i! zam?;HTrAt^aArN*_ebqD<3ooX!~})`JKzr?9_*0wHS5{IiC6-?(6fCU^ZNgmfLYJ> zVZ&ZSL&h9L1<`=)fWMb`utQG3tY-%!u>|ggo)d^;UeET&Ks*?;y;;xp4fy>Mh)+KR zu>(U8GhhefARciCW<5Ko!lh z560{uuIGkcG^3$`8;6gHar_v#^BMQW`hbrC zSVf)X3*Twf%At$?L4i?W!K*F!K?|<6;H?(?H4AQ;i8b0aQ$Xz&+-1SvwP0z%&s*>@ z3&v~KwBZ#*ug(zQ23YVJ3qEJT@5?Q{*`ijq_SVYNy?Cn+mF@EhysTdy%HMxN$hQvM zV-M#ll!X6|7S+0@FYHr|t=sqP*!3h`%4sZK-q$@hsjf8t%Nr@zsQbvubv;Kue{3xK ziubpNspXl Date: Tue, 28 Jul 2026 17:43:46 -0700 Subject: [PATCH 4/6] add test for overflow --- csrc/pfqaterm.c | 126 ++++++++++++++++++++++++++++++++++++---- platforms/unix/pfqaterm | Bin 36712 -> 36824 bytes 2 files changed, 116 insertions(+), 10 deletions(-) diff --git a/csrc/pfqaterm.c b/csrc/pfqaterm.c index 79026f0..726d248 100644 --- a/csrc/pfqaterm.c +++ b/csrc/pfqaterm.c @@ -52,6 +52,8 @@ PFQA_INSTANTIATE_GLOBALS; /* How long the user has to type them. */ #define TYPING_TIME_MSEC (5000) +#define MYEOL "\r\n" + /*************************************************************** ** Print a message using the terminal API under test. */ @@ -65,6 +67,15 @@ static void TermPrint( const char *msg ) sdTerminalFlush(); } +/** Print a message and a line terminator. + */ +static void TermPrintLine( const char *msg ) +{ + TermPrint(msg); + TermPrint(MYEOL); + sdTerminalFlush(); +} + /*************************************************************** ** Throw away any characters that are already waiting so that ** stale input cannot satisfy the test. @@ -85,7 +96,7 @@ static void DrainTerminal( void ) /*************************************************************** ** Test sdQueryTerminal(), sdTerminalIn() and sdSleepMillis(). */ -static void pfQaTerminalIO( void ) +static void pfQaQueryTerminal( void ) { int numPolls; int query; @@ -95,14 +106,13 @@ static void pfQaTerminalIO( void ) DrainTerminal(); - TermPrint( "Terminal QA for pForth\n" ); - /* Nothing has been typed yet so the terminal should be quiet. */ ASSERT_EQ( FFALSE, sdQueryTerminal() ); ASSERT_EQ( 0, sdSleepMillis( POLL_PERIOD_MSEC ) ); - TermPrint( "Please press a letter key.\n" ); + TermPrintLine(MYEOL "----- pfQaQueryTerminal"); + TermPrintLine( "Please press a letter key." ); /* Poll until a character arrives or we run out of patience. */ for( numPolls = 0; numPolls < MAX_POLLS; numPolls++ ) @@ -114,7 +124,7 @@ static void pfQaTerminalIO( void ) if( numPolls >= MAX_POLLS ) { - TermPrint( "TIMED OUT! No key was pressed.\n" ); + TermPrintLine( "TIMED OUT! No key was pressed." ); ASSERT_LT( numPolls, MAX_POLLS ); } @@ -132,8 +142,8 @@ static void pfQaTerminalIO( void ) ASSERT_NE( EOF, c ); EXPECT_TRUE( isalpha( c ) ); TermPrint( "You pressed '" ); - sdTerminalEcho( (char) c ); - TermPrint( "'\n" ); + sdTerminalOut( (char) c ); + TermPrintLine( "'" ); /* The character was consumed so the terminal should be quiet again. */ ASSERT_EQ( FFALSE, sdQueryTerminal() ); @@ -159,7 +169,9 @@ static void pfQaTerminalBuffering( void ) /* Nothing has been typed yet so the terminal should be quiet. */ ASSERT_EQ( FFALSE, sdQueryTerminal() ); - TermPrint( "Please type 5 letters within the next 5 seconds.\n" ); + TermPrintLine(MYEOL "----- pfQaTerminalBuffering"); + TermPrintLine( "Please type any 5 letters within the next 5 seconds." ); + TermPrintLine( "They may not be echoed." ); /* Ignore the terminal completely while the user types. */ ASSERT_EQ( 0, sdSleepMillis( TYPING_TIME_MSEC ) ); @@ -182,7 +194,7 @@ static void pfQaTerminalBuffering( void ) TermPrint( "You typed '" ); TermPrint( typed ); - TermPrint( "'\n" ); + TermPrintLine( "'" ); /* We read every character so the terminal should be quiet again. */ ASSERT_EQ( FFALSE, sdQueryTerminal() ); @@ -191,12 +203,106 @@ static void pfQaTerminalBuffering( void ) return; } +/*************************************************************** +** Test that characters echoed while the user is typing. +*/ +static void pfQaTerminalEcho( void ) +{ + int i; + int c; + + DrainTerminal(); + +/* Nothing has been typed yet so the terminal should be quiet. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + + TermPrintLine(MYEOL "----- pfQaTerminalEcho"); + TermPrintLine( "Please type 5 letters or numbers at any speed:" ); + +/* All 5 characters should have been buffered while we were asleep. */ + for( i = 0; i < NUM_BUFFERED_CHARS; i++ ) + { + c = sdTerminalIn(); + sdTerminalEcho(c); + } + TermPrintLine(""); + TermPrintLine("You should have seen each key echo once and only once.\n"); + +error: + return; +} + +/*************************************************************** +** Test for overflow when blasting characters. +*/ +static void pfQaTerminalOverflow( void ) +{ + int i; + int c; + const char text[] = "abcdefghijklmnopqrstuvwxyz1234567890"; + char typed[sizeof(text)]; + int enabled = 1; + + DrainTerminal(); + +/* Nothing has been typed yet so the terminal should be quiet. */ + ASSERT_EQ( FFALSE, sdQueryTerminal() ); + + TermPrintLine(MYEOL "----- pfQaTerminalOverflow"); + TermPrintLine("Testing for terminal input buffer overflow."); + TermPrintLine("Copy the string below, with no spaces, to your Paste buffer."); + TermPrint(MYEOL " "); + TermPrintLine(text); + + TermPrintLine(MYEOL "Now Paste the String into the terminal and hit ENTER or RETURN"); + TermPrintLine("as many times as you like."); + TermPrintLine("When you are done, hit '.' and ENTER or RETURN to stop."); + + while (enabled) { + for( i = 0; i < sizeof(typed); i++ ) typed[i] = 0; /* Clear typed buffer. */ + for( i = 0; i < (int)(sizeof(text) - 1); i++ ) + { + c = sdTerminalIn(); + sdTerminalEcho(c); + if (c == '.') { + TermPrintLine(MYEOL "Stop requested."); + enabled = 0; + break; + } + typed[i] = c; + /* TermPrint(" - got "); TermPrintLine(typed); */ + if (c != text[i]) { + TermPrintLine(MYEOL "Dropped character"); + TermPrintLine(typed); + DrainTerminal(); + enabled = 0; + ASSERT_EQ(text[i], c); + break; + } + } + TermPrintLine(MYEOL "Waiting for ENTER or RETURN."); + c = sdTerminalIn(); /* Discard EOL */ + ASSERT_TRUE(!isalpha(c)); + if (enabled) { + TermPrintLine(MYEOL "SUCCESS - Paste again and hit ENTER or RETURN."); + } + } + + TermPrintLine("pfQaTerminalOverflow test complete."); + +error: + return; +} + /***************************************************************/ int main( void ) { sdTerminalInit(); - pfQaTerminalIO(); + TermPrintLine( "Terminal QA for pForth" ); + pfQaQueryTerminal(); pfQaTerminalBuffering(); + pfQaTerminalEcho(); + pfQaTerminalOverflow(); sdTerminalTerm(); PFQA_PRINT_RESULT; diff --git a/platforms/unix/pfqaterm b/platforms/unix/pfqaterm index 8eb7cbc2cddc1a81b5f968064a47e3f72999654a..16aef7604fb469713085229d0ab05015983c9c74 100755 GIT binary patch literal 36824 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 delta 3494 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 Date: Tue, 28 Jul 2026 17:47:01 -0700 Subject: [PATCH 5/6] rm pfqaterm binary --- platforms/unix/pfqaterm | Bin 36824 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 platforms/unix/pfqaterm diff --git a/platforms/unix/pfqaterm b/platforms/unix/pfqaterm deleted file mode 100755 index 16aef7604fb469713085229d0ab05015983c9c74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36824 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 From d14b2a836d0e908e4310b30b82630e7aeecd0028 Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 28 Jul 2026 17:47:57 -0700 Subject: [PATCH 6/6] gitignore pfqaterm binary --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a1359c7..239c5c7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ **/pforth **/pforth.dic **/pforth_standalone +**/pfqaterm + platform/win32/**/.vs platform/win32/**/Debug platform/win32/**/Release