\ Detect forth system and use appropriate prelude.

\ Josh Grams <josh@qualdan.com>

\ This code is gifted to the public domain.  Specifically, you may use,
\ modify, and redistribute it without limitation, but it comes with
\ ABSOLUTELY NO WARRANTY.

\ 2009-??-?? - Original version (early 2009, I think).
\ 2010-01-08 - added bigFORTH, VFX Forth
\ 2010-03-08 - Refactored to interpreted tests.
\ 2010-03-09 - Added iForth and design notes.

\ Currently detects: (iForth and VFX Forth not tested)
  \ bigFORTH   - http://www.jwdt.com/~paysan/bigforth.html
  \ ciforth    - http://home.hccnet.nl/a.w.m.van.der.horst/ciforth.html
  \ FICL       - http://ficl.sourceforge.net/
  \ Gforth     - http://www.jwdt.com/~paysan/gforth.html
  \ iForth     - http://home.iae.nl/users/mhx/i4faq.html
  \ kForth     - http://ccreweb.org/software/kforth/kforth.html
  \ PFE        - http://pfe.sourceforge.net/
  \ pForth     - http://www.softsynth.com/pforth/
  \ SP-Forth   - http://spf.sourceforge.net/
  \ VFX Forth  - http://www.mpeforth.com/
  \ Win32Forth - http://win32forth.sourceforge.net/

\ Other systems to consider (most of these aren't standard):
  \ 4p         - http://maschenwerk.de/
  \ dsForth    - http://www.delosoft.com/
  \ FINA       - http://code.google.com/p/fina-forth/
  \ hForth     - http://www.taygeta.com/hforth.html
  \ IsForth    - http://isforth.com/
  \ NTF/LXF    - http://falth.homelinux.net/readme2.html
  \ MinForth   - http://home.arcor.de/a.s.kochenburger/minforth.html
  \ RetroForth - http://retroforth.org/


\ Rationale
\ ---------

\ This eventually came to be fairly simple, but it took me several
\ iterations to get it "right", so I'm publishing it in case it may save
\ someone else some work.

\ A good test must:
\ 
\ * Reliably detect the current system: some free systems don't provide
\   a way to test for this, so we have to get creative.
\
\ * Run out of the box on all other systems.  Many useful words aren't
\   in the CORE wordset and hence aren't provided by even all standard
\   systems.  Also, most so-called standard systems have words which are
\   implemented in a sub-standard fashion.


\ Helper Words
\ ------------

\ Process the rest of line only if FLAG is true.  [IF] .. [THEN] don't
\ exist everywhere, so we use this conditional comment word insted.
: uses ( flag -- )  0= IF POSTPONE \ THEN ;

\ [DEFINED] doesn't exist everywhere, and on some systems the
\ interpreter uses WORD, so `BL WORD FIND` doesn't work in the
\ interpreter.
: ?? ( "name" -- flag )  BL WORD FIND SWAP DROP 0= 0= ;

\ We need a string comparison word, but on ciforth, COMPARE is not
\ loaded by default.
?? STR= 0= uses : MATCH? >R COUNT ROT COUNT ROT = R> AND ;
?? STR= 0= uses : (STR=) BEGIN DUP 0 > WHILE MATCH? 1- REPEAT 0= ;
?? STR= 0= uses : STR= ROT 2DUP = >R MIN (STR=) >R 2DROP R> R> AND ;

\ Dummy ENVIRONMENT? (since kForth doesn't have it)
?? ENVIRONMENT? 0= uses : ENVIRONMENT? 2DROP 0 ;

\ The return from ENVIRONMENT? is a bit of a nuisance, so we have words
\ to deal with various possibilities and return a single flag.
: env-flag?  DUP IF DROP THEN ;              \ flag true?
: env-str?  DUP IF >R 2DROP R> THEN ;        \ string present?
: env-str=  ROT IF STR= ELSE 2DROP 0 THEN ;  \ string matches?


\ System Tests
\ ------------

\ Originally I defined a word to check for the presence of each system.
\ But Win32Forth doesn't like it if you compile ENVIRONMENT? into a word
\ (apparently it isn't available in turnkey applications).  I could have
\ gotten around that by precomputing the values and defining constants.
\ 
\ But then I realized that there was no sense in cluttering up the
\ dictionary with all those words.  So this version just uses
\ interpreted tests.  I recommend that your system-specific preludes
\ define a no-op word named after the Forth system.  Then you can later
\ do e.g. `[defined] ciforth [if] ... [then]`.
\
\ One reason *for* defining a test word for each system was that ANS
\ CORE doesn't require S" to work in interpretation state.  But the FILE
\ wordset does, and since this is in a file...  At any rate, all systems
\ which I have tested have an interpreted S".  If you add a system which
\ doesn't, you could replace S" with something like:
\
\ : PAD" ( -- c-addr u )  [CHAR] " WORD  COUNT PAD PLACE  PAD COUNT ;

\ Each system has a comment describing how to invoke the system for
\ testing purposes, the test itself, and the `uses` line which gives an
\ example of how to include another source file (some systems are
\ case-sensitive, some only define INCLUDED, and so on).

\ bigforth compat.f -e bye
S" BIGFORTH" ENVIRONMENT? env-str?
   uses include compat/bigforth.f

\ lina -s compat.f
S" NAME" ENVIRONMENT? S" ciforth" env-str=
   uses S" compat/ciforth.f" INCLUDED

\ ficl compat.f
\ Grrr.  FICL has no way to quit automatically after running a script.
S" ficl-version" ENVIRONMENT? env-str?
   uses include compat/ficl.f

\ gforth compat.f -e bye
S" gforth" ENVIRONMENT? env-str?
   uses include compat/gforth.f

\ ???
S" IFORTH" ENVIRONMENT? env-flag?
	uses ." iForth (untested)" cr

\ kforth compat.f -e bye
?? NONDEFERRED
   uses include compat/kforth.f

\ pfe -q -y compat.f
S" FORTH-NAME" ENVIRONMENT? S" pfe" env-str=
   uses include compat/pfe.f

\ pforth compat.f
?? ::::loadp4th.fth
   uses include compat/pforth.f

\ spf4 compat.f BYE
S" FORTH-SYS" ENVIRONMENT? S" SP-FORTH" env-str=
   uses S" compat/spf.f" INCLUDED
	   \ REQUIRE CASE-INS lib/ext/caseins.f

\ ??? vfx include compat.f bye ???
?? VFXFORTH
   uses ." VFX Forth (untested)" CR

\ win32forth include compat.f bye
S" WIN32FORTH" ENVIRONMENT? env-str?
   uses include compat/win32forth.f
