| FTH(1) | General Commands Manual | FTH(1) |
fth —
fth |
[-DdQqrv] [-C
so‐lib‐path]
[-E eval]
[-e eval]
[-f init‐file]
[-I fs‐path]
[-S “lib
init”] [-s
file] [file ...] |
fth |
[-alnp] [-e
eval] [-F
fs]
[-i[suffix]]
[file ...] |
fth |
-V |
fth based on John
Sadler's Ficl, Forth-inspired command
language. This manual page provides information for running and
programming fth in a UNIX
command line environment, see libfth(3) for Forth as an
extension language.
The fth interpreter can also be used as a
command line filter and process files in-place. The options
-a, -e,
-i, -l,
-n, -p and in addition
-F are provided for this purpose, see
EXAMPLES below.
-a-e eval. The
split string is the field separator *fs*, default a
space. Can be combined with -n,
-p and in-place option
-i[suffix]. See also options
-F and -l.-C
path-D-d-E
eval-e.-e
eval-e
eval can be considered between
lambda: ( -- ) eval
;and is in compile state! If multiple calls appear, all but the last are in interpret state.
For example, the following renames config.h to config.h.orig and reads it line by line. If a line occurs containing
#define
HAVE_COMPLEX_DOUBLEreplaces entire line with
/* #undef HAVE_COMPLEX_DOUBLE
*/otherwise writes the original line to
config.h. The first -e
sets the global Forth variable reg to a Regexp
object, the second -e uses this variable for
testing. The eval of the first
-e is evaluated in interpret state before
reading the file while the eval of the second
-e is evaluated in compile state in a nameless
lambda: (--)
eval ; word while reading the file line by
line:
% fth -ni.orig \
-e '/#define HAVE_COMPLEX_DOUBLE/ value reg' \
-e 'reg *line* re= if \
"/* #undef HAVE_COMPLEX_DOUBLE */\n" \
else \
*line* \
then' config.h
-F
fs-a. See
also implicit loop and in-place options -i,
-l, -n and
-p.-f
file-Q to
prevent loading initialization files.
-I
path-i[suffix]-e eval on each
line in-place. If no suffix was specified, writes to
the same file after processing, otherwise copies original to the backup
file before reading it. See option -e above for an
example and see also implicit loop options -a,
-F, -l,
-n -p.
Note: There are no spaces allowed between
-i and suffix if
suffix was specified!-l-n, -p and
in-place option -i[suffix].
See also options -a and
-F.-n-e eval
on each line while not echoing every
*line* to standard output. See also implicit loop
and in-place options -a,
-F, -i,
-l and -p.-p-e eval
on each line while echoing every *line* unaltered to
standard output. See also implicit loop and in-place options
-a, -F,
-i, -l and
-n.-Q-q-r-r changes this
behavior to something like a
read‐eval‐loop instead of a
read‐eval‐print‐loop.-S
“lib init”-S "dbm
Init_dbm"Multiple calls are possible.
-s
file-s file. This must be the
last option given to the fth interpreter. Options
after that are taken as script options and can be used for
getopt processing in the script. This makes it
possible to create hash bang scripts with a first line like
#! /usr/pkg/bin/fth
-sNote the space after #!. It's a Forth
word starting a comment and must be separated by at least one space.
% cat hello-world.fth
#! /usr/pkg/bin/fth -s
·" Hello, World!" cr
-V-v( a b c -- d )The left side of the double dash shows the stack required by the word, the ride side shows what the word left on stack. One or both sides may be empty.
( -- )( a -- )( -- a )Parse words have the following kind of stack effect:
( "name" -- )Parse words read their input from the input stream in contrary to
regular words which expect their input on stack;
"name" is expected after the word. As a
parse word example, fth has
help ( "name" --
)which is used like
help aproposThis word takes its arguments from the input stream, in this case apropos, and tries to find its help strings, which are returned if found.
There is another kind of words, so called procs (see in subsection
Procs And Xts, word
<{), they may show a slightly different stack
effect because they can have keyword and optional arguments and may look
like this:
( :key host "localhost"
:optional port 13 -- str )Local variables are automatically defined,
host is set to string "localhost" and
port to integer 13, the return value of this example
is a String object. You may specify these with :host
"pumpkin" and :port
79 before calling the word. For example,
${prefix}/share/fth/fth-lib/net.fs contains
finger ( :key host
"localhost" :optional user getlogin -- str )which can be used in either of these forms:
finger \ default values for host and
user"yorick" finger \ default
value for host:host "pumpkin" finger \
default value for user"yorick" :host
"pumpkin" finger-a was specified when implicit loop and
in-place processing takes place, these are the corresponding first nine
single elements of *farray*.-a was specified when implicit loop and
in-place processing takes place, prints the corresponding single elements
of *farray* with the string of
*ofs* attached, default a single space.-a was specified when implicit loop and
in-place processing takes place, auto-split array of current input
line.map ...
end-map loops.fth searches for C
extension libraries (*.so).fth searches for Forth
script files (*.fs).REG_EXTENDED.fth calls five hooks if they are not empty: before and
after loading source files and in interactive mode before starting and after
ending the repl as well as every time before showing the prompt.
before-load-hook
( filename -- f )
before-load-hook lambda: <{ fname -- f }>
"\\ loading %s\n" #( fname ) fth-print
#t
; add-hook!
after-load-hook
( filename -- )
after-load-hook lambda: <{ fname -- }>
"\\ %s loaded\n" #( fname ) fth-print
; add-hook!
before-repl-hook
( -- )
before-repl-hook reset-hook!
before-repl-hook lambda: <{ -- }>
." \" cr
." \ Starting FTH on " date .string ." !" cr
." \" cr
; add-hook!
after-repl-hook
( history -- )
\ 20201116031253 0
"mail" .getservbyname
after-repl-hook lambda: <{ history -- }>
\ Remove duplicates from history file.
history readlines array-reverse! { hary }
#() "" "" { nhary hline tline }
hary array-length 0 ?do
hary i array-ref to hline
hary i 1+ array-ref to tline
nhary hline array-member? unless
nhary hline array-unshift
tline array-unshift drop
then
2 +loop
history nhary writelines
; add-hook!
before-prompt-hook
( prompt pos -- new-prompt )
before-prompt-hook lambda: <{ prompt pos -- new-prompt }>
"fth (%d) ok " '( pos ) string-format
; add-hook!
Or with standout and bold mode, see gl_prompt_style(3) and Tecla Variables below for *promptstyle*:
#t to *promptstyle*
before-prompt-hook lambda: <{ prompt pos -- new-prompt }>
"%%Sfth (%d)%%s %%Bok%%b " '( pos ) string-format
; add-hook!
M-^V and from vi-mode to emacs-mode via
M-^E. To start in vi-mode, put a line like
edit-mode viin your ~/.teclarc file. A history of the
last command-lines can be listed with ^Xh, the last
10 history entries can be listed with M-10^Xh. The
Tab-key or ^I initiates word completion. If the
Forth dictionary has more than one entry starting with characters before the
cursor, show all, if only one definition exists, completes it and adds a
space after the completed word. If the Forth dictionary has no entries
starting with the characters before the cursor, try filename completion. For
complete key listings and function descriptions, see
tecla(7).
If the first character of the command-line is an exclamation point ‘!’, history expansion similar to csh(1) takes place:
If the first character of the command-line is a caret ‘^’, history substitution similar to csh(1) takes place:
^search^replace(^)^ is optional.gl-all, only unique history events are
entered in the history list. If set to gl-prev and
the last history event is the same as the current, the current command is
not entered. If not defined (undef, the default), all history events are
entered.FTH_HISTORY, or, if not set,
~/.fth-history is used.FTH_HISTORY_LENGTH or,
if not set, 100 is used.bindkey
( :optional key action -- )bindkey
( -- )bindkey
( key -- )The following sets edit-mode to vi and nobeep:
"edit-mode vi \n
nobeep" bindkeyIf key is a predefined constant, sets the specific value. The following constants are valid:
The following sets edit-mode to vi and nobeep with predefined constants:
gl-vi bindkeygl-nobeep
bindkeybindkey
( key action -- )"^G"
"user-interrupt" bindkeyIf key is a string and action is anything else, unbind key from last bind.
"^G" #f
bindkeySee tecla(7) for bindings and actions.
history
( :optional action arg -- )gl-add
arggl-cleargl-load
[arg]gl-save
[arg]gl-show
[arg]
history ⇒ returns entire history as string
gl-show history ⇒ same as above
10 history ⇒ returns 10 last history events
gl-show 10 history ⇒ same as above
gl-load history ⇒ loads from *histfile*
gl-load nil history ⇒ same as above
gl-load file history ⇒ loads from FILE
gl-save history ⇒ saves to *histfile*
gl-save nil history ⇒ same as above
gl-save file history ⇒ saves to FILE
gl-add line history ⇒ adds LINE to history
gl-clear history ⇒ clears entire history
history-lineno
( -- n )history-next
( -- line )history-prev
( -- line )tecla-get-line
( prompt -- line )tecla-query-char
( prompt -- c )tecla-puts
( :optional text -- )tecla-read-char
( -- c )tecla-repl
( -- )(?)do ... (+)loop, begin
... again, begin ... until, and
begin ... while ... repeat,
fth provides each ... end-each
and map ... end-map loops for arrays and similar
objects.
begin
( -- ) compile-onlyagain
( -- ) compile-onlybegin and
again over and over again. Press
^C to stop the endless loop.
0
begin
dup . 1+
again
begin
( -- ) compile-onlywhile
( f -- ) compile-onlyrepeat
( -- ) compile-onlywhile and repeat and
starts over after begin for the next test.
"test.file" io-open-read { io }
begin
io io-eof? not
while
io io-gets fth-print
repeat
io io-close
begin
( -- ) compile-onlyuntil
( f -- ) compile-onlybegin and
until as long as flag f is
#f.
"localhost" :port 79 io-nopen { io }
io "mike\n" io-puts
begin
io io-gets fth-print
io io-eof?
until
io io-close
do
( limit start -- ) compile-only?do
( limit start -- ) compile-onlyloop
( -- ) compile-only?do starts only if
limit is greater than start.
3 0 do i . loop ⇒ 0 1 2
each
( obj -- val ) compile-onlyend-each
( -- ) compile-only
#( 0 1 2 ) each . end-each ⇒ 0 1 2
map
( obj -- ) compile-onlymap!
( obj -- ) compile-onlyend-map
( -- obj ) compile-onlyend-map is set as new current value
of obj.
#( 0 1 2 ) value a1
a1 map i *key* + end-map ⇒ #( 0 2 4 ) \ a copy of a1
a1 .$ ⇒ #( 0 1 2 )
a1 map! i *key* + end-map ⇒ #( 0 2 4 ) \ a1 has changed
a1 .$ ⇒ #( 0 2 4 )
Interpret state loops for use outside word definitions in scripts
or in the repl work like their compile state cousins above. The body of the
following [do] ... [loop], [each]
... [end-each] and [map] ... [end-map] is in
compile state, loop indexes i,
j, k and
leave etc can be used like in colon definitions.
[do]
( limit start -- )[loop]
( -- )
3 0 [do] i . [loop] ⇒ 0 1 2
[each]
( obj -- val )[end-each]
( -- )
#( 0 1 2 ) [each] . [end-each] ⇒ 0 1 2
[map]
( obj -- )[map!]
( obj -- )[end-map]
( -- obj )
#( 0 1 2 ) value a1
a1 [map] i *key* + [end-map] ⇒ #( 0 2 4 ) \ a copy of a1
a1 .$ ⇒ #( 0 1 2 )
a1 [map!] i *key* + [end-map] ⇒ #( 0 2 4 ) \ a1 has changed
a1 .$ ⇒ #( 0 2 4 )
let:
#( 0 1 ) { ary }
ary array-length ⇒ 2
ary 0 array-ref ⇒ 0
ary 2 array-push ⇒ #( 0 1 2 )
ary array-length ⇒ 3
ary array-shift ⇒ 0
ary array-shift ⇒ 1
ary array-shift ⇒ 2
ary array-length ⇒ 0
"" { fs }
#( 0 1 2 ) to ary
\ val: current value
ary each { val }
fs "array[%d]: %d\n" '( i val ) string-format
string-push to fs
end-each ⇒ "array[0]: 0\n ..."
*key*: current value
ary map
*key* 10 *
end-map ⇒ #( 0 10 20 )
;let
#()
( -- ary ).array
( ary -- )array->array
( ary1 -- ary2 )
#( 0 #{ 'foo 10 } 2 ) value ary1
ary1 array->array value ary2
ary1 1 array-ref 'foo 30 hash-set!
ary1 ⇒ #( 0 #{ 'foo 30 } 2 )
ary2 ⇒ #( 0 #{ 'foo 30 } 2 )
array->list
( ary -- lst )
#( 0 #{ 'foo 10 } 2 ) value ary
ary array->list value lst
ary 1 array-ref 'foo 30 hash-set!
lst ⇒ '( 0 #{ 'foo 30 } 2 )
ary ⇒ #( 0 #{ 'foo 30 } 2 )
array-append
( ary1 ary2 -- ary1+ary2 )
#( 0 1 2 ) #( 3 4 ) array-append ⇒ #( 0 1 2 3 4 )
#( 0 1 2 ) 10 array-append ⇒ #( 0 1 2 10 )
array-clear
( ary -- )array-compact
( ary1 -- ary2 )array-compact!
( ary -- ary' )array-concat
( vals len -- ary ) alias:
>arrayarray-copy
( ary1 -- ary2 )
#( 0 #{ 'foo 10 } 2 ) value ary1
ary1 array-copy value ary2
ary1 1 array-ref 'foo 30 hash-set!
ary1 ⇒ #( 0 #{ 'foo 30 } 2 )
ary2 ⇒ #( 0 #{ 'foo 10 } 2 )
array-delete!
( ary idx -- val )array-delete-key
( ary key -- val )array-fill
( ary val -- )array-find
( ary key -- key )array-index
( ary key -- idx )array-insert
( ary idx val -- ary2 )
array-insert!array-insert! changes the original array
contents.array-join
( ary sep -- str )
#( 0 1 2 ) "--" array-join ⇒ "0--1--2"
#( 0 1 2 ) nil array-join ⇒ "0 1 2"
array-length
( obj -- len )array-member?
( ary key -- f )array-pop
( ary -- val )array-push
( ary val -- ary' )
#( 0 1 2 ) 10 array-push ⇒ #( 0 1 2 10 )
array-ref
( ary idx -- val )array-reject
( ary1 proc-or-xt args -- ary2 )
array-reject!array-reject returns a new array with
elements where proc-or-xt results in #f, nil, or 0,
and array-reject! removes all elements from
ary where proc-or-xt results
not in #f, nil, or 0. In the example n1 corresponds to the current array
element and n2 comes from args, here 2.
#( 0 1 2 3 4 ) lambda: <{ n1 n2 -- f }>
n1 n2 >
; #( 2 ) array-reject ⇒ #( 0 1 2 )
\ or a bit shorter:
#( 0 1 2 3 4 ) <'> > 2 array-reject ⇒ #( 0 1 2 )
array-reverse
( ary1 -- ary2 )
array-reverse!array-reverse! changes the original array
contents.array-search
( ary reg -- res )array-set!
( ary idx val -- )array-shift
( ary -- val )array-sort
( ary1 proc-or-xt -- ary2 )
array-sort!array-sort! changes the original array contents.
#( 2 1 0 ) lambda: <{ a b -- f }>
a b < if
-1
else
a b > if
1
else
0
then
then
; array-sort ⇒ #( 0 1 2 )
array-subarray
( ary start end -- subary )
#( 0 1 2 3 4 ) 2 4 array-subarray ⇒ #( 2 3 )
#( 0 1 2 3 4 ) -3 -1 array-subarray ⇒ #( 2 3 4 )
#( 0 1 2 3 4 ) -3 nil array-subarray ⇒ #( 2 3 4 )
array-uniq
( ary1 -- ary2 )
array-uniq!array-uniq! changes the original array
contents.array-unshift
( ary val -- ary' )
#( 0 1 2 ) 10 array-unshift ⇒ #( 10 0 1 2 )
array=
( ary1 ary2 -- f )array?
( obj -- f )make-array
( len :key initial-element --
ary )assoc?
( obj -- f )>assoc
( vals len -- ary )assoc-array
( ass key -- key-val|#f ) alias:
array-assocassoc-ref
( ass key -- val|#f ) alias:
array-assoc-refassoc-delete!
( ass key -- ass' ) alias:
array-assoc-remove!assoc-set!
( ass key val -- ass' ) alias:
array-assoc-set! assocobject->assoc
( obj -- ass )'()
( -- lst ).list
( lst -- )>list
( vals len -- lst )car
( lst -- val )cadr
( lst -- val )caddr
( lst -- val )cadddr
( lst -- val )cdr
( lst -- val )cddr
( lst -- val )acons
( key val alst1 -- alst2 )cons
( val lst1 -- lst2 )cons2
( val1 val2 lst1 -- lst2 )cons?
( obj -- f )last-pair
( lst -- lp )
'( 0 1 2 3 ) last-pair ⇒ '( 3 )
list->array
( lst -- ary )
'( 0 #{ 'foo 10 } 2 ) value lst1
lst1 list->array value ary2
lst1 1 list-ref 'foo 30 hash-set!
lst1 ⇒ '( 0 #{ 'foo 30 } 2 )
ary2 ⇒ #( 0 #{ 'foo 30 } 2 )
list-append
( arg0 arg1 ... argn n -- lst )list-copy
( lst1 -- ary2 )
'( 0 #{ 'foo 10 } 2 ) value lst1
lst1 list-copy value lst2
lst1 1 list-ref 'foo 30 hash-set!
lst1 ⇒ '( 0 #{ 'foo 30 } 2 )
lst2 ⇒ '( 0 #{ 'foo 10 } 2 )
list-delete
( lst1 key -- lst2 )
list-delete!list-delete! changes the original list contents.
list-fill
( lst val -- lst' )list-index
( lst key -- idx )list-insert
( lst1 idx val -- lst2 )list-length
( obj -- len )list-member?
( lst key -- f )list-ref
( lst idx -- val )list-reverse
( lst1 -- ary2 )list-set!
( lst idx val -- )list-slice
( lst1 idx :key count 1 -- lst2 )
list-slice!list-slice!
changes the original list contents.
#( 0 1 1 2 ) 1 :count 2 list-slice ⇒ #( 0 2 )
list-tail
( lst1 idx -- lst2 )list=
( lst1 lst2 -- f )list?
( obj -- f )make-list
( len :key initial-element nil --
lst )nil?
( obj -- f )null?
( obj --f )pair?
( obj -- f )set-car!
( lst val -- lst' )set-cdr!
( lst val -- lst' )alist?
( obj -- f )>alist
( vals len -- ass )alist-list
( ass key -- key-val|#f ) alias:
list-assocalist-ref
( ass key -- val|#f ) alias:
list-assoc-refalist-delete!
( ass key -- ass' ) alias:
list-assoc-remove!alist-set!
( ass key val -- ass' ) alias:
list-assoc-set!object->alist
( obj -- ass )"foo" 0o755 file-mkdir
file-atime
( name -- time )time->string.file-basename
( name ext -- base )
"/home/mike/cage.snd" #f file-basename ⇒ "cage.snd"
"/home/mike/cage.snd" nil file-basename ⇒ "cage"
"/home/mike/cage.snd" "nd" file-basename ⇒ "cage.s"
"/home/mike/cage.snd" /\.(snd|wave)$/ file-basename ⇒ "cage"
file-chdir
( path -- ) alias:
chdirHOME.
path may contain ‘~’ as an
abbreviation for home directory, see chdir(2).file-chmod
( name mode -- )file-chroot
( path -- )file-copy
( src dst -- )file-ctime
( name -- time )time->string.file-delete
( name -- )file-dir
( dir -- files-ary )file-dirname
( name -- path )
"/home/mike/cage.snd" file-dirname ⇒ "/home/mike"
file-eval
( name -- )include
except that name must be on stack (while include is
a parse word). With file-eval one can load files
from within word definitions. Raises load-error
exception if file-eval fails.file-fullpath
( name -- path )file-install
( src dst mode -- f )
: install-lib { src dst mode -- }
src dst mode file-install if
"%s --> %04o %s" '( src mode dst )
else
"%s is up-to-date" '( dst )
then fth-print cr
;
"libsndlib.so" "/usr/opt/lib/s7" 0o755 install-lib
file-length
( name -- len )file-match-dir
( dir reg -- files-ary )file-mkdir
( name mode -- )file-mkfifo
( name mode -- )file-mtime
( name -- time )time->string.file-pwd
( -- path )file-realpath
( name -- path )HOME. If
realpath(3) is successful, the resolved path will be
returned, otherwise name with ‘~’
replacement will be returned.
"~" file-realpath ⇒ "/home/mike"
"/usr/pkg" file-chdir ⇒ "/usr/pkg"
file-pwd ⇒ "/usr/pkg"
"../bin" file-realpath ⇒ "/usr/bin"
file-rename
( src dst -- )file-rmdir
( name -- )file-shell
( cmd -- str ) alias:
shellfile-split
( name -- ary )
"/home/mike/cage.snd" file-split
⇒ #( "/home/mike" "cage.snd" )
file-symlink
( src dst -- )file-system
( cmd -- f )file-touch
( name time -- )
\ set modification time an hour earlier
"main.c" current-time 3600 - file-touch
\ reset modification time to current time
"main.c" nil file-touch
file-truncate
( name size -- )open-file and
close-file, here are the corresponding pipe words.
open-pipe
( addr u fam -- fp ior )close-pipe
( fp -- ior )This example reads from the shell command pwd(1) and prints the result to standard output:
256 constant max-line
create line-buffer max-line 2 + allot
s" pwd" r/o open-pipe throw value FP
line-buffer max-line FP read-line throw drop
line-buffer swap type
FP close-pipe throw
file-block?
( name -- f )-b.file-character?
( name -- f )-c.file-directory?
( name -- f )-d.file-executable?
( name -- f )-x.file-exists?
( name -- f )-e.file-fifo?
( name -- f )-p.file-grpowned?
( name -- f )-G.file-owned?
( name -- f )-O.file-readable?
( name -- f )-r.file-setgid?
( name -- f )-g.file-setuid?
( name -- f )-u.file-socket?
( name -- f )-S.file-sticky?
( name -- f )-k.file-symlink?
( name -- f )-h.file-writable?
( name -- f )-w.file-zero?
( name -- f )
let:
#{} { hs }
hs 'a #( 0 1 2 ) hash-set!
hs .hash ⇒ #{ 'a => #( 0 1 2 ) }
hs 'b "text" hash-set!
hs .hash ⇒ #{ 'a => #( 0 1 2 ) 'b => "text" }
hs 'a hash-ref ⇒ #( 0 1 2 )
hs 'b hash-ref ⇒ "text"
hs 'c hash-ref ⇒ #f
hs 'a hash-delete! ⇒ '( 'a #( 0 1 2 ) )
hs .hash ⇒ #{ 'b => "text" }
hs hash-clear
hs .hash ⇒ #{}
"" { fs }
#{ 'a 6 } to hs
\ val: current '( key val )
hs each { val }
fs "%s: %s\n" val string-format string-push to fs
end-each ⇒ "'a: 6\n"
\ *key*: current '( key val )
hs map
*key* 1 array-ref 10 *
end-map ⇒ #{ 'a 60 }
;let
Words follow handling Hash Object Types:
.hash
( hash -- )>hash
( vals len -- hash )
'a 0 'b 1 4 >hash ⇒ #{ 'a ⇒ 0 'b ⇒ 1 }
hash->array
( hash -- ass )
#{ 'a 0 'b 1 } hash->array
⇒ #( #( 'a 0 ) #( 'b 1 ) )
hash-clear
( hash -- )hash-copy
( hash1 -- hash2 )hash-delete!
( hash key -- ary )hash-each
( hash proc-or-xt -- )
#{ 'a 0 'b 1 } lambda: <{ key val -- }>
"%s=%s\n" #( key val ) fth-print
; hash-each
hash-equal?
( obj1 obj2 -- f ) alias:
hash=hash-find
( hash key -- ary )hash-keys
( hash -- keys )hash-values
( hash -- vals )hash-length
( obj -- len )hash-map
( hash1 proc-or-xt -- hash2 )
#{ 'a 0 'b 1 } lambda: <{ key val -- val }>
val 10 +
; hash-map ⇒ #{ 'a => 10 'b => 11 }
hash-member?
( hash key -- f )hash-ref
( hash key -- value )hash-search
( hs reg -- res )hash-set!
( hash key value -- )hash?
( obj -- f )make-hash
( -- hash ) alias:
#{}make-hash-with-len
( size -- hash )Usage of properties:
#f properties ⇒ #{}
"string" value obj
obj 'a "hello" property-set!
obj 'a property-ref ⇒ "hello"
obj 'b property-ref ⇒ #f
obj properties ⇒ #{ 'a => "hello" }
#f properties ⇒ #{ "string" => #{ 'a => "hello" } }
properties
( obj -- props )property-ref
( obj key -- val )property-set!
( obj key val -- )Usage of object-properties:
"string" value obj
obj 'a "hello" object-property-set!
obj 'a object-property-ref ⇒ "hello"
obj 'b object-property-ref ⇒ #f
obj object-properties ⇒ #{ 'a => "hello" }
object-properties
( obj -- props )object-property-ref
( obj key -- val )object-property-set!
( obj key val -- )Usage of word-properties:
<'> noop 'a "hello" word-property-set!
<'> noop 'a word-property-ref ⇒ "hello"
<'> noop 'b word-property-ref ⇒ #f
<'> noop word-properties ⇒ #{ 'a => "hello" \
'documentation => "noop" }
word-properties
( xt -- props )word-property-ref
( xt key -- val )word-property-set!
( xt key val -- ).hook
( hook -- )create-hook
( arity help "name"
-- )
2 "A simple hook." create-hook my-new-hook
#( 2 0 #f ) "A simple hook." create-hook my-new-hook
hook->array
( hook -- procs ) aliases:
hook->list hook-procshook-add
( hook proc-or-xt -- ) alias:
add-hook!hook-apply
( hook args -- value-list ) alias:
run-hook
2 make-hook value hk1
hk1 <'> + 2 make-proc add-hook!
hk1 #( 1 2 ) run-hook ⇒ #( 3 )
hook-arity
( hook -- arity )
2 make-hook hook-arity ⇒ #( 2 0 #f )
hook-clear
( hook -- ) alias:
reset-hook!hook-delete
( hook proc-or-name -- prc ) alias:
remove-hook!hook-empty?
( hook -- f )hook-member?
( hook proc-or-name -- f )hook-name
( hook -- name )hook-names
( hook -- name-list )hook=
( obj1 obj2 -- f )hook?
( obj -- f )make-hook
( arity -- hook )
2 make-hook value my-new-hook
#( 2 0 #f ) make-hook value my-new-hook
set-*stdin*
( io -- old )set-*stdout*
( io -- old )set-*stderr*
( io -- old )version-control
( -- val )set-version-control
( val -- )io-open-file
( :key fam r/o args -- io )io-open-input-file
( :key args -- io )io-open-output-file
( :key args -- io )Examples
:filename "foo" io-open-file value io1 :command "ls -lF" io-open-file value io2 :string "test string" io-open-file value io3 :socket nil :port 79 io-open-file value io4 :soft-port "test" io-open-file value io5
io-open
( name :key fam r/o if-exists overwrite --
io )io-open-read
( name -- io )io-open-write
( name :key if-exists overwrite --
io )make-file-portmake-file-input-portmake-file-output-portmake- words are aliases
for the corresponding io- ones.The following constants are predefined for file access mode :fam:
If the keyword :if-exists was not specified, overwrites a possible existing file if opened for writing. The following :if-exists keywords are provided:
VERSION_CONTROL and the global Fth variable
version-control.Examples
"in-test" io-open value ro1 "in-test" :fam r/o io-open value ro2 "out-test" :fam w/o io-open value wo1 "out-test" :fam w/o :if-exists :overwrite io-open value wo2 "out-test" :fam r/w :if-exists :error io-open value rw1 "out-test" :fam r/w :if-exists :rename io-open value rw2
io-popen
( cmd :key fam r/o -- io )io-popen-read
( cmd -- io )io-popen-write
( cmd -- io )make-pipe-portmake-pipe-input-portmake-pipe-output-portio-popen can be
opened read/write with :fam r/a.
The make- words are aliases for the corresponding
io- ones. If the global environment variable
FTH_POPEN_SHELL is defined and has a shell
pathname, popen(3) uses this shell for execution.Examples
\ read pipe "ls -lAF ~/" io-popen-read value rio \ or #( "ls" "-lAF" "~/" ) io-popen value rio rio io->string fth-print rio io-close \ write pipe "cat" io-popen-write value wio wio "hello" io-puts wio io-close \ read/write pipe (only where mode "r+" is allowed) "fth -" :fam r/a io-popen value rwio rwio "80 f2c\n" io-puts rwio io-gets fth-print rwio io-close
io-sopen
( str :key fam r/o -- io )io-sopen-read
( str -- io )io-sopen-write
( str -- io )make-string-portmake-string-input-portmake-string-output-portmake- words are aliases
for the corresponding io- ones.Examples
"test-string" value s s io-sopen value rio rio io-read fth-print rio io-close s :fam w/a io-sopen value aio aio " with appended contents" io-write aio io-rewind aio io-read fth-print aio io-close s fth-print ⇒ "test-string with appended contents"
io-nopen
(host :key args -- io )make-socket-portOpens a new socket server or connects to an already
established one. host is a host name
(AF_INET/AF_INET6) or a path name (AF_UNIX). If
host is not a string, "localhost" will
be used. port is the connection port (default
1024) if domain is AF_INET/AF_INET6, otherwise
unused, and domain can be AF_INET6 (default),
AF_INET, or AF_UNIX. If the :domain keyword was
specified, uses that domain, otherwise socket(2) tries
AF_INET6 first. If that fails, tries AF_INET. type
can be SOCK_STREAM or SOCK_DGRAM. socket(2) is opened
with domain, type, and
hard-coded flag 0. fam can be
r/w (default) or server.
In the latter case, the returned IO object is opened as a server,
otherwise the IO object is opened as a client. Raises
socket-error exception if
socket(2) or connect(2) fail. The
make- word is an alias.
Examples
"localhost" :port 25 io-nopen value io
io "HELP\r\n" io-puts
io io-gets fth-print
io io-close
.io
( io -- )io->string
( io -- str )io-address
( io -- ip-addr )io-close
( io -- )io-closed?
( io -- f )io-eof?
( io -- f ) alias:
io-eos?io-exit-status
( -- n ) alias:
exit-statusio-fdopen
( fd :key fam r/o -- io )
2 :fam w/o io-fdopen value err-io
err-io "our error log" io-write
err-io io-flush ⇒ "our error log" (on standard error)
io-filename
( io -- name ) alias:
io-hostnameio-fileno
( io -- fd ) alias:
io-fdio-flush
( io -- )io-getc
( io -- c )io-input?
( obj -- f )io-output?
( obj -- f )io-mode
( io -- mode )io-pos-ref
( io -- pos ) alias:
io-tellio-pos-set!
( io pos -- )io-putc
( io c -- )io-read
( io -- line ) aliases:
io-gets io-recvio-readlines
( io -- array-of-lines )io-reopen
( io1 name :key fam io1-fam --
io2 )
"1-test" io-open-write value io1
io1 "hello" io-write
io1 "2-test" io-reopen value io2
io1 io-closed? ⇒ #t
io2 "world" io-write
io2 io-close
io2 io-closed? ⇒ #t
"1-test" readlines ⇒ #( "hello" )
"2-test" readlines ⇒ #( "world" )
*stderr* "error.log" io-reopen value err-io
io-rewind
( io -- )io-seek
( io offset :key whence io-seek-set --
pos )io-select
( :key readfds writefds exceptfds timeout --
f )io-tmpfile
( -- io )io-write
( io line -- ) aliases:
io-puts io-sendio-write-format
( io fmt args -- )io-writelines
( io array-of-lines -- )io=
( obj1 obj2 -- f )io?
( obj -- f )readlines
( name -- array-of-lines )writelines
( name array-of-lines -- )fd-close
( obj -- )OPEN_MAX (128), close(2) is
used.fd-dup2
( old-fd new-fd -- )fd-ioctl
( fd request flag -- res )FIOCLEXFIONCLEXFIONBIOFIOASYNCSIGIO.FIONREADFIOSETOWNSIGIO and SIGURG
signals (sockets).FIOGETOWNSIGIO and
SIGURG signals.fd-read
( fd -- line )OPEN_MAX (128), returns 0, #f for EOF is returned,
otherwise the read line is returned. See also
read(2).fd-write
( fd line -- )OPEN_MAX (128). See also
write(2).net-eos?
( fd -- )make-sockaddr
( host port domain -- addr )make-socket-io
( fd -- io ) alias:
net-fd->ionet-accept
( fd host domain -- io )net-bind
( fd host port domain -- )net-connect
( fd host port domain -- io )net-listen
( fd -- )net-recv
( fd flags -- msg )net-recvfrom
( fd flags addr -- msg )net-recvfrom2
( fd flags host port domain --
msg )net-send
( fd msg flags -- )net-sendto
( fd msg flags addr -- )net-sendto2
( fd msg flags host port domain
-- )net-shutdown
( fd how -- )net-socket
( domain type -- fd )net-socketpair
( type -- fd-ary )net-getpeername
( fd -- name )net-getsockname
( fd -- name )gethostbyaddr
( ip -- hash )
.gethostbyaddr ( ip
-- ).gethostbyaddr prints these entries
nicely.gethostbyname
( host -- hash )
.gethostbyname ( host
-- ).gethostbyname prints these entries
nicely.getservbyname
( serv -- hash )
.getservbyname ( serv --
).getservbyname prints these entries nicely.getservbyport
( port -- hash )
.getservbyport ( port --
).getservbyport prints these entries
nicely.h_errno
( -- n )hstrerrno
( n -- str )Socket Examples
This is the simple TCP client/server network example found in Chapter 6 of UNIX Network Programming (1990) by W. Richard Stevens.
\
\ The server reads one line at a time from the socket
\ and writes each line back to the sender.
\
: str-echo { so -- }
nil { line }
begin
so io-gets to line
line "\n" string<>
while
so line io-puts
repeat
;
\
\ The client reads one line from file IO and writes it to the socket,
\ then reads a line back from the socket and writes it to *stdout*.
\
: str-cli { so io -- }
nil { line }
begin
io io-gets to line
line ".\n" string<>
while
so line io-puts
*stdout* so io-gets io-puts
repeat
so "\n" io-puts
;
\
\ Callback for server.
\
: echo-cb { so sfd -- prc; self -- }
0 proc-create ( prc )
sfd , so ,
does> { self -- }
self @ ( sfd ) fd-close
self cell+ @ { so }
so str-echo
%s finished\n" '( so ) fth-stderr
so io-close
;
\
\ Start the TCP server at one terminal.
\
: tcp-server ( -- )
"0.0.0.0" { serv-addr }
"localhost" { cli-addr }
6543 { port }
AF_INET SOCK_STREAM net-socket { sfd }
sfd serv-addr port AF_INET net-bind
sfd net-listen
begin
sfd cli-addr AF_INET net-accept ( so )
sfd echo-cb fork ." pid " . cr
again
;
\
\ Start the TCP client at a second terminal and begin writing.
\ The server echos each line back.
\
: tcp-client ( -- )
"localhost" { serv-addr }
6543 { port }
AF_INET SOCK_STREAM net-socket { sfd }
serv-addr port AF_INET net-connect ( so )
*stdin* str-cli
;
FICL_VM_STATE_INTERPRETINTERPRET_STATEFICL_VM_STATE_COMPILECOMPILE_STATE
state @ COMPILE_STATE = if
\ compile state action here
else
\ interpret state action here
then
Bytes
String Constants
add-feature
( feature -- )
'snd add-feature
add-load-lib-path
( path -- )
"/home/mike/lib/fth" add-load-lib-path
add-load-path
( path -- )
"/home/mike/share/fth" add-load-path
apropos
( obj -- ary )
/do/ apropos ⇒ #( "doLocal" ... )
dl-load
( "lib" "func"
-- )
dl-load dbm Init_dbm
include
( "name" -- )HOME if name begins with
this character. With include one can load a file
more than once. Before loading name, runs hook
before-load-hook. After loading
name, runs hook
after-load-hook. Raises
no-such-file exception if file doesn't exist and
load-error exception if an error occurred during
load.
include hello
install
( "file" -- )-e is
necessary because the last occurrence of -e will
be compiled but install is a parse word and won't
work in compile state.
\ from script:
install snd-test.fs
install sndlib.so
\ from shell command prompt:
% fth -ve 'install sndlib.so' -e ''
install-file
( file -- )
\ from script:
"snd-test.fs" install-file
"sndlib.so" install-file
\ from shell command prompt:
% fth -ve '"sndlib.so" install-file'
load-init-file
( file -- )HOME directory, loads it, otherwise does nothing.
Replaces ‘~’ with HOME if
name begins with this character.
".my-fth-init" load-init-file
provided?
( obj -- f )
'fth provided? ⇒ #t
'foo provided? ⇒ #f
require
( "name" -- )HOME if
name begins with this character. With
require one can load files only once. Before
loading name, runs hook
before-load-hook. After loading
name, runs hook
after-load-hook. Raises
no-such-file exception if file doesn't exist and
load-error exception if an error occurred during
load.
require hello
unshift-load-lib-path
( path -- )
"/home/mike/lib/fth" unshift-load-lib-path
unshift-load-path
( path -- )
"/home/mike/share/fth" unshift-load-path
fth-catch
( ?? obj exc arg -- ?? res )If something went wrong, catching depends on exc and returning on arg. If exc is #t, all exceptions will be caught, if exc is an exception, only this exception will be caught.
The return value depends an arg. If arg is nil, '( exc exc-msg ) will be returned, if arg is a proc-or-xt, the result of this will be returned, if arg is neither nil nor a proc-or-xt, arg itself will be returned.
#( 0.3 0.3 0.3 ) value ary
ary 2 <'> array-ref #t nil fth-catch ⇒ 0.3 #f
ary 4 <'> array-ref 'out-of-range #t fth-catch
⇒ #( 0.3 0.3 0.3 ) 4 #t
: ary-handler { retval -- val }
"from handler: %S\n" #( retval ) fth-print
#t ( return value )
;
ary 4 0.4 <'> array-set!
'out-of-range <'> ary-handler fth-catch
prints: ⇒ from handler: \
#( 'out-of-range "array-set! (ary_set) arg 2: \
4 is out of range" )
⇒ 0.4 #t
ary 2 0.4 <'> array-set!
'out-of-range <'> ary-handler fth-catch ⇒ #f
fth-raise
( exc fmt args -- )
'bad-arity "%s: %s args required, got %s"
#( proc 3 2 ) fth-throw
⇒ #<bad-arity in test-proc: 3 args required, got 2>
#f #f #f fth-raise
⇒ reraise last exception
fth-throw
( exc args -- )
\
\ ARGS: any object
\
'bad-arity proc fth-throw
⇒ #<bad-arity in test-proc>
\
\ ARGS: nil or #()
\
'bad-arity nil fth-throw
⇒ #<bad-arity: proc has bad arity>
\
\ ARGS: #( string )
\
'bad-arity #( "test-proc" ) fth-throw
⇒ #<bad-arity in test-proc>
\
\ ARGS: #( fmt arg1 arg2 arg3 )
\
'bad-arity #( "%s: %s args required, got %s"
proc
3
2 ) fth-throw
⇒ #<bad-arity in test-proc: 3 args required, got 2>
stack-reset
( ?? -- )current-time
( -- secs )date
( -- str )gmtime
( secs -- ary )localtime
( secs -- ary )mktime
( ary -- secs )
#( 28 40 2 14 0 112 6 13 #f 3600 "CET" ) mktime
strftime
( fmt secs -- str )
"%a %b %d %H:%M:%S %Z %Y" current-time strftime
⇒ "Sat Jan 14 02:40:28 CET 2012"
strptime
( str fmt -- secs )
"2012 01 14" "%Y %m %d" strptime time->string
⇒ "Sat Jan 14 02:40:28 CET 2012"
time
( -- r )time->string
( secs -- str )
current-time time->string ⇒ "Sat Jan 14 02:40:28 CET 2012"
time-reset
( -- )utime
( -- utime stime )
utime ⇒ 0.171875 0.0234375
closelog
( -- )environ
( -- hash )errno
( -- n )exec
( cmd -- )FTH_POPEN_SHELL or
SHELL is set to a shell pathname, use this shell,
otherwise use /bin/sh to execute
cmd. If cmd is an array of
strings, no shell expansion takes place and the first element of
cmd should be a program name. See
exec(3) for more information.
\ string
lambda: <{}> "man exec" exec ; fork 0 waitpid
exit-status 0=
\ array of strings
lambda: <{}> #( "man" "exec" ) exec ; fork 0 waitpid
exit-status 0=
fork
( xt -- pid )
lambda: <{}> "man fork" exec ; fork 0 waitpid
exit-status 0=
getegid
( -- id )getenv
( name -- value )geteuid
( -- id )getgid
( -- id )gethostname
( -- str ) alias:
hostnamegetlogin
( -- str )getpgrp
( -- pgrp )getpid
( -- id )getppid
( -- id )getrusage
( -- ary )
.getrusage
( -- ).getrusage prints
this array.getsid
( pid -- sid )getuid
( -- id )kill
( pid sig -- )SIGKILL. See
kill(2) for more information.openlog
( ident logopt facility -- )putenv
( name value -- ) alias:
setenvsetegid
( id -- )seteuid
( id -- )setgid
( id -- )sethostname
( str -- )setsid
( -- sid )setuid
( id -- )signal
( sig xt -- old-xt )
SIGINT lambda: { sig -- }
"\nSIGINT (#%d) received\n" '( sig ) fth-stderr
; signal value old-xt
sleep
( secs -- )strerror
( n -- str )strsignal
( n -- str )syslog
( priority fmt :optional args
-- )LOG_EMERGLOG_ALERTLOG_CRITLOG_ERRLOG_WARNINGLOG_NOTICELOG_INFOLOG_DEBUGtcgetpgrp
( fd -- pgrp )
getpgrp STDOUT_FILENO tcgetpgrp = if
⇒ foreground process
else
⇒ background process
then
umask
( :optional mask nil -- mask )uname
( -- hs )
.uname
( -- ).uname prints these
slots.wait
( -- pid )
lambda: <{}> #( "man" "wait" ) exec ; fork value pid
wait pid = if ." finished" then
waitpid
( pid flags -- )See waitpid(2) for more information.
lambda: <{}> #( "man" "waitpid" ) exec ; fork 0 waitpid
exit-status 0=
getopt
( argv opts -- c )
% cat getopt-test.fth
#! /usr/pkg/bin/fth -s
: main ( -- )
#f { bflag }
#f { ffile }
#t to opterr \ getopt prints error messages
begin
*argv* "bf:" getopt ( ch ) dup
while ( ch )
case
<char> b of #t to bflag endof
<char> f of optarg to ffile endof
<char> ? of
"usage: [-b] [-f file]\n" .stderr
1 (bye) \ exit with return code 1
endof
endcase
repeat ( ch ) drop
optind 0 ?do *argv* array-shift drop loop
*argv* array-length to *argc*
"-b: %s, -f: %s\n" #( bflag ffile ) fth-print
;
main
0 (bye) \ exit with return code 0
% ./getopt-test.fth
⇒ -b: #f, -f: #f
% ./getopt-test.fth -b
⇒ -b: #t, -f: #f
% ./getopt-test.fth -bf outfile
⇒ -b: #t, -f: outfile
% ./getopt-test.fth -f
⇒ fth: option requires an argument -- f
⇒ usage: [-b] [-f file]
% ./getopt-test.fth -h
⇒ fth: illegal option -- h
⇒ usage: [-b] [-f file]
getopt-long
( argv opts longopts -- c )
: long-test
#f { bflag }
#f { ffile }
#f to opterr
#( #( "flag" no-argument <char> b )
#( "file" required-argument <char> f ) ) { opts }
begin
*argv* "bf:" opts getopt-long ( ch ) dup
while ( ch )
case
<char> b of #t to bflag endof
<char> f of optarg to ffile endof
<char> ? of
"-%c requires an argument"
#( optopt ) fth-warning
endof
endcase
repeat drop ( ch )
optind 0 ?do *argv* array-shift drop loop
*argv* array-length to *argc*
"-b, --flag (default #f): %s\n" #( bflag ) fth-print
"-f, --file (default #f): %s\n" #( ffile ) fth-print
;
(bye)
( n -- )at-exit
will be executed and the current process will be terminated with exit code
n._exit!
( n -- )at-exit
( obj -- )at-exit are
possible, all procs or xts will be called in order. The stack effect of
obj is ( -- ). See atexit(3) for
more information.
lambda: <{ -- }> "test.file" file-delete ; at-exit
.cflags
( -- )
config-cflags ( --
str ).libs
( -- )
config-libs ( --
str ).long-version
( -- )
.version
( -- ).memory
( -- ).prefix
( -- )
config-prefix ( --
str )configure-args
( -- str )ver
( -- addr len )
ver type ⇒ "1.4.2 (2020/11/20) [x86_64-pkgsrc-netbsd]"
bignum?
complex? even?exact?
fixnum? float?inexact?
inf? integer?long-long?
nan? number?odd?
prime? ratio?rational?
ulong-long? unsigned?0<
0<> 0>0<=
0= 0>=negative?
zero? positive?<
<> ><= =
>=u<
u<> u>u<=
u= u>=d0<
d0<> d0>d0<=
d0= d0>=dnegative?
dzero? dpositive?
1 d0>= ⇒ #t
1.0 d0< ⇒ #f
d<
d<> d>d<=
d= d>=
1 2.0 d< ⇒ #t
1.0 2 d= ⇒ #f
du<
du<> du>du<=
du= du>=
1 2.0 du< ⇒ #t
1.0 2 du= ⇒ #f
c0<>c0=
1.0+1.0i c0<> ⇒ #t
0.0+0.0i c0= ⇒ #t
1 c0= ⇒ #f
c<>c=
1.0+1.0i 1+i c= ⇒ #t
1+0i 2.0 c<> ⇒ #t
1 1+0i c= ⇒ #t
b0<
b0<> b0>b0<=
b0= b0>=b<
b<> b>b<=
b= b>=q0<
q0<> q0>q0<=
q0= q0>=q<
q<> q>q<=
q= q>=f>s
( x -- n ) aliases:
d>s c>s b>s q>ss>d
( x -- d ) aliases:
f>d >llong make-long-longs>ud
( x -- ud ) aliases:
f>ud make-ulong-longs>f
( x -- r ) aliases: d>f c>f b>f
q>fs>c
( x -- c ) aliases:
f>c q>c >cs>b
( x -- b ) aliases:
f>b >bignum make-bignums>q
( x -- q ) aliases:
f>q c>q1+
1- 2+ 2- 2* 2/abs
negate+ - *
/max
mind2*
d2/dabs
dnegated+
d- d* d/dmax
dmin1/f
f2* f2/fabs
fnegatef+
f- f* f/fmax
fminf**
alias: fpowfacos
( r1 -- r2 )facosh
( r1 -- r2 )falog
( r1 -- r2 )fasin
( r1 -- r2 )fasinh
( r1 -- r2 )fatan
( r1 -- r2 )fatan2
( r1 r2 -- r3 )fatanh
( r1 -- r2 )fceil
( r1 -- r2 )fcos
( r1 -- r2 )fcosh
( r1 -- r2 )fexp
( r1 -- r2 )fexpm1
( r1 -- r2 )flog
( r1 -- r2 )flog10
( r1 -- r2 )flog2
( r1 -- r2 )flog1p
( r1 -- r2 ) alias:
flogp1floor
( r1 -- r2 )fround
( r1 -- r2 )fsin
( r1 -- r2 )fsincos
( r1 -- r2 r3 )fsinh
( r1 -- r2 )fsqrt
( r1 -- r2 )ftan
( r1 -- r2 )ftanh
( r1 -- r2 )ftrunc
( r1 -- r2 )fsincos
returns sin(r1) and cos(r1). r1 can be any type of
number but should fit in ficlFloat.
1/c
cnegatec+
c- c* c/c**
alias: cpowComplex-I
( -- I )cabs
( c1 -- c2 )cabs2
( c1 -- c2 )cacos
( c1 -- c2 )cacosh
( c1 -- c2 )carg
( c1 -- c2 )casin
( c1 -- c2 )casinh
( c1 -- c2 )catan
( c1 -- c2 )catan2
( c1 c2 -- c3 )catanh
( c1 -- c2 )ccos
( c1 -- c2 )ccosh
( c1 -- c2 )cexp
( c1 -- c2 )clog
( c1 -- c2 )clog10
( c1 -- c2 )conj
( c1 -- c2 )conjugate
( c1 -- c2 )csin
( c1 -- c2 )csinh
( c1 -- c2 )csqrt
( c1 -- c2 )ctan
( c1 -- c2 )ctanh
( c1 -- c2 )magnitude
( c1 -- c2 )b2*
b2/babs
bnegateb+
b- b* b/b**
alias: bpowbmax
bminbgcd
( x y -- z )blcm
( x y -- z )broot
( b1 u -- b2 n )bsqrt
( b1 -- b2 n )bmod
( b1 b2 -- b3 n )b/mod
( b1 b2 -- b3 b4 n )blshift
( b1 n -- b2 )brshift
( b1 n -- b2 )1/q
qabs qceil qfloor qnegateq+
q- q* q/q**
qpowfegetround
( -- n )fesetround
( n -- )See fenv(3), fegetround(3), and fesetround(3).
>complex
( r1 r2 -- c ) alias:
make-rectangulardenominator
( x -- n )exact->inexact
( x -- r )imag-ref
( x -- r ) alias:
image-refinexact->exact
( x -- n )inf
( -- inf )make-polar
( real theta -- c )make-ratio
( num den -- q )nan
( -- NaN )numerator
( x -- n )rationalize
( x err -- y )real-ref
( x -- r )rand-seed-ref
( -- seed )rand-seed-set!
( seed -- )frandom
( r -- -r...+r )random
( r -- 0.0..r ).r
( n1 n2 -- )
17 3 .r ⇒ | 17 |
bn.
( b -- )
17.0 bn. ⇒ |17 |
c.
( c -- )
17.0+1.0i c. ⇒ |17.0+1.0i |
d.
( d -- )
17 d. ⇒ |17 |
d.r
( d n -- )
17 3 d.r ⇒ | 17 |
f.r
( r n -- )
17.0 3 f.r ⇒ |17.000 |
q.
( q -- )
17.0 q. ⇒ |17/1 |
u.r
( u n -- )
17 3 u.r ⇒ | 17 |
ud.
( ud -- )
17 ud. ⇒ |17 |
ud.r
( ud n -- )
17 3 ud.r ⇒ | 17 |
uf.r
( r len-all len-after-comma -- )
17.0 8 3 uf.r ⇒ | 17.000 |
17.0 8 2 uf.r ⇒ | 17.00 |
backtrace
( -- ) alias:
btframe-depth
( -- n ) alias: stack-levelobject-print-length
( -- n )
set-object-print-length ( n
-- )gc-marked?
( obj -- f )gc-protected?
( obj -- f )gc-permanent?
( obj -- f )gc-mark
( obj -- obj )gc-unmark
( obj -- obj )gc-protect
( obj -- obj )gc-unprotect
( obj -- obj )gc-on
( -- #f )gc-off
( -- #f )gc-run
( -- )gc-stats
( -- )gc-protected-objects
( -- ary )gc-permanent-objects
( -- ary )instance-gen-ref
( obj -- gen )instance-obj-ref
( obj -- gen )instance-gen-ref
returns the GEN-struct of obj,
instance-obj-ref returns the OBJ-struct of
obj, used for example by
make-object-type-from.
instance?
( obj -- f )instance-of?
( obj type -- f )make-instance
( gen obj -- instance )make-object-type
( name -- object-type )object-type?
( obj -- f )make-object-type
creates a new object-type name and adds
name to the feature list, creates a constant
fth-name of object-type and returns the new
object-type name. The new created object-type can be
used to bind words to it. object-type? checks if
obj is an object-type.make-object-type-from
( name base -- object-type )object-type-ref
( obj -- struct )object-types
( -- ary )set-object->array
( xt obj -- )set-object->string
( xt obj -- )set-object-apply
( xt obj arity -- )set-object-copy
( xt obj -- )set-object-dump
( xt obj -- )set-object-equal-p
( xt obj -- )set-object-free
( xt obj -- )set-object-inspect
( xt obj -- )set-object-length
( xt obj -- )set-object-mark
( xt obj -- )set-object-value-ref
( xt obj -- )set-object-value-set
( xt obj -- )object-xxx
word to object-type obj..inspect
( obj -- )object-inspect
( obj -- str )object-dump
( obj -- str ).inspect
prints inspect string of obj while the other words
return the inspect and dump string of obj. The dump
string may be evaled to reinstate the object from a file.
.object-name
( obj -- )object-name
( obj -- name )cycle-ref
( obj -- val )cycle-set!
( obj value -- )cycle-start!
( obj index -- )cycle-start@
( obj -- index )cycle-start0
( obj -- )first-ref
( obj -- val )first-set!
( obj value -- )second-ref
( obj -- val )second-set!
( obj value -- )third-ref
( obj -- val )third-set!
( obj value -- )last-ref
( obj -- val )last-set!
( obj value -- )hash-id
( obj -- id )object-id
( obj -- id )hash-id
returns hash id computed from string representation of
obj. Objects with the same contents have the same
id. object-id returns object id of
obj, a uniq number.
object->array
( obj -- ary )object->string
( obj -- str )object-apply
( obj args -- result ) alias:
apply
fth_set_object_apply(vct_tag, vct_ref, 1, 0, 0); /* C */
<'> enved-ref fth-enved 1 set-object-apply \ Forth
object-copy
( obj1 -- obj2 )object-debug-hook
( obj -- hook )
#( 0 1 ) value ary
ary .inspect ⇒ #<array[2]: #<fixnum: 0> #<fixnum: 1>>
ary object-debug-hook lambda: <{ str obj -- new-str }>
"debug-inspect: %s" #( obj ) string-format
; add-hook!
ary .inspect ⇒ #<debug-inspect: #( 0 1 )>
ary object-debug-hook hook-clear
ary .inspect ⇒ #<array[2]: #<fixnum: 0> #<fixnum: 1>>
object-empty?
( obj -- f ) alias:
empty?object-equal?
( obj1 obj2 -- f ) alias:
equal?object-index
( obj key -- index ) alias:
indexobject-find
( obj key -- value ) alias:
detectobject-member?
( obj key -- f ) alias:
member?object-length
( obj -- len ) alias:
lengthobject-range?
( obj index -- f ) alias:
range?object-ref
( obj index -- val )object-set!
( obj index value -- )object-set+!
( obj index value -- )object-set-!
( obj index value -- )object-set*!
( obj index value -- )object-set/!
( obj index value -- )object-sort
( obj cmp-xt -- ary ) alias:
sort
: numb-sort { val1 val2 -- n }
val1 val2 < if
-1
else
val1 val2 > if
1
else
0
then
then
;
#( 6 2 8 1 ) <'> numb-sort object-sort ⇒ #( 1 2 6 8 )
make-soft-port words. For example one can split the
output to the snd(1) listener and to standard error or to a
log file.
Input Example
"in-test.text" io-open-read value *io*
:port-name "read-soft"
:read-line lambda: <{ -- line }> *io* io-read ;
:close lambda: <{ -- }> *io* io-close ;
make-soft-input-port value prt
prt port-read ⇒ first line of in-test.text
prt port-close
Output example
The output is split to the Snd listener with
snd-print and to standard error with
.stderr. snd-print returns its input string which we
use for .stderr. Nothing have to be closed and a :close proc isn't
necessary.
:port-name "sndout"
:write-line lambda: <{ line -- }> line snd-print ( line ) .stderr ;
make-soft-output-port value prt
prt "hello" port-write
make-soft-port
( :key args -- prt )make-soft-input-port
( :key args -- prt )make-soft-output-port
( :key args -- prt )The words above know the following keywords. Not all procs are required.
The prt argument in the following words may be an IO object returned from io- or port-words, or #f. In the latter case uses Ficl input resp. Ficl output.
port->string
( prt -- str )port-close
( prt -- )port-flush
( prt -- )port-closed?
( prt -- f )port-display
( prt obj -- )port-getc
( prt -- c )port-gets
( prt -- str ) alias:
port-readport-input?
( obj -- f )port-output?
( obj -- f )port-putc
( prt c -- )port-puts
( prt str -- ) alias:
port-writeport-puts-format
( prt fmt args -- ) alias:
port-write-format
#f "hello, %s" #( "world" ) port-puts-format
⇒ hello, world
port?
( obj -- f )with-input-port
( obj :key args -- str )
obj ( io --
str )with-input-from-port
( obj :key args -- str )
obj ( --
str )with-input-from-port points
the input IO to *stdin*.If the obj argument for input is nil, read the entire IO object, otherwise execute obj as a proc-or-xt. After reading is finished close IO object and return resulting string.
lambda: <{ io -- str }>
io io->string
; :filename "file.test" with-input-port
<'> io-readlines :command "ls -l" with-input-port
nil :string "hello" with-input-port
lambda: <{ -- str }>
*stdin* io->string
; :filename "file.test" with-input-from-port
nil :command "ls -l" with-input-from-port
nil :string "hello" with-input-from-port
with-output-port
( obj :key args -- )
obj ( io
-- )with-output-to-port
( obj :key args -- )
obj ( -- )with-error-to-port
( obj :key args -- )
obj ( -- )with-output-to-port points
the output IO to *stdout* and
with-error-to-port points it to
*stderr*.If the obj argument for output is a string, write the string to the IO object, if obj is an array, write its contents to the IO object, otherwise execute obj as a proc-or-xt. After writing is finished close IO object.
"hello" :filename "file.test" with-output-port
"file.test" readlines :command "cat" with-output-to-port
"" value s
lambda: <{ io -- }>
io "hello" io-write
; :string s with-output-port
lambda: <{ -- }>
\ all three do the same and put the string to *stdout*:
\ *stdout* "hello" io-write
\ #f "hello" port-write
." hello"
; :string s with-output-to-port
lambda: <{ -- }>
*stderr* "hello" io-write
; :string s with-error-to-port
.proc
( prc -- )<'set>
( "name" --
set-name|#f )
128 <'set> object-print-length execute
128 set-object-print-length
<{
( -- ){ }
and {{ }} this form handles two keywords,
:key and :optional. Variable names are
taken from keyword and optional names. This word can span over more than
one lines but without empty lines or comments in between. If
:key and :optional is used together,
:key must come first. All keyword and optional variables
must have default values. This word is immediate and compile only and can
only be used in word definitions.
: optkey-test <{ a b c
:key d 10 e 20 :optional f 30 g 40 -- ary }>
#( a b c d e f g )
;
1 2 3 optkey-test ⇒ #( 1 2 3 10 20 30 40 )
:d 11 1 :e 22 2 3 4 optkey-test ⇒ #( 1 2 3 11 22 4 40 )
<{}>
( -- )
: we-dont-need-args <{}> ;
<'> we-dont-need-args proc? ⇒ #t
defined?
( "name" -- f )
defined? 10 ⇒ #f
defined? nil ⇒ #t
defined? + ⇒ #t
doc"
( <ccc>" -- )
: new-word ( -- )
doc" our documentation may contain \
\"double quotes\".
Escape them with a backslash."
\ we do nothing
;
help new-word ⇒ new-word ( -- ) our documentation may
contain "double quotes".
Escape them with a backslash.
documentation-ref
( obj -- str )documentation-set!
( obj str -- )get-func-name
( -- name )
: new-word
get-func-name .$
space
10
;
new-word ⇒ new-word 10
get-optarg
( req def -- val )
: optarg-test ( a b c=33 d=44 e=55 -- ary )
4 55 get-optarg { e }
3 44 get-optarg { d }
2 33 get-optarg { c }
{ a b }
#( a b c d e )
;
1 2 optarg-test ⇒ #( 1 2 33 44 55 )
1 2 3 4 optarg-test ⇒ #( 1 2 3 4 55 )
1 2 3 4 5 6 7 optarg-test ⇒ 1 2 #( 3 4 5 6 7 )
get-optargs
( lst req -- vals )
: optargs-test ( a b c=33 d=44 e=55 -- ary )
#( 33 44 55 ) 2 get-optargs { a b c d e }
#( a b c d e )
;
1 2 optargs-test ⇒ #( 1 2 33 44 55 )
1 2 3 4 optargs-test ⇒ #( 1 2 3 4 55 )
1 2 3 4 5 6 7 optargs-test ⇒ 1 2 #( 3 4 5 6 7 )
get-optkey
( key def -- val )
: optkey-test ( start dur keyword-args -- ary )
:frequency 440.0 get-optkey { freq }
:initial-phase pi get-optkey { phase }
{ start dur }
#( start dur freq phase )
;
0 1 optkey-test ⇒ #( 0.0 1.0 440.0 3.14159 )
0 2 :frequency 330.0 optkey-test ⇒ #( 0.0 2.0 330.0 3.14159 )
get-optkeys
( ary req -- vals )
: optkeys-test ( start dur keyword-args -- ary )
#( :frequency 440.0
:initial-phase pi )
2 get-optkeys { start dur freq phase }
#( start dur freq phase )
;
0 1 optkeys-test ⇒ #( 0.0 1.0 440.0 3.14159 )
0 2 :frequency 330.0 optkeys-test ⇒ #( 0.0 2.0 330.0 3.14159 )
help
( "name" -- )
help make-array \ Forth word
help array \ topic
help-add!
( obj str -- )help-ref
( obj -- str )help-set!
( obj str -- )
#( "behemoth" "pumpkin" "mugli" ) value hosts
hosts "local-net hostnames" help-set!
hosts help-ref ⇒ "local-net hostnames"
lambda:
( -- xt )
lambda: ( a b -- c ) + ; value plus
plus help-ref ⇒ lambda: ( a b -- c )
1 2 plus execute ⇒ 3
1 2 lambda: ( a b -- c ) * ; execute ⇒ 2
latestxt
( -- xt )local-variables
( -- vars )
: word-with-locals { foo -- }
10 { bar }
local-variables each
.$ space
end-each
;
20 word-with-locals ⇒ #{ "bar" => 10 "foo" => 20 }
make-proc
( xt arity -- prc )
<'> + 2 make-proc ⇒ +
lambda: ( a b -- c )
+
; #( 2 0 #f ) make-proc ⇒ lambda-009
proc->xt
( prc -- xt )proc-apply
( prc args -- res ) alias:
run-proc
<'> + 2 make-proc value plus
plus #( 5 6 ) proc-apply ⇒ 11
proc-arity
( prc -- arity )proc-create
( arity -- prc )create it goes with
does>.
: input-fn ( gen -- proc; dir self -- r )
{ gen }
1 proc-create \ returns proc with one argument
gen , \ stores gen for later use in DOES
does> { dir self -- r } \ dir (ignored here) self (address)
self @ \ returns our gen
readin \ returns readin value
;
instrument: src-simp <{ start dur amp sr sr-env fname -- }>
:file fname find-file make-readin { f }
:input f INPUT-FN :srate sr make-src { sc }
:envelope sr-env :duration dur make-env { en }
start dur run
i sc en env #f src amp f* *output* outa drop
loop
f mus-close drop
;instrument
0 1.5 0.5 0.2 #( 0 0 50 1 100 0 ) "fyow.snd"
<'> src-simp with-sound
proc-name
( prc -- name )proc-source-ref
( proc-or-xt -- str )proc-source-set!
( prc str -- )proc?
( obj -- f )running-word
( -- xt )
: new-word
running-word xt->name .$
space
10
; new-word ⇒ new-word 10
see2
( "name" -- )set!
( "name" -- )
128 set! object-print-length
128 set-object-print-length
set-execute
( xt -- ?? )
128 <'> object-print-length set-execute
128 set-object-print-length
set-xt
( xt1 -- xt2 )
128 <'> object-print-length set-xt execute
128 set-object-print-length
source-file
( xt -- file )source-line
( xt -- line )source-ref
( obj -- str )source-set!
( obj str -- )thunk?
( obj -- f )trace-var
( var proc-or-xt -- )to.
mus-array-print-length ⇒ 8
8 value *clm-array-print-length*
<'> *clm-array-print-length* lambda: <{ val -- res }>
val set-mus-array-print-length
; trace-var
24 to *clm-array-print-length*
*clm-array-print-length* ⇒ 24
mus-array-print-length ⇒ 24
<'> *clm-array-print-length* untrace-var
untrace-var
( var -- )word?
( obj -- f )word-create
( name -- )does>-part as body.
: make-setter ( name -- ; hs val self -- )
{ name }
name "!" $+ word-create
name ,
does> { hs val self -- }
hs self @ ( slot ) val hash-set!
;
"user-time" make-setter ⇒ creates setter word 'user-time!'
#{} value hs
hs 3.2 user-time!
hs ⇒ #{ "user-time" => 3.2 }
name->xt
( name -- xt )
1 2 "+" name->xt execute ⇒ 3
xt->name
( xt -- str )
<'> + xt->name ⇒ "+"
xt->origin
( xt -- str )xt?
( obj -- f )REG_EXTENDED. The variable can be set with the
following predefined constants, if more than one are used, combine them
with or:
For example, set matching to ignore case before creating a new regexp:
REG_EXTENDED REG_ICASE or to *re-syntax-options*
or:
No default is set.
/
( <ccc>/ -- reg )
/(B|b)+/ ⇒ /(B|b)+/
make-regexp
( str -- reg )
"(B|b)+" make-regexp value reg
re-match
( reg str start -- n )
/b+/ "aabaab" 0 re-match ⇒ 1
/b+/ "aabaac" 3 re-match ⇒ -1
re-search
( reg str start range -- n )
/b+/ "aabaab" 2 1 re-search ⇒ 2
/b+/ "aabaab" 0 1 re-search ⇒ -1
re/
( space<ccc>/ -- reg )
re/ (B|b)+/ ⇒ /(B|b)+/
regexp-match
( reg str -- len|#f ) aliases
regexp= re=
/.*(bar)/ value reg
reg "foobar" regexp-match ⇒ 6
reg 0 apply ⇒ foobar
reg 1 apply ⇒ bar
reg 2 apply ⇒ #f
regexp-replace
( reg str1 replace -- str2 )
/(foo)/ "foo-bar" "***\\1***" regexp-replace
⇒ ***foo***-bar
Note the double backslashes on back reference characters.
regexp-search
( reg str :key start 0 range -1 --
pos|#f )if. If keyword
range is -1 (default), the entire string will be
searched.
/foo/ "foobar" :start 0 :range 6 regexp-search ⇒ #t (pos 0)
/(bar)/ value reg
reg "foobar" :start 0 :range 2 regexp-search ⇒ #f
reg "foobar" :start 3 :range 2 regexp-search ⇒ 3
reg 0 apply ⇒ bar
reg 1 apply ⇒ bar
reg 2 apply ⇒ #f
regexp?
( obj -- f )
/^$/ regexp? ⇒ #t
.string
( obj -- ) aliases:
.$ .g.error
( obj -- )warning
( str -- ) alias:
warnerror
( str -- )die
( str -- )fth-warning
( fmt :optional args -- )fth-error
( fmt :optional args -- )fth-die
( fmt :optional args -- )#<warning: ...> continuing
execution, or in #<error: ...> and throw
error-exit exception, or in
#<die: ...> and exit the interpreter with
return code 1 (EXIT_FAILURE); args is optional. See
string-format for
fmt description.
fth-format
( fmt :optional args -- str )fth-read
( -- str )fth-print
( fmt :optional args -- ).stdout
( obj -- ).stderr
( obj -- ).debug
( obj -- )fth-stdout
( fmt :optional args -- )fth-stderr
( fmt :optional args -- )fth-debug
( fmt :optional args -- ).debug
and fth-debug wrap output
in #<DEBUG(F): ...>. Ficl output and
standard output may differ as well as Ficl error output and standard
error.String Create Words
"
( <ccc>" -- str )
"pumpkin" ⇒ "pumpkin"
""
( -- str )$"
( space<ccc>" -- str )
$" pumpkin" ⇒ "pumpkin"
$>string
( addr len -- str )string>$
( str -- addr len )type and evaluate
require this kind of strings.
$cr
( -- str )$space
( -- str )$spaces
( n -- str )int->char
( n -- c )make-string
( len :key initial-element ' ' --
str )
3 :initial-element <char> x make-string ⇒ "xxx"
string-format
( fmt args -- ) alias
format
"%04d %8.2f %b %X %o" #( 128 pi 255 255 255 ) string-format
⇒ "0128 3.14 11111111 FF 377"
The format string can have zero or more of the following flags:
#b, B,
o and O conversion,
add a zero before the output, for x and
X conversion, add a ‘0x’
respective ‘0X’ before the output. For
a, A,
e, E,
f, F,
g and G conversion,
the result will always have a decimal point.-0The following conversion specifiers are known:
%aAeEfFgGcbdouxXpobject-inspect.sobject->string.Smobject-dump.General String Words
char?
( obj -- )string->array
( str -- ary )
"foo" string->array ⇒ #( 102 111 111 )
string-append
( str1 str2 -- str3 ) alias:
$+string-capitalize
( str1 -- str2 )
string-capitalize!string-capitalize! changes the original string
contents.string-chomp
( str1 -- str2 )
string-chomp!string-chomp! changes
the original string contents.string-concat
( objs len -- str ) alias:
>string
0 1 2 " foo " "b" "a" "r" 7 >string
⇒ "012 foo bar"
string-copy
( str1 -- str2 )string-delete!
( str idx -- val )string-downcase
( str1 -- str2 )
string-downcase!string-downcase! changes the original
string contents.string-eval
( str -- ?? )
7 "3 4 + +" string-eval ⇒ 14
string-eval-with-status
( str -- ?? status )BREAKERROR_EXITINNER_EXITOUT_OF_TEXTRESTARTUSER_EXITstring-fill
( str char -- str' )string-find
( str1 key -- str2|#f )
"hello world" "l" string-find ⇒ "llo world"
"hello world" /ell/ string-find ⇒ "ello world"
string-index
( str key -- idx )
"hello world" "orl" string-index ⇒ 7
string-insert!
( str idx val -- str' )string-length
( str -- len )string-member?
( str key -- f )
"hello world" "ell" string-member? ⇒ #t
"hello world" /ell/ string-member? ⇒ #t
string-pop
( str -- char )string-push
( str val -- str' ) alias:
<<string-ref
( str idx -- val )string-replace
( str1 from to -- str2 )
string-replace!string-replace! changes the original string
contents.string-reverse
( str1-- str2 )
string-reverse!string-reverse! changes the original string
contents.string-set!
( str idx val -- )string-shift
( str -- char )string-split
( str sep -- ary )
"foo:bar:baz:" ":" string-split
⇒ #( "foo" "bar" "baz" )
"foo:bar:baz:" /:/ string-split
⇒ #( "foo" "bar" "baz" )
string-substring
( str1 start end -- str2 )
"hello world" 2 4 string-substring ⇒ "ll"
"hello world" 0 -1 string-substring ⇒ "hello world"
"hello world" -4 -2 string-substring ⇒ "orl"
"hello world" -4 nil string-substring ⇒ "orld"
string-unshift
( str val -- str' )string-upcase
( str1 -- str2 )
string-upcase!string-upcase! changes the original
string contents.string-cmp
( str1 str2 -- n )string<
( str1 str2 -- f )string<>
( str1 str2 -- f )string=
( str1 str2 -- f )string>
( str1 str2 -- f )string?
( obj -- f ).symbol
( sym -- )create-symbol
( "name" -- )
create-symbol new-symbol ⇒ creates symbol 'new-symbol
make-symbol
( name -- sym )
"new-symbol" make-symbol ⇒ 'new-symbol
symbol-name
( sym -- str )
'new-symbol symbol-name ⇒ "new-symbol"
symbol=
( obj1 obj2 -- f )symbol?
( obj -- f ).keyword
( kw -- )create-keyword
( "name" -- )
create-keyword new-keyword ⇒ creates keyword :new-keyword
keyword-name
( kw -- name )
:new-keyword keyword-name ⇒ "new-keyword"
keyword=
( obj1 obj2 -- f )keyword?
( obj -- f )make-keyword
( name -- kw )
"new-keyword" make-keyword ⇒ :new-keyword
.exception
( ex -- )create-exception
( msg "name" -- )
"New test exception" create-exception new-exception
⇒ creates 'new-exception
exception-last-message-ref
( ex -- msg )exception-last-message-set!
( ex msg -- )exception-message-ref
( ex -- msg )exception-message-set!
( ex msg -- )exception-name
( ex -- name )
'new-exception exception-name ⇒ "new-exception"
exception=
( obj1 obj2 -- f )exception?
( obj -- f )make-exception
( name msg -- ex )
"New test exception" create-exception new-exception
⇒ creates 'new-exception
symbol->exception
( sym -- ex )fth reads the following global environment variables:
FTH_DICTIONARY_SIZEFTH_LOCALS_SIZEFTH_RETURN_SIZEFTH_STACK_SIZEFTH_FTHPATHFTH_HISTORYFTH_HISTORY_LENGTHFTH_INIT_FILEFTH_LIBPATHFTH_POPEN_SHELLfth_popen() as well as
exec, if cmd is a string, use this shell for
execution of shell commands. If not defined,
fth_popen() falls back to
/bin/sh, and exec, if cmd
is a string, falls back to SHELL or, if not set,
/bin/sh.Furthermore, fth checks the following
shell variables:
fth uses a global and a local initialization file and a
history file.
FTH_INIT_FILE.FTH_HISTORY.fth utility exits 0 on success,
and >0 if an error occurs.
fth interpreter:
Prints 32 Fahrenheit as Celsius (0.0):
% fth -e "32 f2c .
cr"The following loads the C extension library
libxm.so with its initialization function
Init_libxm() and the Forth source file
motif-script.fs, executes word
main and exits:
% fth -S "libxm Init_libxm"
-e "main" motif-script.fsAdds path ~/share/forth in front of *load-path*, loads Forth source file sound-script.fs and starts the repl. Initialization files ${prefix}/etc/fthrc and ~/.fthrc are loaded if they exist:
% fth -I ~/share/forth
sound-script.fsPrints compiler and linker flags for
CFLAGS and LIBS:
% fth -e .cflags% fth -e .libs% fth -e "config-cflags .g space
config-libs .g cr"Runs Forth script check.fth and provides
option -a and option -b with
argument 10 to the script which should handle at least
these two; exits if finished:
% fth -s check.fth -ab
10If the first line in check.fth is
#! /usr/pkg/bin/fth -schmod 0755 check.fth% ./check.fth -ab 10Prints name (column 1) and login time (column 5) from the who(1) command output:
who | fth -ane '.*1* .*5*
cr'The same with output field separator set to " == ":
who | fth -ane '" == " to
*ofs* .*1* .*5* cr'Print login names and their uids found in /etc/passwd:
cat /etc/passwd | fth -aF: -e
'"%5s %s\n" #( *3* *1* ) fth-print'If the only option is a dash
‘-’, fth reads
from standard input and prints the result to standard output. The following
examples print the same result (~26.7):
% echo "80 f2c" | tee foo |
fth -% cat foo | fth -% fth - < foo% fth -80 f2c <enter>26.66666666666667bye%W. Richard Stevens, UNIX Network Programming, Prentice Hall, Englewood Cliffs, N.J., 1990.
fth version 1.4.5.
fth is based on Ficl,
Forth-inspired command language, version 4.0.31 written by
John Sadler.
fth and this manual page were written by
Michael Scholz
⟨mi-scholz@users.sourceforge.net⟩.
| 2025/01/22 | NetBSD 10.99.12 |