summaryrefslogtreecommitdiff
path: root/man/2
diff options
context:
space:
mode:
Diffstat (limited to 'man/2')
-rw-r--r--man/2/0intro189
-rw-r--r--man/2/INDEX493
-rw-r--r--man/2/alphabet-intro236
-rw-r--r--man/2/arg168
-rw-r--r--man/2/asn1621
-rw-r--r--man/2/attrdb237
-rw-r--r--man/2/bloomfilter89
-rw-r--r--man/2/bufio318
-rw-r--r--man/2/bufio-chanfill57
-rw-r--r--man/2/cfg159
-rw-r--r--man/2/command132
-rw-r--r--man/2/convcs367
-rw-r--r--man/2/crc62
-rw-r--r--man/2/daytime96
-rw-r--r--man/2/dbm222
-rw-r--r--man/2/debug382
-rw-r--r--man/2/devpointer57
-rw-r--r--man/2/dhcpclient354
-rw-r--r--man/2/dialog74
-rw-r--r--man/2/dict57
-rw-r--r--man/2/dis488
-rw-r--r--man/2/diskblocks120
-rw-r--r--man/2/disks317
-rw-r--r--man/2/dividers68
-rw-r--r--man/2/draw-0intro268
-rw-r--r--man/2/draw-context167
-rw-r--r--man/2/draw-display389
-rw-r--r--man/2/draw-example116
-rw-r--r--man/2/draw-font111
-rw-r--r--man/2/draw-image909
-rw-r--r--man/2/draw-point66
-rw-r--r--man/2/draw-pointer38
-rw-r--r--man/2/draw-rect138
-rw-r--r--man/2/draw-screen137
-rw-r--r--man/2/drawmux68
-rw-r--r--man/2/encoding50
-rw-r--r--man/2/env52
-rw-r--r--man/2/ether77
-rw-r--r--man/2/exception36
-rw-r--r--man/2/factotum174
-rw-r--r--man/2/filepat80
-rw-r--r--man/2/filter112
-rw-r--r--man/2/filter-deflate89
-rw-r--r--man/2/filter-slip52
-rw-r--r--man/2/format249
-rw-r--r--man/2/fsproto89
-rw-r--r--man/2/geodesy146
-rw-r--r--man/2/hash91
-rw-r--r--man/2/ida151
-rw-r--r--man/2/imagefile157
-rw-r--r--man/2/ip334
-rw-r--r--man/2/ir254
-rw-r--r--man/2/itslib101
-rw-r--r--man/2/keyring-0intro296
-rw-r--r--man/2/keyring-auth101
-rw-r--r--man/2/keyring-certtostr56
-rw-r--r--man/2/keyring-crypt120
-rw-r--r--man/2/keyring-gensk49
-rw-r--r--man/2/keyring-getmsg68
-rw-r--r--man/2/keyring-getstring90
-rw-r--r--man/2/keyring-ipint147
-rw-r--r--man/2/keyring-rc445
-rw-r--r--man/2/keyring-sha1142
-rw-r--r--man/2/keyset79
-rw-r--r--man/2/lock39
-rw-r--r--man/2/math-0intro79
-rw-r--r--man/2/math-elem106
-rw-r--r--man/2/math-export52
-rw-r--r--man/2/math-fp205
-rw-r--r--man/2/math-linalg146
-rw-r--r--man/2/mpeg74
-rw-r--r--man/2/names113
-rw-r--r--man/2/newns40
-rw-r--r--man/2/palmfile542
-rw-r--r--man/2/plumbmsg291
-rw-r--r--man/2/pop385
-rw-r--r--man/2/popup102
-rw-r--r--man/2/prefab-0intro75
-rw-r--r--man/2/prefab-compound262
-rw-r--r--man/2/prefab-element468
-rw-r--r--man/2/prefab-environ54
-rw-r--r--man/2/prefab-style95
-rw-r--r--man/2/print341
-rw-r--r--man/2/prof225
-rw-r--r--man/2/pslib46
-rw-r--r--man/2/rand35
-rw-r--r--man/2/readdir101
-rw-r--r--man/2/regex108
-rw-r--r--man/2/registries318
-rw-r--r--man/2/scsiio144
-rw-r--r--man/2/secstore250
-rw-r--r--man/2/security-0intro162
-rw-r--r--man/2/security-auth157
-rw-r--r--man/2/security-login93
-rw-r--r--man/2/security-random43
-rw-r--r--man/2/security-ssl76
-rw-r--r--man/2/selectfile57
-rw-r--r--man/2/sets226
-rw-r--r--man/2/sexprs362
-rw-r--r--man/2/sh561
-rw-r--r--man/2/smtp58
-rw-r--r--man/2/spki446
-rw-r--r--man/2/spki-verifier91
-rw-r--r--man/2/spree604
-rw-r--r--man/2/spree-allow129
-rw-r--r--man/2/spree-cardlib628
-rw-r--r--man/2/spree-gather105
-rw-r--r--man/2/spree-objstore63
-rw-r--r--man/2/srv66
-rw-r--r--man/2/string177
-rw-r--r--man/2/stringinttab87
-rw-r--r--man/2/styx416
-rw-r--r--man/2/styxconv77
-rw-r--r--man/2/styxpersist80
-rw-r--r--man/2/styxservers902
-rw-r--r--man/2/styxservers-nametree180
-rw-r--r--man/2/sys-0intro302
-rw-r--r--man/2/sys-bind201
-rw-r--r--man/2/sys-byte2char68
-rw-r--r--man/2/sys-chdir40
-rw-r--r--man/2/sys-dial247
-rw-r--r--man/2/sys-dirread59
-rw-r--r--man/2/sys-dup62
-rw-r--r--man/2/sys-export116
-rw-r--r--man/2/sys-fauth61
-rw-r--r--man/2/sys-fd2path46
-rw-r--r--man/2/sys-file2chan158
-rw-r--r--man/2/sys-fversion71
-rw-r--r--man/2/sys-iounit35
-rw-r--r--man/2/sys-millisec24
-rw-r--r--man/2/sys-open135
-rw-r--r--man/2/sys-pctl142
-rw-r--r--man/2/sys-pipe45
-rw-r--r--man/2/sys-print271
-rw-r--r--man/2/sys-read94
-rw-r--r--man/2/sys-remove23
-rw-r--r--man/2/sys-seek48
-rw-r--r--man/2/sys-self83
-rw-r--r--man/2/sys-sleep29
-rw-r--r--man/2/sys-stat283
-rw-r--r--man/2/sys-tokenize56
-rw-r--r--man/2/sys-utfbytes28
-rw-r--r--man/2/sys-werrstr26
-rw-r--r--man/2/tabs74
-rw-r--r--man/2/tftp54
-rw-r--r--man/2/timers89
-rw-r--r--man/2/tk270
-rw-r--r--man/2/tkclient229
-rw-r--r--man/2/translate135
-rw-r--r--man/2/ubfa273
-rw-r--r--man/2/venti107
-rw-r--r--man/2/virgil54
-rw-r--r--man/2/volume51
-rw-r--r--man/2/w3c-css349
-rw-r--r--man/2/w3c-xpointers382
-rw-r--r--man/2/wait100
-rw-r--r--man/2/wmclient235
-rw-r--r--man/2/wmlib90
-rw-r--r--man/2/wmsrv295
-rw-r--r--man/2/workdir25
-rw-r--r--man/2/xml266
161 files changed, 27330 insertions, 0 deletions
diff --git a/man/2/0intro b/man/2/0intro
new file mode 100644
index 00000000..297bade3
--- /dev/null
+++ b/man/2/0intro
@@ -0,0 +1,189 @@
+.TH INTRO 2
+.SH NAME
+intro \- introduction to Limbo modules for the Inferno system
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+include "tk.m";
+tk := load Tk Tk->PATH;
+
+.I "... etc."
+
+.I "Generically:"
+.EE
+.EX
+include "\fImodule\fP.m";
+.EE
+.fi
+.IB module " := "
+.BI load " Module"
+.IB Module ->PATH;
+.SH DESCRIPTION
+This section introduces the Limbo modules available to the programmer;
+see the corresponding manual pages for more information.
+Each module is declared with a single Limbo
+.B include
+file.
+Before calling a module's functions, an application must
+.B load
+the module; the application stores the resulting value in a variable for later use as
+the module qualifier.
+The examples above illustrate the style.
+It will usually be necessary in some cases to qualify names with the appropriate
+module pointer or to
+.B import
+the types and functions; the manual pages assume the names are accessible
+in the current scope.
+.PP
+Although many modules are self-contained,
+dependencies may exist.
+For example, the system module,
+.BR Sys ,
+provides basic services that many other modules require.
+These are the Inferno equivalent to `system calls'.
+.PP
+In a few cases, several related modules
+share a single
+.B include
+file;
+for instance,
+.BR security.m .
+.PP
+The manual pages describe how to
+.B include
+a module definition during
+compilation and
+.B load
+an implementation during execution.
+The documentation also lists relevant functions or abstract
+data types.
+Although the
+.B include
+files declare these components, the manual pages list them explicitly.
+In all cases, the enclosing
+.B module
+declaration is assumed so that unqualified identifiers can be
+used in the text without ambiguity, reducing clutter in the text.
+In practice when programming, many consider it good style to
+use an explicit module reference for functions and constants.
+.PP
+The Limbo modules are identical on any machine that is running Inferno,
+whether native or hosted, which enables Limbo programs to be written
+and tested on any Inferno system.
+.PP
+Many modules are described in a single page, such as
+.IR regex (2).
+Several larger modules are explained in several sections, such as
+.IR math-intro (2),
+.IR math-elem (2),
+.IR math-fp (2),
+and
+.IR math-linalg (2).
+.SS Exceptions
+Exception handling is now part of the Limbo language, replacing an older
+scheme that used special system calls.
+Various exceptions can be raised by the virtual machine when run-time errors
+are detected.
+These are the common ones:
+.RS
+.TP
+.B "alt send/recv on same chan"
+It is currently illegal for a channel to appear in two
+.B alt
+statements if they either both receive or both send on it.
+(It is fine to send in one and receive in the other.)
+.TP
+.B "array bounds error"
+Array subscript out of bounds.
+.TP
+.B "dereference of nil"
+Attempt to use a
+.B "ref"
+adt or index an array with value
+.B "nil" .
+.TP
+.B "invalid math argument"
+Inconsistent values provided to functions of
+.IR math-intro (2).
+.TP
+.B "module not loaded"
+Attempt to use an uninitialised module variable.
+.TP
+.B "negative array size"
+The limit in an array constructor was negative.
+.TP
+.BI "out of memory:" " pool"
+The given memory
+.I pool
+is exhausted.
+.I Pool
+is currently one of
+.B main
+(kernel memory including Tk allocations),
+.B heap
+(most Limbo data),
+and
+.B image
+memory for
+.IR draw (3).
+.TP
+.B "zero divide"
+Integer division (or mod) by zero.
+.RE
+.PP
+There are currently two more classes of exception string with a conventional interpretation
+imposed not by the run-time system proper, but by Limbo components:
+.RS
+.TP
+.BI "fail:" "reason"
+Commands use this exception to provide an `exit status' to a calling program,
+particularly the shell
+.IR sh (1);
+see also
+.IR sh (2).
+The status is given by the
+.I reason
+following the
+.RB ` fail: '
+prefix.
+.TP
+.BI "assertion:" "error"
+A module detected the specified internal
+.IR error .
+This is most often used for cases where a particular possibility ``cannot happen''
+and there is no other need for an error value in the interface.
+.RE
+.PP
+Otherwise, most module interfaces tend to use explicit error return values, not exceptions.
+.PP
+Note that a Limbo exception handler can do pattern matching to catch a class of exceptions:
+.IP
+.EX
+{
+ \f2body of code to protect\fP
+} exception e {
+"out of memory:*" =>
+ \f2recovery action\fP
+"assertion:*" =>
+ fatal_error(e);
+}
+.EE
+.PP
+The effect of an unhandled exception in a process that is part of an error-recovery group
+can be controlled using the mechanisms described in
+.IR prog (3)
+as accessed using
+.IR exception (2).
+.SH SEE ALSO
+.IR draw-intro (2),
+.IR exception (2),
+.IR keyring-intro (2),
+.IR math-intro (2),
+.IR prefab-intro (2),
+.IR security-intro (2),
+.IR sys-intro (2)
diff --git a/man/2/INDEX b/man/2/INDEX
new file mode 100644
index 00000000..6c7d8e44
--- /dev/null
+++ b/man/2/INDEX
@@ -0,0 +1,493 @@
+intro 0intro
+alphabet alphabet-intro
+alphabet-intro alphabet-intro
+arg arg
+asn1 asn1
+decode asn1
+encode asn1
+attrdb attrdb
+bloomfilter bloomfilter
+bufio bufio
+bufiofill bufio
+bufio bufio-chanfill
+bufio-chanfill bufio-chanfill
+chanfill bufio-chanfill
+attr cfg
+cfg cfg
+record cfg
+tuple cfg
+command command
+btos convcs
+convcs convcs
+stob convcs
+crc crc
+daytime daytime
+filet daytime
+gmt daytime
+local daytime
+now daytime
+text daytime
+time daytime
+tm2epoch daytime
+dbf dbm
+dbm dbm
+init dbm
+debug debug
+devpointer devpointer
+applycfg dhcpclient
+bootconf dhcpclient
+bootp dhcpclient
+dhcp dhcpclient
+dhcpclient dhcpclient
+lease dhcpclient
+removecfg dhcpclient
+dialog dialog
+getstring dialog
+prompt dialog
+dict dict
+dis dis
+block diskblocks
+disk diskblocks
+diskblocks diskblocks
+tempfile diskblocks
+chstext disks
+disk disks
+disks disks
+pcpart disks
+readn disks
+dividers dividers
+draw draw-0intro
+draw-intro draw-0intro
+context draw-context
+draw-context draw-context
+display draw-display
+draw-display draw-display
+draw draw-example
+draw-example draw-example
+example draw-example
+draw-font draw-font
+font draw-font
+draw-image draw-image
+image draw-image
+draw-point draw-point
+point draw-point
+draw-pointer draw-pointer
+pointer draw-pointer
+draw-rect draw-rect
+rect draw-rect
+draw-screen draw-screen
+screen draw-screen
+drawmux drawmux
+dec encoding
+enc encoding
+encoding encoding
+env env
+ether ether
+exception exception
+factotum factotum
+mount factotum
+proxy factotum
+rpc factotum
+expand filepat
+filepat filepat
+match filepat
+filter filter
+deflate filter-deflate
+filter-deflate filter-deflate
+inflate filter-deflate
+filter-slip filter-slip
+slip filter-slip
+format format
+
+fsproto fsproto
+fsproto fsproto fsproto
+readprotofile fsproto
+readprotostring fsproto
+geodesy geodesy
+hash hash
+hashtable hash
+consistent ida
+frag ida
+fragment ida
+ida ida
+reconstruct ida
+imagefile imagefile
+readgif imagefile
+readjpg imagefile
+readpicfile imagefile
+readpng imagefile
+readxbitmap imagefile
+remap imagefile
+ip ip
+ir ir
+itslib itslib
+keyring intro keyring-0intro
+keyring-intro keyring-0intro
+auth keyring-auth
+keyring keyring-auth
+keyring-auth keyring-auth
+readauthinfo keyring-auth
+writeauthinfo keyring-auth
+certtostr keyring-certtostr
+keyring keyring-certtostr
+keyring-certtostr keyring-certtostr
+pktostr keyring-certtostr
+sktostr keyring-certtostr
+strtocert keyring-certtostr
+strtopk keyring-certtostr
+strtosk keyring-certtostr
+aescbc keyring-crypt
+aessetup keyring-crypt
+descbc keyring-crypt
+desecb keyring-crypt
+dessetup keyring-crypt
+ideacbc keyring-crypt
+ideaecb keyring-crypt
+ideasetup keyring-crypt
+keyring keyring-crypt
+keyring-crypt keyring-crypt
+dhparams keyring-gensk
+gensk keyring-gensk
+genskfrompk keyring-gensk
+keyring keyring-gensk
+keyring-gensk keyring-gensk
+sktopk keyring-gensk
+getmsg keyring-getmsg
+keyring keyring-getmsg
+keyring-getmsg keyring-getmsg
+senderrmsg keyring-getmsg
+sendmsg keyring-getmsg
+getbytearray keyring-getstring
+getstring keyring-getstring
+keyring keyring-getstring
+keyring-getstring keyring-getstring
+putbytearray keyring-getstring
+puterror keyring-getstring
+putstring keyring-getstring
+ipint keyring-ipint
+keyring keyring-ipint
+keyring-ipint keyring-ipint
+keyring keyring-rc4
+keyring-rc4 keyring-rc4
+rc4 keyring-rc4
+rc4back keyring-rc4
+rc4setup keyring-rc4
+rc4skip keyring-rc4
+hmac_md5 keyring-sha1
+hmac_sha1 keyring-sha1
+keyring keyring-sha1
+keyring-sha1 keyring-sha1
+md4 keyring-sha1
+md5 keyring-sha1
+sha1 keyring-sha1
+sign keyring-sha1
+verify keyring-sha1
+keyset keyset
+lock lock
+intro math-0intro
+math math-0intro
+math-intro math-0intro
+acos math-elem
+acosh math-elem
+asin math-elem
+asinh math-elem
+atan math-elem
+atan2 math-elem
+atanh math-elem
+cbrt math-elem
+cos math-elem
+cosh math-elem
+erf math-elem
+erfc math-elem
+exp math-elem
+expm1 math-elem
+hypot math-elem
+j0 math-elem
+j1 math-elem
+jn math-elem
+lgamma math-elem
+log math-elem
+log10 math-elem
+log1p math-elem
+math math-elem
+math-elem math-elem
+pow math-elem
+pow10 math-elem
+sin math-elem
+sinh math-elem
+sqrt math-elem
+tan math-elem
+tanh math-elem
+y0 math-elem
+y1 math-elem
+yn math-elem
+export_int math-export
+export_real math-export
+export_real32 math-export
+import_int math-export
+import_real math-export
+import_real32 math-export
+math math-export
+math-export math-export
+math math-fp
+math-fp math-fp
+dot math-linalg
+gemm math-linalg
+iamax math-linalg
+math math-linalg
+math-linalg math-linalg
+norm1 math-linalg
+norm2 math-linalg
+sort math-linalg
+mpeg mpeg
+basename names
+cleanname names
+dirname names
+elements names
+isprefix names
+names names
+pathname names
+relative names
+rooted names
+newns newns
+categories palmfile
+dbinfo palmfile
+doc palmfile
+entry palmfile
+palmfile palmfile
+pfile palmfile
+record palmfile
+plumbmsg plumbmsg
+pop3 pop3
+add popup
+changebutton popup
+event popup
+mkbutton popup
+popup popup
+intro prefab-0intro
+prefab prefab-0intro
+prefab-intro prefab-0intro
+compound prefab-compound
+prefab prefab-compound
+prefab-compound prefab-compound
+element prefab-element
+prefab prefab-element
+prefab-element prefab-element
+environ prefab-environ
+prefab prefab-environ
+prefab-environ prefab-environ
+prefab prefab-style
+prefab-style prefab-style
+style prefab-style
+print print
+prof prof
+profile prof
+pslib pslib
+rand rand
+readdir readdir
+regex regex
+registries registries
+scsi scsiio
+scsiio scsiio
+secstore secstore
+intro security-0intro
+security-intro security-0intro
+auth security-auth
+client security-auth
+init security-auth
+security-auth security-auth
+server security-auth
+login security-login
+security-login security-login
+random security-random
+randombuf security-random
+randomint security-random
+security-random security-random
+connect security-ssl
+secret security-ssl
+security-ssl security-ssl
+ssl security-ssl
+selectfile selectfile
+sets sets
+sexp sexprs
+sexprs sexprs
+sh sh
+smtp smtp
+cert spki
+hash spki
+key spki
+name spki
+seqel spki
+signature spki
+spki spki
+subject spki
+toplev spki
+valid spki
+spki-verifier spki-verifier
+verifier spki-verifier
+verify spki-verifier
+spree spree
+allow spree-allow
+spree-allow spree-allow
+cardlib spree-cardlib
+spree-cardlib spree-cardlib
+gatherengine spree-gather
+spree-gather spree-gather
+objstore spree-objstore
+spree-objstore spree-objstore
+srv srv
+append string
+drop string
+in string
+prefix string
+quoted string
+splitl string
+splitr string
+splitstrl
+splitstrr string
+string string
+string string string
+take string
+tobig string
+toint string
+tolower string
+toupper string
+unquoted string
+stringinttab stringinttab
+dir2text styx
+istmsg styx
+packdir styx
+packdirsize styx
+qid2text styx
+readmsg styx
+rmsg styx
+styx styx
+tmsg styx
+unpackdir styx
+styxconv styxconv
+styxpersist styxpersist
+styxservers styxservers
+nametree styxservers-nametree
+styxservers styxservers-nametree
+styxservers-nametree styxservers-nametree
+intro sys-0intro
+sys sys-0intro
+sys-intro sys-0intro
+bind sys-bind
+mount sys-bind
+sys-bind sys-bind
+unmount sys-bind
+byte2char sys-byte2char
+char2byte sys-byte2char
+sys-byte2char sys-byte2char
+chdir sys-chdir
+sys-chdir sys-chdir
+announce sys-dial
+dial sys-dial
+listen sys-dial
+sys-dial sys-dial
+dirread sys-dirread
+sys-dirread sys-dirread
+dup sys-dup
+fildes sys-dup
+sys-dup sys-dup
+export sys-export
+sys-export sys-export
+fauth sys-fauth
+sys-fauth sys-fauth
+fd2path sys-fd2path
+sys-fd2path sys-fd2path
+file2chan sys-file2chan
+sys-file2chan sys-file2chan
+fversion sys-fversion
+sys-fversion sys-fversion
+iounit sys-iounit
+sys-iounit sys-iounit
+millisec sys-millisec
+sys-millisec sys-millisec
+create sys-open
+open sys-open
+sys-open sys-open
+pctl sys-pctl
+sys-pctl sys-pctl
+pipe sys-pipe
+sys-pipe sys-pipe
+fprint sys-print
+print sys-print
+sprint sys-print
+sys-print sys-print
+pread sys-read
+pwrite sys-read
+read sys-read
+stream sys-read
+sys-read sys-read
+write sys-read
+remove sys-remove
+sys-remove sys-remove
+seek sys-seek
+sys-seek sys-seek
+self sys-self
+sys-self sys-self
+sleep sys-sleep
+sys-sleep sys-sleep
+fstat sys-stat
+fwstat sys-stat
+stat sys-stat
+sys-stat sys-stat
+wstat sys-stat
+sys-tokenize sys-tokenize
+tokenize sys-tokenize
+sys-utfbytes sys-utfbytes
+utfbytes sys-utfbytes
+sys-werrstr sys-werrstr
+werrstr sys-werrstr
+mktabs tabs
+tabs tabs
+tabsctl tabs
+tftp tftp
+timers timers
+cmd tk
+imageget tk
+imageput tk
+keyboard tk
+namechan tk
+pointer tk
+quote tk
+tk tk
+toplevel tk
+handler tkclient
+makedrawcontext tkclient
+onscreen tkclient
+settitle tkclient
+snarfget tkclient
+snarfput tkclient
+startinput
+tkclient tkclient
+tkclient tkclient tkclient
+toplevel tkclient
+wmctl tkclient
+mkdictname translate
+opendict translate
+opendicts translate
+translate translate
+readubf ubfa
+ubfa ubfa
+uvalue ubfa
+writeubf ubfa
+venti venti
+virgil virgil
+volume volume
+w3c w3c-css
+w3c-css w3c-css
+w3c w3c-xpointers
+w3c-xpointers w3c-xpointers
+wait wait
+makedrawcontext wmclient
+snarfget wmclient
+snarfput wmclient
+window wmclient
+wmclient wmclient
+wmlib wmlib
+wmsrv wmsrv
+workdir workdir
+xml xml
diff --git a/man/2/alphabet-intro b/man/2/alphabet-intro
new file mode 100644
index 00000000..bb8c2bc4
--- /dev/null
+++ b/man/2/alphabet-intro
@@ -0,0 +1,236 @@
+.TH ALPHABET-INTRO 2
+.SH NAME
+Alphabet \- experimental typed shell
+.SH DESCRIPTION
+.SS "Values, type characters and signatures"
+Each Alphabet typeset defines one Limbo data type, conventionally
+named
+.BR Value .
+It is usually a discriminated union (pick), with each arm of the
+pick representing one of the types in the typeset.
+Each one of these types is given a character. These characters are
+used to describe all value- and module-types within alphabet.
+The set of typeset characters implemented by a typeset is
+known as its
+.IR alphabet .
+.PP
+For example, in the
+.I alphabet
+root typeset
+(see
+.IR alphabet-main (2)),
+a string is represented by
+the letter ``s'', held at the Limbo level as
+a
+.BR "ref Value.S" .
+.PP
+Each alphabet module has a
+.I "type signature"
+which describes its
+return type and the number and type of any flags or
+arguments that it allows.
+Inside an
+.I alphabet
+typeset, this signature is represented as a simple
+string where the first character (always present)
+indicates the return type of the module. Subsequent
+characters up until the first minus (``-'') sign (or the
+end of the string) indicate
+the module's required argument types.
+If the last character is an asterisk
+.RB ( * ),
+it allows an unlimited repetition of the preceding argument type.
+.PP
+These may be followed by any number of options, each indicated with a
+minus character, followed by the option character and then the type
+characters of any arguments it requires.
+.PP
+For instance, the following Alphabet declaration:
+.EX
+ /mount [-abc] [-x /string] /wfd /string -> /status
+.EE
+can be represented by the signature
+.BR `` rws-a-b-xs-c ''.
+.SS "Typesets and proxies"
+The root typeset
+(see
+.IR alphabet-main(2))
+is implemented internally to the
+.I alphabet
+module. All other types are defined by
+.I external
+typesets.
+.PP
+An external
+.I alphabet
+typeset is conventionally represented by two header files
+defining the interface to the typeset, and two modules
+giving its implementation. Suppose we are to
+create a new typeset, say
+.B /foo .
+We would create the following files:
+.TP 10
+.B /module/alphabet/foo.m
+.B Foo.m
+declares the interface used by all modules within the typeset.
+The existing typeset interface files (for instance
+.BR alphabet/grid.m ,
+documented in
+.IR alphabet-grid (2))
+provide examples of this kind of interface.
+.TP
+.B /appl/alphabet/footypes.b
+This module translates
+between
+.I "internal values"
+(each held as a
+.B Value
+as declared in
+.BR foo.m )
+and
+.I "external values"
+(each held as a
+.B Value
+as declared in the parent typeset, in this case by
+the
+.I alphabet
+module itself).
+Since Limbo does not provide a way of
+holding an arbitrary type directly, internal
+values are instead stored in a table by a local
+.IR proxy
+(see below),
+and referred to externally by their index there.
+.TP
+.B /appl/alphabet/foo.b
+.B Foo.b
+provides the basic type-manipulation
+primitives needed by the typeset, for instance
+the translation from type character to type name.
+It is also a convenient place to implement
+helper functions to make using the typeset easier.
+For instance, it is conventional for
+a typeset's
+.B Value
+adt to contain one eponymously named member function for each
+type character, making sure that the
+.B Value
+is actually of that type and returning the widened type,
+or raising an exception otherwise.
+For instance, in the root typeset,
+.IB v .s()
+returns the type
+.BR "ref Value.S" ,
+or raises an error if
+.I v
+is not of that type.
+.TP
+.B /module/alphabet/footypes.m
+.B Footypes.m
+provides an interface to the typeset proxy module,
+.BR footypes.b ,
+that allows direct
+access to values in the
+.B foo
+typeset, while still allowing
+manipulation of those values by an
+.I alphabet
+instance.
+.PP
+
+The proxy module,
+.BR footypes.b ,
+must define at least one function,
+.BR proxy ,
+which returns a channel through which
+all operations on the typeset take place.
+The
+.B Proxy
+module (see
+.IR alphabet-proxy (2))
+provides a generic implementation of such a translator;
+if
+.B footypes.b
+uses this, it needs only define the mapping
+between values in its parent typeset and its own values.
+.PP
+
+
+.SS "alphabet-main(2)"
+.TP 10
+.B types()
+.B Types
+is always the first function in a module to be called.
+It should do nothing but return the type signature string of the module.
+.TP
+.B init()
+.B Init
+is called to allow the module to initialise its global
+state. It is called once only.
+It is permissible for this function to raise a
+.RB `` fail: ''
+exception on failure. The text
+following the
+.RB `` fail: ''
+prefix should describe the reason why.
+.TP
+\f5run\fR(\fIerrorc\fP, \fIr\fP, \fIopts\fP, \fIargs\fP)
+.RS
+.B Run
+runs an actual instance of the module. It must be re-entrant.
+The signature of the
+.B run
+function varies from typeset to typeset,
+but usually includes the above arguments.
+.I Args
+holds a list of the arguments passed to the module;
+.I opts
+holds all the flags that have been specified.
+Each flag is represented with a tuple, say: (\fIc\fR, \fIoptargs\fP),
+where
+.I c
+gives the option character, and
+.I optargs
+is a list holding any arguments the flag requires.
+The arguments and options passed to the module are guaranteed
+to conform with the type signature returned from
+.BR types .
+Note that each flag may be passed multiple times to the module.
+.PP
+If the run succeeds, it should return the
+resulting value. If the module returns a value that was passed in,
+and it contains a reference-count, the count should
+be incremented before returning,
+If the module succeeds, it is responsible for the
+disposal of any arguments and option arguments that it has been given.
+Appropriate disposal depends on the type of the argument,
+but
+.IB v .free(0)
+is always sufficient to dispose of value
+.IR v .
+.PP
+If the run fails, it should return
+.BR nil ;
+its arguments will automatically be freed in this case.
+.PP
+While processing the
+.B run
+request, the module should send error and debugging diagnostics
+to the
+.I errorc
+channel (it should take care never to send an empty string).
+If it spawns any new processes, it can use the
+.BR Report ,
+.IR r ,
+(see
+.IR alphabet-reports (2))
+to create new diagnostic channels for these processes.
+When such an diagnostic channel is no longer in use,
+the module should send an empty string on it.
+It should take care that
+.B Report.start
+is called
+.I before
+.B run
+returns.
+.RE
diff --git a/man/2/arg b/man/2/arg
new file mode 100644
index 00000000..4cb8d937
--- /dev/null
+++ b/man/2/arg
@@ -0,0 +1,168 @@
+.TH ARG 2
+.SH NAME
+arg \- parse program arguments
+.SH SYNOPSIS
+.EX
+include "arg.m";
+arg := load Arg Arg->PATH;
+
+init: fn(argv: list of string);
+setusage: fn(s: string);
+usage: fn();
+progname: fn(): string;
+opt: fn(): int;
+arg: fn(): string;
+earg: fn(): string;
+argv: fn(): list of string;
+.EE
+.SH DESCRIPTION
+.B Arg
+parses a program's argument list in a traditional form,
+as received from a shell or other program
+(see
+.IR command (2)).
+The list must be passed to
+.B init
+to set the state for the other functions.
+.PP
+.B Arg
+takes the first argument to be the program name.
+Subsequent calls to
+.B progname
+return it.
+.PP
+Options are arguments containing one or more letters preceded by
+.B \-
+(dash, hyphen, minus).
+The list of options ends
+before the first argument that does not begin with a
+.BR \- .
+Option lists also end
+after an argument
+.BR \-\- ,
+to allow programs
+to accept arguments
+that would otherwise look like options
+(eg, file names for
+.IR rm (1)
+or a pattern for
+.IR grep (1)).
+Finally, option lists end
+before an argument
+.BR \- ,
+which is traditionally interpreted by some commands as referring to the standard input or output
+(depending on context).
+.PP
+Successive calls to
+.B opt
+return option characters in turn; 0 is returned at the end of the list.
+A program might take a parameter to a given option (eg, an option of the form
+.BI -f file
+or
+.BI -f " file" \f1).\f0
+Following a call to
+.BR opt ,
+a call to
+.BR arg
+will return the rest of the current argument string if not empty,
+failing that, the next argument string if any,
+and otherwise
+.BR nil .
+.B Earg
+is like
+.B arg
+except that if there is no argument associated
+with the option, an error message is printed to
+standard error, and a "\f5fail:usage\fP"
+exception raised.
+.B Setusage
+sets the error message that will be printed in
+this case (preceded by
+.RB ` usage: '
+and followed by a newline).
+.PP
+The argument list remaining after the last call to
+.B opt
+is returned by
+.BR argv .
+.SH EXAMPLE
+The following Limbo program takes options
+.BR b ,
+.B c
+and
+.BR f ,
+where
+.B f
+takes a file name argument.
+.br
+.ne 2i
+.PP
+.EX
+.ps -1
+.vs -1
+.ta \w'12345678'u +\w'12345678'u +\w'12345678'u +\w'12345678'u +\w'12345678'u
+implement Prog;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "arg.m";
+ arg: Arg;
+Prog: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ arg = load Arg Arg->PATH;
+
+ bflag := cflag := 0;
+ file := "";
+ arg->init(args);
+ while((c := arg->opt()) != 0)
+ case c {
+ 'b' => bflag = 1;
+ 'c' => cflag = 1;
+ 'f' => file = arg->arg();
+ * => sys->print("unknown option (%c)\en", c);
+ }
+ args = arg->argv();
+ sys->print("%s %d %d %s\en", arg->progname(), bflag, cflag, file);
+ for(; args != nil; args = tl args)
+ sys->print("%s\en", hd args);
+}
+.ps +1
+.vs +1
+.EE
+.PP
+When invoked as follows:
+.IP
+.B "prog -bc -ffile a b c"
+.PP
+the output is:
+.IP
+.EX
+prog 1 1 file
+a
+b
+c
+.EE
+.PP
+and when invoked by:
+.IP
+.B "./prog -b -f file -z -- -bc"
+.PP
+the output is:
+.IP
+.EX
+unknown option (z)
+\&./prog 1 0 file
+-bc
+.EE
+.SH SOURCE
+.B /appl/lib/arg.b
+.SH SEE ALSO
+.IR sh (1),
+.IR mash (1),
+.IR command (2)
diff --git a/man/2/asn1 b/man/2/asn1
new file mode 100644
index 00000000..45613473
--- /dev/null
+++ b/man/2/asn1
@@ -0,0 +1,621 @@
+.TH ASN1 2
+.SH NAME
+asn1: decode, encode \- ASN.1 (X.208), BER (X.209) encoding
+.SH SYNOPSIS
+.EX
+include "asn1.m";
+asn1 := load ASN1 ASN1->PATH;
+asn1->init();
+
+Elem: adt {
+ tag: Tag;
+ val: ref Value;
+
+ is_seq: fn(e: self ref Elem): (int, list of ref Elem);
+ is_set: fn(e: self ref Elem): (int, list of ref Elem);
+ is_int: fn(e: self ref Elem): (int, int);
+ is_bigint: fn(e: self ref Elem): (int, array of byte);
+ is_bitstring: fn(e: self ref Elem): (int, int, array of byte);
+ is_octetstring: fn(e: self ref Elem): (int, array of byte);
+ is_oid: fn(e: self ref Elem): (int, ref Oid);
+ is_string: fn(e: self ref Elem): (int, string);
+ is_time: fn(e: self ref Elem): (int, string);
+ tostring: fn(e: self ref Elem): string;
+};
+
+Tag: adt {
+ class: int;
+ num: int;
+ constr: int;
+
+ tostring: fn(t: self Tag): string;
+};
+
+Value: adt {
+ pick {
+ Bool or Int =>
+ v: int;
+ Octets or BigInt or Real or Other =>
+ bytes: array of byte;
+ BitString =>
+ unusedbits: int;
+ bits: array of byte;
+ Null or EOC =>
+ ;
+ ObjId =>
+ id: ref Oid;
+ String =>
+ s: string;
+ Seq or Set =>
+ l: list of ref Elem;
+ }
+
+ tostring: fn(v: self ref Value): string;
+};
+
+Oid: adt {
+ nums: array of int;
+ tostring: fn(o: self ref Oid): string;
+};
+
+init: fn();
+decode: fn(a: array of byte): (string, ref Elem);
+decode_seq: fn(a: array of byte): (string, list of ref Elem);
+decode_value: fn(a: array of byte, kind, constr: int):
+ (string, ref Value);
+encode: fn(e: ref Elem): (string, array of byte);
+oid_lookup: fn(o: ref Oid, tab: array of Oid): int;
+print_elem: fn(e: ref Elem);
+
+.EE
+.SH DESCRIPTION
+.B ASN1
+supports decoding and encoding of the ASN.1 Basic Encoding Rules
+(BER, ITU-T Recommendation X.209).
+Despite its name, the module is not a parser for Abstract Syntax Notation One
+(ASN.1, ITU-T Recommendation X.208).
+.PP
+.B ASN1
+handles the BER encodings of all types from the ASN.1 Universal class, and
+provides a simple OBJECT IDENTIFIER comparison facility.
+.PP
+For simplicity,
+.B ASN1
+does not take a description of the ASN.1 module of the data being
+processed.
+Consequently, the (de)composition of tagged types must be performed by the
+application.
+.B ASN1
+does not know the
+context of tagged values and so cannot determine the underlying Universal type
+to be able to encode or decode the value automatically.
+See the section on Tagging for details on how the application
+should handle both implicit and explicit tagging.
+.TP
+.B init()
+The module must be initialised by calling this function
+before any other module functions or associated adt member functions are called.
+.TP
+.BI decode( a )
+Convert the BER encoding given by the byte array
+.I a
+into an
+.B Elem
+representing the ASN.1 value.
+The byte array must contain
+the entire BER encoding of the value and any component values.
+.IP
+Item values not tagged as a Universal type are converted to an
+.B Elem
+comprised of the decoded
+.B Tag
+and a
+value given by the
+.B Value.Octets
+variant, which contains
+the original encoding of the value
+stripped of the BER tag and length header.
+.IP
+The function returns a tuple composed of an error string and
+the decoded
+.BR Elem .
+If no errors are encountered the error string is nil.
+.TP
+.BI decode_seq( a )
+Like
+.B decode
+except that the data in
+.I a
+is the encoding of an item of type SEQUENCE, SEQUENCE OF, SET or SET OF
+which has been stripped of its tag and length header.
+The function decodes all of the items in the SEQUENCE or SET.
+.IP
+The return value is a tuple composed of an error string and the list of
+.BR Elem s
+forming the SEQUENCE or SET.
+.HP
+.BI decode_value( a ,
+.IB kind ,
+.IB constr )
+.br
+Convert the encoding of a single item value to a
+.B Value
+data structure.
+.IP
+The array
+.I a
+does not include the tag and length header.
+Instead, the value's Universal type is given by the
+.I kind
+argument and length is given by that of the array.
+The
+.B constr
+argument indicates if the encoding is in the BER
+constructed form or not.
+A value of 0 indicates that the primitive encoding is used, all other values
+indicate the constructed encoding.
+.IP
+The function returns a tuple composed of an error string and a
+.B Value
+reference.
+.TP
+.BI encode( e )
+Convert the
+.B Elem
+.I e
+to a BER encoding of the element.
+If the element is of a structured type, such as SEQUENCE or SET,
+then all component values are also exhaustively encoded.
+.IP
+The encoding can fail if the
+.B Tag
+and
+.B Value
+of the element are not compatible.
+The
+.I constr
+field of the
+.B Tag
+is currently ignored.
+.IP
+The function returns a tuple comprising an error string and
+the BER encoding.
+If no errors are encountered the error string is nil and the
+second part of the returned tuple is a byte array of the
+BER encoding.
+.TP
+.BI oid_lookup( o ", " tab )
+Lookup an OBJECT IDENTIFIER value in an array of such values.
+Returns the index of the first exact match of
+.I o
+in the
+.I tab
+array.
+Returns -1 if no match is found.
+.TP
+.BI print_elem( e )
+Print a textual representation of the element to standard output.
+The output is that given by
+.BR Elem.tostring() ,
+followed by a newline character.
+.SS "Elem adt"
+This is the principal data structure, representing the value of an ASN.1 item.
+The adt couples a data representation, the
+.BR Value ,
+with its type specifier, the
+.BR Tag .
+.TP
+.B "Elem.tag"
+Specifies the ASN.1 type of the element value.
+See the description of the
+.B Tag
+adt for more details.
+.TP
+.B "Elem.val"
+The value of the element.
+See the description of the
+.B Value
+adt for more details.
+.PP
+All of the
+.IB e .is_ Type
+member functions test whether the specific
+.B Value
+pick variant of
+.B Elem.val
+and the ASN.1 Universal type, given by
+the tag, match and are of the requested form.
+A successful match yields the type specific data from the
+.B Value
+pick variant.
+The association of Universal types to
+.B Value
+pick variants is given in the section on the
+.B Value
+adt.
+.PP
+The function
+.IB e .is_int
+succeeds for BOOLEAN and INTEGER ASN.1 types.
+The function
+.IB e .is_string
+succeeds for all of the ASN.1 Universal string types.
+.PP
+Except for
+.BR is_bitstring ,
+each function returns a tuple of two values.
+The first tuple item is an integer, 1 for success, 0 for failure.
+The second item is the type specific data from the
+.B Value
+pick variant.
+.PP
+.TP
+.IB e ".is_bitstring()"
+Like the
+.BI is_ Type
+functions described above.
+Tests that the element is a BIT STRING and returns its data.
+.IP
+The return value is a tuple comprised of two integers and an array of bytes.
+The byte array represents the bit string.
+The first integer is 1 for success, 0 for failure.
+The second integer is the number of unused bits in the last byte of the data
+array.
+See the description of the
+.B Value.BitString
+variant for more information.
+.TP
+.IB e ".tostring()"
+returns a textual representation of the element formed by joining
+the strings returned from
+.IB e ".tag.tostring()"
+and
+.IB e ".val.tostring()" .
+.PP
+.SS "Tag adt"
+The
+.B Tag
+adt denotes the ASN.1 type of a
+.B Value
+instance.
+.TP
+.B "Tag.class"
+Specifies the class of the type and can take one of the values:
+.BR ASN1->Universal ,
+.BR ASN1->Application ,
+.B ASN1->Context
+or
+.BR ASN1->Private .
+.TP
+.B "Tag.num"
+Identifies the particular type, or tag, within the specified class.
+Tag numbers for the Universal class are given in the
+.B asn1.m
+header file.
+The inconsistent use of upper-case and mixed-case identifiers comes
+straight from the ITU-T Recommendation.
+.TP
+.B "Tag.constr"
+This flag is set by the
+.B ASN1
+decode functions to mark if the BER
+.I constructed
+encoding was used for the value.
+A zero value indicates the BER primitive encoding, non-zero indicates
+the constructed encoding.
+.TP
+.IB t ".tostring()"
+Returns a string representation of the
+.BR Tag .
+For Universal class tags the function returns
+the string
+.RB `` UNIVERSAL
+.IR "Name" '',
+where
+.I Name
+is the standard name of the specified Universal type.
+For other classes the function returns the class name, in upper-case,
+followed by the tag number.
+.SS "Value adt"
+This pick adt provides the representation for values of each of the various
+Universal class types.
+Values of all other classes are represented by the
+.B Value.Octets
+branch of the pick.
+.TP
+.IB v ".tostring()"
+Returns a string representation of the
+.BR Value .
+.PP
+The following table lists
+each variant of the pick, indicating the ASN.1 Universal type values
+it represents, followed by a brief description.
+For each variant of the pick,
+.I v
+is taken to be of that particular type.
+.TP
+.B Value.Bool
+BOOLEAN
+.IP
+.IB v .v
+equals zero for FALSE, non-zero values represent TRUE.
+.TP
+.B Value.Int
+INTEGER, ENUMERATED
+.IP
+The value is given by
+.IB v .v
+.TP
+.B Value.BigInt
+Used for INTEGER values too large to fit a Limbo int.
+.IP
+The array
+.IB v .bytes
+contains the encoding of the value.
+The array does not include the tag and length prefix.
+.TP
+.B Value.Octets
+OCTET_STRING, ObjectDescriptor
+.IP
+The octet string is given by the
+.IB v .bytes
+array.
+.TP
+.B Value.Null
+NULL
+.TP
+.B Value.ObjId
+OBJECT_ID
+.IP
+The OBJECT_ID value is represented by the
+.B Oid
+adt given by
+.IB v .id .
+.TP
+.B Value.Real
+REAL
+.IP
+.B ASN1
+does not convert the value into the Limbo
+.B real
+data type.
+The encoding of the value is given by the
+.IB v .bytes
+array, which does not include the tag and length prefix.
+.TP
+.B Value.Other
+EXTERNAL, EMBEDDED_PDV and Unknown Universal types
+.IP
+The raw bytes of the value, excluding the tag nad length header,
+are given by the
+.IB v .bytes
+array.
+.TP
+.B Value.BitString
+BIT_STRING
+.IP
+The number of bits in the BIT_STRING value does not have to be
+a multiple of 8.
+Bits are packed into bytes MSB first.
+The bytes representing the BIT_STRING value, including the potentially
+incomplete last byte, are given by the
+.IB v .bits
+array.
+The number of unused bits in the last byte of the array is given by
+.IB v .unused ,
+counting from the LSB.
+.IP
+The BER constructed encoding of values other than zero-length is not implemented.
+.TP
+.B Value.EOC
+End of Contents octets marker.
+.IP
+This value is not normally returned to the application; it is used
+privately by BER to support indefinite length value encodings.
+.TP
+.B Value.String
+NumericString, PrintableString, TeletexString,
+VideotexString, IA5String, UTCTime,
+GeneralizedTime, GraphicString, VisibleString,
+GeneralString, UniversalString or BMPString.
+.IP
+The text is given by the
+.IB v .s
+Limbo string.
+Currently no character-set conversion is performed between
+the ASN.1 string byte codes and the Unicode code-points of the Limbo string.
+.TP
+.B Value.Seq
+SEQUENCE, SEQUENCE OF
+.IP
+ASN.1 assigns both constructs the same type tag.
+The difference between them is that, within the
+ASN.1 notation, the elements
+of a SEQUENCE OF structure are constrained to be of the same type.
+BER and, consequently,
+.B ASN1
+do not directly enforce the restriction.
+.IP
+The elements of the sequence are given by the
+.IB v .l
+list.
+.TP
+.B Value.Set
+SET, SET OF
+.IP
+ASN.1 assigns both constructs the same type tag.
+The difference between them is that, within the ASN.1 notation,
+SET items are formed from an unordered list of distinct types, whereas
+SET OF items are formed from an unordered list of the same type.
+BER and
+.B ASN1
+do not enforce these constraints.
+.IP
+The elements of the set are given by the
+.IB v .l
+list.
+.SS "Oid adt"
+The
+.B Oid
+adt provides the value representation for OBJECT IDENTIFERs.
+Within the ASN.1 notation OBJECT IDENTIFIERs ultimately map
+to an ordered list of INTEGERs.
+.TP
+.B Oid.nums
+The value of the OBJECT IDENTIFIER, given as an
+.BR "array of int" .
+.TP
+.IB o .tostring()
+Returns a textual representation of the OBJECT IDENTIFIER in the
+form of a `.' separated list of numbers.
+.SS Tagging
+Tagging is an ASN.1 mechanism for disambiguating values.
+It is usually applied to component types, where several components
+of a structured type have the same underlying Universal class type.
+Tagging allows the client application to determine to which item of the
+structured type a value instance belongs.
+.PP
+There are two types of tagging, implicit and explicit, defining
+the manner in which the values are encoded.
+.PP
+Implicitly tagged values are encoded in the same way as the underlying type,
+but with the tag class and number replaced by that specified.
+.PP
+Explicitly tagged values are encoded in a nested fashion.
+The outermost item bears the specified tag and its contents is the
+full encoding of the original value using the tag of its underlying type.
+.PP
+The following examples of how to decode and encode simple tagged types
+should make the distinction clear.
+.SS "Decoding Tagged Values"
+Consider the following ASN.1 type definitions:
+.PP
+.EX
+ Type1 ::= INTEGER
+ Type2 ::= [Application 2] Type1 -- Explicitly tagged
+ Type3 ::= [3] IMPLICIT Type1 -- Implicitly tagged
+
+.EE
+For each of the types
+the value 16r55 will be decoded as follows:
+.PP
+.EX
+ (error, elem) := asn1->decode(data);
+.EE
+.TP
+.BR Type1 " (primitive type)"
+.EX
+elem.tag.class == Universal
+elem.tag.num == INTEGER
+tagof elem.val == tagof Value.Int
+elem.is_int() == (1, 16r55)
+.EE
+.TP
+.BR Type2 " (explicitly tagged)"
+.EX
+elem.tag.class == Application
+elem.tag.num == 2
+tagof elem.val == tagof Value.Octets
+
+.EE
+The
+.B bytes
+array of the
+.B Value.Octets
+value contains the complete encoding of the
+.B Type1
+value.
+The actual value can be obtained as follows:
+.IP
+.EX
+pick v := elem.val {
+Octets =>
+ (err2, e2) := asn1->decode(v.bytes);
+}
+.EE
+with
+.B e2
+having exactly the same properties as
+.B elem
+in the
+.B Type1
+case above.
+.TP
+.BR Type3 " (implicitly tagged)"
+.EX
+elem.tag.class == Context
+elem.tag.num == 3
+tagof elem.val == tagof Value.Octets
+
+.EE
+In this case the
+.B bytes
+array of the
+.B Value.Octets
+value contains the encoding of just the value part of the Type1 value,
+not the complete encoding.
+The actual value can be obtained as follows:
+.IP
+.EX
+pick v := e.val {
+Octets =>
+ constr := e.tag.constr;
+ (err, val) := asn1->decode_value(v.bytes, INTEGER, constr);
+}
+
+.EE
+Note that the application has to infer the type of the value from
+the context in which it occurs.
+The resultant
+.B val
+is of the type
+.B Value.Int
+with the value 16r55 stored in the
+.B v
+member variable.
+.SS "Encoding Tagged Values"
+To encode the value 16r55 in each of the above types, the following
+data structures are required.
+.TP
+.BR Type1 "(primitive type)"
+.EX
+tag := Tag(Universal, INTEGER, 0);
+val := Value.Int(16r55);
+elem := ref Elem(tag, val);
+(err, data) := asn1->encode(elem);
+.EE
+.TP
+.BR Type2 "(explicitly tagged)"
+.EX
+tag1 := Tag(Universal, INTEGER, 0);
+val1 := Value.Int(16r55);
+elem1 := ref Elem(tag1, val1);
+(err1, data1) := asn1->encode(elem1);
+tag2 := Tag(Application, 2, 0);
+val2 := Value.Octets(data1);
+elem2 := ref Elem(tag2, val2);
+(err, data) := asn1->encode(elem2);
+.EE
+.TP
+.BR Type3 "(implicitly tagged)"
+.EX
+tag := Tag(Context, 3, 0);
+val := Value.Int(16r55);
+elem := ref Elem(tag, val);
+(err, data) := asn1->encode(elem);
+.EE
+.SH SOURCE
+.B /appl/lib/asn1.b
+.SH BUGS
+It is irritating that REAL values are not converted by the module.
+This forces the application to do the conversion to and from the
+raw BER encoding. Fortunately they are rarely used.
+.PP
+String encodings are converted as UTF-8 byte sequences.
+This will result in strings comprising any character codes above 127
+being incorrectly converted.
+.PP
+There is a particular form of BER encoding that the module will
+handle incorrectly, resulting in a decoding error.
+The error occurs when a tagged value is encoded using the
+indefinite length specifier and the constructed representation.
diff --git a/man/2/attrdb b/man/2/attrdb
new file mode 100644
index 00000000..3e35e47f
--- /dev/null
+++ b/man/2/attrdb
@@ -0,0 +1,237 @@
+.TH ATTRDB 2
+.SH NAME
+attrdb \- database of attribute-value pairs
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+include "attrdb.m";
+attrdb := load Attrdb Attrdb->PATH;
+
+Attr: adt {
+ attr: string;
+ val: string;
+ tag: int; # application-defined data, initially 0
+};
+
+Tuples: adt {
+ n: int;
+ pairs: list of ref Attr;
+
+ hasattr: fn(t: self ref Tuples, attr: string): int;
+ haspair: fn(t: self ref Tuples,
+ attr: string, value: string): int;
+ find: fn(t: self ref Tuples, attr: string): list of ref Attr;
+ findbyattr: fn(t: self ref Tuples,
+ attr: string, value: string, rattr: string):
+ list of ref Attr;
+};
+
+Dbentry: adt {
+ n: int;
+ lines: list of ref Tuples;
+
+ find: fn(e: self ref Dbentry, attr: string):
+ list of (ref Tuples, list of ref Attr);
+ findfirst: fn(e: self ref Dbentry, attr: string): string;
+ findpair: fn(e: self ref Dbentry,
+ attr: string, value: string):
+ list of ref Tuples;
+ findbyattr: fn(e: self ref Dbentry,
+ attr: string, value: string, rattr: string):
+ list of (ref Tuples, list of ref Attr);
+};
+
+.ig
+Dbptr: adt {
+ dbs: list of ref Dbf;
+ index: ref Index;
+ pick{
+ Direct =>
+ offset: int;
+ Hash =>
+ current: int;
+ next: int;
+ }
+};
+
+Index: adt {
+ fd: ref Sys->FD;
+ attr: string;
+ mtime: int;
+ size: int;
+};
+
+Dbf: adt {
+ fd: ref Bufio->Iobuf;
+ name: string;
+ mtime: int;
+ indices: list of ref Index;
+
+ open: fn(path: string): ref Dbf;
+ sopen: fn(data: string): ref Dbf;
+};
+..
+
+Db: adt {
+ open: fn(path: string): ref Db;
+ sopen: fn(data: string): ref Db;
+ append: fn(db1: self ref Db, db2: ref Db): ref Db;
+
+ find: fn(db: self ref Db, start: ref Dbptr,
+ attr: string): (ref Dbentry, ref Dbptr);
+ findpair: fn(db: self ref Db, start: ref Dbptr,
+ attr: string, value: string):
+ (ref Dbentry, ref Dbptr);
+ findbyattr: fn(db: self ref Db, start: ref Dbptr,
+ attr: string, value: string, rattr: string):
+ (ref Dbentry, ref Dbptr);
+};
+
+init: fn(): string;
+
+parseentry: fn(s: string, lno: int): (ref Dbentry, int, string);
+parseline: fn(s: string, lno: int): (ref Tuples, string);
+.EE
+.SH DESCRIPTION
+.B Attrdb
+fetches data from textual databases that contain groups of attribute-value pairs.
+The format is defined by
+.IR attrdb (6).
+.PP
+.B Init
+must be called before any other function in the module.
+.PP
+Each logical database is represented by a
+.B Db
+value.
+It can span several physical files, named in the body of a
+.B database
+attribute in the primary file of the database.
+(If no such attribute appears, there is just the one physical file in the database.)
+.TP
+.BI Db.open( path )
+Opens
+.I path
+as a database, and
+returns a (reference to a)
+.B Db
+value that represents it.
+On an error, it returns nil and the system error string contains a diagnostic.
+If
+.I path
+contains a
+.B database
+attribute with associated attributes of the form
+.BI file= filename,
+the logical database is formed by (logically) concatenating the contents
+of each
+.I filename
+in the order listed.
+See
+.IR attrdb (6)
+for details.
+.TP
+.BI Db.sopen( data )
+Treat the contents of the string
+.I data
+as a database, and return a
+.B Db
+value representing it.
+.TP
+.IB db1 .append( db2 )
+Return a
+.B Db
+value that represents the result of logically appending
+the contents of database
+.I db2
+to
+.IR db1 .
+.TP
+.IB db .find( ptr , attr )
+Starting at
+.IR ptr ,
+look in
+.I db
+for the next entry that contains an attribute
+.I attr
+and return a tuple
+.BI ( e , ptr )
+where
+.I e
+is a
+.B Dbentry
+value representing the whole entry, and
+.I ptr
+is a database pointer for the next entry.
+If
+.I attr
+cannot be found,
+.I e
+is nil.
+.TP
+.IB db .findpair( ptr\fP,\fP\ attr\fP,\fP\ value\fP)
+Starting at
+.IR ptr ,
+look in
+.I db
+for the next entry that contains the pair
+.IB attr = value,
+and return a tuple
+.BI ( e , ptr )
+where
+.I e
+is a
+.B Dbentry
+value representing the whole entry, and
+.I ptr
+is a database pointer for the next entry.
+If the given pair
+cannot be found,
+.I e
+is nil.
+.TP
+.IB db .findbyattr( ptr\fP,\fP\ attr\fP,\fP\ value\fP,\fP\ rattr\fP )
+Starting at
+.I ptr
+in
+.IR db ,
+look for the next entry containing both the pair
+.IB attr = value
+and a pair with attribute
+.IR rattr ;
+return a tuple
+.BI ( e , ptr )
+where
+.I e
+is a
+.B Dbentry
+value representing the whole entry, and
+.I ptr
+is a database pointer for the next entry.
+If no such entry can be found,
+.I e
+is nil.
+.PP
+.B Parseline
+takes a line containing a set of space-separated
+.IB attribute = value
+pairs, and returns a tuple
+.BI ( ts , err ) .
+If the line's syntax is correct,
+.I ts
+is a
+.B Tuples
+value that represents the pairs as a list of
+.B Attr
+values.
+If the syntax is wrong (eg, unmatched quote),
+.I ts
+is nil and
+.I err
+contains a diagnostic.
+.SH SOURCE
+.B /appl/lib/attrdb.b
+.SH SEE ALSO
+.IR cfg (2),
+.IR attrdb (6),
+.IR ndb (6)
diff --git a/man/2/bloomfilter b/man/2/bloomfilter
new file mode 100644
index 00000000..fe6046dd
--- /dev/null
+++ b/man/2/bloomfilter
@@ -0,0 +1,89 @@
+.TH BLOOMFILTER 2
+.SH NAME
+Bloomfilter \- Bloom filters
+.SH SYNOPSIS
+.EX
+include "sets.m";
+include "bloomfilter.m";
+bloomfilter := load Bloomfilter Bloomfilter->PATH;
+
+init: fn();
+filter: fn(d: array of byte, logm, k: int): Sets->Set;
+.EE
+.SH DESCRIPTION
+A Bloom filter is a method of representing a set to support probabilistic
+membership queries. It uses independent hash functions of members
+of the set to set elements of a bit-vector.
+.I Init
+should be called first to initialise the module.
+.I Filter
+returns a Set
+.I s
+representing the Bloom filter for the single-member
+set
+.RI { d }.
+.I K
+independent hash functions are used, each of range
+.RI "[0, 2^" logm ),
+to return a Bloom filter
+.RI 2^ logm
+bits wide. It is an error if
+.I logm
+is less than 3 or greater than 30.
+.PP
+Bloom filters can be combined by set union.
+The set represented by Bloom filter
+.I a
+is not a subset of another
+.I b
+if there are any members in
+.I a
+that are not in
+.IR b .
+Together,
+.IR logm ,
+.IR k ,
+and
+.IR n
+(the number of members in the set)
+determine the
+.I "false positve" rate
+(the probability that a membership test will not eliminate
+a member that is not in fact in the set).
+The probability of a
+.I "false positive"
+is approximately (1-e^(-\fIkn\fP/(2^\fIlogm\fP))^\fIk\fP.
+For a given false positive rate,
+.IR f ,
+a useful formula to determine appropriate parameters
+is: \fIk\fP=ceil(-logâ‚‚(\fIf\fP)),
+and \fIlogm\fP=ceil(logâ‚‚(\fInk\fP)).
+.SH EXAMPLES
+Create a 128 bit-wide bloom filter
+.I f
+representing all the elements
+in the string array
+.IR elems ,
+with
+.IR k =6.
+.EX
+ A, B, None: import Sets;
+ for(i:=0; i<len elems; i++)
+ f = f.X(A|B, filter(array of byte elems[i], 7, 6));
+.EE
+Test whether the string
+.I s
+is a member of
+.IR f .
+If there were 12 elements in
+.IR elems ,
+the probability of a false positive would be
+approximately 0.0063.
+.EX
+ if(filter(array of byte s, 7, 6).X(A&~B, f).eq(None))
+ sys->print("'%s' might be a member of f\\n", s);
+.EE
+.SH SOURCE
+.B /appl/lib/bloomfilter.b
+.SH SEE ALSO
+.IR sets (2)
diff --git a/man/2/bufio b/man/2/bufio
new file mode 100644
index 00000000..22f454a8
--- /dev/null
+++ b/man/2/bufio
@@ -0,0 +1,318 @@
+.TH BUFIO 2
+.SH NAME
+bufio, bufiofill \- buffered input/output module
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+
+bufio := load Bufio Bufio->PATH;
+Iobuf: import bufio;
+
+SEEKSTART: con Sys->SEEKSTART;
+SEEKRELA: con Sys->SEEKRELA;
+SEEKEND: con Sys->SEEKEND;
+
+OREAD: con Sys->OREAD;
+OWRITE: con Sys->OWRITE;
+ORDWR: con Sys->ORDWR;
+
+EOF: con -1;
+ERROR: con -2;
+
+Iobuf: adt {
+ seek: fn(b: self ref Iobuf, n: big, where: int): big;
+ offset: fn(b: self ref Iobuf): big;
+
+ read: fn(b: self ref Iobuf, a: array of byte, n: int): int;
+ write: fn(b: self ref Iobuf, a: array of byte, n: int): int;
+
+ getb: fn(b: self ref Iobuf): int;
+ getc: fn(b: self ref Iobuf): int;
+ gets: fn(b: self ref Iobuf, sepchar: int): string;
+ gett: fn(b: self ref Iobuf, sepstring: string): string;
+
+ ungetb: fn(b: self ref Iobuf): int;
+ ungetc: fn(b: self ref Iobuf): int;
+
+ putb: fn(b: self ref Iobuf, b: byte): int;
+ putc: fn(b: self ref Iobuf, c: int): int;
+ puts: fn(b: self ref Iobuf, s: string): int;
+
+ flush: fn(b: self ref Iobuf): int;
+ close: fn(b: self ref Iobuf);
+
+ setfill: fn(b: self ref Iobuf, f: BufioFill);
+};
+
+open: fn(name: string, mode: int): ref Iobuf;
+create: fn(name: string, mode, perm: int): ref Iobuf;
+fopen: fn(fd: ref Sys->FD, mode: int): ref Iobuf;
+aopen: fn(a: array of byte): ref Iobuf;
+sopen: fn(s: string): ref Iobuf;
+
+BufioFill: module
+{
+ fill: fn(b: ref Bufio->Iobuf): int;
+};
+.EE
+.SH DESCRIPTION
+.B Bufio
+provides an interface for buffered I/O.
+A buffer is an adt which
+is created with
+.BR open ,
+.BR fopen ,
+.BR create ,
+.B aopen
+and
+.BR sopen .
+.PP
+.B Open
+takes two parameters, a
+.I filename
+and a
+.IR mode .
+The mode must be
+one of
+.BR OREAD ,
+.BR OWRITE ,
+or
+.B ORDWR
+(also defined in the
+.B Sys
+module).
+.PP
+.B Create
+is similar, but
+creates a new file if necessary, with file permissions
+specified by
+.IR perm
+(see
+.B create
+in
+.IR sys-open (2)),
+or truncates an existing file (without changing its permissions),
+before opening it in the given
+.IR mode ,
+and returning a reference to an
+.B Iobuf
+instance.
+.PP
+Buffered I/O on an already open file is made possible using
+.BR "fopen" ,
+which takes a file descriptor
+.I fd
+and an open
+.IR mode ,
+which must be compatible with the mode of the file descriptor.
+.PP
+The file open functions return a
+.B ref
+.B Iobuf
+to be used in subsequent calls. Thus:
+.PP
+.EX
+ lc := bufio->open("/net/tcp/0/local", bufio->OREAD);
+ addr := lc.gets('\en');
+ lc = nil;
+.EE
+.PP
+will open the file
+.B /net/tcp/0/local
+and read a line (including the terminating newline
+character) from this file to initialize the string variable
+.BR addr .
+The file is closed implicitly by discarding (assigning
+.B nil
+to) the only
+reference to its
+.BR Iobuf .
+.PP
+The function
+.B aopen
+makes the contents of an array of byte
+.I a
+readable through an Iobuf (it may not be written).
+The function
+.B sopen
+similarly makes the contents of a string
+.I s
+readable.
+.PP
+Processes can share the same instance of
+.B Bufio
+and safely open and close different files concurrently, but two processes must not access the same
+.B Iobuf
+concurrently; they must coordinate their access using some external mechanism
+(eg,
+.IR lock (2)).
+.PP
+Each output file must be flushed or closed individually (see
+.B flush
+and
+.B close
+operations below).
+.PP
+The calls implemented by
+.B Iobuf
+are:
+.PP
+.TF setfill
+.PD
+.TP
+.BR seek , \ read ", and " write
+Each has the same parameters as its complement in
+.B Sys
+(see
+.IR sys-seek (2),
+.IR sys-read (2)).
+Note that
+.BR SEEKSTART
+etc. are defined by
+.B Bufio
+as well as by
+.BR Sys ,
+for use by
+.BR seek .
+.TP
+.B offset
+Return the current file offset in bytes, taking account of buffered data.
+.TP
+.B getb
+Read a single byte from the buffered stream and return its value
+as an
+.BR int .
+.TP
+.B getc
+Read a single Unicode character, encoded in UTF
+(see
+.IR utf (6)),
+and
+return its value as an
+.BR int .
+.TP
+.B gets
+Read a line, up to and including a character specified by
+.IR sepchar ,
+typically a newline.
+If none is found, read to the end of the file.
+The returned string includes the terminating character.
+.TP
+.B gett
+Read characters until one of the characters in
+.IR sepstring .
+The returned string includes the separator.
+If none of the separator characters is found,
+read to the end of the file.
+.TP
+.BR ungetb , \ ungetc
+Undoes the effect of the last
+.B getb
+or
+.BR getc ,
+so that a subsequent read will reread the byte
+.RB ( ungetb ),
+or reread the byte(s) of a UTF-encoded character
+.RB ( ungetc )
+.TP
+.BR putb , \ putc ", and " puts
+Each
+writes its argument, a byte, a character, or
+a string, respectively.
+Text is encoded in UTF.
+.TP
+.B setfill
+Associates a
+.B BufioFill
+module instance
+.I f
+with
+.B Iobuf
+.IR b ;
+discussed below.
+.TP
+.B flush
+Flush remaining data in the buffer, if necessary.
+For files opened for writing, data is flushed to the file.
+For files opened for reading, any internally buffered data is discarded,
+and the next read will read from the file.
+.TP
+.B close
+Flush remaining data in the buffer, if necessary, close the
+associated file, and discard buffers associated with the file.
+After close, no further method calls are allowed on the
+.B iobuf
+adt.
+.PP
+The
+.B BufioFill
+module interface can be ignored by most applications.
+It allows an
+.B Iobuf
+to be used to read data from an arbitrary source.
+There is no `standard' implementation to load.
+Instead,
+an application using this interface uses a separate
+.B BufioFill
+module instance such as
+.IR bufio-chanfill (2),
+or provides one itself using
+.IR sys-self (2).
+The resulting module reference is associated,
+using
+.BR setfill ,
+with an
+.B Iobuf
+previously obtained by
+.BR sopen
+(the string parameter limits the buffer space allocated).
+It is up to the
+.B BufioFill
+module's implementation how its
+.B fill
+function replenishes the buffer;
+it should return the number of bytes now in the buffer, or
+.BR Bufio->EOF .
+.SH SOURCE
+.B /appl/lib/bufio.b
+.SH SEE ALSO
+.IR bufio-chanfill (2),
+.IR intro (2),
+.IR sys-open (2),
+.IR sys-read (2),
+.IR sys-seek (2)
+.SH DIAGNOSTICS
+Calls that return a
+.B ref
+type
+(eg.
+.RB open ,
+.BR fopen ,
+.BR gets ,
+and
+.BR gett )
+return
+.B nil
+when encountering end of file or errors. When an error occurs, the
+error string, printable with the
+.B %r format,
+will usually be set as a consequence of an error in the underlying
+.B Sys
+module.
+The other calls return
+.B EOF
+upon encountering end of file, and
+.B ERROR
+when encountering other errors.
+.SH BUGS
+A given
+.B Iobuf
+instance may not be accessed concurrently.
+.PP
+An
+.B Iobuf
+instance must be manipulated by the same module instance that created it.
+.PP
+The
+.B BufioFill
+interface is subject to change.
diff --git a/man/2/bufio-chanfill b/man/2/bufio-chanfill
new file mode 100644
index 00000000..f5908dd3
--- /dev/null
+++ b/man/2/bufio-chanfill
@@ -0,0 +1,57 @@
+.TH BUFIO-CHANFILL 2
+.SH NAME
+bufio: chanfill \- buffered I/O interface to named channel
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+chanfill := load ChanFill ChanFill->PATH;
+
+init: fn(data: array of byte, fid: int,
+ wc: Sys->Rwrite, r: ref Sys->FileIO,
+ b: Bufio): ref Bufio->Iobuf;
+fill: fn(b: ref Bufio->Iobuf): int;
+.EE
+.SH DESCRIPTION
+.B ChanFill
+is an implementation of
+.B BufioFill
+(see
+.IR bufio (2))
+that refills an
+.B Iobuf
+as data is written to a file created by
+.IR sys-file2chan (2),
+which is allowed only one writer.
+.B Init
+returns an
+.B Iobuf
+allocated from the
+.B Bufio
+instance
+.IR b ,
+that when read will return data written to the file by another process.
+.IR Data ,
+.IR fid
+and
+.IR wc
+are the values in the tuple presented by
+.B Sys->file2chan
+on the first write.
+.I Data
+becomes the initial data for the
+.BR Iobuf ;
+.B init
+replies to the writer on
+.IR wc .
+The other values are saved for use by
+.BR fill :
+on later calls to
+by
+.B Bufio
+to refill the buffer,
+.B fill
+waits for a new write request on
+.IB fio .write
+and either fills the buffer or signals end-of-file appropriately.
+.SH SEE ALSO
+.IR bufio (2)
diff --git a/man/2/cfg b/man/2/cfg
new file mode 100644
index 00000000..f7dbaf5e
--- /dev/null
+++ b/man/2/cfg
@@ -0,0 +1,159 @@
+.TH CFG 2
+.SH NAME
+Cfg, Record, Tuple, Attr \- configuration file parser
+.SH SYNOPSIS
+.EX
+include "cfg.m";
+cfg := load Cfg Cfg->PATH;
+
+Attr: adt {
+ name: string;
+ value: string;
+};
+
+Tuple: adt {
+ lnum: int;
+ attrs: list of Attr;
+ lookup: fn(t: self ref Tuple, name: string): string;
+};
+
+Record: adt {
+ tuples: list of ref Tuple;
+ lookup: fn(r: self ref Record, name: string)
+ : (string, ref Tuple);
+};
+
+init: fn(path: string): string;
+lookup: fn(name: string): list of (string, ref Record);
+getkeys: fn(): list of string;
+
+.EE
+.SH DESCRIPTION
+.B Cfg
+parses its configuration file format into a set of
+.BR Record s.
+.PP
+Each line of the configuration file is comprised of a tuple of attributes.
+Comments are introduced by the
+.RB ' # '
+character and run to the end of the input line.
+Empty lines and comments are ignored.
+.PP
+An attribute has a name followed by an optional value.
+The value is specified by separating the name and value
+by an
+.RB ' = '
+character.
+Attribute names and values are input
+.IR words .
+A word is delimited by spacing characters and the
+.RB ' = '
+character.
+If a word needs to include any of these characters then the word may be
+quoted using single or double quotes.
+The start and end quotes must be the same.
+The quoting character may be included in the word by appearing twice.
+.PP
+Examples:
+.EX
+ 'a b c' yields a b c
+ "a b c" yields a b c
+ 'a " c' yields a " c
+ 'a '' c' yields a ' c
+.EE
+.PP
+The name of the first attribute of a tuple is its
+.IR key .
+The
+.I primary tuple value
+is the value of its first attribute.
+.PP
+Tuples whose first attribute name appears at the start of a line (having no
+preceeding spacing characters)
+are treated as the start of a new record.
+A record incorporates all tuples up to the start of the next record.
+The
+.I record key
+is defined to be the name of its first attribute.
+The
+.I primary record value
+is the value of the first attribute.
+.PP
+The
+.B adt
+types
+.BR Attr ,
+.B Tuple
+and
+.B Record
+are direct analogues of the constructs defined above.
+.P
+.TP
+.BI init( path )
+.B Init
+initialises the
+.B Cfg
+module, causing it to open and parse the configuration file
+given by the
+.I path
+argument.
+If an error is encountered in processing the file then
+an error string is returned.
+If there are no errors
+.B init
+returns
+.BR nil .
+.TP
+.BI lookup( name )
+.B Lookup
+returns
+the set of
+.BR Record s
+whose
+.I key
+matches the
+.I name
+argument.
+The return value is a list of
+.RI ( "primary record value" , " record" )
+pairs.
+.TP
+.B getkeys()
+.B Getkeys
+returns a list of the record keys that appear in the configuration file.
+Note that more than one record can have the same key.
+Duplicate key names are not returned by
+.BR getkeys() .
+.TP
+.IB record .lookup( name )
+Returns the first tuple in
+.I record
+whose key matches
+.IR name .
+The return value is
+.RI ( "primary tuple value" , " tuple" ).
+If no matching tuple is found then the value
+.B (nil, nil)
+is returned.
+Note that more than one tuple of the record could have a
+.I key
+that matches
+.IR name .
+Only the first matching tuple is returned.
+If an application makes use of
+multiple tuples with the same
+.I key
+then the
+.IB record .tuple
+list will have to be handled explicitly by the application.
+.TP
+.IB tuple .lookup( name )
+Returns the first attribute in
+.I tuple
+whose name matches
+.IR name .
+The return value is the value of the attribute or
+.B nil
+if no matching attribute was found.
+.SH SOURCE
+.B /appl/lib/cfg.b
diff --git a/man/2/command b/man/2/command
new file mode 100644
index 00000000..d46f9525
--- /dev/null
+++ b/man/2/command
@@ -0,0 +1,132 @@
+.TH COMMAND 2
+.SH NAME
+command \- command interface
+.SH SYNOPSIS
+.nf
+.B
+include "sh.m";
+.BI "cmd := load Command" " path" ;
+
+.EX
+PATH: con "/dis/sh.dis";
+init: fn(ctxt: ref Draw->Context, args: list of string);
+.EE
+.SH DESCRIPTION
+.B Command
+defines the module interface for programs started by the Inferno shells
+.IR sh (1)
+and
+.IR mash (1),
+and the window manager
+.IR wm (1).
+Applications to be run as commands must adhere to it,
+and any application wishing to start another command may use it.
+.PP
+Every command must have an
+.B init
+function with the signature shown above.
+Note that Limbo rules allow a module to expose a larger interface for use by
+other applications (see for instance
+.IR sh (2));
+provided it includes the form of
+.B init
+shown above,
+the module can also be invoked as a command.
+.PP
+.B Ctxt
+provides the graphics context for a windowing application,
+which typically passes it to
+.IR wmlib (2)
+(eg, to
+.IR titlebar )
+or directly to
+.IR tk (2).
+It is
+.B nil
+for commands started by the shells.
+.PP
+The arguments to the command are passed as a simple list of strings,
+.BR args .
+By convention, the name of the command or the name of its
+.B .dis
+file heads the list.
+.PP
+.B PATH
+names the file containing
+.IR sh (1),
+(on small systems, this might actually name an
+instance of
+.IR tiny (1))
+but usually the path name of
+another command will be given to the Limbo
+.B load
+operator:
+.IP
+.EX
+include "sh.m";
+.EE
+\&...
+.IP
+.EX
+cmd := load Command "/dis/date.dis";
+cmd->init(nil, "date" :: nil);
+.EE
+.PP
+In practice more care must be taken when invoking programs.
+In the example above, the current process executes the body of
+.B cmd->init
+and if that executes
+.BR exit ,
+raises an exception,
+or otherwise modifies the state of the process,
+the caller is affected.
+The following is more prudent:
+.IP
+.EX
+.ta 6n +6n
+child(file: string, args: list of string, pidc: chan of int)
+{
+ pidc <-= sys->pctl(Sys->NEWFD|Sys->FORKNS|Sys->NEWPGRP,
+ list of {0, 1, 2});
+ cmd := load Command file;
+ if(cmd == nil){
+ sys->print("can't load %s: %r\en", file);
+ exit;
+ }
+ cmd->init(nil, args);
+}
+parent()
+{
+ pidc := chan of int;
+ spawn child(disfile, args, pidc);
+ pid := <-pidc;
+ \&...
+}
+.EE
+.PP
+A new
+.B child
+process runs the command only after using
+.IR sys-pctl
+to insulate the caller from untoward changes to its environment.
+Note the idiomatic use of a channel to return the child's process ID
+to its parent, which can then if desired use the
+.B wait
+file of
+.IR prog (3)
+to watch over the child and wait for its demise.
+or use the
+.B ctl
+file of
+.IR prog (3)
+to dispose of it.
+Furthermore, any state shared between parent and child can safely
+be accessed by the child before it sends the ID
+because the parent is blocked on the receive.
+.SH SEE ALSO
+.IR mash (1),
+.IR sh (1),
+.IR wm (1),
+.IR sh (2),
+.IR sys-pctl (2),
+.IR sys-exception (2)
diff --git a/man/2/convcs b/man/2/convcs
new file mode 100644
index 00000000..dd0091f3
--- /dev/null
+++ b/man/2/convcs
@@ -0,0 +1,367 @@
+.TH CONVCS 2
+.SH NAME
+Convcs, Btos, Stob \- character set conversion suite
+.SH SYNOPSIS
+.EX
+include "convcs.m";
+convcs := load Convcs Convcs->PATH;
+
+Btos: module {
+ init: fn(arg: string): string;
+ btos: fn(s: Convcs->State, b: array of byte, nchars: int)
+ : (Convcs->State, string, int);
+};
+
+Stob: module {
+ init: fn (arg: string): string;
+ stob: fn(s: Convcs->State, str: string)
+ : (Convcs->State, array of byte);
+};
+
+Convcs: module {
+ State: type string;
+ Startstate: con "";
+
+ init: fn(csfile: string): string;
+ getbtos: fn(cs: string): (Btos, string);
+ getstob: fn(cs: string): (Stob, string);
+ enumcs: fn(): list of (string, string, int);
+ aliases: fn(cs: string): (string, list of string);
+};
+
+.EE
+.SH DESCRIPTION
+The
+.I Convcs
+suite is a collection of
+modules for converting various standard
+coded character sets and character encoding schemes
+to and from the Limbo strings.
+.PP
+The
+.B Convcs
+module provides an entry point to the suite, mapping character set names and aliases
+to their associated
+converter implementation.
+.SS "The Convcs module"
+.TP
+.BI init( csfile )
+.B Init
+should be called once to initialise the internal state of
+.BR Convcs .
+The
+.I csfile
+argument specifies the path of the converter mapping file.
+If this argument is nil, the default mapping file
+.B /lib/convcs/charsets
+is used.
+.TP
+.BI getbtos( cs )
+.B Getbtos
+returns an initialised
+.B Btos
+module for converting from the requested encoding.
+.IP
+The return value is a tuple, holding the module reference and an error string.
+If any errors were encountered in locating, loading or initialising the requested
+converter, the module reference will be nil and the string will contain an explanation.
+.IP
+The character set name,
+.IR cs ,
+is normalised by mapping all upper-case latin1 characters to lower-case before
+comparison with character set names and aliases from the
+.B charsets
+file.
+.TP
+.BI getstob( cs )
+.B Getstob
+returns an initialised
+.B Stob
+module for converting from strings to the requested encoding.
+Apart from the different module type, the return value and semantics are
+the same as for
+.BR getbtos() .
+.TP
+.B enumcs()
+Returns a list describing the set of available converters.
+The list is comprised of
+.RI ( name ,
+.IR desc ,
+.IR mode )
+tuples.
+.IP
+.I Name
+is the standard name of the character set.
+.IP
+.I Desc
+is a more friendly description taken directly from the
+.B desc
+attribute given in the
+.I charsets
+file.
+If the attribute is not given then
+.I desc
+is set to
+.IR name .
+.IP
+.I Mode
+is a bitmap that details the converters available for the given character set.
+Valid
+.I mode
+bits are
+.B Convcs->BTOS
+and
+.BR Convcs->STOB .
+For convenience,
+.B Convcs->BOTH
+is also defined.
+.TP
+.BI aliases( cs )
+Returns the aliases for the character set name
+.IR cs .
+The return value is the tuple
+.BI ( desc ", " aliases ).
+.IP
+.I Desc
+is the descriptive text for the character set, as returned by
+.BR enumcs() .
+.IP
+.I Aliases
+lists all the known aliases for
+.IR cs .
+The first name in the list is the default character set name \- the name
+that all the other aliases refer to.
+If the
+.I aliases
+list is
+.B nil
+then there was an error in looking up the character set name and
+.I desc
+will detail the error.
+.SS "Using a Btos converter"
+The
+.B Btos
+module returned by
+.B getbtos()
+is already initialised and is ready to start the conversion.
+Conversions can be made on a individual basis,
+or in a `streamed' mode.
+.PP
+.IB converter "->btos(" s ,
+.IB b ,
+.IB nchars )
+.RS
+Converts raw byte codes of the character set encoding to a Limbo string.
+.PP
+The argument
+.I s
+is a converter state as returned from the previous call to
+.B btos
+on the same input stream.
+The first call to
+.B btos
+on a particular input stream should give
+.B Convcs->Startstate
+(or
+.BR nil)
+as the value for
+.IR s .
+The argument
+.I b
+is the bytes to be converted.
+The argument
+.I nchars
+is the maximal length of the string to be returned.
+If this argument is
+.B -1
+then as much of
+.I b
+will be consumed as possible.
+A value of
+.B 0
+indicates to the converter that there is no more data and
+that any pending state should be flushed.
+.PP
+The return value of
+.B btos
+is the tuple
+.RI ( state ,
+.IR str ,
+.IR nbytes )
+where
+.I state
+is the new state of the converter,
+.I str
+is the converted string, and
+.I nbytes
+is the number of bytes from
+.I b
+consumed by the conversion.
+.PP
+The same converter module can be used for multiple conversion streams
+by maintaining a separate
+.I state
+variable for each stream.
+.RE
+.SS "Using an Stob converter"
+The
+.B Stob
+module returned by
+.B getstob()
+is already initialised and is ready to start the conversion.
+.PP
+.IB converter "->stob(" s ,
+.IB str )
+.RS
+Converts the limbo string
+.I str
+to the raw byte codes of the character set encoding.
+The argument
+.I s
+represents the converter state and is treated in the same way as for
+.IB converter ->btos()
+described above.
+To terminate a conversion
+.B stob
+should be called with an emtpy string in order to flush
+the converter state.
+.PP
+The return value of
+.B stob
+is the tuple
+.RI ( state ,
+.IR bytes )
+where
+.I state
+is the new state of the converter and
+.I bytes
+is the result of the conversion.
+.RE
+.SS "Conversion errors"
+When using
+.IB converter "->btos()"
+to convert data to Limbo strings,
+any byte sequences that are not valid for the specific character encoding scheme
+will be converted to the Unicode error character 16rFFFD.
+.PP
+When using
+.IB converter "->stob()"
+to convert Limbo strings,
+any Unicode characters that can not be mapped
+into the character set will normally be substituted by the US-ASCII code for `?'.
+Note that this may be inappropriate for certain conversions, such converters will use
+a suitable error character for their particular character set and encoding scheme.
+.SS "Charset file format"
+The file
+.B /lib/convcs/charsets
+provides the mapping between character set names and their implementation modules.
+The file format conforms to that supported by
+.IR cfg (2).
+The following description relies on terms defined in the
+.IR cfg (2)
+manual page.
+.PP
+Each record name defines a character set name.
+If the primary value of the record is non-empty then the name is an alias,
+the value being the real name.
+An alias record must point to an actual converter record, not to another alias, as
+.I Convcs
+only follows one level of aliasing.
+.PP
+Each converter record consists of a set of tuples with the following primary attributes:
+.TP
+.B desc
+A more descriptive name for the character set encoding.
+This attribute is used for the description returned by
+.BR enumcs() .
+.TP
+.B btos
+The path to the
+.B Btos
+module implementation of this converter.
+.TP
+.B stob
+The path to the
+.B Stob
+module implementation of this converter.
+.PP
+Both the
+.B btos
+and
+.B stob
+tuples can have an optional
+.B arg
+attribute which is passed to the
+.B init()
+function of the converter when initialised by
+.IR Convcs .
+If a converter record has neither an
+.B stob
+nor a
+.B btos
+tuple, then it is ignored.
+.PP
+The following example is an extract from the standard Inferno
+.I charsets
+file:
+.PP
+.EX
+cp866=ibm866
+866=ibm866
+ibm866=
+ desc='Russian MS-DOS CP 866'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/ibm866.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/ibm866.cp
+.EE
+.PP
+This entry defines
+.I Stob
+and
+.I Btos
+converters for the character set called
+.BR ibm866 .
+The converters are actually the generic codepage converters
+.B cp_stob
+and
+.B cp_btos
+paramaterized with a codepage file.
+The entry also defines the aliases
+.B cp866
+and
+.B 866
+for the name
+.BR ibm866 .
+.SH FILES
+.TP
+.B /lib/convcs/charsets
+The default mapping between character set names and their implementation modules.
+.TP
+.BI /lib/convcs/ csname .cp
+Codepage files for use by the generic codepage converters
+.B cp_stob
+and
+.BR cp_btos .
+Each file consists of 256 unicode runes mapping codepage byte values to unicode by their index.
+The runes are stored in the utf-8 encoding.
+.SH SOURCE
+.TF /appl/lib/convcs/convcs.b
+.TP
+.B /appl/lib/convcs/convcs.b
+Implementation of the
+.B Convcs
+module.
+.TP
+.B /appl/lib/convcs/cp_btos.b
+Generic
+.I Btos
+codepage converter.
+.TP
+.B /appl/lib/convcs/cp_stob.b
+Generic
+.I Stob
+codepage converter.
+.br
+.PP
+.SH SEE ALSO
+.IR tcs (1),
+.IR cfg (2)
diff --git a/man/2/crc b/man/2/crc
new file mode 100644
index 00000000..f3bc96c4
--- /dev/null
+++ b/man/2/crc
@@ -0,0 +1,62 @@
+.TH CRC 2
+.SH NAME
+crc \- Crc module
+.SH SYNOPSIS
+.EX
+include "crc.m";
+crc := load Crc Crc->PATH;
+
+CRCstate: adt {
+ crc: int;
+ crctab: array of int;
+ reg: int;
+};
+
+init: fn(poly: int, reg: int): ref CRCstate;
+crc: fn(state: ref CRCstate, buf: array of byte, nb: int): int;
+reset: fn(state: ref CRCstate);
+.EE
+.SH DESCRIPTION
+.B Crc
+provides the routines to calculate the CRC (cyclic redundancy
+check) over blocks of data.
+.PP
+.B Init
+initializes the module and must be called first. The parameter
+.I poly
+is the polynomial to use when calculating the CRC value. If a value of
+0 is given, the default polynomial 16redb88320 (8r035556101440) is used. The polynomial
+has its implicit top bit set. The second parameter
+.I reg
+is the number with which to initialize the CRC register. This is commonly 0 but, for example, is
+16rffffffff in the CRC32 algorithm. The final CRC value is also XORed with this number.
+The function
+returns a pointer to an adt that holds the current CRC value,
+the auxiliary table the algorithm uses and the initial register value. These fields should not be accessed
+directly - they are only for internal use.
+.PP
+.B Crc
+calculates the CRC value of the first
+.I nb
+bytes of the array
+.I buf
+given the CRC state
+.I state
+as returned by the
+.I init
+function. It returns the current CRC value. It may be called repeatedly
+to calculate the CRC of a series of arrays of bytes, for example, when
+calculating the CRC value for the bytes in a file.
+.PP
+.B Reset
+sets the CRC state to its initial value in readiness for a new CRC
+calculation. It avoids the need to call
+.I init
+again.
+.SH SOURCE
+.B /appl/lib/crc.b
+.SH SEE ALSO
+.IR sum (1)
+
+
+
diff --git a/man/2/daytime b/man/2/daytime
new file mode 100644
index 00000000..9e284916
--- /dev/null
+++ b/man/2/daytime
@@ -0,0 +1,96 @@
+.TH DAYTIME 2
+.SH NAME
+daytime: text, filet, gmt, local, now, time, tm2epoch \- time conversions
+.SH SYNOPSIS
+.EX
+include "daytime.m";
+daytime := load Daytime Daytime->PATH;
+
+Tm: adt
+{
+ sec: int; # seconds (0 to 59)
+ min: int; # minutes (0 to 59)
+ hour: int; # hours (0 to 23)
+ mday: int; # day of the month (1 to 31)
+ mon: int; # month (0 to 11)
+ year: int; # year-1900; 2000AD is 100
+ wday: int; # day of week (0 to 6, Sunday is 0)
+ yday: int; # day of year (0 to 365)
+ zone: string; # time zone name
+ tzoff: int; # time zone offset (seconds from GMT)
+};
+
+text: fn(tm: ref Tm): string;
+filet: fn(now, t: int): string;
+gmt: fn(tim: int): ref Tm;
+local: fn(tim: int): ref Tm;
+now: fn(): int;
+time: fn(): string;
+tm2epoch: fn(tm: ref Tm): int;
+.EE
+.SH DESCRIPTION
+These routines perform time conversions relative to the
+epoch 00:00:00 GMT, Jan. 1, 1970.
+Note the range of values for each member of the
+.B Tm
+adt.
+The conventions are the same as those of C's
+.IR ctime .
+.PP
+.B Text
+converts a time structure referenced by
+.I tm
+from local or GMT time to a string in the format:
+.IP
+.BR "Sat Jan 1 13:00:00 GMT 2000" .
+.PP
+.B Filet
+converts the file access or modification time
+.I t
+from seconds since the epoch to local time as a string
+in the format:
+.IP
+.B "Jan 1 13:00"
+.PP
+if the file is less than 6 months old or
+.IP
+.B "Jan 1 2000"
+.PP
+if the file is older than 6 months, compared to the time
+.IR now .
+.PP
+.B Gmt
+converts seconds since the epoch, received in
+.IR tim ,
+to a time structure in Greenwich Mean Time (GMT).
+.PP
+.B Local
+converts seconds since the epoch, received in
+.IR tim ,
+to a time structure in local time.
+.PP
+.B Now
+returns the time in seconds since the epoch, which
+it obtains by reading
+.B /dev/time
+(see
+.IR cons (3))
+to get the time in microseconds since the epoch.
+.PP
+.B Time
+converts seconds since the epoch
+to the local time as a string in the format
+.BR "Fri May 19 17:01:36 BST 2000" .
+.PP
+.B Tm2epoch
+converts a time structure referenced by
+.I tm
+from local or GMT time to seconds since the epoch.
+.SH SOURCE
+.B /appl/lib/daytime.b
+.SH SEE ALSO
+.IR cons (3),
+.IR sys-millisec (2)
+.SH BUGS
+The sign bit of a Limbo integer holding a time will turn on 68 years from the
+epoch.
diff --git a/man/2/dbm b/man/2/dbm
new file mode 100644
index 00000000..71935a86
--- /dev/null
+++ b/man/2/dbm
@@ -0,0 +1,222 @@
+.TH DBM 2
+.SH NAME
+Dbm: Dbf, init \- data base with hashed indexing
+.SH SYNOPSIS
+.EX
+include "dbm.m";
+
+dbm := load Dbm Dbm->PATH;
+Datum, Dbf: import dbm;
+
+Datum: type array of byte;
+
+Dbf: adt {
+ create: fn(file: string, perm: int): ref Dbf;
+ open: fn(file: string, flags: int): ref Dbf;
+
+ fetch: fn(db: self ref Dbf, key: Datum): Datum;
+ delete: fn(db: self ref Dbf, key: Datum): int;
+ store: fn(db: self ref Dbf, key: Datum, data: Datum,
+ replace: int): int;
+
+ firstkey: fn(db: self ref Dbf): Datum;
+ nextkey: fn(db: self ref Dbf, key: Datum): Datum;
+
+ flush: fn(db: self ref Dbf);
+ isrdonly: fn(db: self ref Dbf): int;
+};
+
+init: fn();
+.EE
+.SH DESCRIPTION
+.B Dbm
+maintains
+key/content pairs in a data base.
+The functions will handle very large
+(a billion blocks)
+databases and will access a keyed item
+in one or two filesystem accesses.
+.PP
+.IR Key s
+and
+.IR content s
+are both represented by arrays of bytes
+(with the synonym
+.BR Datum ),
+allowing
+arbitrary binary values.
+.PP
+The data base is stored in two files.
+One file is a directory containing a bit map
+and has
+.L .dir
+as its suffix.
+The second file contains all data and has
+.L .pag
+as its suffix.
+An application can access several databases at once, but must avoid
+concurrent operations on any one database (eg, by using a monitor process to control access).
+.PP
+.B Init
+must be called before any other operation of the module.
+.PP
+A database is created by
+.IR Dbf.create ,
+which accepts a file permission parameter
+.IR perm ,
+as described for
+.B Sys->create
+(see
+.IR sys-open (2));
+it creates the two files
+.IB file .dir
+and
+.IB file .pag .
+If successful, it returns a
+.B Dbf
+reference describing the database, which
+is open for reading and writing.
+(It will truncate an existing database.)
+It returns nil if it cannot create the database for some reason,
+and sets the error string.
+.PP
+.B Dbf.open
+accepts a
+.I mode
+parameter as described in
+.IR sys-open (2),
+and opens the existing database in
+.IB file .dir
+and
+.IB file .pag .
+If successful, it returns a
+.B Dbf
+reference describing the database,
+which is open either for reading and writing (ie,
+.BR Sys->ORDWR ),
+or only for reading
+.RB ( Sys->OREAD )
+as determined by
+.IR mode .
+It returns nil if the database cannot be opened successfully, and sets the error string.
+.PP
+The remaining operations apply to an existing
+.B Dbf
+reference
+.IR db :
+.TP
+.IB db .fetch( key )
+Return the data stored under a
+.IR key ;
+nil is returned if the key is not in the database.
+.TP
+.IB db .store( key,\ data,\ replace )
+Store
+.I data
+under the given
+.IR key .
+If
+.I replace
+is non-zero,
+.B store
+will simply replace the existing value by the new one if the key is already
+in the database;
+if
+.I replace
+is zero
+.B store
+will return 0 if the new item was inserted, but
+1 if the key already appears in the database,
+and the new value will not be stored.
+.TP
+.IB db .delete( key )
+.I Key
+and its associated value
+is removed from the database.
+.TP
+.IB db .firstkey()
+Return the first key in the database;
+return nil if the database is empty.
+.TP
+.IB db .nextkey( key )
+Return the key following the given
+.IR key ,
+or nil if there is none.
+.TP
+.IB db .flush()
+Discard any data cached from the file.
+The cache is write-through, so it is not necessary to flush the file
+before the application exits.
+.TP
+.IB db .isrdonly()
+Return true if
+.I db
+was opened only for reading and writes are not allowed.
+.SH EXAMPLE
+.PP
+A linear pass through all keys in a database
+may be made,
+in an (apparently) random order,
+by use of
+.B Dbf.firstkey
+and
+.BR Dbf.nextkey .
+This code will traverse the data base:
+.IP
+.EX
+for(key := db.firstkey(); key != nil; key = db.nextkey(key)){
+ d := db.fetch(key);
+}
+.EE
+.PP
+The order of keys presented by
+.B Dbf.firstkey
+and
+.B Dbf.nextkey
+depends on a hashing function, not on anything
+interesting.
+.SH SOURCE
+.B /appl/lib/dbm.b
+.SH DIAGNOSTICS
+All functions that return an
+.I int
+indicate errors with negative values.
+A zero return indicates success.
+Routines that return pointers, including values of
+.BR Datum ,
+return nil values on error.
+.B Dbf.create
+and
+.B Dbf.open
+return nil on failure to access the database,
+setting the error string to a more detailed diagnostic.
+.SH BUGS
+On some systems (notably Plan 9 but also some Unix systems),
+the
+.B .pag
+file might contain holes where no data block has ever been written so
+that its apparent size is about
+four times its actual content.
+These files cannot be copied
+by normal means (cp, cat)
+without filling in the holes.
+.PP
+Except for
+.B firstkey
+and
+.BR nextkey ,
+.B Datum
+values returned
+by these functions
+point to storage
+that is changed by subsequent calls.
+.PP
+The sum of the sizes of a
+key/content pair must not exceed
+the internal block size
+(currently 512 bytes).
+Moreover all key/content pairs that hash
+together must fit on a single block.
+.B Dbf.store
+will return an error in the event that
+a block fills with inseparable data.
diff --git a/man/2/debug b/man/2/debug
new file mode 100644
index 00000000..b0cd837f
--- /dev/null
+++ b/man/2/debug
@@ -0,0 +1,382 @@
+.TH DEBUG 2
+.SH NAME
+debug \- process debugging
+.SH SYNOPSIS
+.EX
+include "debug.m";
+debug := load Debug Debug->PATH;
+
+Pos: adt
+{
+ file: string;
+ line: int;
+ pos: int;
+};
+Src: adt
+{
+ start: Pos; # range within source files
+ stop: Pos;
+};
+Sym: adt
+{
+ srctopc: fn(s: self ref Sym, src: ref Src): int;
+ pctosrc: fn(s: self ref Sym, pc: int): ref Src;
+};
+
+Module: adt
+{
+ addsym: fn(m: self ref Module, sym: ref Sym);
+ stdsym: fn(m: self ref Module);
+ dis: fn(m: self ref Module): string;
+ sbl: fn(m: self ref Module): string;
+};
+
+Prog: adt
+{
+ cont: fn(p: self ref Prog): string;
+ delbpt: fn(p: self ref Prog, dis: string, pc: int): string;
+ event: fn(p: self ref Prog): string;
+ grab: fn(p: self ref Prog): string;
+ kill: fn(p: self ref Prog): string;
+ setbpt: fn(p: self ref Prog, dis: string, pc: int): string;
+ stack: fn(p: self ref Prog): (array of ref Exp, string);
+ start: fn(p: self ref Prog): string;
+ status: fn(p: self ref Prog): (int, string, string, string);
+ step: fn(p: self ref Prog, how: int): string;
+ stop: fn(p: self ref Prog): string;
+ unstop: fn(p: self ref Prog): string;
+};
+
+Exp: adt
+{
+ name: string;
+ m: ref Module;
+
+ expand: fn(e: self ref Exp): array of ref Exp;
+ val: fn(e: self ref Exp): (string, int);
+ src: fn(e: self ref Exp): ref Src;
+ findsym:fn(e: self ref Exp): string;
+ srcstr: fn(e: self ref Exp): string;
+};
+
+init: fn(): int;
+startprog: fn(dis, dir: string, ctxt: ref Draw->Context,
+ argv: list of string): (ref Prog, string);
+prog: fn(pid: int): (ref Prog, string);
+sym: fn(sbl: string): (ref Sym, string);
+.EE
+.SH DESCRIPTION
+.B Debug
+is the module interface to the debugging facilities provided by
+.IR prog (3).
+It allows facilities for inspection of a program's data structures,
+as it is running, and to start and stop a running program
+under program control.
+.B Init
+must be called before any other function to initialise
+.IR debug 's
+global state.
+.PP
+.B Startprog
+starts up a program under control of the debug module.
+.I Dis
+is the full pathname of the Dis module to load (which must
+be compatible with
+.IR command (2);
+.I dir
+is the current directory in which to put the new process;
+.I ctxt
+and
+.I argv
+are the arguments given to the new process.
+.B Startprog
+returns a tuple
+.RI ( prog ,\ err )
+where
+.I prog
+can be used to interrogate and control the running process,
+as detailed below, unless there is an error, in which case
+.I prog
+will be nil, and
+.I err
+contains a description of the error.
+.B Prog
+is similar to startprog, except that it attaches to an
+already running process identified by
+.IR pid .
+.SS Controlling a process
+A
+.B Prog
+adt provides routines for controlling a running process.
+It implements the following routines.
+Unless otherwise stated, they return
+.B nil
+on success and a diagnostic string on error.
+.TP 10
+.IB prog .cont()
+Run the program until a break point is reached.
+.TP
+.IB prog .delbpt(\fIdis\fP,\ \fIpc\fP)
+.B Delbpt
+deletes the breakpoint in the Dis module with filename
+.I dis
+at Dis instruction
+.IR pc .
+.TP
+.IB prog .event()
+.B Event
+waits for a state transition in the running
+.I prog
+and returns the new state, as returned by a read
+of the
+.B dbgctl
+file (see
+.IR prog (3)).
+.TP
+.IB prog .grab()
+.B Grab
+stops the
+.I prog
+and puts it into a state where single stepping
+is possible.
+.TP
+.IB prog .kill()
+.B Kill
+kills
+.IR prog .
+.TP
+.IB prog .setbpt(\fIdis\fP,\ \fIpc\fP)
+.B Setbpt
+sets a breakpoint in the Dis module with filename
+.I dis
+at Dis instruction
+.IR pc .
+.TP
+.IB prog .stack()
+.B Stack
+returns a tuple
+.RI ( exps ,\ err )
+where
+.I exps
+is an array of
+.B Exp
+adts, each representing one frame of the current
+execution stack of
+.IR prog .
+If an error occurs,
+.I exps
+will be nil, and
+.I err
+will contain a description of the error.
+.TP
+.IB prog .start()
+.B Start
+runs
+.I prog
+until it hits a breakpoint or exits.
+.TP
+.IB prog .status()
+.B Status
+returns a tuple
+(\fIpgrp\fP, \fPuser\fP, \fPstate\fP, \fPmodule\fP)
+where
+.I pgrp
+is the process group id of
+.IR prog ,
+.I user
+is the owner of the process,
+.I state
+is the current state of the process, and
+.I module
+is the module implementation name of the currently
+executing module.
+.TP
+.IB prog .step(\fIhow\fP)
+.B Step
+steps
+.I prog
+forward in a manner specified by
+.IR how ,
+which is one of the following constants:
+.RS
+.TP
+.B StepExp
+Step one expression evaluation.
+.TP
+.B StepStmt
+Step one source statement.
+.TP
+.B StepOver
+Step over one called function.
+.TP
+.B StepOut
+Step until the current function has returned.
+.RE
+.TP
+.IB prog .stop()
+Stop
+.IR prog
+from running.
+.TP
+.IB prog .unstop()
+Release a program from its stopped state;
+breakpoints will no longer be triggered.
+.SS "Inspecting data"
+The
+.B Exp
+adt provides facilities for inspecting
+the data structures of a running Dis process.
+A hierarchical data structure can be expanded into
+an array of its component
+.BR Exp s,
+as long as the appropriate symbol information has
+been located correctly using
+.B stdsym
+or
+.BR addsym ,
+and
+.BR findsym .
+.PP
+A
+.B Pos
+represents a position in a Limbo source code file;
+it holds the source file name, the line number (origin 1)
+and the character within the line (origin 0).
+The
+.B Src
+adt represents a range in a Limbo source code file;
+.B Src.start
+and
+.B Src.stop
+represent the beginning and the end of the
+range, respectively.
+.PP
+A
+.B Sym
+represents a
+.B .sbl
+symbol file, and is created by calling
+.BI sym( p )
+where
+.I p
+is the pathname of the symbol file;
+.B sym
+returns a tuple
+.RI ( sym ,\ err ),
+where if
+.I sym
+is nil,
+.I err
+contains an error message.
+A
+.B Sym
+can map between a Dis PC and a source file address,
+and vice versa.
+For a given
+.B Sym
+.IR sym ,
+.IB sym .srctopc( src )
+returns the PC associated with
+.IR src
+(or -1 on error);
+.IB sym .pctosrc
+converts the other way (and returns
+.B nil
+on error).
+.PP
+Each element
+.I e
+in the top level stack, as returned by
+.BR Prog.stack ,
+has an associated
+.B Module
+.IB e .m
+which needs to be associated with a
+.B Sym
+so that
+.I debug
+can glean from it the type information it needs.
+Given a module
+.IR m ,
+.IB m .stdsym()
+will try and find a symbol file in
+a standard place, but this will fail if the symbol file
+or the Dis file is in a non-standard place.
+.IB M .addsym( s )
+sets the symbol file for
+.I m
+to the
+.B Sym
+.IR s .
+.IB M .dis()
+and
+.IB m .sbl()
+return the paths of the Dis and symbol files associated
+with
+.I m
+respectively.
+.PP
+Each top level stack element
+expands into three elements, ``args'', ``locals'',
+and ``module'', representing the arguments to the function,
+the function's local variables, and the module-global
+variables of the function's module respectively.
+Before a top level stack element can be expanded,
+it is necessary to call
+.B findsym
+on it to locate the function's data.
+.TP 10
+.IB exp .name
+The name of the symbol.
+.TP
+.IB exp .expand()
+Expand a hierarchical structure into an array of its
+component elements. A list element expands into two
+elements named ``hd'' and ``tl''; a tuple into elements
+named ``t0'', ``t1'',..., an array into elements named ``0'', ``1'',..., etc.
+.TP
+.IB exp .val()
+.B Val
+returns a tuple
+.RI ( s ,\ flag )
+where
+.I s
+is a string representation of the value of
+.IR exp ,
+and if
+.I flag
+is zero,
+.I exp
+cannot be expanded.
+.TP
+.IB exp .src()
+.B Src
+returns the file range associated with
+.IR exp.
+.TP
+.IB exp .findsym()
+If
+.I exp
+is a top level stack frame (i.e. one of the members of the array
+returned by
+.BR Prog.stack )
+then
+.B findsym
+will attempt to locate its type and name. If it succeeds,
+it returns the null string, otherwise it returns
+an error indicating the problem.
+.TP
+.IB exp .srcstr()
+.B Srcstr
+returns a string representing the position in the source file
+of
+.IR exp .
+.SH FILES
+.BI /prog/ pid /*
+.SH SOURCE
+.B /appl/lib/debug.b
+.SH SEE ALSO
+.IR wm-deb (1),
+.IR prog (3)
+.SH BUGS
+There is no way of looking at the types of the data extracted.
diff --git a/man/2/devpointer b/man/2/devpointer
new file mode 100644
index 00000000..6433221c
--- /dev/null
+++ b/man/2/devpointer
@@ -0,0 +1,57 @@
+.TH DEVPOINTER 2 mux
+.SH NAME
+devpointer \- I/O interface for the pointer device
+.SH SYNOPSIS
+.EX
+include "draw.m"; # for Draw->Pointer
+include "devpointer.m";
+ptr:= load Devpointer Devpointer->PATH;
+
+init: fn(file: string, posn: chan of ref Draw->Pointer): int;
+bytes2ptr: fn(buf: array of byte) : ref Draw->Pointer;
+ptr2bytes: fn(ptr: ref Draw->Pointer): array of byte;
+.EE
+.SH DESCRIPTION
+.B Devpointer
+reads messages from pointer devices with the same data format as
+.BR /dev/pointer ,
+converting them to
+.B Pointer
+adts.
+.PP
+.B Init
+spawns a process to read continually the pointer device specified by
+.I file
+and send a
+.B Pointer
+adts over the channel specified by
+.IR posn .
+If
+.I file
+is
+.BR nil ,
+the default device is
+.BR /dev/pointer .
+.PP
+.B Bytes2ptr
+converts the array of bytes
+.I buf
+to a
+.B Pointer
+and returns a reference to it.
+.I Buf
+should consist of exactly
+.B Devpointer->Size
+bytes and be in the format returned by
+.BR /dev/pointer .
+.PP
+.B Ptr2bytes
+provides the inverse transformation of
+.BR bytes2ptr :
+it packs the data into an array of bytes of appropriate format,
+which it returns.
+.SH FILES
+.B /dev/pointer
+.SH "SEE ALSO"
+.IR draw-intro (2),
+.IR draw-pointer (2)
diff --git a/man/2/dhcpclient b/man/2/dhcpclient
new file mode 100644
index 00000000..7cab98de
--- /dev/null
+++ b/man/2/dhcpclient
@@ -0,0 +1,354 @@
+.TH DHCPCLIENT 2
+.SH NAME
+Dhcpclient: Bootconf, Lease, bootp, dhcp, applycfg, removecfg \- client's side of dynamic host configuration protocol
+.SH SYNOPSIS
+.EX
+include "dhcp.m"; # sic
+dhcpclient := load Dhcpclient Dhcpclient->PATH;
+Bootconf, Lease: import dhcpclient;
+
+Bootconf: adt {
+ ip: string;
+ ipgw: string;
+ ipmask: string;
+ bootf: string;
+ bootip: string;
+ dhcpip: string;
+ siaddr: string;
+ serverid: string;
+ sys: string;
+ dom: string;
+ lease: int;
+ options: array of array of byte;
+ vendor: array of array of byte;
+
+ new: fn(): ref Bootconf;
+ get: fn(c: self ref Bootconf, n: int): array of byte;
+ getint: fn(c: self ref Bootconf, n: int): int;
+ getip: fn(c: self ref Bootconf, n: int): string;
+ getips: fn(c: self ref Bootconf, n: int): list of string;
+ gets: fn(c: self ref Bootconf, n: int): string;
+ put: fn(c: self ref Bootconf, n: int, a: array of byte);
+ putint: fn(c: self ref Bootconf, n: int, v: int);
+ putips: fn(c: self ref Bootconf, n: int, ips: list of string);
+ puts: fn(c: self ref Bootconf, n: int, s: string);
+};
+
+Lease: adt {
+ configs: chan of (ref Bootconf, string);
+
+ release: fn(l: self ref Lease);
+};
+
+init: fn();
+tracing: fn(debug: int);
+bootp: fn(net: string, ctlifc: ref Sys->FD, device: string,
+ init: ref Bootconf): (ref Bootconf, string);
+dhcp: fn(net: string, ctlifc: ref Sys->FD, device: string,
+ init: ref Bootconf, options: array of int):
+ (ref Bootconf, ref Lease, string);
+
+applycfg: fn(net: string, ctlifc: ref Sys->FD,
+ conf: ref Bootconf): string;
+removecfg: fn(net: string, ctlifc: ref Sys->FD,
+ conf: ref Bootconf): string;
+.EE
+.SH DESCRIPTION
+.B Dhcpclient
+implements the client side of the Dynamic Host Configuration Protocol (DHCP) of Internet RFC2131.
+In the interface, Internet addresses are represented as strings, in forms that
+.IR ip (2)
+can parse, and that can be written directly to control files in
+.IR ip (3).
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+.PP
+.B Bootp
+reserves the UDP port on
+.I net
+for use by BOOTP/DHCP clients, and sends a BOOTP request (ie, one without a DHCP operation code).
+.I Net
+is the name of the network directory (if nil, the default is
+.BR /net ).
+If
+.B bootp
+is to configure the interface according to the results received,
+.I ctlifc
+should be open on the control file of the
+.IB net /ipifc
+directory for the interface to be configured; otherwise it should be nil.
+.B Bootp
+repeats the request periodically until it either receives a reply or has made 5 attempts.
+It returns a tuple
+.BI ( conf,\ err ).
+If it has received a reply,
+.I conf
+refers to a
+.B Bootconf
+value that contains the values received, and
+.I err
+is nil.
+If
+.I ctlifc
+is not nil, the interface will also have been configured appropriately.
+If a valid reply has not been received, or some other error occurred,
+.I conf
+is nil, and
+.I err
+is a diagnostic.
+.PP
+.B Dhcp
+has a similar interface, but runs the full DHCP protocol.
+The
+.I options
+array has integers representing possible DHCP options;
+.B dhcp
+asks the server to provide values for them.
+If
+.I options
+is nil, a few option values are requested that might be useful for Inferno
+(eg, subnet mask, gateway, DNS server, authentication and file servers, and so on).
+If the server does supply them, they can be retrieved either from
+specific fields of
+.BR Bootconf ,
+or using its
+.I get
+operations.
+.I Init
+is also usually nil, but can refer to a
+.B Bootconf
+that provides some values to suggest to the server, for instance if the client
+knows a previously-assigned address stored in non-volatile memory.
+.B Dhcp
+returns a tuple
+.BI ( conf,\ lease,\ err ),
+where
+.I conf
+and
+.I err
+are just as for
+.BR bootp ,
+and the new component
+.I lease
+is a reference to a
+.B Lease
+value that gives access to the state of the client's address assignment.
+.PP
+DHCP allows a server to assign a client an address permanently, or to lease it for a specified time.
+In the latter case,
+.B Bootconf.lease
+will have a non-zero value, and
+the client must periodically renew the lease to retain the address, and
+.B dhcp
+creates a process to do so.
+The
+.B Lease
+value provides a way for that process to communicate changes (if any) to the network configuration.
+Each time the configuration changes, the process will send a message on the channel
+.BR configs .
+(The channel is buffered, and
+.B dhcp
+first discards any previous notifications not yet received, so there are no ill effects
+if no process ever receives from the channel.)
+Each message is a tuple
+.BI ( conf,\ diag ).
+If a new state change has been made successfully,
+.I conf
+refers to a
+.B Bootconf
+value with the details.
+Otherwise,
+.I conf
+is nil and
+.I diag
+explains what went wrong.
+In any case, the watchdog process continues to try to extend the lease, or failing that,
+obtain a new network configuration, perhaps from another server.
+.B Lease.release
+may be called to release the leased address and stop the watchdog.
+.PP
+.B Bootconf
+has the following operations:
+.TP
+.B new()
+Return a reference to a
+.B Bootconf
+with values initialised to nil or 0.
+.TP
+.IB bc .get( n )
+Return the value of DHCP option
+.I n
+as a raw array of bytes.
+Return nil if the option is not set.
+.TP
+.IB bc .getint( n )
+Return the value of option
+.I n
+interpreted as an integer.
+Return zero if the option is not set.
+.TP
+.IB bc .getip( n )
+Return the first Internet address provided for option
+.IR n .
+.TP
+.IB bc .getips( n )
+Return a list of all the Internet addresses provided for option
+.IR n .
+.TP
+.IB bc .gets( n )
+Return the value of option
+.I n
+as a string.
+.TP
+.IB bc .put( n,\ a )
+Set the value of DHCP option
+.I n
+to the bytes of byte array
+.IR a .
+If
+.I a
+is nil,
+.B put
+removes any existing value for the option.
+.TP
+.IB bc .putint( n,\ v)
+Set option
+.I n
+to the integer value
+.IR v .
+.TP
+.IB bc .putips( n,\ ips )
+Set option
+.I n
+to the list of Internet addresses
+.IR ips .
+.TP
+.IB bc .puts( n,\ s )
+Set option
+.I n
+to the string
+.IR n .
+.PP
+.B Dhcpclient
+names a few constants representing commonly-used configuration options (attributes).
+They are suitable parameters for the option selector
+.I n
+of
+.BR Bootconf 's
+.I get
+and
+.I put
+functions.
+The first set of constants name options for both BOOTP and DHCP:
+.PP
+.PD 0
+.TP 25
+.B Odnsserver
+Internet address(es) of Domain Name Servers
+.TP
+.B Odomainname
+Current domain (see
+.BR Bootconf.dom )
+.TP
+.B Ohostname
+Host name (see
+.BR Bootconf.sys )
+.TP
+.B Omask
+Network mask (IPv4).
+Also see
+.BR Bootconf.ipmask .
+.TP
+.B Onetbiosns
+NetBIOS servers
+.TP
+.B Ontpserver
+Network Time Protocol servers
+.TP
+.B Opop3server
+POP3 mail servers
+.TP
+.B Orouter
+Default router for subnet (see
+.BR Bootconf.ipgw )
+.TP
+.B Osmtpserver
+SMTP mail delivery servers
+.TP
+.B Ovendorinfo
+Vendor-specific data (see below)
+.TP
+.B Owwwserver
+HTTP proxy
+.PD
+.PP
+The second set has DHCP options:
+.PP
+.PD 0
+.TP 25
+.B Obootfile
+Name of the file containing a kernel for the client to load (eg, by TFTP); see
+.BR Bootconf.bootf .
+.TP
+.B Olease
+Lease time for IP address, in seconds (also see
+.BR Bootconf.lease )
+.TP
+.B Omaxmsg
+Maximum DHCP size the client is willing to accept (minimum 576 bytes).
+.TP
+.B Orebindingtime
+Time interval in seconds from address assignment to the time address must be rebound.
+.TP
+.B Orenewaltime
+Time interval in seconds from address assignment to first attempt to renew the address.
+.TP
+.B Otftpserver
+TFTP server from which to fetch kernel and parameter files; see
+.BR Bootconf.bootip .
+.TP
+.B Ovendorclass
+Identify vendor type and configuration of client. Inferno sets
+this to
+.B plan9_386
+(sic) to encourage Plan 9 DHCP servers to respond; other servers will ignore it.
+.PD
+.PP
+The final set give vendor-specific options that Inferno shares with Plan 9:
+.PP
+.PD 0
+.TP 25
+.B Ovendor
+Flag OR'd in to an option number to mark it as destined for the `vendor information' section.
+.TP
+.B OP9auth
+Authentication server
+.RB ( Ovendor|129 )
+.TP
+.B OP9fs
+File server
+.RB ( Ovendor|128 )
+.PD
+.PP
+Given a network configuration in
+.IR conf ,
+and a valid file descriptor for a network interface's control file,
+in the network
+.IR net ,
+.B applycfg
+sets the basic interface parameters (address, network mask, default gateway),
+and writes other parameters to
+.IR net /ndb ;
+conversely,
+.B removecfg
+removes from the interface just those parameters set by
+.IR conf .
+Normally these functions are called automatically, as required, by
+.B dhcp
+and its watchdog process.
+.SH SOURCE
+.B /appl/lib/dhcpclient.b
+.SH SEE ALSO
+.IR bootpd (8),
+.IR dhcp (8)
diff --git a/man/2/dialog b/man/2/dialog
new file mode 100644
index 00000000..bec2f045
--- /dev/null
+++ b/man/2/dialog
@@ -0,0 +1,74 @@
+.TH DIALOG 2
+.SH NAME
+dialog: prompt, getstring \-
+basic dialog boxes
+.SH SYNOPSIS
+.EX
+include "dialog.m";
+dialog := load Dialog Dialog->PATH;
+
+init: fn();
+prompt: fn(ctxt: ref Draw->Context, p: ref Draw->Image,
+ icon, title, msg: string,
+ dflt: int, labs: list of string): int;
+getstring: fn(ctxt: ref Draw->Context, p: ref Draw->Image,
+ s: string): string;
+.EE
+.SH DESCRIPTION
+.B Dialog
+module provides two simple dialog boxes
+for use by
+.IR wm (1)
+applications.
+.B Init
+should be called once to initialise its internal state.
+.PP
+.B Prompt
+uses the graphics context
+.I ctxt
+to pop up a dialog box to prompt the user to choose from a set of alternatives,
+or to acknowledge a message.
+The box is created near the northwest corner of
+the parent window
+.IR p ,
+represented by the window's image.
+(If the parent window is a Tk Toplevel
+.IR t ,
+for instance, the appropriate value is
+.IB t .image \f1.)\fP
+If
+.I p
+is nil, the box is centred on the screen.
+The box
+has the given
+.I title
+and an optional
+.IR icon .
+It displays the given
+.I msg
+and a number of buttons, labelled with the strings in
+.IR labs .
+The dialog box waits for the user to push a button, and then
+returns the index of the button pushed (the first element of
+.I labs
+is index 0).
+If the user types a newline, the
+.I dflt
+value is returned. The button with the
+.I dflt
+index is specially outlined in the dialog box.
+.PP
+.B Getstring
+pops up a dialog box near the parent window
+.IR p .
+The box contains the
+.I msg
+and an entry widget.
+It waits for the user to type a string and a newline,
+and then returns the typed string, without the newline.
+.SH SOURCE
+.B /appl/lib/dialog.b
+.SH SEE ALSO
+.IR draw-context (2),
+.IR tk (2),
+.IR wmlib (2)
diff --git a/man/2/dict b/man/2/dict
new file mode 100644
index 00000000..6564e278
--- /dev/null
+++ b/man/2/dict
@@ -0,0 +1,57 @@
+.TH DICT 2
+.SH NAME
+dict - list of string pairs
+.SH SYNOPSIS
+.EX
+include "dict.m";
+dict := load Dictionary Dictionary->PATH;
+
+Dict: adt {
+ add: fn(d: self ref Dict, e: (string, string));
+ delete: fn(d: self ref Dict, k: string);
+ lookup: fn(d: self ref Dict, k: string): string;
+ keys: fn(d: self ref Dict): list of string;
+};
+.EE
+.SH DESCRIPTION
+.B Dict
+provides a simple string to string association list:
+.TP
+.IB d .add( e )
+Adds a new tuple
+.IR e
+to the list,
+representing a new
+.RI ( "key ,\ value" )
+pair.
+.TP
+.IB d .delete ( k )
+Deletes all pairs with key
+.I k
+from the list.
+.TP
+.IB d .lookup( k )
+Tries to find a pair with key
+.I k
+and returns its associated value,
+or nil if the key was not found.
+.TP
+.IB d .keys()
+Returns a list of all
+keys
+in the list.
+.SH SOURCE
+.B /appl/lib/dict.b
+.SH SEE ALSO
+.IR hash (2)
+.SH BUGS
+No attempt is made to
+keep keys unique in the list; if more
+than one pair exists with the same key, then
+.B lookup
+will select one of them arbitrarily.
+.PP
+Computational overhead of lookup and deletion of
+keys is proportional
+to the number of pairs in the list.
+
diff --git a/man/2/dis b/man/2/dis
new file mode 100644
index 00000000..bb3cdc91
--- /dev/null
+++ b/man/2/dis
@@ -0,0 +1,488 @@
+.TH DIS 2
+.SH NAME
+dis \- read Dis object files
+.SH SYNOPSIS
+.EX
+include "dis.m";
+dis := load Dis Dis->PATH;
+
+Inst: adt
+{
+ op: int;
+ addr: int;
+ mid: int;
+ src: int;
+ dst: int;
+};
+
+Type: adt
+{
+ size: int;
+ map: array of byte;
+};
+
+Data: adt
+{
+ op: int; # encoded op
+ n: int; # number of elements
+ off: int; # byte offset in data space
+ pick {
+ Zero => # DEFZ
+ Bytes => # DEFB
+ bytes: array of byte;
+ Words => # DEFW
+ words: array of int;
+ String => # DEFS
+ str: string;
+ Reals => # DEFF
+ reals: array of real;
+ Array => # DEFA
+ typex: int;
+ length: int;
+ Aindex => # DIND
+ index: int;
+ Arestore => # DAPOP
+ Bigs => # DEFL
+ bigs: array of big;
+ }
+};
+
+Link: adt
+{
+ pc: int;
+ desc: int;
+ sig: int;
+ name: string;
+};
+
+Import: adt
+{
+ sig: int;
+ name: string;
+};
+
+Except: adt
+{
+ s: string;
+ pc: int;
+};
+
+Handler: adt
+{
+ pc1: int;
+ pc2: int;
+ eoff: int;
+ ne: int;
+ t: ref Type;
+ etab: array of ref Except;
+};
+
+Mod: adt
+{
+ name: string;
+ srcpath: string;
+
+ magic: int;
+ rt: int;
+ ssize: int;
+ isize: int;
+ dsize: int;
+ tsize: int;
+ lsize: int;
+ entry: int;
+ entryt: int;
+
+ inst: array of ref Inst;
+ types: array of ref Type;
+ data: list of ref Data;
+ links: array of ref Link;
+ imports: array of array of ref Import;
+ handlers: array of ref Handler;
+
+ sign: array of byte;
+};
+
+init: fn();
+loadobj: fn(file: string): (ref Mod, string);
+op2s: fn(op: int): string;
+inst2s: fn(i: ref Inst): string;
+.EE
+.SH DESCRIPTION
+The
+.B Dis
+module decodes the contents of a Dis object file containing a single module,
+of the format defined by
+.IR dis (6).
+The module defines many constants, giving symbolic names to
+Dis instruction codes, addressing mode masks, magic numbers, and other
+bits of the object code.
+.PP
+.B Init
+must be called before any other function, to initialise the module.
+.PP
+.B Loadobj
+reads a Dis object file from
+.IR file ,
+and returns a reference to a
+.B Mod
+adt that represents the module's contents, as the first element of the tuple;
+the string element of the tuple is nil.
+On error, the string element contains a diagnostic, and the
+reference is nil.
+.PP
+.B Op2s
+returns the assembly-language representation, as used by
+.IR asm (1),
+of the Dis operation code
+.IR op .
+It returns the string
+.IB ` OP op'
+if
+.I op
+does not correspond to a known operation code.
+.PP
+.B Inst2s
+returns a string corresponding to a disassembly of Dis instruction
+.IR i ,
+including addressing modes.
+.PP
+The module defines integer constants giving
+symbolic names to the Dis instruction codes, all of the form
+.BI I name
+where
+.I name
+is the name of the instruction, all in upper case:
+.IP
+.BR INOP ,
+.BR IALT ,
+.BR INBALT ,
+\&...
+.BR INEWZ ,
+.BR INEWAZ ,
+.BR IRAISE
+.PP
+The name
+.B MAXDIS
+is also defined; it has the value of the first unassigned Dis operation code.
+.PP
+Most of the members of the adt types have an obvious interpretation
+on reference to
+.IR dis (6).
+.PP
+The adt
+.B Mod
+represents a single module.
+It contains values extracted from the module's header,
+and references to structures representing the contents of
+the Dis file's code, data, type
+and external linkage sections:
+.TF entryt
+.PD
+.TP
+.B magic
+The constant
+.B XMAGIC
+(unsigned Dis module)
+or the constant
+.B SMAGIC
+(signed Dis module).
+.TP
+.B sign
+If
+.B magic
+is
+.BR SMAGIC ,
+the
+.B sign
+field contains the bytes in the signature section of the module header.
+Otherwise, there is no signature and
+.B sign
+is
+.BR nil .
+.TP
+.B name
+The name of the implementation module.
+.TP
+.B srcpath
+The source of the dis file relative to the inferno root.
+.TP
+.B rt
+Run-time options: a bit mask of the constants
+.BR MUSTCOMPILE ,
+.B DONTCOMPILE
+and
+.BR SHAREMP .
+.TP
+.B ssize
+Stack extent
+.TP
+.B isize
+Number of instructions
+.TP
+.B dsize
+Size in bytes of the module's global data area
+.TP
+.B tsize
+Number of type descriptors
+.TP
+.B lsize
+Number of external linkage descriptors
+.TP
+.B entry
+PC (instruction offset) of the default entry point for the module
+.TP
+.B entryt
+Index of the type descriptor for the module's entry point
+.TP
+.B inst
+Array representing the contents of the code segment;
+length
+.IB m .isize
+.TP
+.B types
+Array of the module's type descriptors;
+length
+.IB m .tsize
+.TP
+.B data
+list of data descriptors representing instructions for creating the module's data segment
+.TP
+.B links
+array of the module's external linkage descriptors (for exported functions); length
+.IB m .lsize
+.TP
+.B imports
+an array of import descriptor tables, one table for each module imported by this
+module. Each table is an array of pairs giving the signature and name of each
+function imported.
+.TP
+.B handlers
+an array of exception handlers used in this module. Each handler consists of
+the range of pc's it covers, the exception structure offset within the
+frame, the number of declared exceptions (as opposed to strings) in the handler,
+the type (if any) of any memory to clear when the exception occurs and a table
+of exceptions. The latter is an array containing pairs of exceptions and
+pc values. The final entry gives the pc to jump to
+in the '*' case or -1 if not applicable.
+.PP
+The
+.B Type
+adt represents the value of a type descriptor:
+.TF entryt
+.PD
+.TP
+.B size
+Size in bytes of the object represented by this descriptor
+.TP
+.B map
+Bitmap describing the location of pointers in the object (see
+.IR dis (6))
+.PP
+The
+.B Link
+adt represents the value of a link descriptor:
+.TF entryt
+.PD
+.TP
+.B name
+Name of the exported function
+.TP
+.B pc
+Instruction index in
+.B Mod.code
+of the function's entry point
+.TP
+.B desc
+Index in
+.B Mod.types
+of the type describing the function's stack frame
+.TP
+.B sig
+Integer hash of the function's type signature
+.PP
+The
+.B Inst
+adt represents a single Dis instruction in the instruction stream.
+The member
+.B op
+is the Dis instruction code.
+The member
+.B addr
+contains the addressing mode flags for middle, source and destination operands.
+Constants are defined to help unpack it.
+.PP
+The middle operand description is selected by the constant mask
+.BR ARM :
+.IP
+.IB i ".addr & ARM"
+.PP
+The valid results and interpretation are as follows:
+.IP
+.RS
+.TF AXNON
+.TP
+.B AXNON
+No middle operand.
+.TP
+.B AXIMM
+.BI $ n
+.TP
+.B AXINF
+.IB n (fp)
+.TP
+.B AXINM
+.IB n (mp)
+.PD
+.RE
+.PP
+The source operand's addressing mode is extracted as follows:
+.IP
+.BI ( i ".addr>>3)&AMASK"
+.PP
+The following combinations are valid, where
+.I n
+is the value in
+.IB i .src :
+.IP
+.RS
+.TF AIND|AMP
+.TP
+.B AXXX
+No operand
+.TP
+.B AFP
+The operand is
+.IB n (fp)
+.TP
+.B AMP
+The operand is
+.IB n (mp)
+.TP
+.B AIMM
+The operand is
+.BI $ n
+(ie, immediate literal
+.IR n )
+.TP
+.B AIND|AFP
+The operand is
+.IB si ( fi (fp))
+.TP
+.B AIND|AMP
+The operand is
+.IB si ( fi (mp))
+.RE
+.PD
+.PP
+where
+.I fi
+is the offset for the first indirection, extracted from
+.IR n :
+.IP
+.BI ( n ">>16)&16rFFFF)" ,
+.PP
+and
+.I si
+is the offset for the second indirection, also extracted from
+.IR n:
+.IP
+.BI ( n "&16rFFFF)" .
+.PP
+The destination addressing mode is interpreted in a similar way,
+except that the addressing mode is extracted as follows:
+.IP
+.BI ( i ".addr&AMASK)"
+.PP
+and the value of the offset
+.I n
+is found in
+.IB i .dst .
+.I Fi
+and
+.I si
+are extracted from
+.I n
+as before.
+.PP
+Finally,
+.B Data
+adt represents a data item, which tells the system's module loader
+how to initialise part of the module's global data segment.
+It has the following members:
+.TP
+.B op
+the encoded type and length; usually ignored: the
+.B pick
+tag and
+.BR n ,
+below,
+usually suffice
+.TP
+.B n
+the number of data values
+.TP
+.B off
+the byte offset of the first data value to initialise, relative to the current loading base
+.PP
+The alternatives of the
+.B pick
+select the correct variant to see the data values encoded in the
+object file as Limbo values
+of the correct type.
+The interpretation is straightforward for the tags
+.BR Bytes ,
+.BR Words ,
+.B Bigs
+and
+.BR Reals :
+the corresponding array members are arrays of
+.B n
+elements of the appropriate type.
+The remaining cases are as follows:
+.TF Arestore
+.PD
+.TP
+.B String
+The member
+.B str
+has the decoded representation of the
+corresponding
+.I n
+data bytes from the object file.
+.TP
+.B Array
+The member
+.B typex
+is the index in
+.B Mod.types
+of the array's type, and member
+.B length
+is its length.
+.TP
+.B Aindex
+This alternative can appear only following a value of
+.BR Data.Array .
+The member
+.B index
+is an index into the corresponding array as represented in the global data space,
+which determines a new loading base address for subsequent
+.B Data
+items.
+The previous base address is stacked on an internal stack.
+.TP
+.B Arestore
+Pop the address from the internal address stack and make that the current
+loading address.
+The request marks the end of a sequence of
+.B Data
+items initialising an array.
+.SH SOURCE
+.B /appl/lib/dis.b
+.SH SEE ALSO
+.IR disdep (1),
+.B wm/rt
+in
+.IR wm-misc (1),
+.IR dis (6)
+.br
+"The Dis Virtual Machine", in Volume 2.
diff --git a/man/2/diskblocks b/man/2/diskblocks
new file mode 100644
index 00000000..15c79e26
--- /dev/null
+++ b/man/2/diskblocks
@@ -0,0 +1,120 @@
+.TH DISKBLOCKS 2
+.SH NAME
+Diskblocks: Block, Disk, tempfile \- temporary storage of variable-sized blocks
+.SH SYNOPSIS
+.EX
+include "diskblocks.m";
+diskblocks := load Diskblocks Diskblocks->PATH;
+
+Block: adt {
+ addr: big; # address on file
+ n: int; # size in bytes
+};
+
+Disk: adt {
+ init: fn(fd: ref Sys->FD, gran: int, maxblock: int): ref Disk;
+ new: fn(d: self ref Disk, n: int): ref Block;
+ release: fn(d: self ref Disk, b: ref Block);
+ read: fn(d: self ref Disk, b: ref Block,
+ a: array of byte, n: int): int;
+ write: fn(d: self ref Disk, b: ref Block,
+ a: array of byte, n: int): ref Block;
+};
+
+init: fn();
+tempfile: fn(): ref Sys->FD;
+.EE
+.SH DESCRIPTION
+.B Diskblocks
+manages a set of variable-sized blocks on a temporary file.
+.PP
+.B Init
+must be called before any other function in the module.
+.PP
+Each block has an address and a size in bytes, represented by a value of type
+.BR Block .
+.PP
+Each file is represented by the type
+.BR Disk ,
+providing the following operations:
+.TF 8n
+.TP
+.BI init( fd\f5,\fP\ gran\f5,\fP\ maxblock )
+Initialises the file
+.I fd
+for use as temporary block storage and returns a reference to a
+.B Disk
+to describe it.
+.I Fd
+must be open for reading and writing, and must refer to a file that allows random access.
+Blocks are allocated in multiples of the granularity
+.IR gran ,
+in bytes;
+the largest possible block is
+.I maxblock
+bytes, which must be a multiple of
+.IR gran .
+.TP
+.IB d .new( n )
+Allocate a block of
+.I n
+bytes on Disk
+.I d
+and return a reference to it.
+.TP
+.IB d .release( b )
+Free the Block
+.IR b ,
+making it available for reallocation.
+.TP
+.IB d .write( b\f5,\fP\ a\f5,\fP\ n )
+Write
+.I n
+bytes from array
+.I a
+to Block
+.I b
+on Disk
+.IR d ,
+returning a reference to the resulting Block.
+If
+.I b
+is nil or
+.I n
+exceeds
+.IR b 's
+current size,
+.B write
+allocates a new block (releasing
+.IR b ).
+Thus the returned value might differ from
+.IR b ,
+and must be used in subsequent IO requests.
+.TP
+.IB d .read( b\f5,\fP\ a\f5,\fP\ n )
+Read
+.I n
+bytes from Block
+.I b
+on Disk
+.I d
+into array
+.IR a ,
+returning the number of bytes read.
+.I N
+must not exceed
+.IB b .n .
+.PD
+.PP
+.B Tempfile
+returns a file descriptor referring to a newly-created temporary file,
+suitable for use by
+.BR Disk.init .
+The file will be removed automatically
+when the file descriptor is closed.
+.SH SOURCE
+.B /appl/lib/diskblocks.b
+.SH DIAGNOSTICS
+A function that returns an integer returns -1 on error; a function that returns a reference
+returns nil on error.
+The system error string is set in either case.
diff --git a/man/2/disks b/man/2/disks
new file mode 100644
index 00000000..17970a52
--- /dev/null
+++ b/man/2/disks
@@ -0,0 +1,317 @@
+.TH DISKS 2
+.SH NAME
+disks: Disk, PCpart, readn, chstext \- generic disk and partition interface
+.SH SYNOPSIS
+.EX
+include "disks.m";
+
+disks := load Disks Disks->PATH;
+
+Disk: adt {
+ prefix: string; # prefix before partition name
+ part: string; # partition name (nil if not partition)
+ fd: ref Sys->FD;
+ wfd: ref Sys->FD;
+ ctlfd: ref Sys->FD;
+ rdonly: int; # non-zero if readonly
+ dtype: string; # device type
+
+ secs: big; # number of sectors in device or partition
+ secsize: int; # device's sector size
+ size: big; # size of device or partition
+ offset: big; # within larger disk, perhaps
+ width: int; # of disk size in bytes as decimal string
+ c: int; # geometry: cyl, head, sectors
+ h: int;
+ s: int;
+ chssrc: string; # source of c/h/s values
+
+ open: fn(f: string, mode: int, noctl: int): ref Disk;
+};
+
+PCpart: adt {
+ active: int; # Active or 0
+ ptype: int;
+ base: big; # base block address
+ offset: big; # block offset from base to partition
+ size: big; # in sectors
+
+ extract: fn(a: array of byte, d: ref Disk): PCpart;
+ bytes: fn(p: self PCpart, d: ref Disk): array of byte;
+};
+
+init: fn();
+readn: fn(fd: ref Sys->FD, buf: array of byte, n: int): int;
+chstext: fn(p: array of byte): string;
+.EE
+.SH DESCRIPTION
+.B Disks
+provides a simple way to gather
+and use information about
+.IR floppy (3)
+and
+.IR sd (3)
+disks and disk partitions,
+as well as plain files.
+.PP
+.B Init
+must be called before invoking any other operations of the module
+.PP
+.B Disk.open
+opens
+.I file
+and returns a reference to a
+.B Disk
+value to represent the disk.
+.I Mode
+should be either
+.BR Sys->OREAD
+or
+.BR Sys->ORDWR
+to establish the open mode.
+.B Open
+always opens
+.I file
+for reading and stores that file descriptor in
+the element
+.IR fd .
+If the mode is not
+.BR Sys->OREAD ,
+.I opendisk
+also opens
+.I file
+for writing and stores that file descriptor in
+.BR wfd .
+The two file descriptors are kept separate to
+help prevent accidents.
+If
+.I noctl
+is not set,
+.B open
+looks for a
+.B ctl
+file in the same directory as the
+disk file;
+if it finds one, it declares
+the disk to be
+an
+.IR sd (3)
+device,
+setting
+.B dtype
+to
+\f5"sd"\fP.
+If the passed
+.I file
+is named
+.BI fd n disk \fR,
+it looks for a file
+.BI fd n ctl \fR,
+and if it finds that,
+declares the disk to be
+a floppy disk, of type
+\f5"floppy"\fP.
+If either control
+file is found, it is opened for reading
+and writing, and the resulting file descriptor
+is saved as
+.BR ctlfd .
+Otherwise the returned disk
+has type
+\f5"file"\fP.
+.PP
+.B Open
+then stores the file's length
+(as given by
+.IR sys-stat (2))
+in
+.BR size .
+If the disk is an
+.IR sd (3)
+partition,
+.B open
+reads the sector size from the control
+file and stores it in
+.BR secsize ;
+otherwise the sector size is assumed to be 512,
+as is the case for floppy disks.
+.B Open
+stores the disk size measured in sectors in
+.BR secs .
+.PP
+If the disk is an
+.IR sd (3)
+partition,
+.B open
+parses the
+control
+file to find the partition's offset
+within its disk;
+otherwise it sets
+.B offset
+to zero.
+If the disk is an ATA disk,
+.B open
+reads
+the disk geometry (number of cylinders, heads, and sectors)
+from the
+.B geometry
+line in the
+.I sd
+control file;
+otherwise it sets these to zero as well.
+.B Name
+is initialized with the base name of
+the disk partition, and is useful for forming messages to the
+.I sd
+control file.
+.B Prefix
+is set to the original
+.I file
+name without the
+.B name
+suffix.
+.PP
+The IBM PC BIOS interface allocates
+10 bits for the number of cylinders, 8 for
+the number of heads, and 6 for the number of sectors per track.
+Disk geometries are not quite so simple
+anymore, but to keep the interface useful,
+modern disks and BIOSes present geometries
+that still fit within these constraints.
+These numbers are still used when partitioning
+and formatting disks.
+.B Open
+employs a number of heuristics to discover this
+supposed geometry and store it in the
+.BR c ,
+.BR h ,
+and
+.B s
+elements of
+.BR Disk .
+Disk offsets in partition tables and
+in FAT descriptors are stored in a form
+dependent upon these numbers, so
+.I opendisk
+works hard to report numbers that
+agree with those used by other operating
+systems; the numbers bear little or no resemblance
+to reality.
+.PP
+.B Chssrc
+names the source of the geometry values:
+.B disk
+(values returned by disk itself);
+.B part
+(values stored in PC partition table);
+or
+.B guess
+(calculated by module's heuristics).
+.PP
+.B Readn
+attempts to read exactly
+.I n
+bytes from file
+.I fd
+into
+.IR buf ,
+using as many
+.IR sys-read (2)
+calls as required.
+It helps insulate a program from any peculiar underlying IO boundaries
+of a device.
+It returns less than
+.I n
+only if end-of-file is reached.
+It returns -1 if the first read fails.
+.PP
+The PC BIOS and operating systems support an arcane system of disk partitions:
+a partition table at the end of the master boot record
+defines up to four partitions.
+One (or perhaps more) of those can be an extended partition
+that heads a chain (or perhaps roots a tree) of partition tables
+elsewhere on disk, allowing many more than four partitions in all.
+.B Disks
+represents a partition table entry by a value of type
+.BR PCpart .
+It provides the following operations and values:
+.TP
+.B active
+Has the value
+.B Disks->Active
+if it is bootable, and zero otherwise.
+.TP
+.B ptype
+Partition type;
+.B Disks->Type9
+is used by Plan 9 and Inferno (see
+.IR prep (8)).
+.TP
+.B base
+Address of the extended partition that started the chain (or rooted the tree) containing this partition.
+Zero for primary partitions defined by the master boot record.
+.TP
+.B offset
+Block address of the start of the partition relative to the
+.BR base .
+.TP
+.B size
+Size of the partition in sectors.
+.TP
+.BI extract( "a, d" )
+Extracts the relevant data from an array of bytes
+.I a
+containing a PC-format partition table entry on
+.B Disk
+.IR d ,
+and returns a
+.B PCpart
+value that represents the partition.
+.TP
+.IB pc .bytes( d )
+Return an array of bytes containing the PC-format partition
+table entry corresponding to
+.IR pc .
+It will always be
+.B TentrySize
+bytes long.
+.PP
+Several other values are defined here for convenience:
+.TP
+Active
+Value for
+.B PCpart.active
+if the partition is bootable.
+.TP
+.B Type9
+Partition type used by Plan 9 and Inferno.
+.TP
+.B Toffset
+Offset (in bytes) of the partition table in a master boot record or extended partition start sector.
+.TP
+.B TentrySize
+Size in bytes of a partition table entry.
+.TP
+.B NTentry
+Number of table entries.
+.TP
+.B Magic0
+.PD0
+.TP
+.B Magic1
+Each sector containing a partition table should end with
+these two bytes (a master boot record must end with them).
+.PP
+.B Chstext
+takes a 3-byte array containing the packed cylinder/head/sector
+representation of a disk address and returns the corresponding text
+in the form
+.BI c / h / s.
+.SH SOURCE
+.B /appl/lib/disks.b
+.SH SEE ALSO
+.IR scsiio (2),
+.IR floppy (3),
+.IR sd (3),
+.IR prep (3)
diff --git a/man/2/dividers b/man/2/dividers
new file mode 100644
index 00000000..710308d7
--- /dev/null
+++ b/man/2/dividers
@@ -0,0 +1,68 @@
+.TH DIVIDERS 2
+.SH NAME
+Dividers \- user-draggable tk dividing bars
+.SH SYNOPSIS
+.EX
+include "dividers.m";
+dividers := load Dividers Dividers->PATH;
+Divider: import dividers;
+
+init: fn();
+Divider: adt {
+ new: fn(win: ref Tk->Toplevel, w: string, wl: list of string, dir: int):
+ (ref Divider, chan of string);
+ event: fn(d: self ref Divider, e: string);
+};
+.EE
+.SH DESCRIPTION
+.I Dividers
+presents an interface allowing Tk widgets to
+be arranged within a window, divided by bars which
+can be dragged by the user to determine the proportion
+of the available space to allocate to each widget.
+The groups can be stacked vertically or horizontally.
+.I Divider
+widgets can be nested.
+.PP
+.B Init
+must be called before anything else, to allow
+.I Dividers
+to initialise its internal state.
+.B Divider.new
+creates a new divider widget; it will be named
+.IR w ,
+and it will divide up the widgets named in
+the list
+.IR wl .
+.I Dir
+can be
+.BR Dividers->NS ,
+to stack the widgets one on top of another,
+or
+.BR Dividers->EW
+to stack the widgets left-right.
+.B Divider.new
+returns a new
+.B Divider
+adt, and a channel through which
+.B Divider
+events will be received.
+The application should arrange that events
+received on this channel be passed to the
+.B event()
+function.
+.PP
+A
+.B Divider
+widget must be informed if its size has changed
+by configuring its width and height appropriately;
+it does the same to the items it is dividing.
+.SH SOURCE
+.B /appl/lib/dividers.b
+.SH BUGS
+It should not be necessary to inform the
+.B Divider
+widget of size changes.
+.PP
+The event-based mechanism seems somewhat
+contrary to the preferred Limbo way of doing things.
diff --git a/man/2/draw-0intro b/man/2/draw-0intro
new file mode 100644
index 00000000..6fb4384a
--- /dev/null
+++ b/man/2/draw-0intro
@@ -0,0 +1,268 @@
+.TH DRAW-INTRO 2
+.SH NAME
+draw \- basic graphics facilities module
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+setalpha: fn(rgba: int, alpha: int): int;
+.EE
+.SH DESCRIPTION
+Inferno's
+.B Draw
+module provides basic graphics facilities, defining drawing
+contexts, images, character fonts, and rectangular geometric operations.
+See
+.IR wmlib (2)
+and
+.IR tk (2)
+for higher level operations, such as windows and menu handling.
+.SS Pixels
+Images are defined on a rectangular region of
+an integer plane with a picture element, or
+.IR pixel ,
+at each grid point.
+Pixel values are integers with between 1 and 32 bits per pixel, and all
+pixels in a given image have the same size, or
+.IR depth .
+Some operations allow images with different depths to be combined,
+for example to do masking.
+Images have one or more channels: colour channels, greyscale channels, colour map indices,
+and others, as described in
+.IR colour (6).
+Each pixel value contains a component of each such channel.
+All pixels in an image have the same size, or
+.IR depth ,
+and the same component structure.
+.PP
+When an image is displayed, the value of each pixel determines the colour
+of the display, according to the interpretation of the image's channels.
+For instance, on `true colour' displays, the display image might contain red, blue and green
+colour channels, and each pixel value will have red, blue and green colour components.
+For displays with only 8 bits per pixel or less,
+Inferno uses a fixed colour map for each display depth (see
+.IR colour (6)).
+Facilities exist in
+.IR draw-display (2)
+to convert between (red, green, blue)
+triplets and colour-mapped pixel values,
+but the mapping is often done automatically by the graphics operations
+when images with different channel structures are combined.
+.PP
+.B Draw
+uses a standard representation of colour constants in calls to create coloured images
+or to initialise new images with a given colour.
+This is referred to as `32-bit RGBA format'.
+Each constant colour is represented as a 32-bit integer, with 8-bit red, blue and green colour components,
+and an 8-bit alpha component, in that order from most to least significant byte.
+.PP
+The RGB values in a colour are
+.I premultiplied
+by the alpha value; for example, a 50% red is
+.B "int 16r7F00007F"
+not
+.BR "int 16rFF00007F" .
+The function
+.B Draw->setalpha
+performs the alpha computation on a given colour
+.I rgba
+in 32-bit RGBA format,
+ignoring its initial alpha value, and returning the
+result of multiplying each colour component by the supplied
+.BR alpha .
+For example, to make a 50% red color value, one could execute
+.B draw->setalpha(Draw->Red,
+.BR 16r7F) .
+.SS Terminology
+.TF Pointer
+.PD
+.TP
+.B Point
+The graphics plane is defined on an integer grid,
+with each
+.RI ( x ",\ " y )
+coordinate identifying
+the upper left corner of the corresponding pixel.
+The plane's origin, (0,\ 0), resides at the upper left corner of the screen;
+.I x
+and
+.I y
+coordinates increase to the right and down.
+The abstract data type,
+.BR Point
+defines a coordinate position.
+.TP
+.B Rect
+The type
+.B Rect
+defines a rectangular region of the plane.
+It comprises two
+.BR Points ,
+.B min
+and
+.BR max ,
+and specifies the region defined by pixels with coordinates
+greater than or equal to
+.B min
+and strictly less than
+.BR max ,
+in both
+.I x
+and
+.IR y .
+This
+.I half-open
+property allows rectangles that share an edge to have equal coordinates on the edge.
+.TP
+.B Display
+The type
+.B Display
+represents a physical display, corresponding to a single connection to a
+.IR draw (3)
+device.
+Besides the image of the display itself, the
+.B Display
+type also stores references to off-screen images, fonts, and so on.
+The contents of such images are stored in the display device, not in the client
+of the display, which affects how they are allocated and used, see for example
+.IR draw-image (2).
+.TP
+.B Screen
+The
+.B Screen
+type is used to manage a set of windows on an image, typically but not necessarily
+that of a display.
+.B Screens
+and hence windows may be built recursively upon windows for
+subwindowing or even on off-screen images.
+.TP
+.B Image
+The
+.B Image
+type provides basic operations on groups of pixels.
+Through a few simple operations, most importantly the
+.B draw
+image combination operator
+(see
+.IR draw-image (2)),
+the
+.B Image
+type provides the building blocks for
+.BR Display ,
+.BR Screen ,
+and
+.BR Font .
+.TP
+.B Font
+A
+.B Font
+defines which character image to draw for each character code value.
+Although all character drawing operations ultimately use the
+.B draw
+primitive on the underlying images,
+.B Fonts
+provide convenient and efficient management of display text.
+Inferno uses the 16-bit Unicode character encoding, so
+.B Fonts
+are managed hierarchically to control their size and to make
+common subsets such as ASCII or Greek efficient in practice.
+See
+.IR draw-font (2),
+.IR utf (6),
+and
+.IR font (6).
+.TP
+.B Context
+A
+.B Context
+provides an interface to the system graphics and interactive devices.
+The system creates this context when it starts an application.
+.TP
+.B Pointer
+The
+.B Pointer
+type conveys information for pointing devices, such as mice or trackballs.
+.SS More about Images
+.PP
+An image occupies a rectangle,
+.BR Image.r ,
+of the graphics plane.
+A second rectangle,
+.BR Image.clipr ,
+defines a clipping region for the image.
+Typically, the clipping rectangle is the same as the basic image,
+but they may differ.
+For example, the clipping region may be made smaller and centered on
+the basic image to define a protected border.
+.PP
+The pixel structure of an
+.B Image
+is stored as
+.B Chans
+value
+.BR Image.chans ;
+the image's pixel depth in bits is stored as integer
+.BR Image.depth .
+.PP
+An image may be marked for replication: when set, the boolean
+.B Image.repl
+causes the image
+to behave as if replicated across the entire integer plane,
+thus tiling the destination graphics area
+with copies of the source image.
+When replication is turned on,
+the clipping rectangle limits the extent of the replication and may
+even usefully be disjoint from
+.BR Image.r .
+See
+.IR draw-image (2)
+for examples.
+.PP
+The
+.B Image
+member functions provide facilities for drawing text and geometric objects,
+manipulating windows, and so on.
+.PP
+Objects of type
+.BR Display ,
+.BR Font ,
+.BR Screen ,
+and
+.B Image
+must be allocated by the member functions;
+if such objects are created with a regular Limbo
+definition, they will not behave properly and may generate run-time errors.
+.PP
+There are no ``free'' routines for graphics objects.
+Instead Limbo's garbage
+collection frees them automatically.
+As is generally so within Limbo,
+one can eliminate references by assigning
+.B nil
+to reference variables, returning from functions
+whose local variables hold references, etc.
+.SH RETURN VALUES
+Most drawing operations operate asynchronously, so they have
+no error return.
+Functions that allocate objects return
+.B nil
+for failure; in such cases the system error string may be
+interrogated (such as by the
+.B %r
+format (see
+.IR sys-print (2)))
+for more information.
+.SH SOURCE
+.B /libinterp/draw.c
+.br
+.B /libdraw/*.c
+.SH SEE ALSO
+.IR draw (3),
+.IR ir (2),
+.IR prefab-intro (2),
+.IR tk (2),
+.IR wmlib (2),
+.IR colour (6),
+.IR font (6),
+.IR image (6)
diff --git a/man/2/draw-context b/man/2/draw-context
new file mode 100644
index 00000000..98dde368
--- /dev/null
+++ b/man/2/draw-context
@@ -0,0 +1,167 @@
+.TH DRAW-CONTEXT 2
+.SH NAME
+Context \-
+graphics environment
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Context: adt
+{
+ display: ref Display; # frame buffer on which windows reside
+ wm: chan of (string,
+ chan of (string, ref Wmcontext)); # wmgr connection
+};
+
+# connection to window manager for one or more windows (as Images)
+Wmcontext: adt
+{
+ kbd: chan of int; # incoming characters from keyboard
+ ptr: chan of ref Pointer; # incoming stream of mouse positions
+ ctl: chan of string; # commands from wm to application
+ wctl: chan of string; # commands from application to wm
+ images: chan of ref Image; # exchange of images
+ connfd: ref Sys->FD; # connection control
+ ctxt: ref Draw->Context;
+};
+.EE
+.SH DESCRIPTION
+The
+.B Context
+type encapsulates the data types and channels used by an interactive application,
+and establishes a context for graphics output and window management.
+A reference to the
+.B Context
+is passed as the first argument to an application when it begins execution:
+.PP
+.EX
+include "draw.m"
+
+Command: module
+{
+ init: fn(nil: ref Draw->Context; nil: list of string);
+};
+.EE
+.PP
+Most programs do not create
+.B Contexts
+but instead inherit one from their parent, typically a shell or window system.
+.PP
+.SS Context interface
+.PP
+The following elements of
+.B Context
+are used by
+.IR wm :
+.TF display
+.PD
+.TP
+.B display
+The
+.B Display
+adt to which the application is connected; may be
+.BR nil .
+See
+.IR draw-display (2).
+.TP
+.B wm
+A shared channel through which a private channel
+can be set up with a window manager.
+A client application sends a tuple containing a request string
+(of a format defined by the window manager) and a private reply channel.
+It receives a tuple in reply on that channel; the tuple contains
+a string (eg, an acknowledgement or diagnostic) and a reference to
+a
+.B Wmcontext
+value containing channels by which the application can interact with the
+window manager.
+.SS Wmcontext interface
+The
+.B Wmcontext
+provides a set of channels and file descriptors
+through which the window manager and application interact.
+The elements of the adt are used as follows:
+.PP
+.TF connfd
+.PD
+.TP
+.B kbd
+A channel of type
+.B int
+that delivers keystrokes from a keyboard.
+.TP
+.B ptr
+A channel of type
+.B ref
+.B Pointer
+that delivers events from a pointing device such as a mouse.
+See
+.IR devpointer (2).
+.TP
+.B ctl
+A channel of type
+.B string
+that delivers control messages from the
+window manager to the application.
+.TP
+.B wctl
+A channel of type
+.BR string ,
+which if initialised is
+used by the application to send control messages to the window manager.
+It is not used by the current
+.IR wm (1)
+or
+.IR tkclient (2).
+.TP
+.B images
+A channel of type
+.B ref
+.B Image
+that allows the window manager and application to exchange images
+(eg, when resizing, or to supply a cursor image).
+.TP
+.B connfd
+A file descriptor that can be used to provide per-client connection control.
+For instance, a client can store a file descriptor open on a
+.IR sys-file2chan (2)
+provided by the window manager, and the window manager will shut down
+input to the application when the connection closes (eg, if the application
+exits unexpectedly).
+.B Connfd
+is also used to write requests to the window manager.
+Conventionally a request is a list of words formatted as
+by
+.B quoted
+in
+.IR string (2).
+A request starting with an exclamation mark
+.BR "" ( ! )
+if successful will result in an image being sent down the
+.B image
+channel; the rectangle of the image indicates the rectangle
+that has been allocated on the screen. If only the origin
+is to be changed by the window manager, a nil image is
+sent first (giving the application a chance to suspend operations
+on the window), and then the original image, with its origin set
+appropriately.
+.TP
+.B image
+This is used as described above.
+.TP
+.B ctxt
+Initialised with the
+.B ctxt
+value that provided the initial connection on the
+.B wm
+channel.
+.RE
+.SH SEE ALSO
+.IR wm (1),
+.IR wmlib (2),
+.IR mux (1),
+.IR draw-intro (2),
+.IR ir (2),
+.IR prefab-intro (2),
+.IR tk (2)
diff --git a/man/2/draw-display b/man/2/draw-display
new file mode 100644
index 00000000..90dbcb8d
--- /dev/null
+++ b/man/2/draw-display
@@ -0,0 +1,389 @@
+.TH DRAW-DISPLAY 2
+.SH NAME
+Display \-
+connection to draw device
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Display: adt
+{
+ image: ref Image;
+ white: ref Image;
+ black: ref Image;
+ opaque: ref Image;
+ transparent: ref Image;
+
+ allocate: fn(dev: string): ref Display;
+ startrefresh:fn(d: self ref Display);
+ publicscreen:fn(d: self ref Display, id: int):
+ ref Screen;
+ newimage: fn(d: self ref Display,
+ r: Rect, chans: Chans,
+ repl, rgba: int):
+ ref Image;
+ color: fn(d: self ref Display, rgba: int):
+ ref Image;
+ colormix: fn(d: self ref Display, one: int, three: int):
+ ref Image;
+ rgb: fn(d: self ref Display, red, green, blue: int):
+ ref Image;
+ namedimage: fn(d: self ref Display, name: string):
+ ref Image;
+ open: fn(d: self ref Display, name: string):
+ ref Image;
+ readimage: fn(d: self ref Display, fd: ref Sys->FD):
+ ref Image;
+ writeimage: fn(d: self ref Display, fd: ref Sys->FD,
+ i: ref Image): int;
+ rgb2cmap: fn(d: self ref Display, red, green, blue: int):
+ int;
+ cmap2rgb: fn(d: self ref Display, c: int):
+ (int, int, int);
+ cmap2rgba: fn(d: self ref Display, c: int):
+ int;
+};
+
+Chans: adt
+{
+ mk: fn(s: string): Chans;
+ text: fn(c: self Chans): string;
+ eq: fn(c: self Chans, d: Chans): int;
+ depth: fn(c: self Chans): int;
+};
+.EE
+.SH DESCRIPTION
+The
+.B Display
+type represents a connection to a
+.IR draw (3)
+device.
+This device is the external representation of a physical
+display, such as a CRT, and its associated memory.
+It contains the storage for all images,
+even invisible ones, so all
+.B Image
+objects must be allocated
+through
+.B Display
+member functions.
+Graphics operations that use multiple
+.B Image
+objects may not mix images from different
+.BR Displays .
+.PP
+The pixel channel structure of an
+.B Image
+is determined when the image is allocated (including the image allocated by the system
+to represent a physical display).
+This structure is described externally by a channel format string,
+described in
+.IR colour (6),
+and internally by a value of the
+.B Chans
+adt,
+which is used when allocating new images in the calls below.
+.B Draw
+defines a set of constants of type
+.B Chans
+for common channel types:
+.BR GREY1 ,
+.BR GREY2
+and
+.BR GREY8
+for greyscale (depths 1, 2 and 8);
+.BR CMAP8
+for 8-bit
+.IR rgbv (8)
+colour-mapped images;
+.BR RGB16
+for 16-bit
+.B r5g6b5
+colour images;
+.BR RGB24
+for 24-bit colour;
+and
+.BR RGBA32
+for 24-bit colour with alpha channel.
+.B Chans
+has the following operations:
+.TP 10
+.BI Chans.mk( s )
+Return the
+.B Chans
+value corresponding to the channel format string
+.I s
+(see
+.IR image (6)
+for the syntax of
+.IR s ).
+.TP 10
+.IB c .depth()
+Return the depth in bits of
+.IR c .
+The result is 0 if
+.I c
+is invalid; in particular,
+.BI Chans.mk( s ).depth()
+is zero if
+.I s
+is invalid.
+.TP
+.IB c .text()
+Return the format string corresponding to
+.IR c .
+.TP
+.IB c .eq( d )
+Return true if
+.I d
+has the same channel structure as
+.IR c ;
+return false otherwise.
+.PP
+Colours in the calls below are specified as 32-bit integers (`32-bit RGBA format') containing
+red, green, blue and alpha components as 8-bit values, in order
+from most to least significant byte.
+The 8-bit colour component values express illumination, ranging from 0 (no colour)
+to 255 (saturated).
+For the alpha component, 0 is fully transparent, and 255 is fully opaque.
+.PP
+.B Display
+itself has the following components:
+.PP
+.TP 10
+.B image
+The visible contents of the display;
+draw on
+.B image
+to change the display.
+.TP
+.BR white ", " black
+Replicated images of a single pixel,
+either all ones (white) or all zeroes (black).
+.TP
+.BR opaque ", " transparent
+Replicated images of a single pixel,
+either all ones (fully opaque) or all zeroes (fully transparent).
+Used as mattes for
+basic graphical operations.
+.TP
+.BI allocate( dev )
+Attach to a new display, represented by the
+.IR draw (3)
+device mounted in the specified
+.I dev
+directory.
+If
+.I dev
+is the empty string,
+.B /dev
+is used.
+The return value is
+.B nil
+if the allocation fails.
+.TP
+.IB d .startrefresh()
+After allocating a
+.B Display
+object, the application should spawn a process to call
+.BR startrefresh ;
+this thread will receive and process window refresh events
+from the device.
+.TP
+.IB d .publicscreen( id )
+Create a locally addressable pointer to a public
+.BR Screen ;
+see \f2display-screen\fP(2).
+.TP
+.IB d .newimage( r\fP,\fP\ chans\fP,\fP\ repl\fP,\fP\ rgba )
+Allocate an off-screen
+.BR Image .
+The arguments supply values for the
+.BR Image 's
+.BR r ,
+.BR chans ,
+and
+.BR repl ,
+and an initial pixel value
+.I rgba
+in 32-bit RGBA format,
+used to paint the image
+when created.
+It can be
+.B Draw\->Transparent
+to create a fully transparent image to draw on to form an
+arbitrarily-shaped image or matte.
+If it is
+.BR Draw\->Nofill ,
+the image is not initialised.
+The image's
+.B clipr
+is initialized to
+.BR r .
+.TP
+.IB d .color( rgba )
+Creates a single-pixel,
+replicated off-screen image of the specified colour,
+expressed in 32-bit RGBA format.
+The
+.B Draw
+module defines constants for several dozen colours:
+.RS
+.IP
+.EX
+Opaque: con int 16rFFFFFFFF;
+Transparent: con int 16r00000000;
+Black: con int 16r000000FF;
+White: con int 16rFFFFFFFF;
+Red: con int 16rFF0000FF;
+Green: con int 16r00FF00FF;
+Blue: con int 16r0000FFFF;
+Cyan: con int 16r00FFFFFF;
+Magenta: con int 16rFF00FFFF;
+Yellow: con int 16rFFFF00FF;
+Grey: con int 16rEEEEEEFF;
+Paleyellow: con int 16rFFFFAAFF;
+Darkyellow: con int 16rEEEE9EFF;
+Darkgreen: con int 16r448844FF;
+Palegreen: con int 16rAAFFAAFF;
+Medgreen: con int 16r88CC88FF;
+Darkblue: con int 16r000055FF;
+Palebluegreen: con int 16rAAFFFFFF;
+Paleblue: con int 16r0000BBFF;
+Bluegreen: con int 16r008888FF;
+Greygreen: con int 16r55AAAAFF;
+Palegreygreen: con int 16r9EEEEEFF;
+Yellowgreen: con int 16r99994CFF;
+Medblue: con int 16r000099FF;
+Greyblue: con int 16r005DBBFF;
+Palegreyblue: con int 16r4993DDFF;
+Purpleblue: con int 16r8888CCFF;
+Notacolor: con int 16rFFFFFF00;
+Nofill: con Notacolor;
+.EE
+.PP
+The special values
+.BR Draw\->Opaque
+(fully opaque)
+and
+.BR Draw\->Transparent
+(fully transparent)
+are useful as the pixel values for
+.B Display.newimage
+when forming a matte.
+The special value
+.B Draw\->Nofill
+tells
+.B Display.newimage
+not to paint a new image with any colour, leaving it uninitialised.
+.RE
+.TP
+.IB d .colormix( one\fP,\fP\ three )
+Allocate background colours.
+On true color displays, it returns a 1×1 replicated image whose pixel is the result of mixing the two
+colours in a one to three ratio;
+both colours are expressed in 32-bit RGBA format.
+On 8-bit color-mapped displays, it returns a 2×2 replicated image
+with one pixel coloured
+.I one
+and the other three
+with
+.I three
+(after translation through the colour map).
+This simulates a wider range of tones than can
+be represented by a single pixel value on a colour-mapped display.
+.TP
+.IB d .rgb( red\fP,\fP\ green\fP,\fP\ blue )
+Uses the values of red, green, and blue to create
+a single-pixel replicated image of that colour.
+The values are intensities that range from 0 (no colour) to 255 (saturated).
+The alpha component is always 255 (fully opaque).
+.TP
+.IB d .namedimage ( name )
+Returns a reference to the image published as
+.I name
+on display
+.I d
+by
+.B Image.nameimage
+(see
+.IR draw-image (2)).
+This allows unrelated processes to share the image (eg, a window manager and client).
+.TP
+.IB d .open( name )
+Read an image
+description from the named
+file and return an
+.B Image
+holding the picture.
+See
+.IR image (6)
+for more information about image files.
+.TP
+.IB d .readimage( fd )
+Analogous to
+.BR open ,
+but from an open file descriptor rather than a named file.
+.TP
+.IB d .writeimage( fd\fP,\fP\ i )
+Complement of
+.BR readimage :
+write an image file representing
+.B i
+to the open file descriptor.
+.TP
+.IB d .rgb2cmap( red\fP,\fP\ green\fP,\fP\ blue )
+Return the
+.I rgbv
+colour map index (see
+.IR colour (6))
+of the colour that best matches
+the given colour triple. The values of the components range from
+0 (no colour) to 255 (saturated).
+.TP
+.IB d .cmap2rgb( c )
+Return the colour triple (red, blue, green) corresponding to colour
+map index
+.IR c .
+.TP
+.IB d .cmap2rgba( c )
+Return the 32-bit RGBA representation of the colour corresponding to colour
+map index
+.IR c .
+The alpha component is always 255 (fully opaque).
+.ig
+.TP
+.IB d .cursor(\fIi\fP,\ \fIp\fP)
+Set the current cursor.
+If
+.I i
+is the image of the current display,
+then the graphics cursor will be set
+to its default value, otherwise
+.I i
+must be an image with ldepth 0
+and the following rules apply: the size of the
+cursor will be half the horizontal height of
+.I i
+(subject to system-dependent restrictions on cursor
+size). The top half and the bottom half of the image
+are treated as two independent masks. When the
+cursor is drawn, pixels congruent with non-zero bits
+in the top half are cleared
+and then pixels congruent with non-zero bits in the
+bottom half are set.
+.I P
+gives the offset added to the mouse position when drawing
+the cursor image.
+.TP
+.IB d .cursorset(\fIp\fP)
+Set the position of the mouse cursor to
+.IR p .
+.SH BUGS
+The interface to
+.B cursor
+does not allow the use of colour mouse cursors,
+even on systems that allow them. The interface is likely
+to change in this respect.
+..
diff --git a/man/2/draw-example b/man/2/draw-example
new file mode 100644
index 00000000..e006e724
--- /dev/null
+++ b/man/2/draw-example
@@ -0,0 +1,116 @@
+.TH DRAW-EXAMPLE 2
+.SH NAME
+draw: example \-
+simple program illustrating image primitives
+.SH DESCRIPTION
+This manual page presents a self-contained simple program that illustrates most
+of the feature of the basic draw library.
+It must be run at the top-level Inferno shell prompt, not within a window system,
+as it establishes its own connection to the display and writes directly
+on the display, not in a private window.
+.PP
+The program exercises the drawing primitives, taking particular care
+to maintain a consistent coordinate system for the combinations of
+images on the display. Comments in the code introduce each step.
+.PP
+.EX
+implement Test;
+
+include "sys.m";
+
+include "draw.m";
+
+Test: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+ sys := load Sys Sys->PATH;
+ draw := load Draw Draw->PATH;
+ Display, Font, Rect, Point, Image, Screen: import draw;
+
+ #
+ # Set up connection to display and initialize colours.
+ #
+ display := draw->Display.allocate(nil);
+ disp := display.image;
+ red := display.color(Draw->Red);
+ blue := display.color(Draw->Blue);
+ white := display.color(Draw->White);
+ yellow := display.color(Draw->Yellow);
+
+ #
+ # Paint the screen red.
+ #
+ disp.draw(disp.r, red, nil, disp.r.min);
+ sys->sleep(5000);
+
+ #
+ # Texture a region with rectangular tiles.
+ #
+ texture := display.newimage(((0,0),(2,3)),
+ disp.chans, 1, Draw->Black);
+ texture.clipr = ((-10000,-10000),(10000,10000));
+ # put something in the texture
+ texture.draw(((0,0),(1,3)), white, nil, (0,0));
+ texture.draw(((0,0),(2, 1)), white, nil, (0,0));
+ # use texture as both source and mask to let
+ # destination colour show through
+ disp.draw(((100,100),(200,300)), texture,
+ texture, (0,0));
+ sys->sleep(5000);
+
+ #
+ # White-out a quarter of the pixels in a region,
+ # to make the region appear shaded.
+ #
+ stipple := display.newimage(((0,0),(2,2)),
+ disp.chans, 1, Draw->Transparent);
+ stipple.draw(((0,0),(1,1)), display.opaque,
+ nil, (0,0));
+ disp.draw(((100,100),(300,250)), white,
+ stipple, (0,0));
+ sys->sleep(5000);
+
+ #
+ # Draw textured characters.
+ #
+ font := Font.open(display, "*default*");
+ disp.text((100,310), texture, (0,0), font,
+ "Hello world");
+ sys->sleep(5000);
+
+ #
+ # Draw picture in elliptical frame.
+ #
+ delight := display.open("/icons/delight.bit");
+ piccenter := delight.r.min.add(delight.r.max).div(2);
+ disp.fillellipse((250,250), 150, 50,
+ delight, piccenter);
+ disp.ellipse((250,250), 150, 50, 3, yellow, (0,0));
+ sys->sleep(5000);
+
+ #
+ # Draw a parabolic brush stroke using an elliptical brush
+ # to reveal more of the picture, consistent with what's
+ # already visible.
+ #
+ dx : con 15;
+ dy : con 3;
+ brush := display.newimage(((0,0),(2*dx+1,2*dy+1)), disp.chans,
+ 0, Draw->Black);
+ brush.fillellipse((dx,dy), dx, dy, display.white,
+ (0,0));
+ for(x:=delight.r.min.x; x<delight.r.max.x; x++){
+ y := (x-piccenter.x)*(x-piccenter.x)/80;
+ y += 2*dy+1; # so whole brush is visible at top
+ xx := x+(250-piccenter.x)-dx;
+ yy := y+(250-piccenter.y)-dy;
+ disp.gendraw(((xx,yy),(xx+2*dx+1,yy+2*dy+1)),
+ delight, (x-dx, y-dy), brush,
+ (0,0));
+ }
+}
+.EE
diff --git a/man/2/draw-font b/man/2/draw-font
new file mode 100644
index 00000000..c68d0ef4
--- /dev/null
+++ b/man/2/draw-font
@@ -0,0 +1,111 @@
+.TH DRAW-FONT 2
+.SH NAME
+Font \-
+character images for Unicode text
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Font: adt
+{
+ name: string;
+ height: int;
+ ascent: int;
+ display: ref Display;
+
+ open: fn(d: ref Display, file: string): ref Font;
+ build: fn(d: ref Display, name, desc: string): ref Font;
+ width: fn(f: self ref Font, str: string): int;
+};
+.EE
+.SH DESCRIPTION
+The
+.B Font
+type defines the appearance of characters drawn with the
+.B Image.text
+primitive (see
+.IR draw-image (2)).
+.B Fonts
+are usually read from files and are selected based on their
+size, their style, the portion of Unicode space they represent,
+and so on.
+.PP
+Fonts are built from a series of subfonts that define contiguous portions
+of the Unicode character space, such as the ASCII or the
+Greek alphabet.
+Font files are textual descriptions of the allocation of characters in
+the various regions of the Unicode space; see
+.IR font (6)
+for the format.
+Subfonts are not visible from Limbo.
+.PP
+A default font, named
+.BR *default* ,
+is always available.
+.PP
+The type incorporates:
+.TP 10
+.BR ascent ", " height
+These define the vertical sizes
+of the font, in pixels.
+The
+.B ascent
+is the distance from the font baseline to the top of
+a line of text;
+.B height
+gives the interline spacing, that is, the distance from
+one baseline to the next.
+.TP
+.B name
+This field
+identifies the font, either
+the name of
+the file from which the font was read, or
+.B
+"*default*"
+for the default font.
+.TP
+.B display
+Tells on which display the font resides.
+.TP
+.BI open( d\fP,\fP\ file\fP)
+The
+.B open
+method creates a
+.B Font
+by reading the contents of the named
+.IR file .
+Fonts are cached, so an open request may return a pointer to an
+existing
+.BR Font ,
+without rereading the file.
+The name
+.B
+"*default*"
+always describes a defined font.
+Fonts are created for an instance of a
+.B Display
+object, even though the creation
+functions are in type
+.BR Font .
+.TP
+.BI build( d\fP,\fP\ name\fP,\fP\ desc )
+.B Build
+creates a
+.B Font
+object by reading the description from the string
+.B desc
+rather than a file.
+.I Name
+specifies the name of the font to be created.
+.TP
+\f2f\fP\f5.width(\fP \f2str\fP \f5)\fP
+The
+.B width
+method returns the width in pixels that
+.I str
+would occupy if drawn by
+.B Image.text
+in the Font
+.IR f .
diff --git a/man/2/draw-image b/man/2/draw-image
new file mode 100644
index 00000000..477e69e0
--- /dev/null
+++ b/man/2/draw-image
@@ -0,0 +1,909 @@
+.TH DRAW-IMAGE 2
+.SH NAME
+Image \-
+pictures and drawing
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+# compositing operators
+SinD: con 1<<3;
+DinS: con 1<<2;
+SoutD: con 1<<1;
+DoutS: con 1<<0;
+
+S: con SinD|SoutD;
+SoverD: con SinD|SoutD|DoutS;
+SatopD: con SinD|DoutS;
+SxorD: con SoutD|DoutS;
+
+D: con DinS|DoutS;
+DoverS: con DinS|DoutS|SoutD;
+DatopS: con DinS|SoutD;
+DxorS: con DoutS|SoutD;
+
+Clear: con 0;
+
+Image: adt
+{
+ r: Rect;
+ clipr: Rect;
+ chans: Chans;
+ depth: int;
+ repl: int;
+
+ display: ref Display;
+ screen: ref Screen;
+
+ draw: fn(dst: self ref Image, r: Rect, src: ref Image,
+ mask: ref Image, p: Point);
+ drawop: fn(dst: self ref Image, r: Rect, src: ref Image,
+ mask: ref Image, p: Point, op: int);
+ gendraw: fn(dst: self ref Image, r: Rect, src: ref Image,
+ p0: Point, mask: ref Image, p1: Point);
+ gendrawop: fn(dst: self ref Image, r: Rect, src: ref Image,
+ p0: Point, mask: ref Image, p1: Point, op: int);
+ line: fn(dst: self ref Image, p0,p1: Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point);
+ lineop: fn(dst: self ref Image, p0,p1: Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point, op: int);
+ poly: fn(dst: self ref Image, p: array of Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point);
+ polyop: fn(dst: self ref Image, p: array of Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point, op: int);
+ bezspline: fn(dst: self ref Image, p: array of Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point);
+ bezsplineop: fn(dst: self ref Image, p: array of Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point, op: int);
+ fillpoly: fn(dst: self ref Image, p: array of Point,
+ wind: int, src: ref Image, sp: Point);
+ fillpolyop: fn(dst: self ref Image, p: array of Point,
+ wind: int, src: ref Image, sp: Point, op: int);
+ fillbezspline: fn(dst: self ref Image, p: array of Point,
+ wind: int, src: ref Image, sp: Point);
+ fillbezsplineop: fn(dst: self ref Image, p: array of Point,
+ wind: int, src: ref Image, sp: Point, op: int);
+ ellipse: fn(dst: self ref Image, c: Point, a, b,
+ thick: int, src: ref Image, sp: Point);
+ ellipseop: fn(dst: self ref Image, c: Point, a, b,
+ thick: int, src: ref Image, sp: Point, op: int);
+ fillellipse:fn(dst: self ref Image, c: Point, a, b: int,
+ src: ref Image, sp: Point);
+ fillellipseop:fn(dst: self ref Image, c: Point, a, b: int,
+ src: ref Image, sp: Point, op: int);
+ arc: fn(dst: self ref Image, c: Point, a, b, thick: int,
+ src: ref Image, sp: Point, alpha, phi: int);
+ arcop: fn(dst: self ref Image, c: Point, a, b, thick: int,
+ src: ref Image, sp: Point,
+ alpha, phi: int, op: int);
+ fillarc: fn(dst: self ref Image, c: Point, a, b: int,
+ src: ref Image, sp: Point, alpha, phi: int);
+ fillarcop: fn(dst: self ref Image, c: Point, a, b: int,
+ src: ref Image, sp: Point,
+ alpha, phi: int, op: int);
+ bezier: fn(dst: self ref Image, a,b,c,d: Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point);
+ bezierop: fn(dst: self ref Image, a,b,c,d: Point,
+ end0,end1,thick: int,
+ src: ref Image, sp: Point, op: int);
+ fillbezier: fn(dst: self ref Image, a,b,c,d: Point, wind:int,
+ src: ref Image, sp: Point);
+ fillbezierop: fn(dst: self ref Image, a,b,c,d: Point, wind:int,
+ src: ref Image, sp: Point, op: int);
+ arrow: fn(a,b,c: int): int;
+ text: fn(dst: self ref Image, p: Point, src: ref Image,
+ sp: Point, font: ref Font, str: string): Point;
+ textop: fn(dst: self ref Image, p: Point, src: ref Image,
+ sp: Point, font: ref Font, str: string,
+ op: int): Point;
+ textbg: fn(dst: self ref Image, p: Point, src: ref Image,
+ sp: Point, font: ref Font, str: string,
+ bg: ref Image, bgp: Point): Point;
+ textbgop: fn(dst: self ref Image, p: Point, src: ref Image,
+ sp: Point, font: ref Font, str: string,
+ bg: ref Image, bgp: Point, op: int): Point;
+ border: fn(dst: self ref Image, r: Rect, i: int,
+ src: ref Image, sp: Point);
+ borderop: fn(dst: self ref Image, r: Rect, i: int,
+ src: ref Image, sp: Point, op: int);
+
+ readpixels: fn(src: self ref Image, r: Rect,
+ data: array of byte): int;
+ writepixels:fn(dst: self ref Image, r: Rect,
+ data: array of byte): int;
+ name: fn(im: self ref Image, s: string, in: int): int;
+ top: fn(win: self ref Image);
+ bottom: fn(win: self ref Image);
+ flush: fn(win: self ref Image, func: int);
+ origin: fn(win: self ref Image, log, scr: Point): int;
+};
+.EE
+.SH DESCRIPTION
+The
+.B Image
+type defines rectangular pictures and the methods to draw upon them;
+it is also the building block for higher level objects such as
+windows and fonts.
+In particular, a window is represented as an
+.BR Image ;
+no special operators are needed to draw on a window.
+Off-screen images can have an alpha channel, which gives each pixel an opacity
+factor, which in turn allows non-rectangular images to be defined
+(ie, pixels made fully transparent by the alpha channel
+do not appear when the image is displayed).
+Many drawing operations allow images to be shaped, or partial transparency added, by using the alpha
+channel of another image as a mask (also called a `matte').
+There are two functions in
+.B Image
+for each such operation.
+One has an
+.B op
+suffix, and takes an explicit image compositing operator:
+.BR S ,
+.BR D ,
+.BR SinD , ...,
+.BR SoverD
+and so on.
+(See the Porter-Duff paper mentioned below for the meaning of each operation.)
+The other function (without the
+.B op
+suffix) provides as its default operation the most common operation,
+.BR SoverD ,
+by which the source image, within its matte, is drawn over the destination image.
+.PP
+An
+.B Image
+has a pixel channel structure as described in
+.IR colour (6),
+represented by a value of the
+.B Chans
+adt,
+defined in
+.IR draw-display (2).
+The channel structure of an image is fixed when the image is allocated.
+.PP
+.B Image
+has the following components:
+.TP 10
+.B display
+Tells on which display the image resides.
+.TP
+.B screen
+If the image is a window on a
+.B Screen
+(see
+.IR draw-screen (2)),
+this field refers to that screen; otherwise it is nil.
+.TP
+.B r
+The coordinates of the rectangle in the plane for which the
+.B Image
+has defined pixel values.
+It should not be modified after the image is created.
+.TP
+.B clipr
+The clipping rectangle: operations that read or write
+the image will not access pixels outside
+.BR clipr .
+Frequently,
+.B clipr
+is the same as
+.BR Image.r ,
+but it may differ; see in particular the discussion of
+.BR Image.repl .
+The clipping region may be modified dynamically.
+.TP
+.B chans
+The pixel channel structure of the image; the value
+should not be modified after the image is created.
+.TP
+.B depth
+The number of bits per pixel in the picture:
+it is simply a convenience since it is necessarily equal to
+.BR chans.depth() ,
+and it should not be modified after the image is created.
+.TP
+.B repl
+A boolean value specifying whether the image is tiled to cover
+the plane when used as a source for a drawing operation.
+If
+.B Image.repl
+is zero, operations are restricted to the intersection of
+.B Image.r
+and
+.BR Image.clipr .
+If
+.B Image.repl
+is set,
+.B Image.r
+defines the tile to be replicated and
+.B Image.clipr
+defines the portion of the plane covered by the tiling, in other words,
+.B Image.r
+is replicated to cover
+.BR Image.clipr ;
+in such cases
+.B Image.r
+and
+.B Image.clipr
+are independent.
+.IP
+For example, a replicated image with
+.B Image.r
+set to ((0,\ 0),\ (1,\ 1)) and
+.B Image.clipr
+set to ((0,\ 0),\ (100,\ 100)),
+with the single pixel of
+.B Image.r
+set to blue,
+behaves identically to an image with
+.B Image.r
+and
+.B Image.clipr
+both set to ((0,\ 0),\ (100,\ 100)) and all pixels set to blue.
+However,
+the first image requires far less memory.
+The replication flag may be modified dynamically along with the clipping
+rectangle.
+.TP
+.IB dst .draw( r\fP,\fP\ src\fP,\fP\ mask\fP,\fP\ p\fP )
+.PD0
+.TP
+.IB dst .drawop( r\fP,\fP\ src\fP,\fP\ mask\fP,\fP\ p\fP,\fP\ op )
+.PD
+.B Draw
+is the standard drawing function.
+Only those pixels within the intersection of
+.IB dst .r
+and
+.IB dst .clipr
+will be affected;
+.B draw
+ignores
+.IB dst .repl\fR.
+The operation proceeds as follows
+(this is a description of the behavior, not the implementation):
+.RS
+.IP 1.
+If
+.B repl
+is set in
+.I src
+or
+.IR mask ,
+replicate their contents to fill
+their clip rectangles.
+.IP 2.
+Translate
+.I src
+and
+.I mask
+so
+.I p
+is aligned with
+.IB r .min\fR.
+.IP 3.
+Set
+.I r
+to the intersection of
+.I r
+and
+.IB dst .r\fR.
+.IP 4.
+Intersect
+.I r
+with
+.IB src .clipr\fR.
+If
+.IB src .repl
+is false, also intersect
+.I r
+with
+.IB src .r\fR.
+.IP 5.
+Intersect
+.I r
+with
+.IB mask .clipr\fR.
+If
+.IB mask .repl
+is false, also intersect
+.I r
+with
+.IB mask .r\fR.
+.IP 6.
+For each location in
+.IR r ,
+combine the
+.I dst
+pixel using the alpha value corresponding to the
+.I mask
+pixel.
+If the
+.I mask
+has an explicit alpha channel, the alpha value corresponding to the
+.I mask
+pixel is simply that pixel's alpha channel.
+Otherwise, the alpha value is the NTSC greyscale equivalent of the colour value,
+with white meaning opaque and black transparent.
+.RE
+.IP
+In terms of the Porter-Duff compositing algebra,
+.I draw
+replaces the
+.I dst
+pixels with
+.RI ( src
+in
+.IR mask )
+over
+.IR dst .
+.I Drawop
+is almost identical, but applies the compositing operation
+.I op
+instead:
+.RI ( src
+in
+.IR mask )
+.I op
+.IR dst .
+.IP
+The various
+pixel channel formats
+involved need not be identical.
+If the channels involved are smaller than 8-bits, they will
+be promoted before the calculation by replicating the extant bits;
+after the calculation, they will be truncated to their proper sizes.
+For
+.B draw
+and
+.B gendraw
+only,
+if
+.I mask
+is nil, no mask is used.
+.TP
+\f2dst\fP.\f5gendraw(\f2r\fP, \f2src\fP, \f2p0\fP, \f2mask\fP, \f2p1\fP)\fP
+.PD0
+.TP
+\f2dst\fP.\f5gendrawop(\f2r\fP, \f2src\fP, \f2p0\fP, \f2mask\fP, \f2p1\fP\f5, \f2op\fP)\fP
+.PD
+Similar to \f5draw()\fP except that it aligns the source and mask differently:
+.I src
+is aligned so
+.I p0
+corresponds to
+.IB r . min
+and
+.I mask
+is aligned so
+.I p1
+corresponds to
+.IB r . min .
+For most purposes with simple masks and source images,
+.B draw
+is sufficient, but
+.B gendraw
+is the general operator and the one the other drawing primitives are built upon.
+.TP
+\f2dst\fP.\f5line(\f2p0\fP, \f2p1\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5lineop(\f2p0\fP, \f2p1\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Line
+draws in
+.I dst
+a line of width
+.RI 1+2* thick
+pixels joining points
+.I p0
+and
+.IR p1 .
+The line is drawn using pixels from the
+.I src
+image aligned so
+.I sp
+in the source corresponds to
+.I p0
+in the destination.
+The line touches both
+.I p0
+and
+.IR p1 ,
+and
+.I end0
+and
+.I end1
+specify how the ends of the line are drawn.
+.B Draw->Endsquare
+terminates the line perpendicularly to the direction of the line; a thick line with
+.B Endsquare
+on both ends will be a rectangle.
+.B Draw->Enddisc
+terminates the line by drawing a disc of diameter
+.RI 1+2* thick
+centered on the end point.
+.B Draw->Endarrow
+terminates the line with an arrowhead whose tip touches the endpoint.
+See the description of
+.B arrow
+for more information.
+.IP
+.B Line
+and the other geometrical operators are equivalent to calls to
+.B gendraw
+using a mask produced by the geometric procedure.
+.TP
+\f2dst\fP.\f5poly(\f2p\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5polyop(\f2p\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Poly
+draws a general polygon; it
+is equivalent to a series of calls to
+.B line
+joining adjacent points in the array of
+.B Points
+.IR p .
+The ends of the polygon are specified as in
+.BR line ;
+interior lines are terminated with
+.B Enddisc
+to make smooth joins.
+The source is aligned so
+.I sp
+corresponds to
+.IB p [0]\f1.
+.TP
+\f2dst\fP.\f5bezspline(\f2p\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5bezsplineop(\f2p\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Bezspline
+takes the same arguments as
+.B poly
+but draws a quadratic B-spline (despite its name) rather than a polygon.
+If the first and last points in
+.I p
+are equal, the spline has periodic end conditions.
+.TP
+\f2dst\fP.\f5fillpoly(\f2p\fP, \f2wind\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5fillpolyop(\f2p\fP, \f2wind\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Fillpoly
+is like
+.B poly
+but fills in the resulting polygon rather than outlining it.
+The source is aligned so
+.I sp
+corresponds to
+.IB p [0]\f1.
+The winding rule parameter
+.I wind
+resolves ambiguities about what to fill if the polygon is self-intersecting.
+If
+.I wind
+is
+.BR ~0 ,
+a pixel is inside the polygon if the polygon's winding number about the point
+is non-zero.
+If
+.I wind
+is 1,
+a pixel is inside if the winding number is odd.
+Complementary values (0 or ~1) cause outside pixels to be filled.
+The meaning of other values is undefined.
+The polygon is closed with a line if necessary.
+.TP
+\f2dst\fP.\f5fillbezspline(\f2p\fP, \f2wind\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5fillbezsplineop(\f2p\fP, \f2wind\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Fillbezspline
+is like
+.B fillpoly
+but fills the quadratic B-spline rather than the polygon outlined by
+.IR p .
+The spline is closed with a line if necessary.
+.TP
+\f2dst\fP.\f5ellipse(\f2c\fP, \f2a\fP, \f2b\fP, \f2thick\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5ellipseop(\f2c\fP, \f2a\fP, \f2b\fP, \f2thick\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Ellipse
+draws in
+.I dst
+an ellipse centered on
+.I c
+with horizontal and vertical semiaxes
+.I a
+and
+.IR b .
+The source is aligned so
+.I sp
+in
+.I src
+corresponds to
+.I c
+in
+.IR dst .
+The ellipse is drawn with thickness
+.RI 1+2* thick .
+.TP
+\f2dst\fP.\f5fillellipse(\f2c\fP, \f2a\fP, \f2b\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5fillellipseop(\f2c\fP, \f2a\fP, \f2b\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Fillellipse
+is like
+.B ellipse
+but fills the ellipse rather than outlining it.
+.TP
+.IB dst .arc(\fIc\fP,\ \fIa\fP,\ \fIb\fP,\ \fIthick\fP,\ \fIsrc\fP,\ \fIsp\fP,\ \fIalpha\fP,\ \fIphi\fP)
+.PD0
+.TP
+.IB dst .arcop(\fIc\fP,\ \fIa\fP,\ \fIb\fP,\ \fIthick\fP,\ \fIsrc\fP,\ \fIsp\fP,\ \fIalpha\fP,\ \fIphi\fP,\ \fIop\fP)
+.PD
+.I Arc
+is like
+.IR ellipse ,
+but draws only that portion of the ellipse starting at angle
+.I alpha
+and extending through an angle of
+.IR phi .
+The angles are measured in degrees counterclockwise from the positive
+.I x
+axis.
+.TP
+.IB dst .fillarc(\fIc\fP,\ \fIa\fP,\ \fIb\fP,\ \fIsrc\fP,\ \fIsp\fP,\ \fIalpha\fP,\ \fIphi\fP)
+.PD0
+.TP
+.IB dst .fillarcop(\fIc\fP,\ \fIa\fP,\ \fIb\fP,\ \fIsrc\fP,\ \fIsp\fP,\ \fIalpha\fP,\ \fIphi\fP,\ \fIop\fP)
+.PD
+.I Fillarc
+is like
+.IR arc ,
+but fills the sector with the source color.
+.TP
+\f2dst\fP.\f5bezier(\f2a\fP, \f2b\fP, \f2c\fP, \f2d\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5bezierop(\f2a\fP, \f2b\fP, \f2c\fP, \f2d\fP, \f2end0\fP, \f2end1\fP, \f2thick\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Bezier
+draws the
+cubic Bezier curve defined by
+.B Points
+.IR a ,
+.IR b ,
+.IR c ,
+and
+.IR d .
+The end styles are determined by
+.I end0
+and
+.IR end1 ;
+the thickness of the curve is
+.RI 1+2* thick .
+The source is aligned so
+.I sp
+in
+.I src
+corresponds to
+.I a
+in
+.IR dst .
+.TP
+\f2dst\fP.\f5fillbezier(\f2a\fP, \f2b\fP, \f2c\fP, \f2d\fP, \f2wind\fP, \f2src\fP, \f2sp\fP)
+.PD0
+.TP
+\f2dst\fP.\f5fillbezierop(\f2a\fP, \f2b\fP, \f2c\fP, \f2d\fP, \f2wind\fP, \f2src\fP, \f2sp\fP, \f2op\fP)
+.PD
+.B Fillbezier
+is to
+.B bezier
+as
+.B fillpoly
+is to
+.BR poly .
+.TP
+.BI arrow( "a,\ b,\ c" )
+.B Arrow
+is a function to describe general arrowheads; its result is passed as
+.I end
+parameters to
+.BR line ,
+.BR poly ,
+etc.
+If all three parameters are zero, it produces the default arrowhead,
+otherwise,
+.I a
+sets the distance along line from end of the regular line to tip,
+.I b
+sets the distance along line from the barb to the tip,
+and
+.I c
+sets the distance perpendicular to the line from edge of line to the tip of the barb,
+all in pixels.
+.TP
+.IB dst .border( r\fP,\fP\ i\fP,\fP\ src\fP,\fP\ sp\fP)
+.PD0
+.TP
+.IB dst .borderop( r\fP,\fP\ i\fP,\fP\ src\fP,\fP\ sp\fP,\ \f2op\fP)
+.PD
+.I Border
+draws in
+.I dst
+an outline of rectangle
+.I r
+in the given
+.I src
+colour.
+The outline has width
+.IR i ;
+if positive, the border goes inside the rectangle; negative, outside.
+The source is aligned so
+.I sp
+corresponds to
+.IB r .min .
+.TP
+.IB dst .text( p\fP,\fP\ src\fP,\fP\ sp\fP,\fP\ font\fP,\fP\ str\fP)
+.PD0
+.TP
+.IB dst .textop( p\fP,\fP\ src\fP,\fP\ sp\fP,\fP\ font\fP,\fP\ str\fP,\ \f2op\fP)
+.TP
+.IB dst .textbg( p\fP,\fP\ src\fP,\fP\ sp\fP,\fP\ font\fP,\fP\ str\fP,\ \f2bg\fP,\ \f2bgp\fP)
+.PD0
+.TP
+.IB dst .textbgop( p\fP,\fP\ src\fP,\fP\ sp\fP,\fP\ font\fP,\fP\ str\fP,\ \f2bg\fP,\ \f2bgp\fP,\ \f2op\fP)
+.PD
+.B Text
+draws in
+.I dst
+characters specified by the string
+.I str
+and font
+.IR font ;
+it is equivalent to a series of calls to
+.B gendraw
+using source
+.I src
+and masks determined by the character shapes.
+The text is positioned with the left of the first character at
+.IB p .x
+and the top of the line of text at
+.IB p .y\f1.
+The source is positioned so
+.I sp
+in
+.I src
+corresponds to
+.I p
+in
+.IR dst .
+.B Text
+returns a
+.B Point
+that is the position of the next character that would be drawn if the string were longer.
+.IP
+For characters with undefined
+or zero-width images in the font, the character at font position 0 (NUL) is drawn.
+.IP
+.B Text
+draws the text leaving the background intact.
+.B Textbg
+draws the background colour
+.I bg
+behind the characters, with the alignment specified by point
+.IR bgp ;
+it is otherwise the same as
+.BR text .
+.TP
+.IB src .readpixels( r\fP,\fP\ data )
+.B Readpixels
+fills the
+.I data
+array with pixels from the specified rectangle of the
+.I src
+image.
+The pixels are presented one horizontal line at a time,
+starting with the top-left pixel of
+.IR r .
+Each scan line starts with a new byte in the array,
+leaving the last byte of the previous line partially empty, if necessary.
+Pixels are packed as tightly as possible within
+.IR data ,
+regardless of the rectangle being extracted.
+Bytes are filled from most to least significant bit order,
+as the
+.I x
+coordinate increases, aligned so
+.IR x =0
+would appear as the leftmost pixel of its byte.
+Thus, for a 1-bit deep greyscale image,
+the pixel at
+.I x
+offset 165 within the rectangle will be in a
+.I data
+byte with mask value
+.B 16r04
+regardless of the overall
+rectangle: 165 mod 8 equals 5, and
+.B "16r80\ >>\ 5" equals
+.BR 16r04 .
+It is an error to call
+.B readpixels
+with an array that is too small to hold the rectangle's pixels.
+The return value is the number of bytes copied.
+The arrangement of pixels in arrays of bytes is described in
+.IR image (6).
+.TP
+.IB dst .writepixels( r\fP,\fP\ data )
+.B Writepixels
+copies pixel values from the
+.I data
+array to the specified rectangle in the
+.I dst
+image.
+The format of the data is that produced by
+.BR readpixels .
+The return value is the number of bytes copied.
+It is an error to call
+.B writepixels
+with an array that is too small to fill the rectangle.
+.TP
+.IB im .name( s , in )
+Publish the image
+.I im
+on its display under name
+.IR s ,
+if
+.I in is non-zero;
+otherwise,
+.I s
+must be an already published name and it is withdrawn from publication.
+A published image can be retrieved using
+.B Display.namedimage
+(see
+.IR draw-display (2)).
+This function returns -1 on error, typically because the name is already in use
+(for
+.I in
+non-zero), or does not exist
+(for
+.I in
+zero).
+.TP
+.IB win .top()
+If the image
+.I win
+is a window,
+.B top
+pulls it to the ``top'' of the stack of windows on its
+.BR Screen ,
+perhaps obscuring other images.
+If
+.I win
+is not a window,
+.B top
+has no effect.
+.TP
+.IB win .bottom()
+If the image
+.I win
+is a window,
+.B bottom
+pulls it to the ``bottom'' of the stack of windows on its
+.BR Screen ,
+perhaps obscuring it.
+If
+.I win
+is not a window,
+.B bottom
+has no effect.
+.TP
+.IB image .flush( flag )
+The connection to a display has a buffer used to gather graphics requests
+generated by calls to the draw library.
+By default, the library flushes the buffer at the conclusion of any
+call that affects the visible display
+image itself.
+The
+.B flush
+routine allows finer control of buffer management.
+The
+.I flag
+has three possible values:
+.B Flushoff
+turns off all automatic flushing caused by writes to
+.IR image ,
+typically a window or the display image itself
+(buffers may still be written when they fill or when other objects on the display
+are modified);
+.B Flushnow
+causes the buffer to be flushed immediately;
+and
+.B Flushon
+restores the default behaviour.
+.TP
+\f2win\fP.\f5origin(\f2log\fP, \f2scr\fP)
+When a window is created (see
+.IR draw-screen (2)),
+the coordinate system within the window is identical to that of the screen:
+the upper left corner of the window rectangle is its physical location on the display,
+not for example (0, 0).
+This symmetry may be broken, however:
+.B origin
+allows control of the location of the window on the display and the coordinate
+system used by programs drawing on the window.
+The first argument,
+.IR log ,
+sets the upper left corner of the logical (in-window) coordinate system without
+changing the position of the window on the screen.
+The second argument,
+.IR scr ,
+sets the upper left corner of physical (on-screen) coordinate system, that is, the
+window's location on the display, without changing the internal coordinate system.
+Therefore, changing
+.I scr
+without changing
+.I log
+moves the window without requiring the client using it to be notified of the change;
+changing
+.I log
+without changing
+.I scr
+allows the client to set up a private coordinate system regardless of the window's
+location.
+It is permissible for values of
+.I scr
+to move some or all of the window off screen.
+.B Origin
+returns \-1 if the image is not a window or, in the case of changes to
+.IR scr ,
+if there are insufficient resources available to move the window;
+otherwise it returns 1.
+.SH SOURCE
+.B /libdraw
+.SH SEE ALSO
+.IR draw-intro (2),
+.IR draw-display (2),
+.IR draw-point (2),
+.IR draw-rect (2),
+.IR draw-screen (2),
+.IR colour (6),
+.IR image (6),
+.IR font (6)
+.IR utf (6)
+.PP
+T. Porter, T. Duff.
+``Compositing Digital Images'',
+.I "Computer Graphics
+(Proc. SIGGRAPH), 18:3, pp. 253-259, 1984.
+.SH DIAGNOSTICS
+These functions raise exceptions if argument images are nil,
+except for
+.B draw
+and
+.B gendraw
+where the mask image is optional and may be nil.
+.SH BUGS
+Anti-aliased characters can be drawn by defining a font
+with multiple bits per pixel, but there are
+no anti-aliasing geometric primitives.
diff --git a/man/2/draw-point b/man/2/draw-point
new file mode 100644
index 00000000..a64a3665
--- /dev/null
+++ b/man/2/draw-point
@@ -0,0 +1,66 @@
+.TH DRAW-POINT 2
+.SH NAME
+Point \-
+coordinate position
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Point: adt
+{
+ x: int;
+ y: int;
+
+ add: fn(p: self Point, q: Point): Point;
+ sub: fn(p: self Point, q: Point): Point;
+ mul: fn(p: self Point, i: int): Point;
+ div: fn(p: self Point, i: int): Point;
+ eq: fn(p: self Point, q: Point): int;
+ in: fn(p: self Point, r: Rect): int;
+};
+.EE
+.SH DESCRIPTION
+.PP
+The
+.B Point
+data type specifies a position in the integer grid.
+.TP 10
+.BR x ", " y
+The coordinate position. The coordinates increase to the right
+.RI ( x )
+and down
+.RI ( y ).
+.TP
+.IB p .add( q )
+Returns the point
+.BI ( p .x+ q .x,
+.IB p .y+ q .y)\fR.
+.TP
+.IB p .sub( q )
+Returns the point
+.BI ( p .x\- q .x,
+.IB p .y\- q .y)\fR.
+.TP
+.IB p .mul( i )
+Returns the point
+.BI ( p .x* i ,
+.IB p .y* i )\fR.
+.TP
+.IB p .div( i )
+Returns the point
+.BI ( p .x/ i ,
+.IB p .y/ i )\fR.
+.TP
+.IB p .eq( q )
+Returns non-zero if the points' coordinates are equal and zero otherwise.
+.TP
+.IB p .in( r )
+Returns non-zero if point
+.I p
+lies within rectangle
+.I r
+and zero otherwise.
+.SH SEE ALSO
+.IR draw-intro (2),
+.IR draw-rect (2)
diff --git a/man/2/draw-pointer b/man/2/draw-pointer
new file mode 100644
index 00000000..3383362e
--- /dev/null
+++ b/man/2/draw-pointer
@@ -0,0 +1,38 @@
+.TH DRAW-POINTER 2
+.SH NAME
+Pointer \-
+state of a pointer device such as a mouse
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Pointer: adt
+{
+ buttons: int;
+ xy: Point;
+};
+.EE
+.SH DESCRIPTION
+.TP 10
+.B buttons
+Each button on the device corresponds to a bit in
+.BR buttons ;
+zero bits indicate released (or non-existent), and one bits indicate pressed.
+The bits, from least to most significant positions,
+represent the buttons from left to right.
+.TP
+.B xy
+The pointer's screen coordinates.
+.PP
+.IR Mux (1)
+uses the
+.B cptr
+member of the
+.B Draw->Context
+adt to pass pointer events through to applications.
+.SH SEE ALSO
+.IR devpointer (2),
+.B mouse
+in
+.IR tk (2)
diff --git a/man/2/draw-rect b/man/2/draw-rect
new file mode 100644
index 00000000..ca069378
--- /dev/null
+++ b/man/2/draw-rect
@@ -0,0 +1,138 @@
+.TH DRAW-RECT 2
+.SH NAME
+Rect \-
+rectangular portion of the plane
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Rect: adt
+{
+ min: Point;
+ max: Point;
+
+ canon: fn(r: self Rect): Rect;
+ dx: fn(r: self Rect): int;
+ dy: fn(r: self Rect): int;
+ eq: fn(r: self Rect, s: Rect): int;
+ Xrect: fn(r: self Rect, s: Rect): int;
+ inrect: fn(r: self Rect, s: Rect): int;
+ clip: fn(r: self Rect, s: Rect): (Rect, int);
+ combine: fn(r: self Rect, s: Rect): Rect;
+ contains: fn(r: self Rect, p: Point): int;
+ addpt: fn(r: self Rect, p: Point): Rect;
+ subpt: fn(r: self Rect, p: Point): Rect;
+ inset: fn(r: self Rect; n: int): Rect;
+};
+.EE
+.SH DESCRIPTION
+The type
+.B Rect
+defines a rectangular portion of the integer grid.
+.TP 10
+.BR min ", " max
+These
+members define the upper left
+.RB ( min )
+and lower right
+.RB ( max )
+points for the rectangle.
+The rectangle contains the pixels
+.BI "min.x\ \fR\(<=\ " "x\ \fR<\ " max.x
+and
+.BI "min.y\ \fR\(<=\ " "y\ \fR<\ " max.y\fR.
+In general,
+.B Rect
+coordinates should be in canonical form:
+.BR min.x "\ \(<=\ " max.x
+and
+.BR min.y "\ \(<=\ " max.y .
+Some functions give undefined results if the
+input rectangles are not canonical.
+.TP
+.IB r .canon()
+Returns a canonical rectangle by sorting the coordinates of
+.IR r .
+.TP
+.IB r .dx()
+Returns the horizontal dimension of
+.IR r .
+.TP
+.IB r .dy()
+Returns the vertical dimension of
+.IR r .
+.TP
+.IB r .eq( s )
+Returns non-zero if the rectangles
+.I r
+and
+.I s
+have the same coordinates and zero otherwise.
+.TP
+.IB r .Xrect( s )
+Returns non-zero if the rectangles
+.I r
+and
+.I s
+intersect and zero otherwise.
+.I Intersection
+means the rectangles share at least one pixel; zero-sized rectangles do not intersect.
+.TP
+.IB r .inrect( s )
+Returns non-zero if
+.I r
+is completely inside
+.I s
+and zero otherwise.
+Rectangles with equal coordinates are considered to be inside each other.
+Zero-sized rectangles contain no rectangles.
+.TP
+.IB r .clip( s )
+Computes the intersection between
+.I r
+and
+.IR s .
+If the input rectangles intersect,
+.B clip
+returns the resulting rectangle
+and a non-zero integer value.
+If the rectangles do not intersect,
+.B clip
+returns
+.I r
+and a zero value.
+.TP
+.IB r .combine( s )
+Returns the smallest rectangle sufficient
+to cover all the pixels of
+.I r
+and
+.IR s .
+.TP
+.IB r .contains( p )
+Returns non-zero if the rectangle
+.I r
+contains the pixel with the coordinates of
+.I p
+and zero otherwise.
+Zero-sized rectangles contain no points.
+.TP
+.IB r .addpt( p )
+Returns the rectangle
+.BI ( r .min.add( p ),
+.IB r .max.add( p ))\fR.
+.TP
+.IB r .subpt( p )
+Returns the rectangle
+.BI ( r .min.sub( p ),
+.IB r .max.sub( p ))\fR.
+.TP
+.IB r .inset( n )
+Returns the rectangle
+.BI ( r .min.add(( n ,
+.IB n )),
+.IB r .max.sub(( n ,
+.IB n ))\fR.
+The result will not be in canonical form if the inset amount is
+too large for the rectangle.
diff --git a/man/2/draw-screen b/man/2/draw-screen
new file mode 100644
index 00000000..5a0d283b
--- /dev/null
+++ b/man/2/draw-screen
@@ -0,0 +1,137 @@
+.TH DRAW-SCREEN 2
+.SH NAME
+Screen \-
+windows and subwindows on a display
+.SH SYNOPSIS
+.EX
+include "draw.m";
+draw := load Draw Draw->PATH;
+
+Screen: adt
+{
+ id: int;
+ image: ref Image;
+ fill: ref Image;
+ display: ref Display;
+
+ allocate: fn(image, fill: ref Image, public: int): ref Screen;
+ newwindow: fn(screen: self ref Screen, r: Rect,
+ backing:int, rgba: int): ref Image;
+ top: fn(screen: self ref Screen, wins: array of ref Image);
+};
+.EE
+.SH DESCRIPTION
+A
+.B Screen
+is the data structure representing a set of windows visible on a particular
+.B Image
+such as the display or a parent window.
+.TP 10
+.B id
+When a
+.B Screen
+object is allocated (see
+.B allocate
+below), the system assigns it a unique integer,
+.BR id .
+It may be declared ``public'' and accessible to
+arbitrary processes and machines with access to the screen's
+.BR Display .
+The
+.B id
+value may be used as an argument to
+.BR Display.publicscreen ;
+see
+.IR draw-display (2).
+.TP
+.B fill
+When windows are deleted from a screen, the system uses the
+.B fill
+image to repaint the screen's base image.
+.TP
+.B image
+The image upon which the windows appear.
+.TP
+.B display
+The display upon which the screen resides.
+.TP
+.BI allocate( image\fP,\fP\ fill\fP,\fP\ public )
+.B Allocate
+makes a new
+.B Screen
+object.
+The
+.I image
+argument provides the base image on which the windows will be made.
+The
+.I fill
+argument provides the
+.B Screen.fill
+image.
+.B Allocate
+does not affect the contents of
+.IR image ;
+it may be necessary after allocation to paint the base image with
+.BR fill .
+.IP
+Using a non-zero
+.I public
+argument allocates a public screen; zero requests a private screen.
+Public screens may be attached by any process
+on any machine with access to the
+.B Display
+upon which the screen is allocated, enabling remote processes to
+create windows on the screen.
+Knowing only the
+.B id
+field of the original
+.BR Screen ,
+the remote process can call the
+.B Display.publicscreen
+function to acquire a handle to the screen.
+The
+.B image
+and
+.B fill
+fields of a
+.B Screen
+obtained this way are
+.BR nil ,
+but they are not needed for ordinary window management.
+.TP
+.IB screen .newwindow( r\fP,\fP\ backing\fP,\fP\ rgba )
+Allocates a window
+on the display at the specified rectangle with the background
+colour
+.IR rgba ,
+expressed in 32-bit RGBA format; the return value is an
+.B Image
+that may be used like any other.
+The
+.I backing
+parameter can be
+.BR Draw->Refbackup ,
+which provides backing store to store obscured parts of the window when necessary,
+and is used by the window manager and its clients; or
+.BR Draw->Refnone ,
+wihch provides no refresh, and is used for windows that are transient, or are already protected by backing
+store.
+.TP
+.IB screen .top( wins )
+.B Top
+organizes a group of windows on a screen.
+Given
+.IR wins ,
+an array of window images, it places the
+.I wins[0]
+element at the top,
+.I wins[1]
+behind that, and so on,
+with the last element of
+.I wins
+in front of the all the windows on the screen not in
+.IR wins .
+Images in the array must be on the specified
+.I screen
+.RB ( nil
+elements are ignored).
diff --git a/man/2/drawmux b/man/2/drawmux
new file mode 100644
index 00000000..0da1b9e3
--- /dev/null
+++ b/man/2/drawmux
@@ -0,0 +1,68 @@
+.TH DRAWMUX 2
+.SH NAME
+drawmux \- multiplex stream of draw requests
+.SH SYNOPSIS
+.EX
+include "drawmux.m";
+drawmux := load Drawmux Drawmux->PATH;
+
+init: fn(): (string, ref Draw->Display);
+newviewer: fn(fd: ref Sys->FD);
+.EE
+.SH DESCRIPTION
+.B Drawmux
+puts itself between the invoking application and
+.B /dev/draw
+(see
+.IR draw (3)),
+so that the contents of the current display can be replicated elsewhere.
+.PP
+.B Init
+returns a new
+.B Display
+(see
+.IR draw-display (2))
+representing a connection to a virtual display device.
+Subsequent
+.B Draw
+requests to that display
+(see
+.IR draw-intro (2))
+are forwarded to the underlying
+.IR draw (3)
+device to appear on the physical display, but can also replicated
+elsewhere, typically in a window on a remote display.
+.PP
+.B Newviewer
+prepares the virtual display end of a
+.B Drawmux
+connection for each new viewer of the display created by a previous call to
+.BR init .
+The file descriptor
+.I fd
+is a connection to the viewer.
+The remote viewer must first write 24 bytes on that connection,
+containing two decimal numbers (each 11 digits and a space),
+giving the identifier of a public screen on the viewer's display, on which
+.B newviewer
+will replicate the
+.B Drawmux
+display,
+and the log (base 2) of the number of bits per pixel for windows created on that screen.
+The remote viewer must then use
+.B Sys->export
+(see
+.IR sys-dial (2))
+to export its
+.BR /dev/draw ,
+which
+.B newviewer
+expects to find as the root of the exported hierarchy.
+Subsequent draw operations on the
+.B Drawmux
+display will be replicated on the public screen exported by the viewer.
+Shutting down the connection shuts down the multiplexor for that viewer.
+.SH SEE ALSO
+.IR wm-dmview (1),
+.IR draw-intro (2),
+.IR draw (3)
diff --git a/man/2/encoding b/man/2/encoding
new file mode 100644
index 00000000..6dc5189f
--- /dev/null
+++ b/man/2/encoding
@@ -0,0 +1,50 @@
+.TH ENCODING 2
+.SH NAME
+Encoding: enc, dec \- encoding and decoding of byte arrays as text
+.SH SYNOPSIS
+.EX
+include "encoding.m";
+base16 := load Encoding Encoding->BASE16PATH;
+base32 := load Encoding Encoding->BASE32PATH;
+base32a := load Encoding Encoding->BASE32APATH;
+base64 := load Encoding Encoding->BASE64PATH;
+
+enc: fn(a: array of byte): string;
+dec: fn(s: string): array of byte
+.EE
+.SH DESCRIPTION
+.B Encoding
+presents a common interface to several ways of encoding binary data (represented in arrays of bytes)
+as printable text, to be included in essentially textual data (such as XML) or
+sent through e-mail systems (as in MIME).
+.PP
+.B Enc
+returns a string with a textual encoding of the binary data in
+.IR a .
+.PP
+.B Dec
+returns an array of bytes containing the binary data encoded in
+.IR s .
+.PP
+Four encodings are provided, including all those defined by RFC3548;
+load the one required from the given path.
+.TP
+.B BASE16PATH
+Encode in base 16, representing each byte as a pair of hexadecimal digits, using upper-case letters (RFC3548).
+.TP
+.B BASE32PATH
+Encode in base 32, encoding 5 bits per character, using upper-case letters, digits `2' to `7', padded with `=', as per RFC3548.
+.TP
+.B BASE32APATH
+Alternative encoding in base 32, encoding 5 bits per character, using digits `2' to `7', letters (either case) except `l' and `o', not padded.
+.TP
+.B BASE64PATH
+Encode in base 64, encoding 6 bits per character, using upper- and lower-case letters, digits, `+' and `/',
+padded with `=' (RFC3548).
+.PP
+When decoding, white space and illegal characters are ignored;
+base 16 and base 32 decoders are case-insensitive.
+.SH SOURCE
+.B /appl/lib/encoding
+.SH SEE ALSO
+.IR convcs (2)
diff --git a/man/2/env b/man/2/env
new file mode 100644
index 00000000..185bd332
--- /dev/null
+++ b/man/2/env
@@ -0,0 +1,52 @@
+.TH ENV 2
+.SH NAME
+env \- environment module
+.SH SYNOPSIS
+.EX
+include "env.m";
+env = load Env Env->PATH;
+
+getenv: fn(var: string): string;
+setenv: fn(var: string, val: string): int;
+getall: fn(): list of (string, string);
+clone: fn(): int;
+new: fn(): int;
+.EE
+.SH DESCRIPTION
+.B Env
+provides an interface to manipulate environment variables which may then be shared
+between processes.
+.B Getenv
+returns the value of the environment variable
+.I var
+passed as a parameter,
+or
+.B nil
+if the variable is not set. It does
+this by reading the contents of
+.BI /env/ var.
+.B Setenv
+sets the value of the environment variable
+.I var
+to
+.I val.
+The value may be nil to unset the variable. It does this by writing the string
+.I val
+to
+.BI /env/ var.
+The routine returns a negative number if it fails to set the variable for any reason.
+.B Getall
+returns all the variables in the current environment as a list of (variable, value) pairs.
+.B Clone
+copies the current environment and places the process in a new environment group. Changes now
+made to the environment will not affect the environment of other processes.
+.B New
+places the process in a new empty environment group. Changes made in this new environment will
+not affect other processes.
+.SH SOURCE
+.B /appl/lib/env.b
+.SH SEE ALSO
+.IR env (1),
+.IR sys-pctl (2),
+.IR env (3)
+
diff --git a/man/2/ether b/man/2/ether
new file mode 100644
index 00000000..fdd144af
--- /dev/null
+++ b/man/2/ether
@@ -0,0 +1,77 @@
+.TH ETHER 2
+.SH NAME
+ether \- Ethernet address manipulation
+.SH SYNOPSIS
+.EX
+include "ether.m";
+ether := load Ether Ether->PATH;
+
+Eaddrlen: con 6;
+
+init: fn();
+parse: fn(s: string): array of byte;
+text: fn(a: array of byte): string;
+addressof: fn(dev: string): array of byte;
+eqaddr: fn(a, b: array of byte): int;
+.SH DESCRIPTION
+.B Ether
+provides a small set of functions that manipulate Ethernet MAC addresses,
+for the use of the few applications such as
+.IR bootpd (8)
+that must work with them.
+.PP
+.B Init
+must be called before using any other function in the module.
+.PP
+.B Parse
+takes a textual representation of a MAC address in
+.I s
+and returns its internal representation as an array of bytes of length
+.BR Eaddrlen ,
+the form used in packets read and written via
+.IR ether (3).
+.I S
+is a string of twelve hexadecimal digits, corresponding to the six bytes of a MAC address.
+Each pair of digits can optionally be separated by a colon.
+If
+.I s
+is invalid,
+.B parse
+returns nil.
+.PP
+.B Text
+takes an array of bytes of length
+.B Eaddrlen
+and returns its textual representation (a string of twelve hexadecimal digits).
+It returns
+.LR <invalid>
+if the array is less than
+.BR Eaddrlen ,
+but it ignores any bytes beyond that.
+.PP
+.B Addressof
+returns the MAC address of the given Ether device
+.I dev
+(eg,
+.LR /net/ether0 ),
+which it reads from
+.IB dev /addr .
+It returns nil and sets the error string if that file does not exist or is invalid.
+.PP
+.B Eqaddr
+returns true iff
+.I a
+and
+.I b
+are the same address.
+.SH FILES
+.TF /net/etherN/addr
+.TP
+.IB net /ether N /addr
+hardware address of Ether
+.I N
+.SH SOURCE
+.B /appl/lib/ether.b
+.SH SEE ALSO
+.IR ip (2),
+.IR ether (3)
diff --git a/man/2/exception b/man/2/exception
new file mode 100644
index 00000000..e654bfeb
--- /dev/null
+++ b/man/2/exception
@@ -0,0 +1,36 @@
+.TH EXCEPTION 2
+.SH NAME
+exception \- Exception module
+.SH SYNOPSIS
+.EX
+include "exception.m";
+exc := load Exception Exception->PATH;
+
+getexc: fn(pid: int): (int, string, string);
+setexcnotifyleader: fn(pid: int): int;
+setexcpropagate: fn(pid: int): int;
+.EE
+.SH DESCRIPTION
+.B Except
+provides exception-related utility routines to read or write to system
+device files.
+.PP
+.B Getexc
+returns the last exception to be raised on the process with the given process
+id. A process id of -1 is taken to mean the current process. The returned
+triple gives the pc value, the module and the exception name or 0, nil, nil
+if no exception has occurred.
+.PP
+.B Setexcnotifyleader
+and
+.B setexcpropagate
+set 'exceptions notifyleader' and 'exceptions propagate' respectively on the given
+process. 0 is returned on success,
+-1 on failure (for instance if the process is not a group leader or does not exist).
+See
+.I prog (3)
+for the actual meaning of these settings.
+.SH SOURCE
+.B /appl/lib/exception.b
+.SH SEE ALSO
+.IR prog (3)
diff --git a/man/2/factotum b/man/2/factotum
new file mode 100644
index 00000000..b13062aa
--- /dev/null
+++ b/man/2/factotum
@@ -0,0 +1,174 @@
+.TH FACTOTUM 2
+.SH NAME
+Factotum: mount, proxy, rpc \- client interface to factotum
+.SH SYNOPSIS
+.EX
+include "factotum.m";
+auth := load Factotum Factotum->PATH;
+
+Authinfo: adt{
+ cuid: string; # ID on caller
+ suid: string; # ID on server
+ cap: string; # capability (only valid on server side)
+ secret: array of byte; # key for encryption
+};
+
+AuthRpcMax: con \fR...\fP;
+
+init: fn();
+mount: fn(fd: ref Sys->FD, mnt: string, flags: int, aname: string):
+ (int, ref Authinfo);
+getuserpasswd: fn(keyspec: string): (string, string);
+rpc: fn(facfd: ref Sys->FD, verb: string, a: array of byte):
+ (string, array of byte);
+proxy: fn(afd: ref Sys->FD, facfd: ref Sys->FD, arg: string):
+ ref Authinfo;
+.EE
+.SH DESCRIPTION
+.B Factotum
+interacts with an instance of the authentication agent
+.IR factotum (4)
+to authenticate a client to a server.
+It can also interact with Plan 9's
+.I factotum
+if that is in the name space (as well as or instead of
+.IR factotum (4)).
+.PP
+.B Init
+must be called before any other function.
+.PP
+.B Mount
+is similar to
+.B Sys->mount
+(see
+.IR sys-bind (1)),
+but uses
+.I factotum
+to authenticate,
+if the server requires it.
+.B Factotum->mount
+should be used instead of
+.B Sys->mount
+when mounting file servers that use
+.IR auth (5)
+to authenticate.
+(If the server on
+.I fd
+does not require authentication,
+.B Factotum->mount
+simply calls
+.BR Sys->mount .)
+.B Mount
+returns
+.RI ( v , ai ).
+If the integer
+.I v
+is non-negative, the mount succeeded;
+on error,
+.I v
+is negative, either the authentication or the mount failed,
+.I ai
+is nil, and the system error string contains a diagnostic.
+If the server required authentication and that was successful,
+.I ai
+is a non-nil reference to an
+.B Authinfo
+value containing the agreed user IDs, a capability for
+.IR cap (3)
+that is valid only on the server, and an array of bytes
+containing a shared secret that can be used by client
+and server to create encryption and hashing keys for the conversation.
+.PP
+.B Getuserpasswd
+returns a tuple
+.RI ( user , password )
+containing the values for the
+.B user
+and
+.B !password
+attributes of a factotum entry that has
+.B proto=pass
+and matches the given
+.IR keyspec .
+The tuple values are nil if no entry matches or the caller lacks permission to see them.
+.PP
+.B Proxy
+links an authenticating server on
+.I afd
+with the
+.I factotum
+agent on
+.IR facfd .
+Typically
+.I facfd
+is the result of
+.IP
+.EX
+sys->open("/mnt/factotum/rpc", Sys->ORDWR)
+.EE
+.PP
+.I Afd
+is typically the result of
+.IR sys-open (2),
+.IR sys-dial (2),
+or
+.IR sys-fauth (2).
+.I Params
+gives any parameters for
+.IR factotum ,
+as a string containing space-separated
+.IB attr = value
+pairs.
+.B Proxy
+ferries messages between the server and
+.I factotum
+until the end of the selected authentication protocol.
+If authentication failed,
+.B proxy
+returns nil; otherwise on success it always returns a non-nil reference to an
+.B Authinfo
+value with contents as above, but if the protocol does not
+supply that authentication data, all the values are nil.
+.PP
+.B Rpc
+does one message exchange with the
+.I factotum
+on
+.IR facfd .
+It writes a message containing the given
+.I verb
+and optional binary parameter
+.IR a ,
+and returns
+.RI ( v , a )
+where
+.I v
+is the response string from
+.I factotum
+and
+.I a
+is an optional binary parameter for that response.
+Exceptionally,
+.I v
+is the string
+\f5"rpc failure"\fP
+if communication fails or a message is garbled, or
+\f5"no key"\fP
+if
+.B rpc
+cannot find a suitable key.
+See
+.IR factotum (4)
+for details of the protocol.
+.PP
+.B AuthRpcMax
+is an integer constant giving the maximum size of a message in an
+.B rpc
+exchange.
+.SH SOURCE
+.B /appl/lib/factotum.b
+.SH SEE ALSO
+.IR sys-bind (2),
+.IR sys-fauth (2),
+.IR factotum (4),
+.IR auth (5)
diff --git a/man/2/filepat b/man/2/filepat
new file mode 100644
index 00000000..0f8eff5b
--- /dev/null
+++ b/man/2/filepat
@@ -0,0 +1,80 @@
+.TH FILEPAT 2
+.SH NAME
+filepat: expand, match \- file pattern matching
+.SH SYNOPSIS
+.EX
+include "filepat.m";
+filepat := load Filepat Filepat->PATH;
+
+expand: fn(pat: string): list of string;
+match: fn(pat, name: string): int;
+.EE
+.SH DESCRIPTION
+.B Expand
+builds a list of file names in alphabetical order that match
+the pattern
+.IR pat .
+The pattern is tokenised using
+.B /
+as a delimiter.
+.PP
+.B Match
+returns 1 if
+.I name
+matches the pattern
+.IR pat ,
+and 0 otherwise.
+.PP
+The
+.I pat
+passed to
+.B match
+and
+.B expand
+may include combinations of the special characters
+.BR * ,
+.BR ? ,
+.BR [ ,
+and
+.BR ] .
+.PP
+The asterisk
+.B *
+matches a string of zero or more characters.
+.PP
+The query
+.B ?
+matches any single character.
+.PP
+The notation
+.BI [ s ]\f1,
+where
+.I s
+is a nonempty string, matches any
+single character in
+.IR s .
+The notation
+.BI [^ s ]\f1,
+where
+.IR s
+is a nonempty string, matches any
+single character not in
+.IR s .
+The characters
+.BR * ,
+.BR ? ,
+and
+.BR [
+have no special meaning within s.
+.PP
+If any character
+is preceded by the character
+.BR \e ,
+that character loses any special meaning
+and is interpreted literally.
+.SH SOURCE
+.B /appl/lib/filepat.b
+.SH SEE ALSO
+.IR sys-tokenize (2),
+.IR readdir (2)
+.IR regex (2)
diff --git a/man/2/filter b/man/2/filter
new file mode 100644
index 00000000..0922337b
--- /dev/null
+++ b/man/2/filter
@@ -0,0 +1,112 @@
+.TH FILTER 2
+.SH NAME
+filter \- data processing interface
+.SH SYNOPSIS
+.B
+include "filter.m";
+.br
+.BI "filter := load Filter " filterpath ";"
+
+.EX
+Rq: adt {
+ pick {
+ Start =>
+ pid: int;
+ Fill or Result =>
+ buf: array of byte;
+ reply: chan of int;
+ Finished =>
+ buf: array of byte;
+ Info =>
+ msg: string;
+ Error =>
+ e: string;
+ }
+};
+
+init: fn();
+start: fn(param: string): chan of ref Rq;
+.EE
+.SH DESCRIPTION
+.B Filter
+defines a general module interface for byte-stream processing.
+This manual page documents how to use the interface, and
+by implication how a
+.B Filter
+module should behave.
+There is a different implementation module for each filter type
+and algorithm (eg, for compression or line encoding).
+All implementations are instances of type
+.BR Filter ,
+loaded from the Dis file
+.IR filterpath ,
+given in the manual page for each standard filter
+(or you can write your own to match this specification).
+For details of each existing filter module, see
+.IR filter-deflate (2)
+and following manual pages.
+.PP
+.B Init
+must be called before any other operation of a filter module.
+.PP
+.B Start
+sets the filter going;
+.I param
+can be used to pass any filter-specific information
+to the processor.
+.B Start
+spawns a new thread to do the processing; it returns
+a channel that is used to receive requests from the
+filter.
+The first message sent is always
+.BR Rq.Start ;
+.I pid
+is the process id of the new process spawned.
+.PP
+Subsequent messages are:
+.TF Rq.Finished
+.PD
+.TP
+.B Rq.Fill
+A request by the filter to fill
+.I buf
+with data.
+The number of bytes that have actually
+been placed in the buffer should be sent
+on
+.IR reply .
+If \-1 is sent, the filter will terminate.
+If the value is 0, the filter will terminate once it has processed
+all its input.
+.TP
+.B Rq.Result
+.I Buf
+contains data from the filter.
+Receipt of the the data must be acknowledged
+by sending a value on
+.IR reply .
+If the value is \-1, the filter will terminate.
+.TP
+.B Rq.Finished
+The filter has finished processing.
+.I Buf
+contains any data that was not consumed
+by the filter. The filter terminates after
+sending this message.
+.TP
+.B Rq.Info
+This message is used to send a string of
+arbitrary information from the filter
+during the course of its processing.
+.TP
+.B Rq.Error
+The filter has encountered an error when processing.
+.I E
+is a string describing the error. The filter terminates
+after sending this message.
+.SH SOURCE
+.B /module/filter.m
+.SH SEE ALSO
+.IR gzip (1),
+.IR filter-deflate (2),
+.IR filter-slip (2)
diff --git a/man/2/filter-deflate b/man/2/filter-deflate
new file mode 100644
index 00000000..34b320fb
--- /dev/null
+++ b/man/2/filter-deflate
@@ -0,0 +1,89 @@
+.TH FILTER-DEFLATE 2
+.SH NAME
+deflate, inflate \- data compression filters
+.SH SYNOPSIS
+.EX
+include "filter.m";
+
+deflate := load Filter Filter->DEFLATEPATH;
+inflate := load Filter Filter->INFLATEPATH;
+
+init: fn();
+start: fn(param: string): chan of ref Rq;
+.EE
+.SH DESCRIPTION
+These implementation modules conform to the
+.B Filter
+module interface for data-processing filters.
+For details of the interface, see
+.IR filter (2).
+.PP
+.I Deflate
+implements gzip-compatible stream compression.
+The
+.I param
+string argument to
+.B start
+can contain one or more of the following option characters:
+.RS 10
+.TP
+.RB ` d '
+Enable debugging output. Each line of debugging output
+is provided in an
+.B Rq.Info
+message.
+.TP
+.RB ` v '
+Enable verbose mode. Each line of verbose output
+is provided in an
+.B Rq.Info
+message.
+.TP
+.RB ` h '
+Add a gzip header and footer to the data. With this flag,
+the data after filtering will be in exactly the same
+format as a gzip file, with accompanying checksum.
+.TP
+.RB ` 0 '\ to\ ` 9 '
+Specifies the level of compression to be used (9 highest). See
+.IR gzip (1).
+.RE
+.PP
+.I Inflate
+performs the inverse operation to
+.BR deflate .
+If the
+.I param
+argument to
+.B start
+begins with the character
+.RB ` h '
+then the input to the filter is assumed to be in the
+standard gzip file format; the output will be checked
+for integrity. While processing, the
+.B Rq.Info
+message is used to transmit some information; the type
+of information is determined by the first word of
+.IR msg ,
+as follows:
+.RS
+.TP
+.B file
+The rest of
+.I msg
+(after a following space) is the name of the original filename
+before compression.
+.TP
+.B mtime
+The rest of
+.I msg
+(after a following space) is the modification time of the
+original file before compression.
+.RE
+.SH SOURCE
+.B /appl/lib/deflate.b
+.br
+.B /appl/lib/inflate.b
+.SH SEE ALSO
+.IR gzip (1),
+.IR filter (2)
diff --git a/man/2/filter-slip b/man/2/filter-slip
new file mode 100644
index 00000000..6b35f46c
--- /dev/null
+++ b/man/2/filter-slip
@@ -0,0 +1,52 @@
+.TH FILTER-SLIP 2
+.SH NAME
+slip \- SLIP data framing protocol
+.SH SYNOPSIS
+.EX
+include "filter.m";
+
+slip := load Filter Filter->SLIPPATH;
+
+init: fn();
+start: fn(param: string): chan of ref Rq;
+.EE
+.SH DESCRIPTION
+.I Slip
+provides the SLIP data framing protocol described by RFC1055.
+The module is an implementation of the general data-processing module type
+.BR Filter ;
+see
+.IR filter (2)
+for details of that general interface.
+.PP
+.B Init
+must be called before any other operation of the module.
+.PP
+.B Start
+begins SLIP line encoding or decoding via the channel it returns,
+following the protocol of
+.IR filter (2).
+.I Param
+is one of the two following strings:
+.TF encode
+.PD
+.TP
+.B encode
+The filter takes the block of data obtained by each
+.B Rq.Fill
+message, adds framing and escape characters as required,
+and returns the resulting data block in an
+.B Rq.Result
+message.
+.TP
+.B decode
+The filter operates on the data in
+.B Rq.Fill
+messages as a single stream of bytes, providing an
+.B Rq.Result
+message for each framed message found in the stream,
+with escape characters processed to retrieve the original data.
+.SH SOURCE
+.B /appl/lib/slip.b
+.SH SEE ALSO
+.IR filter (2)
diff --git a/man/2/format b/man/2/format
new file mode 100644
index 00000000..8f95ae5c
--- /dev/null
+++ b/man/2/format
@@ -0,0 +1,249 @@
+.TH FORMAT 2
+.SH NAME
+format \- structured data interchange
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "bufio.m";
+include "sexprs.m";
+include "format.m";
+format := load Format Format->PATH;
+
+Fmtspec: adt {
+ name: string;
+ fields: cyclic array of Fmtspec;
+};
+Fmt: adt {
+ kind: int;
+ fields: cyclic array of Fmt;
+};
+Fmtval: adt {
+ text: fn(v: self Fmtval): string;
+ val: ref Sexprs->Sexp;
+ recs: cyclic array of array of Fmtval;
+};
+Fmtfile: adt {
+ spec: array of Fmtspec;
+ descr: array of byte;
+
+ new: fn(spec: array of Fmtspec): Fmtfile;
+ open: fn(f: self Fmtfile, name: string):
+ ref Bufio->Iobuf;
+ read: fn(f: self Fmtfile, iob: ref Bufio->Iobuf):
+ (array of Fmtval, string);
+};
+init: fn();
+spec2se: fn(spec: array of Fmtspec): list of ref Sexprs->Sexp;
+spec2fmt: fn(spec: array of Fmtspec): array of Fmt;
+se2fmt: fn(spec: array of Fmtspec, se: ref Sexprs->Sexp):
+ (array of Fmt, string);
+rec2val: fn(spec: array of Fmtspec, rec: ref Sexprs->Sexp):
+ (array of Fmtval, string);
+.EE
+.SH DESCRIPTION
+.B Format
+provides support for programs that wish to marshal and unmarshal
+structured data. It is designed to enable a client to
+request that the structure data is provided by the server in a particular
+format, and for the server to be able to check that it is capable of providing
+that format.
+.PP
+A
+.I record
+consists of a set of
+.IR fields ,
+each represented by one element in an
+.IR sexprs (2)
+list. The content of a field can be a simple value, or it can hold a list containing
+any number of sub-records, each holding a set of fields, recursively defined as above.
+.PP
+The
+.B Fmtspec
+type defines the format for a field in a record.
+.I Name
+gives the name of the field, and
+.I fields
+gives the structure of the fields in any sub-records it contains
+(for a field with a simple value, this will be nil).
+Thus an array of
+.B Fmtspec
+values can define the structure of all the fields in a record.
+Here is an example structure specification:
+.IP
+.EX
+Name, Address, Phone: con iota;
+Number, Kind: con iota;
+spec := array[] of {
+ Address => Fmtspec("address", nil),
+ Name => Fmtspec("name", nil),
+ Phone => Fmtspec("phone", array[] of {
+ Kind => Fmtspec("kind", nil),
+ Number => Fmtspec("number", nil),
+ }),
+};
+.EE
+.PP
+By placing each field in the structure specification
+at a known index, a link is made from the symbolic constants in the program
+to the textual field names.
+.PP
+A structure specification may also be represented by
+a list of S-expressions, where each member of the list
+names a field in the structure. If a member is itself
+a list, it specifies a field containing sub-records: its first member gives the name of the field, and
+subsequent members specify the fields in its sub-records.
+For example, the above specification could be written as the
+S-expression:
+.IP
+.EX
+(name address (phone number kind))
+.EE
+.PP
+The
+.B Fmt
+type also defines a record structure, but
+.I "with respect"
+to an existing
+.B Fmtspec
+structure specification.
+An
+.B Fmt
+value represents a field, and
+.I kind
+holds the index of that field in the original structure specification.
+.PP
+.I Se2fmt
+converts from an S-expression list,
+.IR se
+(a structure specification),
+to a set of
+.B Fmt
+values.
+The specification must be a subset of
+.IR spec ;
+i.e. each field in
+.I se
+must exist in
+.IR spec .
+.I Se2fmt
+returns a tuple
+.BI ( "f, err" ) .
+If the specification is bad,
+.I f
+will be nil, and
+.I err
+describes the error.
+Otherwise, each member of
+.I f
+gives a field specified by
+.IR se .
+For example, given the above structure definition, after executing:
+.IP
+.EX
+ se := Sexp.parse("(address (phone number))").t0;
+ (f, err) := se2fmt(spec, se);
+.EE
+.PP
+.IB f [0].kind
+will hold the symbolic constant
+.BR Address ,
+and
+.IB f [1].fields[0].kind
+will hold
+.BR Number .
+.PP
+.I Spec2se
+converts from a structure representation to its S-expression
+equivalent.
+.I Spec2fmt
+converts it to an array of
+.B Fmt
+structures mirroring it (equivalent to, but more efficient than,
+.BI se2fmt(spec2se( spec )).t0\fR)
+.SS "Data representation"
+The above specifications do not define a format for the
+representation of the actual data. For convenience however,
+.B Format
+defines its own S-expression-based data format.
+In this form, the fields in a record are represented by items
+in an S-expression list. A field containing sub-records is represented as
+a (possibly empty) list containing the sub-records;
+otherwise the value of a field may be an arbitrary S-expression.
+.PP
+For example, a record corresponding to the
+structure specification
+.IP
+.EX
+(name address (phone kind number))
+.EE
+.PP
+might look like:
+.IP
+.EX
+("Jonny Dawes" "24 Crag Lane"
+ ((home "+44 7924 43535") (office "034 433 645")))
+.EE
+.PP
+.I Rec2val
+cracks such a record,
+.IR rec ,
+into its component values, checking
+that it is structurally compatible with the specification,
+.IR spec ,
+and returning a tuple
+.BI ( "fields, err" ) .
+If it failed,
+.I fields
+will be nil, and
+.I err
+describes the error. Otherwise
+each member of
+.IR fields ,
+say
+.IR v ,
+holds the value of its equivalent field in
+.IR spec .
+For fields without sub-records,
+.IB v .val
+holds the field's value;
+otherwise
+.IB v .recs
+holds an array with one member for each
+sub-record, each holding an array of fields
+defined recursively as above.
+.PP
+Some file servers
+provide files to which a format specification may
+be written, and which provide a sequence of records
+in that format when read.
+The
+.B Fmtfile
+type provides support for such files.
+It provides the following operations:
+.TP
+.BI Fmtfile.new( spec )
+returns a new
+.B Fmtfile
+value
+that can be used to open files and read records
+conforming to the given
+.IR spec .
+.TP
+.IB f .open(\fIname\fP)
+opens such a file, writes the format specification to it,
+and returns an
+.B Iobuf
+(see
+.IR bufio (2))
+ready for reading the file.
+.TP
+.IB f .read
+reads a record from the file; its return is the
+same as that from
+.BR rec2val .
+.SH SOURCE
+/appl/lib/format.b
+.SH SEE ALSO
+.IR sexprs (2),
+.IR bufio (2),
+.IR sexprs (6)
diff --git a/man/2/fsproto b/man/2/fsproto
new file mode 100644
index 00000000..9f0c5487
--- /dev/null
+++ b/man/2/fsproto
@@ -0,0 +1,89 @@
+.TH FSPROTO 2
+.SH NAME
+FSproto:
+FSproto: readprotofile, readprotostring \- read file system prototype file
+.SH SYNOPSIS
+.EX
+include "fsproto.m";
+fsproto := load FSproto FSproto->PATH;
+
+Direntry: type (string, string, ref Sys->Dir);
+
+init: fn(): string;
+
+readprotofile: fn(proto: string, root: string,
+ entries: chan of Direntry,
+ warnings: chan of (string, string)): string;
+
+readprotostring: fn(proto: string, root: string,
+ entries: chan of Direntry,
+ warnings: chan of (string, string));
+.EE
+.SH DESCRIPTION
+.B FSproto
+provides an interface to read a file system prototype file,
+as defined by
+.IR proto (6).
+.PP
+.B Init
+must be called before any other function in the module.
+.PP
+.B Readprotofile
+reads a file system prototype from the file
+.IR proto .
+It traverses the file system, starting at the given
+.IR root ,
+and each file or directory encountered that is mentioned
+in the prototype causes
+.B readprotofile
+to send a
+.B Direntry
+tuple on the channel
+.IR entries .
+The tuple has the form
+.BI ( old , new , dir\fP\f5)\fP
+where
+.I old
+is the name of the current file or directory,
+rooted at
+.IR root ,
+.I new
+is the same file's name
+.I relative
+to
+.IR root ,
+and
+.I dir
+is a reference to the
+.B Sys->Dir
+directory information for
+.IR old ,
+as produced by
+.IR sys-stat (2).
+When all files in
+.I root
+have been examined,
+.B readprotofile
+sends a single tuple with all nil components on
+.IR entries .
+For each error that occurs during processing (eg, unable to open a directory)
+.B readprotofile
+sends a tuple
+.BI ( old , diag )
+on the channel
+.IR warnings ,
+naming the file and giving a diagnostic string,
+but processing continues.
+.PP
+.B Readprotostring
+reads a file system prototype from the string
+.I proto
+itself.
+Otherwise, its operation is the same as
+.BR readprotofile .
+.SH SOURCE
+.B /appl/lib/fsproto.b
+.SH SEE ALSO
+.IR fs (1),
+.IR proto (6),
+.IR mkfs (8)
diff --git a/man/2/geodesy b/man/2/geodesy
new file mode 100644
index 00000000..73c5331a
--- /dev/null
+++ b/man/2/geodesy
@@ -0,0 +1,146 @@
+.TH GEODESY 2
+.SH NAME
+geodesy \- Geodesy module
+.SH SYNOPSIS
+.EX
+include "geodesy.m";
+geodesy := load Geodesy Geodesy->PATH;
+
+# easting, northing
+Eano: adt{
+ e: real;
+ n: real;
+};
+
+# latitude, longitude in radians
+Lalo: adt{
+ la: real;
+ lo: real;
+};
+
+OSGB36, Ireland65, ED50, WGS84, ITRS2000, ETRS89: con iota;
+
+Natgrid, IrishNatgrid, UTMEur, UTM: con iota;
+
+init: fn(d: int, t: int, z: int);
+format: fn(d: int, t: int, z: int);
+os2en: fn(s: string): (int, Eano);
+en2os: fn(en: Eano): string;
+str2lalo: fn(s: string): (int, Lalo);
+lalo2str: fn(lalo: Lalo): string;
+str2en: fn(s: string): (int, Eano);
+en2lalo: fn(en: Eano): Lalo;
+lalo2en: fn(lalo: Lalo): Eano;
+datum2datum: fn(lalo: Lalo, f: int, t: int): Lalo;
+.EE
+.SH DESCRIPTION
+.B Geodesy
+provides routines to deal with (some) terrestrial coordinate systems.
+.PP
+Eastings and northings are defined by the
+.B Eano
+adt and are measured in metres and latitude and longitude (which should be in radians) by the
+.B Lalo
+adt. Latitude is in the range -π/2 to π/2 radians and longitude in the
+range -π to π radians.
+.PP
+.B OSGB36
+(Ordnance Survey Great Britain 1936),
+.B Ireland65
+(Ireland 1965),
+.B ED50
+(European Datum 1950),
+.B WGS84
+(World Geodetic System 1984),
+.B ITRS2000
+(International Terrestrial Reference System 2000), and
+.B ETRS89
+(European Terrestrial Reference System 1989) are the current datums defined. Helmert transformations are used
+to convert between them. Note that
+.B Ireland65
+and
+.B ED50
+are currently not supported and
+.B WGS84
+and
+.B ITRS2000
+are considered equivalent.
+.PP
+.B Natgrid
+(National Grid),
+.B IrishNatgrid
+(Irish National Grid),
+.B UTMEur
+(European Universal Transverse Mercator), and
+.B UTM
+(Universal Transverse Mercator) are the current transverse Mercator projections supported.
+.PP
+The following functions are provided
+.TP
+.B init
+The module should always be initialized first. The parameters are
+the required datum (default WGS84), transverse Mercator projection (default Natgrid) and UTM zone (default 30) if appropriate. Negative values or out of range values are
+ignored.
+.TP
+.B format
+Parameters as above. Alters the current settings at any time though care
+must be taken to ensure existing coordinates are still treated as in their
+original form.
+.TP
+.B os2en
+Converts an Ordnance Survey National Grid reference to an easting, northing.
+The formats XYen, XYeenn, XYeeennn, XYeeeennnn, XYeeeeennnnn, eenn,
+eeennn, eeeennnn, eeeeennnnn and eeeeeennnnnn are allowed. Here X and
+Y are upper case letters, e is an easting digit and n is a northing digit. The
+reference can therefore be rounded to the nearest decakilometre, kilometre,
+hectometre, decametre or metre. The first element of the returned tuple is zero
+if the string has an incorrect format.
+.TP
+.B en2os
+Converts an easting, northing to an OS reference in the form XYeeeeennnnn
+as above.
+.TP
+.B str2lalo
+Converts a latitude/longitude string to a latitude, longitude. The string
+may have the formats deg[N|S], deg:min[N|S] or deg:min:sec[N|S] for
+latitude, deg[E|W], deg:min[E|W] or deg:min:sec[E|W] for longitude. The
+latitude must come first, then optional white space, then the longitude.
+Degrees, minutes and seconds may be integer or real. Format errors
+are indicated as in
+.B os2en.
+.TP
+.B lalo2str
+Converts a latitude, longitude to string format as above. Seconds are given
+to two decimal places.
+.TP
+.B str2en
+Converts a string in OS or latitude/longitude format as above to an easting, northing.
+Format errors indicated as in
+.B os2en.
+.TP
+.B en2lalo
+Converts an easting, northing to latitude, longitude using the current transverse
+Mercator projection.If the latter is
+.B UTM
+or
+.B UTMEur
+the current zone setting will be used.
+.TP
+.B lalo2en
+Converts latitude, longitude to an easting, northing using the current transverse
+Mercator projection.
+.TP
+datum2datum
+Approximate (Helmert) transformation of a latitude, longitude between any of
+.B OSGB36,
+.B WGS84,
+.B ITRS2000
+or
+.B ETRS89.
+The `from' datum appears first in the parameter list.
+.SH SOURCE
+.B /module/math/geodesy.m
+.br
+.B /appl/math/geodesy.b
+.SH BUGS
+The module is heavily biased towards Great Britain.
diff --git a/man/2/hash b/man/2/hash
new file mode 100644
index 00000000..522069a0
--- /dev/null
+++ b/man/2/hash
@@ -0,0 +1,91 @@
+.TH HASH 2
+.SH NAME
+hash, HashTable \- hash table
+.SH SYNOPSIS
+.EX
+include "hash.m";
+hash := load Hash Hash->PATH;
+
+new: fn(size:int):ref HashTable;
+
+HashTable: adt{
+ insert: fn(h:self ref HashTable, key:string, val:HashVal);
+ find: fn(h:self ref HashTable, key:string):ref HashVal;
+ delete: fn(h:self ref HashTable, key:string);
+ all: fn(h:self ref HashTable): list of HashNode;
+};
+HashVal: adt{
+ i: int;
+ r: real;
+ s: string;
+};
+HashNode: adt{
+ key: string;
+ val: ref HashVal;
+};
+fun1, fun2: fn(s:string, n:int):int;
+.EE
+.SH DESCRIPTION
+The hash module provides support for arrays that are indexed by keys of type
+.BR string .
+
+The values may be any combination of
+.BR int ,
+.BR real ,
+or
+.BR string .
+.B New
+creates and returns a new
+.B HashTable
+with
+.I size
+slots. The hashing works best if
+.I size
+is a prime number. The
+.B HashVal
+adt contains the data values of the hash.
+The
+.B HashNode
+adt contains the key/value pair for each element in the table.
+.TP
+.IB ht .insert( "key, value" )
+Adds a new
+.IR key / value
+pair to the table.
+If an element with the same
+.I key
+already exists,
+it will acquire the new
+.IR value .
+.TP
+.IB ht .find( key )
+Search the table for an element with the given
+.I key
+and return the value found; return nil if none was found.
+.TP
+.IB ht .delete( key )
+Removes any element with the given
+.I key
+from the table.
+.TP
+.IB ht .all()
+Returns a list of all key/value pairs stored in the table.
+.PP
+.B Fun1
+and
+.B fun2
+provide access to two different string hashing functions.
+.B Fun1
+is the function used internally;
+.B fun2
+is the same as that used in the Limbo compiler.
+They each compute the hash value of
+.I s
+and return a value between 0 and
+.IR n \-1.
+.SH SOURCE
+.B /appl/lib/hash.b
+.SH BUGS
+.B HashVal
+should really be a
+.BR pick .
diff --git a/man/2/ida b/man/2/ida
new file mode 100644
index 00000000..127926a8
--- /dev/null
+++ b/man/2/ida
@@ -0,0 +1,151 @@
+.TH IDA 2
+.SH NAME
+Ida: Frag, fragment, consistent, reconstruct \- information dispersal algorithm
+.SH SYNOPSIS
+.EX
+include "ida.m";
+ida := load Ida Ida->PATH;
+
+Frag: adt {
+ dlen: int; # length of original data
+ m: int; # minimum pieces for reconstruction
+ a: array of int; # encoding array row for this fragment
+ enc: array of int; # encoded data
+
+ tag: array of byte; # user data, such as SHA1 hash
+ pack: fn(f: self ref Frag): array of byte;
+ unpack: fn(d: array of byte): ref Frag;
+};
+
+init: fn();
+fragment: fn(data: array of byte, m: int): ref Frag;
+consistent: fn(frags: array of ref Frag): array of ref Frag;
+reconstruct: fn(frags: array of ref Frag): (array of byte, string);
+.EE
+.SH DESCRIPTION
+.B Ida
+implements Rabin's Information Dispersal Algorithm (IDA), an effective scheme
+for fault-tolerant storage and message routing.
+The algorithm breaks an array of bytes (for instance a file or a block of data) into
+.I n
+pieces,
+in such a way that the original data can be recovered using only
+.I m
+of them, where
+.I n
+and
+.I m
+are parameters.
+The module provides the fundamental operations.
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+.PP
+.B Fragment
+takes an array of
+.IR data ,
+and
+.IR m ,
+the minimum number of pieces required for reconstruction,
+and returns a reference to a
+.B Frag
+value representing one encoded fragment of the data.
+At least
+.I m
+calls must be made to
+.B fragment
+to obtain enough such fragments to be able to rebuild the data;
+invariably more fragments are generated to provide the desired level of redundancy.
+.PP
+Each fragment
+.B Frag
+has the following components:
+.TP
+.B dlen
+The length in bytes of the
+.IR data .
+.TP
+.B m
+The minimum number of fragments for reconstruction.
+.TP
+.B a
+The row of an \fIm\fP×\fIm\fP encoding matrix that corresponds to this fragment.
+.TP
+.B enc
+The encoded data, represented by an array of integer values.
+For
+.I L
+bytes of input data, the array will have length
+.\\"$ left ceil L over 2m right ceil $.
+.rm 11
+.ds 12 "\f2L\fP
+.ds 13 "\f12\fP\f2\^m\fP
+.nr 12 0\w'\s+0\*(12'
+.nr 13 0\w'\s+0\*(13'
+.nr 14 \n(12
+.if \n(13>\n(14 .nr 14 \n(13
+.nr 14 \n(14+0.5m
+.ds 12 \v'0.7m'\h'\n(14u-\n(13u/2u'\*(13\v'-0.7m'\
+\h'-\n(13u-\n(12u/2u'\v'-0.6m'\*(12\v'0.6m'\
+\h'-\n(14u-\n(12u/2u+0.1m'\v'-0.3m'\l'\n(14u-0.2m'\h'0.1m'\v'0.3m'
+.ds 12 \^\v'0.13m'\b'\(lc\(bv\(bv'\v'-0.13m'\*(12\v'0.13m'\b'\(rc\(bv\(bv'\v'-0.13m'
+.ds 12 \x'0-0.85m'\*(12\x'1.05m'
+.as 11 \*(12
+.lf 4
+.as 11 ".
+\*(11
+.lf 5
+.PP
+All those values must be stored or transmitted for later use, to reconstruct the data.
+The values in
+.B a
+are in the interval
+.RI "[ 1,\ 65536 ]"
+and those in
+.B enc
+are in the interval
+.RI "[ 0,\ 65536 ]."
+.PP
+.B Reconstruct
+takes an array
+.I frags
+of distinct fragments previously produced by repeated calls to
+.BI fragment( data,\ m )
+and returns a tuple
+.BI ( data,\ err ) .
+Provided at least
+.I m
+suitable fragments are found in
+.IR frags ,
+the
+.I data
+returned will be that originally provided to
+.BR fragment .
+If the parameters of the various fragments in
+.I frags
+disagree, or some other error occurs,
+.I data
+will be nil and
+.I err
+will contain a diagnostic.
+.B Reconstruct
+assumes the fragments it receives are consistent:
+they represent the same encoding parameters, including the value of
+.IR m .
+If it detects an inconsistency, it returns a diagnostic.
+.PP
+.B Consistent
+checks the consistency of a set of fragments, and returns a new subset containing
+only those fragments that agree with the majority in
+.I frags
+on each parameter.
+.SH SOURCE
+.B /appl/lib/ida/ida.b
+.br
+.B /appl/lib/ida/idatab.b
+.SH SEE ALSO
+M Rabin, ``Efficient Dispersal of Information for Security, Load Balancing, and Fault Tolerance'',
+.I JACM
+.BR 36(2) ,
+April 1989,
+pp. 335-348.
diff --git a/man/2/imagefile b/man/2/imagefile
new file mode 100644
index 00000000..7ba9e415
--- /dev/null
+++ b/man/2/imagefile
@@ -0,0 +1,157 @@
+.TH IMAGEFILE 2
+.SH NAME
+imagefile: readgif, readjpg, readpicfile, readpng, readxbitmap, remap \- processing external image file formats
+.SH SYNOPSIS
+.EX
+include "imagefile.m";
+
+gifreader := load RImagefile RImagefile->READGIFPATH;
+jpgreader := load RImagefile RImagefile->READJPGPATH;
+xbmreader := load RImagefile RImagefile->READXBMPATH;
+picreader := load RImagefile RImagefile->READPICPATH;
+pngreader := load RImagefile RImagefile->READPNGPATH;
+
+imageremap := load Imageremap Imageremap->PATH;
+
+Rawimage: adt
+{
+ r: Draw->Rect;
+ cmap: array of byte;
+ nchans: int;
+ chans: array of array of byte;
+ chandesc: int;
+
+ init: fn(bufio: Bufio);
+ read: fn(fd: ref Bufio->Iobuf): (ref Rawimage, string);
+ readmulti: fn(fd: ref Bufio->Iobuf):
+ (array of ref Rawimage, string);
+};
+
+init: fn(bufio: Bufio);
+writeimage: fn(fd: ref Bufio->Iobuf, image: ref Draw->Image)
+ : string;
+
+remap: fn(i: ref RImagefile->Rawimage, d: ref Draw->Display,
+ errdiff: int): (ref Draw->Image, string);
+.EE
+.SH DESCRIPTION
+The
+.B Rawimage
+.B adt
+of module
+.B RImagefile
+defines an internal representation
+and routines for reading images such as GIF and JPEG files.
+To read a set of files of a given format, load the appropriate module,
+pass its
+.B init
+function an implementation of the
+.B Bufio
+module, and pass
+.B read
+an
+.B Bufio->Iobuf
+for each file.
+.B Read
+returns a tuple: a
+.B ref
+.B Rawimage
+that holds the image and an error string.
+If the
+.B Rawimage
+is
+.BR nil ,
+the error string will report the reason.
+Files (particularly GIF files) are often incorrectly encoded but yield usable pictures,
+so even if a
+.B Rawimage
+is returned, the error string may still report problems.
+.PP
+Some image file types (eg, GIF) support having several images in a single file.
+They can be read in all at once using
+.BR readmulti ,
+which returns a tuple with the array of images, and an error string as above.
+.PP
+The
+.B Rawimage
+is always defined as one or more bytes per pixel, with
+.B nchans
+channels of data stored in the array
+.BR chans .
+The
+.B chandesc
+field, described below, specifies the contents of
+.BR chans .
+The
+rectangle
+.B r
+describes the shape of the picture.
+.PP
+The
+.B Rawimage
+type can be converted to a regular
+.B Image
+(see
+.IR draw-image (2))
+by calling module
+.BR Imageremap 's
+function
+.B remap.
+.B Remap
+is passed the
+.BR Rawimage ,
+a
+.B Display
+on which to create the image, and a flag that specifies whether to apply Floyd-Steinberg
+error diffusion code to the result, for smoother rendering of colours at the cost of
+some noise in the image.
+.PP
+How to remap is defined by the
+.B RImagefile
+itself: the field
+.B chandesc
+specifies the type of the various
+.B chans
+of data:
+.B RImagefile->CRGB
+specifies a 3-colour RGB image with no colour map;
+.B RImagefile->CY
+a monotone (luminance-only, grey-scale) image with no colour map;
+and
+.B RImagefile->CRGB1
+a single-channel image with RGB colour map in
+.BR cmap .
+The file readers set
+.B chandesc
+as appropriate for the format of the file.
+.PP
+The writing of image files is defined by the module
+.BR WImagefile.
+To initialize the module, call its
+.B init
+function with an instance of the
+.B Bufio
+module and pass its
+.B writeimage
+function a
+.B Bufio->Iobuf
+representing the output stream and an image of type
+.B Draw->Image.
+.PP
+These functions are split into separate modules to give applications control over
+the memory they need to process images.
+.SH SOURCE
+.B /appl/lib/readgif.b
+.br
+.B /appl/lib/readjpg.b
+.br
+.B /appl/lib/readxbitmap.b
+.br
+.B /appl/lib/readpicfile.b
+.br
+.B /appl/lib/readpng.b
+.SH NOTES
+The JPEG reader handles only the Baseline sequential format as defined by
+the JFIF 1.02 file exchange format.
+.PP
+Functions to write these formats are as yet unimplemented.
diff --git a/man/2/ip b/man/2/ip
new file mode 100644
index 00000000..7739c2b5
--- /dev/null
+++ b/man/2/ip
@@ -0,0 +1,334 @@
+.TH IP 2
+.SH NAME
+IP \- Internet Protocol addresses and interfaces
+.SH SYNOPSIS
+.EX
+include "ip.m";
+ip := load IP IP->PATH;
+IPaddr: import IP;
+
+IPaddr: adt {
+ newv6: fn(nil: array of byte): IPaddr;
+ newv4: fn(nil: array of byte): IPaddr;
+ copy: fn(nil: self IPaddr): IPaddr;
+ eq: fn(nil: self IPaddr, v: IPaddr): int;
+ mask: fn(nil: self IPaddr, m: IPaddr): IPaddr;
+ isv4: fn(nil: self IPaddr): int;
+ ismulticast: fn(nil: self IPaddr): int;
+ isvalid: fn(nil: self IPaddr): int;
+
+ v4: fn(nil: self IPaddr): array of byte;
+ v6: fn(nil: self IPaddr): array of byte;
+ class: fn(nil: self IPaddr): int;
+ classmask: fn(nil: self IPaddr): IPaddr;
+
+ parse: fn(s: string): (int, IPaddr);
+ parsemask: fn(s: string): (int, IPaddr);
+ parsecidr: fn(s: string): (int, IPaddr, IPaddr);
+
+ text: fn(nil: self IPaddr): string;
+ masktext: fn(nil: self IPaddr): string;
+};
+
+v4bcast, v4allsys, v4allrouter, noaddr, allbits: IPaddr;
+selfv6, selfv4: IPaddr;
+v4prefix: array of byte;
+
+Ifcaddr: adt {
+ ip: IPaddr; # local interface address
+ mask: IPaddr; # subnet mask
+ net: IPaddr; # ip & mask
+ preflt: big; # preferred life time
+ validlt: big; # valid life time
+};
+
+Ipifc: adt {
+ index: int; # /net/ipifc/N
+ dev: string; # bound device
+ addrs: list of ref Ifcaddr;
+ sendra: int; # !=0, send router adverts
+ recvra: int; # !=0, receive router adverts
+ mtu: int;
+ pktin: big; # packets in
+ pktout: big; # packets out
+ errin: big; # input errors
+ errout: big; # output errors
+ rp: IPv6rp; # IPv6 route advert parameters
+};
+
+IPv6rp: adt {
+ mflag: int;
+ oflag: int;
+ maxraint: int; # max route advert interval
+ minraint: int; # min route advert interval
+ linkmtu: int;
+ reachtime: int;
+ rxmitra: int;
+ ttl: int;
+ routerlt: int;
+};
+
+init: fn();
+readipifc: fn(net: string, index: int): (list of ref Ipifc, string);
+.EE
+.SH DESCRIPTION
+.B IP
+provides data types and operations that manipulate Internet Protocol addresses,
+and operations that convert between internal and textual address forms,
+for both IPv4 and IPv6.
+The textual forms are those defined by RFC2373.
+Briefly, an IPv6 address is 16 bytes, represented textually as a sequence
+of 8 colon-separated hexadecimal values ranging from
+.B 0
+to
+.BR FFFF ,
+except that any one sequence of zeroes can be replaced by
+.BR :: .
+IPv4 addresses are embedded in the IPv6 space with a prefix of either
+.B 0:0:0:0:0:FFFF
+(for addresses of `IPv4-mapped' nodes), or
+.BR 0:0:0:0:0:0
+(for `IPv4-compatible' IPv6 nodes).
+See RFC2373 for the distinction.
+For convenience in working with such addresses, the textual syntax
+allows the last 4 bytes of an IPv6 address to be specified using a
+restricted IPv4 syntax, allowing an address to end in four dot-separated decimal values
+(for example,
+.BR 0:0:0:0:0:FFFF:127.0.0.1
+for the IPv4 loopback address).
+The functions here also accept the common forms of IPv4 syntax with one or two values
+omitted (eg,
+.B 127.1
+for the loopback address),
+and accept IPv4 format for masks
+(eg,
+.BR 255.255.254.0 ).
+.PP
+.B Init
+must be called once before using any value or function of the module.
+.PP
+An Internet address or network mask is represented by an
+.B IPaddr
+value.
+It has the following operations:
+.TP
+.BI IPaddr.newv6( a )
+Return an
+.B IPaddr
+representing the IPv6 address stored in
+.I a
+as an array of 16 bytes
+.TP
+.BI IPaddr.newv4( a )
+Return an
+.B IPaddr
+representing the IPv4 address stored in
+.I a
+as an array of 4 bytes
+.TP
+.BI IPaddr.parse( s )
+Return a tuple
+.BI ( ok , ip ).
+If
+.I ok
+is 0,
+.I ip
+is an
+.B IPaddr
+representing the address in textual format in the string
+.IR s ,
+which can be in either IPv4 or IPv6 syntax.
+If
+.I ok
+is negative,
+.I s
+was invalid.
+.TP
+.BI IPaddr.parsemask( s )
+.I S
+is a text string defining a mask, in one of three forms:
+.BI / nbits
+where
+.I nbits
+is the number of leading one bits in the mask, ranging from 0 to 128;
+an IPv4 mask (eg,
+.BR 255.255.254.0 );
+or an IPv6 mask.
+Return a tuple
+.BI ( ok , m )\fR.
+If
+.I ok
+is 0,
+.I m
+is an
+.B IPaddr
+representing the mask given by
+.IR s .
+If
+.I ok
+is negative,
+.I s
+was invalid.
+.TP
+.BI IPaddr.parsecidr( s )
+.I S
+is an address-mask combination in Classless Inter-Domain Routing (CIDR) format:
+.IB ip-address / prefix-length,
+where
+.I ip-address
+is an address in any form accepted by
+.B parse
+above, and
+.I prefix-length
+is a decimal value giving the number of leftmost bits in
+.I ip-address
+that form the addressing prefix (ie, subnet prefix).
+Return a tuple
+.BI ( ok , ip , m\fR).
+If
+.I ok
+is 0,
+.I ip
+and
+.I m
+are
+.B IPaddr
+values for the address and mask given by
+.IR s .
+If
+.I ok
+is negative,
+.I s
+is invalid.
+.TP
+.IB ip .copy()
+Return a copy of the value
+.I ip
+.TP
+.IB ip .eq( v )
+Return true (non-zero) if
+.I ip
+represents the same address as
+.IR v ;
+return false (zero) otherwise.
+.TP
+.IB ip .mask( m )
+Return the value
+.BI ( ip & m ) ,
+that is, address
+.I ip
+masked by
+.I m
+.TP
+.IB ip .isv4()
+Return true if
+.I ip
+is an IPv4 address; return false if
+otherwise (it can only be used on a full IPv6 network)
+.TP
+.IB ip .v4()
+Return the value of
+.I ip
+as a 4-byte array in IPv4 representation if it can be so represented;
+if
+.I ip
+is not an IPv4 address, return nil.
+.TP
+.IB ip .v6()
+Return the value of
+.I ip
+in IPv6 addressing format as an array of 16 bytes
+.TP
+.IB ip .class()
+If
+.I ip
+is an IPv4 address, return its class (0 to 3); if it is an IPv6 address, return 6.
+.TP
+.IB ip .classmask()
+If
+.I ip
+is an IPv4 address, return the mask associated with its class; if
+.I ip
+is an IPv6 address, return a mask that is all ones.
+.TP
+.IB ip .ismulticast()
+Return true if
+.I ip
+is a multicast or broadcast address.
+.TP
+.IB ip .isvalid()
+Return true if
+.I ip
+is not the zero address in either IPv4 or IPv6 address space
+.TP
+.IB ip .text()
+Return a textual representation of the address
+.I ip
+in either IPv4 or IPv6 format as appropriate.
+.TP
+.IB ip .masktext()
+Return a textual representation of the address
+.I ip
+as one of: an IPv4 mask;
+.BI / n
+where
+.I n
+is the number of leading 1 bits, as used in CIDR syntax; or
+as a full IPv6 textual address.
+The format used is appropriate to the structure of the value.
+.PP
+The module provides some predefined
+.B IPaddr
+values, mainly for common IPv4 addresses:
+.B v4bcast
+(broadcast address),
+.B v4allsys
+(all hosts multicast address),
+.B v4allrouter
+(all routers multicast address),
+.B selfv4
+(loopback in IPv4),
+.B selfv6
+(loopback in IPv6),
+.B noaddr
+(all zero address, used before a node has an address),
+.B v4noaddr
+(all zero address with IPv4 prefix),
+and
+.B allbits
+(address of all 1 bits).
+The 12-byte IPv6 prefix for IPv4 embedded addresses is provided in
+the array of bytes
+.BR v4prefix .
+.PP
+.B Readipifc
+returns a list of the host's IP interfaces
+and the attributes and addresses of each,
+read from the interface status files in
+.BR /net/ipifc .
+On an error, the string in the returned tuple contains a diagnostic and the list is nil.
+Each interface is represented by an
+.B Ipifc
+value, which contains a list of local interface addresses,
+.BR addrs .
+Each local address is represented by an
+.B Iplifc
+value in that list.
+.SH FILES
+.TF /net/ipifc/N/status
+.TP
+.B /net/ipifc
+directory of IP interfaces
+.TP
+.BI /net/ipifc/ n /status
+status and addresses of interface
+.I n
+.SH SOURCE
+.B /appl/lib/ip.b
+.SH SEE ALSO
+.IR ether (2),
+.IR ip (3)
+.SH BUGS
+.B Readipifc
+is currently only usable in native Inferno.
+That will change shortly.
diff --git a/man/2/ir b/man/2/ir
new file mode 100644
index 00000000..e86bef06
--- /dev/null
+++ b/man/2/ir
@@ -0,0 +1,254 @@
+.TH IR 2
+.SH NAME
+ir \- infrared remote control module
+.SH SYNOPSIS
+.EX
+include "ir.m";
+
+ir := load Ir Ir->PATH; # for real remotes
+simir := load Ir Ir->SIMPATH; # for keyboard simulator
+
+init: fn(irc: chan of int, pidc: chan of int): int;
+translate: fn(key: int): int;
+.EE
+.SH DESCRIPTION
+Programs running with the Prefab
+toolkit (see
+.IR prefab-intro (2))
+are controlled by an infrared remote
+control device.
+If such a device is not present, the system may simulate
+it from the keyboard by loading the module in file
+.BR Ir->SIMPATH .
+Although originally designed for use with Prefab,
+these modules are general enough to be used directly by non-Prefab
+applications.
+.PP
+The
+.B Ir
+module defines codes
+for representing the remote control keys.
+Whether the remote is real or simulated, the
+.B init
+function does the appropriate actions to initialize the device, and then spawns
+a process to return the codes on the
+.I irc
+channel.
+The process ID of that process
+is sent on the channel
+.I pidc
+when the process starts;
+.BR init 's
+caller must receive it.
+It can be used to kill the controlling process when the application finishes.
+.PP
+The codes are:
+.PP
+.TP
+.BR Ir\->ChanUP ", " Ir\->ChanDN
+The Channel-Up and Channel-Down buttons.
+The keyboard equivalents are
+.B r
+and
+.BR c .
+.TP
+.B Ir\->Enter
+The Enter button.
+The keyboard equivalent is the \s-1SPACE\s0 bar.
+.TP
+.B Ir\->EOF
+An end of file from the remote device.
+After sending one, no more codes will be sent on
+.IR irc .
+.TP
+.B Ir\->Error
+An unknown or invalid input from the remote device.
+.TP
+.BR Ir\->FF ", " Ir\->Rew
+The Fast-Forward and Rewind buttons.
+The keyboard equivalents are
+.B k
+and
+.BR j .
+.TP
+.B Ir\->Mute
+The Mute button.
+There is no keyboard equivalent.
+.TP
+.B Ir\->Power
+The Power button.
+The keyboard equivalent is the
+.B Delete
+key.
+.TP
+.B Ir\->Rcl
+The Recall button.
+The keyboard equivalent is
+.BR x .
+.TP
+.B Ir\->Record
+The Record button.
+There is no keyboard equivalent.
+.TP
+.B Ir\->Select
+The Select button.
+The keyboard equivalent is the
+.B Return
+or
+.B Enter
+key.
+.TP
+.BR Ir\->Up ", " Ir\->Dn
+The Up and Down buttons.
+The keyboard equivalents are
+.B i
+and
+.BR m .
+.TP
+.BR Ir\->VolUP ", " Ir\->VolDN
+The Volume-Up and Volume-Down buttons.
+The keyboard equivalents are
+.B t
+and
+.BR v .
+.TP
+.B
+Ir\->Zero\fR,\fP Ir\->One\fR,\fP Ir\->Two\fR, etc.
+.PD
+The digit buttons, 0 through 9.
+The keyboard equivalents are the corresponding numeral keys.
+.PP
+The
+.B translate
+function converts the device's raw codes into the constants defined by
+the module.
+For example, with the simulated remote control,
+.B translate('3')
+returns
+.BR Ir->Three .
+.B Translate
+is only necessary for programs that wish to manage their own simulation of the remote.
+.PP
+Programs
+that drive the remote control directly,
+must load the appropriate Ir implementation module and initialise it.
+The following example uses the absence of a simulator module
+to infer that a real remote control is available.
+.PP
+.EX
+implement Irtest;
+
+include "sys.m";
+include "draw.m";
+include "ir.m";
+
+Irtest: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+ sys := load Sys Sys->PATH;
+
+ # First try the keyboard Ir simulator.
+ # If that is not present, use Ir directly.
+
+ ir := load Ir Ir->SIMPATH;
+ if(ir == nil)
+ ir = load Ir Ir->PATH;
+ if(ir == nil){
+ sys->print("Ir module not loaded: %r\en");
+ return;
+ }
+ irc := chan of int;
+ pidc := chan of int;
+ if(ir->init(irc, pidc) < 0){
+ sys->print("Can't initialize Ir device: %r\en");
+ return;
+ }
+ pid := <-pidc;
+ while((irraw := <-irc) != Ir->EOF) {
+ irval := ir->translate(irraw);
+ if(irval == Ir->Power)
+ break;
+ sys->print("command %d -> %d\en", irraw, irval);
+ }
+ kill(pid);
+}
+.EE
+.PP
+.IR Mux (1)
+provides one model for the use of an infrared remote control to control
+a group of applications.
+.B Init
+is invoked once by
+.IR mux ,
+and the codes then multiplexed between its applications as follows.
+.I Mux
+creates a graphics context for each application
+(see
+.IR draw-context (2)).
+This context includes channels to the
+.B mux
+program and to the
+.B Ir
+device:
+.B Draw->Context.ctomux
+and
+.BR Draw->Context.cinput .
+Applications do not see the
+.B Ir->Rcl
+command.
+Instead,
+.I mux
+program intercepts it and reactivates its own menu.
+The following example establishes communication with
+.I mux
+and then reads
+.B Ir
+commands until it see
+.BR Ir->Enter .
+.PP
+.EX
+implement Command;
+
+include "sys.m";
+include "draw.m";
+include "ir.m";
+
+Command: module
+{
+ init: fn(ref Draw->Context; list of string);
+};
+
+init(ctxt: ref Draw->Context; argv: list of string)
+{
+ sys := load Sys Sys->PATH;
+
+ # Tell mux to start sending input.
+ ctxt.ctomux <-= Draw->AMstartinput;
+ for(;;) {
+ key := <-ctxt.cinput;
+ sys->print("command %d\en", key);
+ if(key == Ir->Enter)
+ break;
+ }
+
+ # Tell mux this thread is going away.
+ ctxt.ctomux <-= Draw->AMexit;
+}
+.EE
+.SH SOURCE
+.B /appl/lib/ir.b
+.br
+.B /appl/lib/irmpath.b
+.br
+.B /appl/lib/irsim.b
+.SH SEE ALSO
+.IR limbo (1),
+.IR mux (1),
+.IR intro (2),
+.IR draw-intro (2),
+.IR prefab-intro (2)
+
diff --git a/man/2/itslib b/man/2/itslib
new file mode 100644
index 00000000..4b12bcd6
--- /dev/null
+++ b/man/2/itslib
@@ -0,0 +1,101 @@
+.TH ITSLIB 2
+itslib \- test library
+.SH SYNOPSIS
+.EX
+include "itslib.m";
+itslib := load Itslib Itslib->PATH;
+
+S_INFO: con 0;
+S_WARN: con 1;
+S_ERROR: con 2;
+S_FATAL: con 3;
+S_STIME: con 4;
+S_ETIME: con 5;
+ENV_VERBOSITY: con "ITS_VERBOSITY";
+ENV_MFD: con "ITS_MFD";
+
+Tconfig: adt {
+ verbosity: int;
+ mfd: ref Sys->FD;
+ report: fn(t: self ref Tconfig, sev: int, verb: int, msg: string);
+ done: fn(t: self ref Tconfig);
+};
+
+init: fn(): ref Tconfig;
+.EE
+.SH DESCRIPTION
+.B Itslib
+provides a simple error reporting facility for tests which can be run
+by
+.IR itest (1) .
+.PP
+The module must first be initialised by calling
+.B init
+which returns an adt containing the verbosity setting specified
+for this test run, and the message file descriptor
+used to pass messages back to
+.I itest.
+These two items of information are passed to the test via the
+environment variables ITS_VERBOSITY and ITS_MFD.
+.TP
+.BI Tconf.report( severity , verbosity , message)
+Report a message with specified severity and verbosity.
+.I Severity
+must be one of S_INFO, S_WARN, S_ERROR or S_FATAL for Information,
+warnings, errors and fatal errors respectively.
+.I Verbosity
+is an integer between 0 and 9.
+For informatory messages (severity S_INFO), the message will only be
+displayed if the current
+verbosity level is greater than or equal to
+.I verbosity.
+.TP
+.BI Tconf.done()
+Tell the test system that all significant work has been completed.
+This useful when for example results are displayed in an interactive
+manner following the test proper. For recording purposes the test
+will be regarded as having finished when this function is called,
+rather than when the test finally exits.
+.SH EXAMPLE
+A very simple test program.
+.EX
+
+implement T;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+ draw: Draw;
+include "itslib.m";
+ itslib: Itslib;
+ Tconfig, S_INFO, S_WARN, S_ERROR, S_FATAL: import itslib;
+
+T: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+tconf: ref Tconfig;
+
+init(ctxt: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ itslib = load Itslib Itslib->PATH;
+ if (itslib != nil) tconf = itslib->init();
+ report(S_INFO, 5, "Testing addition of 1 + 2");
+ x := 1 + 2;
+ if (x == 3)
+ report(S_INFO, 6, "Addition of 1 + 2 OK");
+ else
+ report(S_ERROR, 5, sys->sprint("Addition of 1 + 2 gave %d", x));
+}
+
+report(sev: int, verb: int, msg: string)
+{
+ if (tconf != nil) tconf.report(sev, verb, msg);
+ else sys->print("%d:%s\n", sev, msg);
+}
+
+.EE
+.SH SEE ALSO
+.IR itest (1),
+.IR sh-test (2)
diff --git a/man/2/keyring-0intro b/man/2/keyring-0intro
new file mode 100644
index 00000000..5e28b068
--- /dev/null
+++ b/man/2/keyring-0intro
@@ -0,0 +1,296 @@
+.TH KEYRING-INTRO 2
+.SH NAME
+Keyring intro \- introduction to the
+.B Keyring
+module
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+
+SigAlg: adt
+{
+ name: string;
+};
+
+PK: adt
+{
+ sa: ref SigAlg;
+ owner: string;
+};
+
+SK: adt
+{
+ sa: ref SigAlg;
+ owner: string;
+};
+
+Certificate: adt
+{
+ sa: ref SigAlg;
+ ha: string;
+ signer: string;
+ exp: int;
+};
+
+DigestState: adt
+{
+ # hidden state
+ copy: fn(d: self ref DigestState): ref DigestState;
+};
+
+Authinfo: adt
+{
+ mysk: ref SK;
+ mypk: ref PK;
+ cert: ref Certificate;
+ spk: ref PK;
+ alpha: ref IPint;
+ p: ref IPint;
+};
+.EE
+.SH DESCRIPTION
+This module contains a mixed set of functions that variously:
+.IP \(bu
+perform infinite precision modular arithmetic; see
+.IR keyring-ipint (2)
+.IP \(bu
+form cryptographically secure digests; see
+.IR keyring-sha1 (2)
+.IP \(bu
+generate public/private key pairs and transform them
+to and from textual form; see
+.IR keyring-gensk (2)
+and
+.IR keyring-certtostr (2)
+.IP \(bu
+encrypt data, using AES, DES, or IDEA; see
+.IR keyring-crypt (2)
+.IP \(bu
+create and verify cryptographic signatures using the
+public keys; see
+.IR keyring-auth (2)
+.IP \(bu
+authenticate the parties on a connection; see
+.IR keyring-auth (2)
+.IP \(bu
+read and write files containing the information
+needed to authenticate the parties on a connection; see
+.IR keyring-auth (2)
+.IP \(bu
+send Limbo byte arrays and strings across a connection; see
+.IR keyring-getstring (2)
+.PP
+Each collection is discussed in turn.
+.SS "Large Precision Arithmetic"
+The
+.B IPint
+adt
+is provided to allow some cryptographic functions to
+be implemented in Limbo.
+.B IPint
+stands for infinite precision integer, though, for
+space considerations, our
+implementation limits the maximum integer to
+2\u\s-2\&8192\s0\d-1.
+.PP
+An
+.B IPint
+can be converted into two external formats.
+The first is
+an array of bytes in which the first byte is the highest order
+byte of the integer. This format is useful when
+communicating with the
+.IR ssl (3)
+device.
+The second is a MIME base 64 format, that
+allows
+.BR IPint s
+to be stored in files or transmitted across
+networks in a human readable form.
+.SS "Public Key Cryptography"
+Public key cryptography has many uses.
+Inferno relies on it only for digital signatures.
+Each Inferno user may generate a
+pair of matched keys, one public and
+one private.
+The private key may be used to digitally
+sign data, the public one to verify the signature.
+Public key algorithms have been chosen to
+make it difficult to spoof a signature or guess
+the private key.
+.PP
+For public keys algorithms to work, there must be a way to
+distribute the public keys:
+in order to verify that
+.B X
+signed something, we must know
+.BR X 's
+public key.
+To simplify the problem, we have instituted a
+trust hierarchy that requires people to
+know only the public keys of certifying authorities (CAs).
+After generating a public key, one can have the
+concatenation of one's name, expiration date, and key
+signed by a CA.
+The information together with the name of the CA
+and the signature is called a
+.IR certificate .
+.PP
+At the beginning of a conversation, the parties
+exchange certificates.
+They then use the CA's public key to verify each
+other's public keys.
+The CA's public key, a system wide Diffie-Hellman
+base and modulus, one's private key, one's
+public key and certificate are kept in
+a Limbo adt called
+.BR Keyring->Authinfo .
+An
+.B Authinfo
+adt can be read from from a file using
+.B readauthinfo
+or written to a file
+using
+.BR writeauthinfo ,
+both from
+.IR keyring-auth (2).
+.PP
+.B Authinfo
+adts are normally created during the login and
+registration procedures described below.
+.SS "Authentication"
+Two parties conversing on a network connection can
+authenticate each other's identity using the functions in
+.IR keyring-auth (2).
+They use the
+.B Keyring->Authinfo
+information to run the Station to Station (STS)
+authentication protocol.
+STS not only authenticates each party's identity to the other but also
+establishes a random bit string known
+only to the two parties.
+This bit string can be used
+as a key to encrypt or authenticate subsequent messages
+sent between the two parties.
+.SS "Secure Communications"
+After exchanging secrets, communicating
+parties may encode the conversation to
+guarantee varying levels of security:
+.IP •
+none
+.IP •
+messages cannot be forged
+.IP •
+messages cannot be intercepted
+.LP
+Encoding uses the line formats
+provided by the Secure Sockets Layer.
+See
+.IR security-intro (2)
+for more detail.
+.SS "Login and registration"
+The Inferno authentication procedure
+requires that both parties possess an
+.B Authinfo
+adt containing
+a locally generated public/private key pair,
+the public key of a commonly trusted CA,
+and a signed certificate from the CA that links
+the party's identity and public key.
+This
+.B Authinfo
+adt is normally kept in a file.
+At some point, however, it must be created, and later
+conveyed securely between the user's machine
+and the CA.
+There are two ways to do this, the login procedure
+and the registration procedure.
+Both require an out of band channel between the
+CA and the user.
+.PP
+The login procedures are used by typed
+commands and by programs using Tk.
+The login procedure relies on the CA and
+the user having established a common secret
+or password.
+This is done securely off line, perhaps by mail or telephone.
+This secret is then used to provide a secure
+path between CA and user machine to transfer
+the certificate and CA public key.
+See
+.IR security-intro (2)
+for more detail.
+.PP
+The registration procedure is built into the
+.IR mux (1)
+interface and is intended for the set top box
+environment.
+When the set top box is first turned on, it
+creates a public/private key pair and
+dials the service provider's CA to get a key
+signed.
+The CA returns its public key and a signed
+certificate, blinded by a random bit string
+known only to the CA.
+A hash of the information is then displayed on the
+user screen.
+The user must then telephone the CA and compare this
+hashed foot print with the one at the CA.
+If they match and the user proves that he is
+a customer, the CA makes the blinding string
+publicly known.
+.SS Data Types
+.TP
+.B SigAlg
+The
+.B SigAlg
+adt contains a single string that specifies the algorithm used for digital signatures.
+The allowable values are
+.BR md5 ,
+.BR md4
+and
+.BR sha1
+that specify which one-way hash function is used to produce a digital signature
+or message digest.
+.TP
+.BR PK " and " SK
+The
+.B PK
+adt contains the data necessary to construct a public key;
+the
+.B SK
+adt contains the data necessary to construct a secret key.
+Both keys are built from the combination of a specified signature algorithm
+and a string representing the name of the owner of the key.
+.TP
+.B Certificate
+The
+.B Certificate
+adt contains a digital signature with the certification of the trusted authority (CA).
+.TP
+.B DigestState
+The
+.B DigestState
+adt contains the hidden state of partially completed hash functions during processing.
+Its
+.B copy
+operation returns a reference to a copy of a given state.
+.TP
+.B Authinfo
+The
+.B Authinfo
+adt contains an individual user's private and public key, the signer's certificate
+and the signer's public key, and the Diffie-Hellman parameters.
+.SH SOURCE
+.B /libcrypt/*.c
+.br
+.B /libinterp/keyring.c
+.br
+.B /libkeyring/*.c
+.SH SEE ALSO
+.IR security-intro (2)
+.br
+B. Schneier,
+.IR "Applied Cryptography" ,
+1996, J. Wiley & Sons, Inc.
diff --git a/man/2/keyring-auth b/man/2/keyring-auth
new file mode 100644
index 00000000..9ed26b2a
--- /dev/null
+++ b/man/2/keyring-auth
@@ -0,0 +1,101 @@
+.TH KEYRING-AUTH 2
+.SH NAME
+keyring: auth, readauthinfo, writeauthinfo \- authenticate a connection
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+auth: fn(fd: ref Sys->FD, info: ref Authinfo, setid: int)
+ : (string, array of byte);
+readauthinfo: fn(filename: string): ref Authinfo;
+writeauthinfo: fn(filename: string, info: ref Authinfo): int;
+.EE
+.SH DESCRIPTION
+.B Auth
+performs mutual authentication over a network connection, usually between a client and a server.
+The function is symmetric: each party runs it on their end of the connection.
+.I Info
+holds the public key of a certifying authority
+.RB ( PKca ),
+the private key of the user
+.RB ( SKu ),
+the public key
+.RB ( PKu )
+of the user signed by the certifying authority
+.RB ( CERTu ),
+and Diffie-Hellman parameters
+.RB ( alpha ,
+.BR p ).
+.PP
+.B Auth
+returns a string and a byte array.
+If the byte array is nil then the authentication has failed and the string is an error message. If the byte array is non-nil, it represents a secret shared by the two communicating parties,
+and the string names the party at the other end of the connection.
+.PP
+If the authentication is successful and
+.I setid
+is non-zero then
+.B auth
+attempts to write the name of the party at the other end of the connection into
+.B /dev/user
+(see
+.IR cons (3));
+no error is generated if that does not succeed.
+If the authentication is not successful and
+.I setid
+is non-zero,
+.B auth
+writes the name
+.B nobody
+into
+.BR /dev/user .
+.PP
+The authentication protocol is based on the Station-to-Station protocol. In the following, the parties are labelled 0 and 1.
+.BI Sig0( x )
+is
+.I x
+signed with 0's private key.
+.IP
+.EX
+0 → 1 alpha**r0 mod p, CERTu0, PKu0
+1 → 0 alpha**r1 mod p, CERTu1, PKu1
+0 → 1 sig0(alpha**r0 mod p, alpha**r1 mod p)
+1 → 0 sig1(alpha**r0 mod p, alpha**r1 mod p)
+.EE
+.PP
+At this point both 0 and 1 share the secret
+.B "alpha**(r0*r1)"
+which is returned in the byte array.
+Amongst other things, it can be the secret to digest or encrypt a conversation
+(see
+.IR security-ssl (2)).
+.PP
+.B Readauthinfo
+reads a representation of an
+.B Authinfo
+from a file.
+It returns nil if there is a read error or a conversion error;
+it returns a reference to the
+.B Authinfo
+otherwise.
+.PP
+.B Writeauthinfo
+writes a representation of
+.I info
+to a file. It returns -1 if the write operation fails, 0 otherwise.
+.SH FILES
+.TF /usr/user/keyring/defaultxxx
+.TP
+.BI /usr/ user /keyring
+The conventional directory for storing
+.B Authinfo
+files
+.TP
+.BI /usr/ user /keyring/default
+The key file normally used by server programs
+.TP
+.BI /usr/ user /keyring/ net ! server
+The key file normally used by clients for a given
+.I server
+.SH SOURCE
+.B /libinterp/keyring.c
diff --git a/man/2/keyring-certtostr b/man/2/keyring-certtostr
new file mode 100644
index 00000000..55b7f142
--- /dev/null
+++ b/man/2/keyring-certtostr
@@ -0,0 +1,56 @@
+.TH KEYRING-CERTTOSTR 2
+.SH NAME
+keyring: certtostr, pktostr, sktostr, strtocert, strtopk, strtosk \- encryption key conversion functions
+.SH SYNOPSIS
+.EX
+include "keyring.m"
+keyring:= load Keyring Keyring->PATH;
+
+strtocert: fn(s: string) : ref Certificate;
+certtostr: fn(c: ref Certificate): string;
+strtopk: fn(s: string) : ref PK;
+pktostr: fn(pk: ref PK) : string;
+strtosk: fn(s: string) : ref SK;
+sktostr: fn(sk: ref SK) : string;
+.EE
+.SH DESCRIPTION
+Certificates, public keys, and private keys are passed over networks and between applications using a Unicode representation. This collection of functions provide a means to convert adts supplied by the system to and from their portable textual representation. These routines are typically used as part of an I/O package for implementing security.
+.PP
+.B Strtocert
+takes a string argument containing a user name, a hash algorithm, a certifying authority and an expiration time. Fields are separated by a newline. The return value is a
+.BR Certificate .
+If the string is of improper format, the result is
+.IR nil .
+.PP
+.B Certtostr
+performs the inverse operation: takes the
+.B Certificate
+.I c
+and produces a text string suitable for communication over a network.
+.PP
+.B Strtopk
+and
+.B strtosk
+take as their arguments a string
+.I s
+representing the public and private keys respectively.
+.I S
+must contain an algorithm name, a user name and the key. Fields are separated by a newline.
+.B Strtopk
+returns a reference to the resulting
+.BR PK ;
+.B strtosk
+returns a reference to the resulting
+.BR SK .
+If the format of
+.I s
+is invalid, the result is
+.IR nil .
+.PP
+.B Pktostr
+and
+.B sktostr
+perform the inverse operations:
+they take a public key (secret key) and produce a printable representation as a string.
+.SH SOURCE
+.B /libinterp/keyring.c
diff --git a/man/2/keyring-crypt b/man/2/keyring-crypt
new file mode 100644
index 00000000..a083e543
--- /dev/null
+++ b/man/2/keyring-crypt
@@ -0,0 +1,120 @@
+.TH KEYRING-CRYPT 2
+.SH NAME
+keyring: aessetup, aescbc, dessetup, descbc, desecb, ideasetup, ideacbc, ideaecb \- data encryption
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+
+Encrypt: con 0;
+Decrypt: con 1;
+
+AESbsize: con 16;
+
+aessetup: fn(key: array of byte, ivec: array of byte): ref AESstate;
+aescbc: fn(state: ref AESstate, buf: array of byte,
+ n: int, direction: int);
+
+DESbsize: con 8;
+
+dessetup: fn(key: array of byte, ivec: array of byte): ref DESstate;
+descbc: fn(state: ref DESstate, buf: array of byte,
+ n: int, direction: int);
+desecb: fn(state: ref DESstate, buf: array of byte,
+ n: int, direction: int);
+
+IDEAbsize: con 8;
+
+ideasetup: fn(key: array of byte, ivec: array of byte): ref IDEAstate;
+ideacbc: fn(state: ref IDEAstate, buf: array of byte,
+ n: int, direction: int);
+ideaecb: fn(state: ref IDEAstate, buf: array of byte,
+ n: int, direction: int);
+.EE
+.SH DESCRIPTION
+These functions encrypt and decrypt blocks of data using different
+encryption algorithms.
+The interfaces are similar.
+.PP
+Each algorithm has an adt that holds the current state for a given encryption.
+It is produced by the setup function for the algorithm,
+.IB alg setup ,
+which is given a secret
+.I key
+and an initialisation vector
+.IR ivec .
+A sequence of blocks of data can then be encrypted or decrypted by repeatedly calling
+.IB alg cbc
+(for `cipher block chaining'), or
+.IB alg ebc
+(the less secure `electronic code book', if provided).
+On each call,
+.I buf
+provides
+.I n
+bytes of the data to encrypt or decrypt.
+.I N
+must be a multiple of the encryption block size
+.IB ALG bsize .
+Exceptionally,
+.B aescbc
+allows
+.I n
+to be other than a multiple of
+.B AESbsize
+in length, but then
+for successful decryption, the decryptor must use the same
+sequence of buffer sizes as the encryptor.
+.I Direction
+is the constant
+.B Encrypt
+or
+.B Decrypt
+as required.
+.I State
+maintains the encryption state, initially produced by the setup function,
+and updated as each buffer is encrypted or decrypted.
+.PP
+The algorithms currently available are:
+.TP
+.B aes
+The Advanced Encryption Standard, AES (also known as Rijndael).
+The
+.I key
+should be 16, 24 or 32 bytes long (128, 192 or 256 bits).
+.I Ivec
+should be
+.B AESbsize
+bytes of random data: random enough to be unlikely to be reused but
+not cryptographically strongly unpredictable.
+.TP
+.B des
+The older Data Encryption Standard, DES.
+.I Key
+is 8 bytes (64 bits), containing a 56-bit key
+encoded into 64 bits where every eighth bit is parity.
+.I Ivec
+is
+.B DESbsize
+bytes of random data.
+.TP
+.B idea
+The International Data Encryption Standard, IDEAâ„¢.
+The
+.I key
+is 16 bytes long (128 bits).
+.I Ivec
+is
+.B IDEAbsize
+bytes of random data.
+.SH SEE ALSO
+.IR keyring-intro (2),
+.IR keyring-rc4 (2),
+.IR security-random (2)
+.PP
+IDEA was patented by Ascom-Tech AG (EP 0 482 154 B1, US005214703),
+currently held by iT_SEC Systec Ltd.
+At time of writing, there was no licence fee required for noncommercial use
+but check
+the current licensing policy of iT_SEC Systec Ltd,
+especially for commercial use.
diff --git a/man/2/keyring-gensk b/man/2/keyring-gensk
new file mode 100644
index 00000000..a4c7fd65
--- /dev/null
+++ b/man/2/keyring-gensk
@@ -0,0 +1,49 @@
+.TH KEYRING-GENSK 2
+.SH NAME
+keyring: genSK, genSKfromPK, sktopk, dhparams \- generate keys
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+genSK: fn(algname, owner: string, length: int): ref SK;
+genSKfromPK: fn(pk: ref PK, owner: string): ref SK;
+sktopk: fn(sk: ref SK): ref PK;
+dhparams: fn(nbits: int): (ref IPint, ref IPint);
+.EE
+.SH DESCRIPTION
+.B GenSK
+generates a public/private key pair, represented by
+.BR SK .
+(Although we call it a `private key',
+.B SK
+contains both the private and public parts of a public key.)
+.I Algname
+is the name of the algorithm to use; in the current implementation, only
+.B elgamal
+and
+.B rsa
+are possible.
+.I Owner
+is the user name to be associated with the key.
+.I Length
+gives the length of the key modulus in bits.
+.B GenSK
+returns nil if an unknown algorithm has been specified.
+.PP
+.B GenSKfromPK
+generates a private key that has the same system parameters as the public key
+.IR pk .
+It is used to generate new keys that are of the same complexity as old keys.
+.PP
+.B Sktopk
+extracts the public part of private key.
+.PP
+.B Dhparams
+creates Diffie-Hellman parameters. The second
+.B IPint
+returned is an
+.I nbits
+long prime number that serves as the modulus.
+The first
+.B IPint
+is a primitive root in the integer field defined by that modulus.
diff --git a/man/2/keyring-getmsg b/man/2/keyring-getmsg
new file mode 100644
index 00000000..bf6958a0
--- /dev/null
+++ b/man/2/keyring-getmsg
@@ -0,0 +1,68 @@
+.TH KEYRING-GETMSG 2
+.SH NAME
+keyring: getmsg, sendmsg, senderrmsg \- send and receive messages on undelimited streams
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+
+getmsg: fn(fd: ref Sys->FD): array of byte;
+sendmsg: fn(fd: ref Sys->FD, buf: array of byte, n: int): int;
+senderrmsg: fn(fd: ref Sys->FD, s: string): int;
+.EE
+.SH DESCRIPTION
+These functions allow arbitrary data, packed into arrays of bytes, to be exchanged
+on network connections using connection-oriented transport protocols that do not preserve
+record boundaries (eg, TCP/IP without
+.IR ssl (3)).
+They are used to implement various authentication protocols, including
+.IR auth (6),
+as implemented by
+.IR keyring-auth (2).
+.PP
+Each data message is transmitted with a five-byte header containing a four-character zero-padded decimal count
+.I n
+terminated by a newline, followed by
+.I n
+bytes of message data.
+An error message has a similar structure, except that the first character
+of the count is replaced by an exclamation mark
+.RB ( ! );
+the message data following
+contains the diagnostic string in its UTF-8 encoding (see
+.IR utf (6)).
+.PP
+.B Getmsg
+reads the next message from
+.I fd
+and returns its data content.
+.PP
+.B Sendmsg
+sends the first
+.I n
+bytes of
+.I buf
+as a message on
+.IR fd ,
+and returns
+.IR n .
+.PP
+.B Senderrmsg
+sends the error message
+.IR s .
+.SH SOURCE
+.B /libinterp/keyring.c
+.SH DIAGNOSTICS
+.B Sendmsg
+and
+.B senderrmsg
+return -1 if there was an error writing to
+.IR fd ;
+they set the system error string.
+.B Getmsg
+returns nil if there was an error reading from
+.IR fd ;
+it sets the system error string to reflect the cause.
+It also returns nil
+if an error message was received instead of a data message;
+the system error string will contain the error message's diagnostic.
diff --git a/man/2/keyring-getstring b/man/2/keyring-getstring
new file mode 100644
index 00000000..783c0106
--- /dev/null
+++ b/man/2/keyring-getstring
@@ -0,0 +1,90 @@
+.TH KEYRING-GETSTRING 2
+.SH NAME
+keyring: getstring, putstring, getbytearray, putbytearray, puterror \- exchange data on delimited streams
+.SH SYNOPSIS
+.EX
+include "keyring.m"
+keyring:= load Keyring Keyring->PATH;
+
+getstring: fn(fd: ref Sys->FD): (string, string);
+putstring: fn(fd: ref Sys->FD, s: string): int;
+getbytearray: fn(fd: ref Sys->FD): (array of byte, string);
+putbytearray: fn(fd: ref Sys->FD, a: array of byte, n: int): int;
+puterror: fn(fd: ref Sys->FD, s: string): int;
+.EE
+.SH DESCRIPTION
+These functions provide
+I/O for strings, byte arrays and error strings over network connections that
+provide a record structure for communication (as provided for arbitrary
+networks by
+.IR ssl (3)).
+.PP
+.B Putstring
+writes string
+.I s
+to
+.IR fd.
+It returns the number of bytes written, or -1 if an error occurred.
+Messages written by
+.B putstring
+are truncated to 4096 bytes.
+.PP
+.B Getstring
+reads a string as written by
+.B putstring
+from
+.IR fd
+and returns a tuple
+.RI ( result , error ).
+If successful, the error
+string is nil.
+.PP
+.B Putbytearray
+writes the array of bytes
+.I a
+to
+.IR fd .
+It returns the number of bytes written, or -1 if an error occurred.
+Messages written by
+.B putbytearray
+are truncated to 4096 bytes.
+.PP
+.B Getbytearray
+reads an array of bytes as written by
+.B putbytearray
+from
+.IR fd
+and returns a tuple of the form
+.RI ( result , error ).
+If successful, the error string is nil.
+.PP
+.B Puterror
+writes an error string
+.I s
+to
+.IR fd .
+It can be used in place of
+.B putstring
+or
+.B putbytearray
+to cause a corresponding
+.B getstring
+or
+.B getbytearray
+to fail
+(in the receiving process),
+forcing them to return the error string
+.IR s .
+It may not be longer than
+.BR Sys->ERRMAX
+bytes.
+.SH SOURCE
+.B /libinterp/keyring.c
+.SH DIAGNOSTICS
+The output functions return an
+.B int
+which is -1 if there was an I/O error,
+and a non-negative value otherwise.
+The input functions
+return a tuple that includes a string indicating the cause of the
+error, as the second element of the tuple.
diff --git a/man/2/keyring-ipint b/man/2/keyring-ipint
new file mode 100644
index 00000000..8a47c001
--- /dev/null
+++ b/man/2/keyring-ipint
@@ -0,0 +1,147 @@
+.TH KEYRING-IPINT 2
+.SH NAME
+keyring: IPint \- `infinite' precision integer utility functions
+.SH SYNOPSIS
+.EX
+include "keyring.m"
+keyring:= load Keyring Keyring->PATH;
+
+IPint: adt
+{
+ iptob64: fn(i: self ref IPint): string;
+ b64toip: fn(str: string) : ref IPint;
+ iptobytes: fn(i: self ref IPint): array of byte;
+ bytestoip: fn(buf: array of byte): ref IPint;
+ iptobebytes: fn(i: self ref IPint): array of byte;
+ bebytestoip: fn(buf: array of byte): ref IPint;
+ inttoip: fn(i: int): ref IPint;
+ iptoint: fn(i: self ref IPint): int;
+ iptostr: fn(i: self ref IPint, base: int): string;
+ strtoip: fn(str: string, base: int): ref IPint;
+ random: fn(minbits, maxbits: int): ref IPint;
+ copy: fn(i: self ref IPint): ref IPint;
+ bits: fn(i: self ref IPint): int;
+ expmod: fn(base: self ref IPint, exp, mod: ref IPint):ref IPint;
+ add: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ sub: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ neg: fn(i: self ref IPint): ref IPint;
+ mul: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ div: fn(i1: self ref IPint, i2: ref IPint): (ref IPint, ref IPint);
+ eq: fn(i1: self ref IPint, i2: ref IPint): int;
+ cmp: fn(i1: self ref IPint, i2: ref IPint): int;
+ shl: fn(i: self ref IPint, n: int): ref IPint;
+ shr: fn(i: self ref IPint, n: int): ref IPint;
+};
+.EE
+.SH DESCRIPTION
+.B IPint
+provides the following arbitrary-length integer manipulation functions required for cryptographic support in Limbo:
+.TP
+.IB i .iptob64()
+Returns a string that represents a large integer textually in base 64 for convenient transmission over a network connection.
+.TP
+.BI b64toip( str )
+Returns the
+.B IPint
+represented by the base-64 encoded
+.IR str .
+.TP
+.IB i .iptobytes()
+Returns an array of bytes representing a large integer. The representation includes both positive and negative numbers.
+.TP
+.BI bytestoip( buf )
+The inverse operation of
+.BR iptobytes .
+.TP
+.IB i .iptobebytes()
+Returns an array of bytes in big-endian format representing the magnitude of a large integer; used for instance to pass a value to
+.IR ssl (3).
+Only non-negative numbers are represented.
+.TP
+.BI bebytestoip( buf )
+The inverse operation of
+.BR iptobebytes .
+.TP
+.BI inttoip( i )
+Creates a new large integer from integer
+.IR i .
+.TP
+.IB i .iptoint()
+Converts a large integer
+.I i
+to an
+.BR int ;
+returns 0 on error.
+.TP
+.IB i .iptostr( base )
+Converts a large integer to a string in base
+.IR base ;
+returns nil on error.
+.TP
+.BI strtoip( str , base )
+Converts a string
+.I str
+representing a number in in base
+.I base
+to a large integer; returns nil on error.
+.TP
+.BI random( minbits , maxbits )
+Returns a large random number with length from
+.I minbits
+to
+.IR maxbits .
+The largest number allowed in the current implementation is
+2^8192-1 .
+The seed for the generator is obtained by duelling clocks.
+.TP
+.IB i .copy()
+Returns a reference to the same value as
+.IR i .
+.TP
+.IB i .bits()
+Returns the number of bits of precision of
+.IR i .
+.TP
+.IB base .expmod( "exp , mod" )
+Returns
+.BI ( base ** exp ") mod " mod.
+.TP
+.IB i1 .add( i2 )
+Returns
+.RI ( i1 + i2 ).
+.TP
+.IB i1 .sub( i2 )
+Returns
+.RI ( i1 - i2 ).
+.TP
+.IB i1 .mul ( i2 )
+Returns
+.IR i1*i2 .
+.TP
+.IB i1 .div ( i2 )
+Returns
+.RI ( i1 / i2,
+.IR i1 mod i2 ).
+.TP
+.IB i1 .eq( i2 )
+Returns 1 if
+.I i1
+and
+.I i2
+are equal; 0 otherwise.
+.TP
+.IB i1 .cmp( i2 )
+Compares two large integers, returning 1 if
+.I i1
+is larger,
+-1 if
+.I i2
+is larger, and 0 if they are equal.
+.TP
+.IB i .shl( n )
+Returns
+.IR i << n
+.TP
+.IB i .shr( n )
+Returns
+.IR i >> n
diff --git a/man/2/keyring-rc4 b/man/2/keyring-rc4
new file mode 100644
index 00000000..516ec51a
--- /dev/null
+++ b/man/2/keyring-rc4
@@ -0,0 +1,45 @@
+.TH KEYRING-RC4 2
+.SH NAME
+keyring: rc4setup, rc4, rc4skip, rc4back \- RC4 encryption
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+
+rc4setup: fn(seed: array of byte): ref RC4state;
+rc4: fn(state: ref RC4state, buf: array of byte, n: int);
+rc4skip: fn(state: ref RC4state, n: int);
+rc4back: fn(state: ref RC4state, n: int);
+.EE
+.SH DESCRIPTION
+These functions implement the stream encryption algorithm that is claimed to
+be equivalent to RSA Security's RC4.
+It is a pseudo-random number generator with a 256
+byte state and a long cycle.
+.PP
+.B Rc4setup
+sets the initial
+.IR seed ,
+which can be any non-zero length, and
+returns a representation of the initial state of the algorithm,
+which is used in subsequent calls.
+.PP
+.B Rc4
+runs the generator starting with the given
+.IR state ,
+and XORs the output of the generator with
+the first
+.I n
+bytes of
+.IR buf ,
+updating the
+.IR state .
+.B Rc4
+is symmetric and is used both to encrypt and decrypt.
+.B Rc4skip
+skips over bytes (eg, to account for lost transmissions);
+.B rc4back
+runs the generator backwards (eg, to account for retransmissions).
+.SH SEE ALSO
+.IR keyring-intro (2),
+.IR keyring-crypt (2)
diff --git a/man/2/keyring-sha1 b/man/2/keyring-sha1
new file mode 100644
index 00000000..e453a25c
--- /dev/null
+++ b/man/2/keyring-sha1
@@ -0,0 +1,142 @@
+.TH KEYRING-SHA1 2
+.SH NAME
+keyring: sha1, md4, md5, hmac_sha1, hmac_md5, sign, verify \- cryptographic digests and digital signatures
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+keyring := load Keyring Keyring->PATH;
+
+.ta \w'verify:\ 'u +\w'fn(\ \ \ 'u
+sha1: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+md4: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+md5: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+hmac_sha1: fn(buf: array of byte, n: int, key: array of byte, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+hmac_md5: fn(buf: array of byte, n: int, key: array of byte, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+sign: fn(sk: ref SK, exp: int, state: ref DigestState,
+ ha: string): ref Certificate;
+verify: fn(pk: ref PK, cert: ref Certificate,
+ state: ref DigestState): int;
+.EE
+.SH DESCRIPTION
+.BR Sha1 ,
+.B md4
+and
+.B md5
+are cryptographically secure hash functions that produce output called a message digest.
+Each function computes a hash of
+.I n
+bytes of the data in
+.IR buf ,
+and updates the current
+.IR state .
+They can be called iteratively to form a single digest for many data blocks.
+The state is kept in the
+.B DigestState
+value referenced by
+.I state
+between calls.
+.I State
+should be
+.B nil
+on the first call, and a newly allocated
+.B DigestState
+will be returned for use in subsequent calls.
+On a call in which
+.I digest
+is not
+.BR nil ,
+the hash is completed and copied into the
+.I digest
+array.
+.B Sha1
+produces a 20-byte hash
+.RB ( SHA1dlen ),
+.B md4
+and
+.B md5
+a 16-byte one
+.RB ( MD4len
+and
+.BR MD5len ).
+.PP
+.B Hmac_sha1
+and
+.B hmac_md5
+are keyed versions of the hashing functions, following Internet RFC2104.
+The
+.I key
+must be provided in each call, but otherwise
+the calling conventions are those of
+.BR sha1 .
+The
+.I key
+must currently be no more than 64 bytes.
+.PP
+.B Sign
+creates a digital signature of a digest from the concatenation of: a message, the name of the signer, and an expiration time.
+.I State
+is the digest state after running
+.BR sha1 ,
+.B md4
+or
+.B md5
+over the message.
+.I Ha
+is a string specifying the hash algorithm to use:
+.B
+"sha"\fR,
+.B
+"sha1"\fR,
+.B
+"md4"\fR
+or
+.B
+"md5"\fR.
+.B Sign
+extends the digest to cover the signer's name
+(taken from the private key,
+.IR sk )
+and the expiration time.
+It returns a certificate containing the digital signature of the digest, signer name, hash algorithm and signature algorithm.
+If any parameter is invalid,
+.B sign
+returns nil.
+The signature algorithm is implied by the type of the private key.
+.PP
+.B Verify
+uses public key
+.I pk
+to verify a certificate.
+It returns non-zero (true) if the certificate is valid; zero (false) otherwise.
+.I State
+is the digest state after running the chosen digest algorithm
+over the message.
+.SH EXAMPLES
+A program to read a file and hash it using SHA might contain the following inner loop:
+.IP
+.EX
+state: ref DigestState = nil;
+while((n := sys->read(fd, buf, len buf)) > 0)
+ state = kr->sha1(buf, n, nil, state);
+digest := array[kr->SHAdlen] of byte;
+kr->sha1(buf, 0, digest, state);
+.EE
+.SH SOURCE
+.B /libinterp/keyring.c
+.br
+.B /libcrypt/hmac.c
+.br
+.B /libcrypt/md4.c
+.br
+.B /libcrypt/md5.c
+.br
+.B /libcrypt/sha1.c
+.SH BUGS
+The MD4 algorithm is included only to allow communication with software
+that might still use it; it should not otherwise be used now, because it
+is easily broken.
diff --git a/man/2/keyset b/man/2/keyset
new file mode 100644
index 00000000..a2efd2f2
--- /dev/null
+++ b/man/2/keyset
@@ -0,0 +1,79 @@
+.TH KEYSET 2
+.SH NAME
+keyset \- find authentication keys matching a signer
+.SH SYNOPSIS
+.EX
+include "keyset.m";
+keyset := load Keyset Keyset->PATH;
+
+init: fn(): string;
+keysforsigner: fn(signername: string, spkthumb: string,
+ user: string, dir: string):
+ (list of (string, string, string), string);
+pkhash: fn(pk: string): string;
+.EE
+.SH DESCRIPTION
+.B Keyset
+looks through a set of certified public keys
+to find one or more keys that have were certified by a given signer.
+.PP
+.B Init
+must be called before any other function in the module.
+It returns nil on success or a diagnostic string on failure.
+.PP
+.B Keysforsigner
+looks for public keys that satisfy given conditions:
+.I signername
+is either the name of a signer or nil (don't care);
+.I spkthumb
+is either a thumbprint of the signer's public key (as produced by
+.BR pkhash ,
+below), or nil (don't care).
+.I User
+is the name of the user that owns the set of keys; if it is nil,
+the user's name is read from
+.BR /dev/user .
+.I Dir
+is the name of the directory holding a collection of the
+.IR user 's
+signed keys as obtained for instance using
+.IR getauthinfo (8);
+if it is nil, the directory
+.BI /usr/ user /keyring
+is used by default.
+Only signed (certified) unexpired keys are considered.
+.B Keysforsigner
+returns a tuple
+.BI ( keys , err ).
+.I Keys
+is list of tuples
+.BI ( keyfile\fB,\fP\ owner\fB,\fP\ signername )
+where
+.I keyfile
+is the full name of a file in
+.I dir
+that holds an apparently suitable key;
+.I owner
+is the name of the key's owner; and
+.I signername
+is the name of the signer in the certificate attached to the key.
+The list is nil if no keys could be found that matched the criteria.
+On an error,
+.I err
+is non-nil and gives a diagnostic.
+.PP
+.B Pkhash
+returns the hexadecimal representation of the SHA-1 hash of public key
+.IR pk ,
+which must be in the canonical textual form produced by
+.B Keyring->pktostr
+(see
+.IR keyring-certtostr (2)).
+.SH SOURCE
+.B /appl/lib/keyset.b
+.SH SEE ALSO
+.IR bind (1),
+.IR keyring-gensk (2),
+.IR keyring-sha1 (2),
+.IR security-auth (2),
+.IR logind (8)
diff --git a/man/2/lock b/man/2/lock
new file mode 100644
index 00000000..ff9a0fa7
--- /dev/null
+++ b/man/2/lock
@@ -0,0 +1,39 @@
+.TH LOCK 2
+.SH NAME
+lock \-
+thread locking.
+.SH SYNOPSIS
+.EX
+include "lock.m";
+lock := load Lock Lock->PATH;
+Semaphore: adt {
+ c: chan of int;
+ obtain: fn(s: self ref Semaphore);
+ release: fn(s: self ref Semaphore);
+ new: fn(): ref Semaphore;
+};
+init: fn();
+.EE
+.SH DESCRIPTION
+.B Lock
+provides semaphore-based mutual exclusion.
+.B Init
+must be called before creating any locks.
+.TP
+.B Semaphore.new()
+Creates and returns a reference to a new
+.B Semaphore
+(lock).
+.TP
+.IB s .obtain()
+Obtains exclusive access to the lock
+.IR s .
+It will block until it can do so.
+.TP
+.IB s .release()
+Releases access to the lock
+.I s
+and allows processes waiting on it to proceed.
+.SH SOURCE
+.B /appl/lib/lock.b
+
diff --git a/man/2/math-0intro b/man/2/math-0intro
new file mode 100644
index 00000000..573d6076
--- /dev/null
+++ b/man/2/math-0intro
@@ -0,0 +1,79 @@
+.TH MATH-INTRO 2
+.SH NAME
+Math: intro \- elementary numerics
+.SH SYNOPSIS
+.EX
+include "math.m";
+math := load Math Math->PATH;
+.EE
+.SH DESCRIPTION
+Inferno's math module and Limbo compiler provide the
+fundamental floating point environment and ``elementary functions''.
+.PP
+Limbo expressions involving only literal and named constants are
+evaluated at compile time with all exceptions ignored.
+However,
+arithmetic on variables is left to run-time, even if data path analysis
+shows the value to be a compile time constant.
+This implies that tools
+generating Limbo source must do their own simplification, and not
+expect the compiler to change
+.B x/x
+into
+.BR 1 ,
+or
+.B -(y-x)
+into
+.BR x-y ,
+or even
+.BR x-0
+into
+.BR x .
+.PP
+Subexpression elimination and other forms of code motion may be done by the
+compiler,
+but not across calls to the mode and status functions described in
+.IR math-fp (2).
+Removal of
+parentheses or factoring is not performed by the compiler.
+The evaluation
+order of
+.B a+b+c
+follows the parse tree and is therefore the same as for
+.BR (a+b)+c .
+These rules are the same as for Fortran and C.
+.PP
+Contracted multiply-add instructions (with a single rounding) are not
+generated by the compiler, though they may be used in the native BLAS
+(linear algebra)
+libraries.
+All arithmetic follows the IEEE floating point standard, except that
+denormalized numbers may be replaced by flush-to-0, depending on what
+the hardware makes feasible.
+.PP
+Binary/decimal conversion is properly rounded.
+In particular, printing
+a real using
+.B %g
+and reading it on a different machine is guaranteed to
+recover identical bits, including
+conversions done by the compiler.
+The one exception is that
+smaller, faster, but sloppier run-time conversion
+routines may be used when mandated by
+limited memory embedded systems.
+Programmers may assume, however,
+that the
+features described in these man pages are present in all Inferno
+systems intended for general computing.
+.SH SOURCE
+.B /libinterp/math.c
+.SH SEE ALSO
+See
+.IR math-fp (2)
+for floating point control and primitive arithmetic operations,
+.IR math-elem (2)
+for the classical elementary functions of applied mathematics,
+and
+.IR math-linalg (2)
+for basic linear algebra functions.
diff --git a/man/2/math-elem b/man/2/math-elem
new file mode 100644
index 00000000..fb3e2e2d
--- /dev/null
+++ b/man/2/math-elem
@@ -0,0 +1,106 @@
+.TH MATH-ELEM 2
+.SH NAME
+Math: cbrt, sqrt, pow, pow10, hypot, exp, expm1, log, log10, log1p, cos, cosh, sin, sinh, tan, tanh, acos, asin, acosh, asinh, atan, atanh, atan2, lgamma, erf, erfc, j0, j1, y0, y1, jn, yn \- elementary functions of applied mathematics
+.SH SYNOPSIS
+.EX
+include "math.m";
+math := load Math Math->PATH;
+
+cbrt, sqrt: fn(x: real): real;
+pow: fn(x, y: real): real;
+pow10: fn(p: int): real;
+hypot: fn(x, y: real): real;
+exp, expm1, log, log10, log1p: fn(x: real): real;
+
+cos, cosh, sin, sinh, tan, tanh: fn(x: real): real;
+acos, asin, acosh, asinh, atan, atanh: fn(x: real): real;
+atan2: fn(y, x: real) of real;
+
+lgamma: fn(x: real): (int,real);
+erf, erfc: fn(x: real): real;
+j0, j1, y0, y1: fn(x: real): real;
+jn, yn: fn(n: int, x: real): real;
+
+.EE
+.SH DESCRIPTION
+These routines implement the basic elementary functions of applied mathematics.
+.PP
+.BI Sqrt( x )
+computes the square root of
+.IR x ,
+.BI cbrt( x )
+the cube root.
+.BI Pow( x , y )
+computes
+.I x
+raised to the exponent
+.IR y ;
+.B pow10
+raises 10 to the integer power
+.IR n .
+.BI Hypot( x , y )
+computes
+\f5sqrt(\f2x\f5*\f2x\f5+\f2y\f5*\f2y\f5)\f1.
+.PP
+.BI Exp( x )
+returns the exponential function of
+.IR x ,
+and
+.BI expm1( x )
+is
+.BI exp( x )-1.
+.PP
+.BI Log( x )
+returns the natural logarithm of
+.IR x ,
+while
+.BI log10( x )
+returns the logarithm base 10 and
+.BI log1p( x )
+returns the logarithm of
+.BI 1+ x\f1.
+.PP
+The trigonometric functions use radians.
+The ranges of the inverse functions are:
+.BI acos
+in [0,\(*p];
+.B asin
+in [-\(*p/2,\(*p/2];
+.B atan
+in [-\(*p/2,\(*p/2];
+and
+.BI atan2( y , x )
+.B =
+.BI arctan( y / x )
+in [-\(*p,\(*p];
+.PP
+The gamma function is implemented by
+.BI lgamma( x )\f1;
+the tuple it returns, say
+.BI ( s , lg )\f1,
+encodes the gamma function by
+.RI \(*G( x )
+=
+.IB s *exp( lg )\f1.
+.PP
+The hyperbolic trigonometric functions
+.B sinh
+etc. behave as expected.
+.B Erf
+is the error function and
+.BI erfc( x )
+is
+.BI 1-erf( x )\f1.
+.PP
+The Bessel functions are computed by
+.BI j0 ,
+.BI j1 ,
+.BI jn ,
+.BI y0 ,
+.BI y1 ,
+and
+.BR yn .
+.SH SOURCE
+.B /libinterp/math.c
+.SH SEE ALSO
+.IR math-intro (2)
diff --git a/man/2/math-export b/man/2/math-export
new file mode 100644
index 00000000..9c6c7b63
--- /dev/null
+++ b/man/2/math-export
@@ -0,0 +1,52 @@
+.TH MATH-EXPORT 2
+.SH NAME
+Math: export_int, export_real, export_real32, import_int, import_real, import_real32 \- conversion to and from external representation
+.SH SYNOPSIS
+.EX
+include "math.m";
+math := load Math Math->PATH;
+
+export_int: fn(b: array of byte, x: array of int);
+export_real32: fn(b: array of byte, x: array of real);
+export_real: fn(b: array of byte, x: array of real);
+
+import_int: fn(b: array of byte, x: array of int);
+import_real32: fn(b: array of byte, x: array of real);
+import_real: fn(b: array of byte, x: array of real);
+.EE
+.SH DESCRIPTION
+These routines convert between Limbo's internal representation of
+integer and floating-point values, and equivalent external representations as
+arrays of bytes, allowing efficient input/output of binary representations.
+.PP
+.BI Export_int( b , \ x )
+converts each integer element of array
+.I x
+into a sequence of 4 bytes in array
+.IR b .
+.PP
+.BI Export_real( b , \ x )
+converts each double-precision floating-point element of array
+.I x
+into a sequence of 8 bytes in array
+.IR b .
+.PP
+.BI Export_real32( b , \ x )
+converts each double-precision floating-point element of array
+.I x
+to a single-precision value, then encodes it as a sequence of 4 bytes in array
+.IR b .
+.PP
+Each
+.BI import_ T
+operation reverses the transformation of the corresponding
+.BI export_ T
+operation, converting an array of bytes containing a sequence of external representations
+into an array of values of the appropriate internal form.
+.PP
+Values are encoded in big-endian order (most significant byte first), with floating-point
+values represented in IEEE 32-bit or 64-bit form (again, most significant byte first).
+.SH SOURCE
+.B /libinterp/math.c
+.SH SEE ALSO
+.IR math-intro (2)
diff --git a/man/2/math-fp b/man/2/math-fp
new file mode 100644
index 00000000..a67b1377
--- /dev/null
+++ b/man/2/math-fp
@@ -0,0 +1,205 @@
+.TH MATH-FP 2
+.SH NAME
+math-fp \- floating point
+.SH SYNOPSIS
+.EX
+include "math.m";
+math := load Math Math->PATH;
+
+Infinity, NaN, MachEps, Pi, Degree: real;
+INVAL, ZDIV, OVFL, UNFL, INEX: int;
+RND_NR, RND_NINF, RND_PINF, RND_Z, RND_MASK: int;
+
+getFPcontrol, getFPstatus: fn(): int;
+FPcontrol, FPstatus: fn(r, mask: int): int;
+ilogb: fn(x: real): int;
+scalbn: fn(x: real, n: int): real;
+copysign: fn(x, s: real): real;
+finite, isnan: fn(x: real): int;
+nextafter: fn(x, y: real): real;
+
+fdim, fmin, fmax: fn(x, y: real): real;
+fabs: fn(x: real): real;
+ceil, floor: fn(x: real): real;
+remainder: fn(x, p: real): real;
+fmod: fn(x, y: real): real;
+modf: fn(x: real): (int,real);
+rint: fn(x: real): real;
+.EE
+.SH DESCRIPTION
+These constants and functions provide control over rounding modes,
+exceptions, and other properties of floating point arithmetic.
+.PP
+.B Infinity
+and
+.B NaN
+are constants containing
+the positive infinity and quiet not-a-number values
+of the IEEE binary floating point standard, double precision.
+.B MachEps
+is 2\u\s-2-52\s0\d, the smallest
+.I e
+such that 1+\f2e\f1 is not equal to 1.
+.B Pi
+is the nearest machine number to the infinitely precise value.
+.B Degree
+is
+.BR Pi/ 180.
+.PP
+Each thread has a floating point control word (governing rounding mode and
+whether a particular floating point exception causes a trap)
+and a floating point status word (storing accumulated exception flags).
+The functions
+.B FPcontrol
+and
+.B FPstatus
+copy bits to the control or status word,
+in positions specified by a mask, returning the previous values of the bits
+specified in the mask.
+The functions
+.B getFPcontrol
+and
+.B getFPstatus
+return the words unchanged.
+.PP
+.BR INVAL ,
+.BR ZDIV ,
+.BR OVFL ,
+.BR UNFL ,
+and
+.B INEX
+are non-overlapping single-bit masks
+used to compose arguments or return values.
+They stand for the five IEEE exceptions:
+`invalid operation' (0/0,0+NaN,Infinity-Infinity,sqrt(-1)),
+`division by zero' (1/0), `overflow' (1.8e308), `underflow' (1.1e-308),
+and `inexact' (.3*.3).
+.PP
+.BR RND_NR ,
+.BR RND_NINF ,
+.BR RND_PINF ,
+and
+.BR RND_Z
+are distinct bit patterns
+for `round to nearest even', `round toward negative infinity',
+`round toward infinity', and `round toward 0',
+any of which can be set or extracted from the floating point control
+word using
+.BR RND_MASK .
+For example,
+.B FPcontrol(0,
+.B UNFL)
+makes underflow silent;
+.B FPstatus(0,
+.B INEX)
+checks and clears the inexact flag; and
+.B FPcontrol(RND_PINF,
+.B RND_MASK)
+sets directed rounding.
+.PP
+By default,
+.B INEX
+is quiet,
+.BR OVFL ,
+.BR UNFL ,
+and
+.B ZDIV
+are fatal,
+and rounding is to nearest even.
+Limbo modules are
+entitled to assume this, and if they wish to use quiet
+underflow, overflow, or zero-divide, they must either
+set and restore the control register or clearly document that
+their caller must do so.
+.PP
+The
+.B ilogb
+function
+returns the nearest integral logarithm base 2 of the absolute value of
+.IR x:
+for positive finite
+.IR x ,
+1 \(<=
+.IB x *2\u-\s-2ilogb( x )\s0\d
+< 2,
+and
+.BI ilogb(- x )
+.B =
+.BI ilogb( x )\f1.
+.BI Scalbn( x , n )
+is a scaled power of two:
+.IB x *2\u\s-2n\s0\d\f1.
+.BI Copysign( x , s )
+has the magnitude of
+.I x
+and the
+sign bit of
+.IR s .
+.BI Nextafter( x , y )
+is the machine number nearest x closer to y.
+Finally,
+.BI finite( x )
+is 0 if
+.I x
+is
+.B Nan
+or
+.B Infinity,
+1 otherwise, and
+.BI isnan( x )
+is 1 if
+.I x
+is
+.B Nan
+and 0 otherwise.
+.PP
+The function
+.BI fdim( x , y)
+=
+.IB x - y
+if
+.I x
+is greater than
+.IR y ,
+otherwise it is 0.
+The functions
+.BR fmin ,
+.BR fmax ,
+.BR fabs ,
+.BR ceil ,
+and
+.B floor
+are the
+customary minimum,
+maximum,
+absolute value,
+and integer rounding routines.
+.PP
+There are two functions for computing the modulus:
+.BI fmod( x , y )
+is the function defined by the C standard which gives the value
+.IB x - i*y
+for some
+.I i
+such that the remainder has the sign of
+.I x
+and magnitude less than the magnitude of
+.IR y ,
+while
+.BI remainder( x , y )
+is the function defined by the IEEE standard
+which gives a remainder of magnitude no more than half the
+magnitude of
+.IR y .
+The function
+.BI modf( x )
+breaks
+.I x
+into integer and fractional parts returned in a tuple, and
+.B rint
+rounds to an integer, following the
+rounding mode specified in the floating point control word.
+.SH SOURCE
+.B /libinterp/math.c
+.SH SEE ALSO
+.IR math-intro (2)
diff --git a/man/2/math-linalg b/man/2/math-linalg
new file mode 100644
index 00000000..5a39e838
--- /dev/null
+++ b/man/2/math-linalg
@@ -0,0 +1,146 @@
+.TH MATH-LINALG 2
+.SH NAME
+Math: dot, norm1, norm2, iamax, gemm, sort \- linear algebra primitives
+.SH SYNOPSIS
+.EX
+include "math.m";
+math := load Math Math->PATH;
+
+dot: fn(x, y: array of real): real;
+norm1, norm2: fn(x: array of real): real;
+iamax: fn(x: array of real): int;
+gemm: fn(transa, transb: int, # upper case N or T
+ m, n, k: int, alpha: real,
+ a: array of real, lda: int,
+ b: array of real, ldb: int, beta: real,
+ c: array of real, ldc: int);
+
+sort: fn(x: array of real, p: array of int);
+.EE
+.SH DESCRIPTION
+These routines implement the basic functions of linear algebra.
+The standard vector inner product and norms are defined as follows:
+.IP
+.BI dot( "x , y" )
+=
+.BI sum( x [ i ]* y\fP[\fPi\fP])
+.IP
+.BI norm1( x )
+=
+.BI sum(fabs( x [ i\ \f5]))
+.IP
+.BI norm2( x )
+=
+.BI sqrt(dot( "x , x" ))
+.PP
+For the infinity norm, the function
+iamax(x)
+computes an integer
+.I i
+such that
+.BI fabs( x [ i ])
+is maximal.
+These are all standard BLAS (basic linear algebra subroutines)
+except that in Inferno they apply only to contiguous (unit stride)
+vectors.
+.PP
+We assume the convention that matrices are represented as
+singly-subscripted arrays with Fortran storage order.
+So for an
+.I m
+by
+.I n
+matrix
+.I A
+we use loops
+with
+.BI 0\(<= i < m
+and
+.BI 0\(<= j < n
+and access
+\f2A\f5[\f2i\f5+\f2m\f5*\f2j\f5]\f1.
+.PP
+Rather than provide the huge number of entry points in BLAS2 and BLAS3,
+Inferno provides the matrix multiply primitive,
+.BR gemm ,
+defined by
+.PP
+.EX
+ \f2A\fP = \f1\(*a\fP*\f2A\fP\f1'\fP*\f2B\fP\f1'\fP + \f1\(*b\fP*\f2C\fP
+.EE
+.PP
+where the apostrophes indicate an optional transposition.
+As shown by the
+work of Kagstrom, Ling, and Van Loan, the other BLAS functionality can
+be built efficiently on top of
+.BR gemm .
+.PP
+Matrix
+.IR a '
+is
+.I m
+by
+.IR k ,
+matrix
+.IR b '
+is
+.I k
+by
+.IR n ,
+and matrix
+.I c
+is
+.I m
+by
+.IR n .
+Here
+.IR a '
+means
+.I a
+.RI ( a ')
+if
+.I transa
+is the constant
+.B 'N'
+.RB ( 'T' ),
+and similarly for
+.IR b '.
+The sizes
+.IR m ,
+.IR n ,
+and
+.I k
+denote the `active' part of
+the matrix.
+The parameters
+.IR lda ,
+.IR ldb ,
+and
+.I ldc
+denote the `leading dimension'
+or size for purposes of indexing.
+So to loop over
+.I c
+use loops
+with
+.BI 0\(<= i < m
+and
+.BI 0\(<= j < n
+and access
+\f2a\f5[\f2i\f5+\f2ldc\f5*\f2j\f5]\f1.
+.PP
+The sorting function
+.BI sort( x , p )
+updates a 0-origin permutation
+.I p
+so that
+.IB x [ p [ i ]]
+\(<=
+.IB x [ p [ i +1]]\f1,
+leaving
+.I x
+unchanged.
+.SH SOURCE
+.B /libinterp/math.c
+.SH SEE ALSO
+.IR math-intro (2)
diff --git a/man/2/mpeg b/man/2/mpeg
new file mode 100644
index 00000000..1691a713
--- /dev/null
+++ b/man/2/mpeg
@@ -0,0 +1,74 @@
+.TH MPEG 2
+.SH NAME
+mpeg \- interface to the mpeg device driver
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "mpeg.m";
+mpeg:= load Mpeg Mpeg->PATH;
+
+play: fn(d: ref Display,
+ w: ref Image,
+ dopaint: int,
+ r: Rect,
+ file: string,
+ notify: chan of string): string;
+ctl: fn(msg: string): int;
+keycolor: fn(d: ref Display): ref Image;
+.EE
+.SH DESCRIPTION
+.B Mpeg
+provides a primitive interface to the
+.IR mpeg (3)
+device.
+.PP
+.B Play
+plays the specified MPEG
+.I file
+in rectangle
+.I r
+within window
+.I w
+on display
+.IR d .
+The
+.I dopaint
+flag specifies whether, before playing the movie, to paint the rectangle with the chroma key colour of the device.
+.PP
+.I Notify
+is a channel upon which to receive errors and status. If
+.I notify
+is
+.BR nil ,
+.B play
+runs synchronously, returning the empty string ("") when the movie completes, or a description of any error.
+If
+.I notify
+is not
+.BR nil ,
+.B play
+spawns an asynchronous process to play the movie and returns the empty string immediately; the process returns the status on the
+.I notify
+channel when the movie completes.
+.PP
+.B Ctl
+writes
+.IR msg ,
+the string given as an argument, to the MPEG control interface
+.BR /dev/mpegctl .
+.PP
+.B Keycolor
+uses the
+.B Display
+.I d
+to create a single-pixel, replicated off screen
+.B Image
+of colour
+.B Chroma
+.RB ( 16r05 ).
+.SH FILES
+.B /dev/mpeg
+.br
+.B /dev/mpegctl
+.SH SOURCE
+.B /appl/lib/mpeg.b
diff --git a/man/2/names b/man/2/names
new file mode 100644
index 00000000..e28abf08
--- /dev/null
+++ b/man/2/names
@@ -0,0 +1,113 @@
+.TH NAMES 2
+.SH NAME
+Names: basename, cleanname, dirname, elements, isprefix, pathname, relative, rooted \- file name manipulation
+.SH SYNOPSIS
+.EX
+include "names.m";
+names := load Names Names->PATH;
+
+basename: fn(name: string, suffix: string): string;
+cleanname: fn(name: string): string;
+dirname: fn(name: string): string;
+elements: fn(name: string): list of string;
+isprefix: fn(a: string, b: string): int;
+pathname: fn(els: list of string): string;
+relative: fn(name: string, root: string): string;
+rooted: fn(root: string, name: string): string;
+.EE
+.SH DESCRIPTION
+.B Names
+provides operations on file names (path names):
+.TF cleanname
+.PD
+.TP
+.B basename
+Return the trailing component of
+.I name
+(the text after the final
+.LR / ),
+shorn of
+.I suffix
+(which may be null).
+.TP
+.B cleanname
+Return a `cleaner' version of
+.IR name :
+there are no redundant and trailing slashes,
+and directory names
+.L .
+and
+.L ..
+have been interpreted lexically.
+If the result would otherwise be the empty string,
+the name
+.L .
+is returned instead.
+.TP
+.B dirname
+Return the directory component of
+.IR name :
+the string up to but not including the final slash(es).
+.TP
+.B elements
+Return a list of the path elements of
+.IR name :
+the words between slashes.
+If
+.I name
+starts with a
+.LR / ,
+the head of the list will be the string
+\&\f5"/"\fP
+but otherwise slashes do not appear.
+.TP
+.B pathname
+Return a path name formed from a list of elements as produced by
+.BR elements .
+.TP
+.B isprefix
+Return true iff path name
+.I a
+is a prefix of path name
+.IR b .
+.TP
+.B relative
+If
+.I name
+is
+.IB root / X
+for some
+.IR X ,
+return
+.IR X ;
+otherwise return
+.I name
+unchanged.
+.TP
+.B rooted
+Return the path name for
+.I name
+relative to a given
+.I root
+directory (either name may be nil).
+If
+.I name
+itself starts with
+.L /
+or
+.LR # ,
+the result is
+.IR name ;
+otherwise it is
+.IB root / name.
+.PP
+See
+.IR sys-intro (2)
+for details of file name syntax and its interpretation.
+.SH SOURCE
+.B /appl/lib/names.b
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-fd2path (2),
+.IR workdir (2)
+
diff --git a/man/2/newns b/man/2/newns
new file mode 100644
index 00000000..4b151558
--- /dev/null
+++ b/man/2/newns
@@ -0,0 +1,40 @@
+.TH NEWNS 2
+.SH NAME
+newns \- build a new name space from a description file
+.SH SYNOPSIS
+.EX
+include "newns.m";
+ns := load Newns Newns->PATH;
+
+newns: fn(user: string, nsfile: string): string;
+.EE
+.SH DESCRIPTION
+.B Newns
+reads file
+.I nsfile
+and builds a new name space based on the commands it contains.
+The file has the format defined by
+.IR namespace (6).
+If
+.I nsfile
+is
+.B nil
+or empty, then
+.B newns
+attempts to read file the file
+.BR namespace .
+.SH SOURCE
+.B /appl/lib/newns.b
+.SH SEE ALSO
+.IR sys-bind (2),
+.IR sys-chdir (2),
+.IR sys-pctl (2),
+.IR namespace (6)
+.SH BUGS
+The
+.I user
+string is currently ignored:
+use
+.B nil
+or the current user name
+.RB ( /dev/user ).
diff --git a/man/2/palmfile b/man/2/palmfile
new file mode 100644
index 00000000..81d62fc2
--- /dev/null
+++ b/man/2/palmfile
@@ -0,0 +1,542 @@
+.TH PALMFILE 2
+.SH NAME
+Palmfile: Categories, DBInfo, Doc, Entry, Pfile, Record \- read Palmâ„¢ file formats
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+include "palmfile.m";
+
+palmfile := load Palmfile Palmfile->PATH;
+
+Pfile: adt {
+ fname: string;
+
+ appinfo: array of byte;
+ sortinfo: array of int;
+
+ entries: array of ref Entry;
+
+ open: fn(name: string, mode: int): (ref Pfile, string);
+. # create: fn(nil: string, mode: int, perm: int, nil: ref DBInfo): ref Pfile;
+ close: fn(pf: self ref Pfile): int;
+ read: fn(pf: self ref Pfile, index: int): (ref Record, string);
+. # append: fn(pf: self ref Pfile, r: ref Record): int;
+ stat: fn(pf: self ref Pfile): ref DBInfo;
+. # wstat: fn(pf: self ref Pfile, nil: ref DBInfo): string;
+. # readid: fn(pf: self ref Pfile, nil: int): (ref Record, string);
+. # setappinfo: fn(pf: self ref Pfile, nil: array of byte);
+. # setsortinfo: fn(pf: self ref Pfile, nil: array of int);
+};
+
+DBInfo: adt {
+ name: string; # database name on Palm
+ attr: int; # file attributes (defined below)
+ dtype: string; # database type (byte[4])
+ version: int; # version of data layout, defined by application
+ creator: string; # creating application (byte[4])
+ ctime: int; # creation time
+ mtime: int; # modification time
+ btime: int; # last backup
+ modno: int; # modification number
+ uidseed: int; # unique record ID seed
+
+ new: fn(name: string, attr: int, dtype: string,
+ version: int, creator: string): ref DBInfo;
+};
+
+Entry: adt {
+ id: int; # resource: id; record: unique ID
+ offset: int; # offset in file
+ size: int; # size in bytes
+ name: int; # resource entry only
+ attr: int; # record entry only
+};
+
+Record: adt {
+ id: int; # resource: ID; data: unique record ID
+ index: int; # record index (origin 0)
+ name: int; # byte[4]: resource record only
+ attr: int; # attributes, defined below, data record only
+ cat: int; # category, data record only
+ data: array of byte; # content of record
+
+. # new: fn(size: int): ref Record;
+};
+
+Categories: adt {
+ renamed: int; # which categories have been renamed
+ labels: array of string; # category names
+ uids: array of int; # corresponding unique IDs
+ lastuid: int; # last unique ID assigned
+ appdata: array of byte; # remaining application-specific data
+
+ new: fn(labels: array of string): ref Categories;
+ unpack: fn(a: array of byte): ref Categories;
+ pack: fn(c: self ref Categories): array of byte;
+};
+
+Doc: adt {
+ version: int;
+ length: int; # uncompressed
+ nrec: int; # text records only
+ recsize: int; # uncompressed
+ position: int;
+ sizes: array of int; # sizes of uncompressed records
+
+ open: fn(file: ref Pfile): (ref Doc, string);
+ read: fn(doc: self ref Doc, i: int): (string, string);
+ iscompressed: fn(doc: self ref Doc): int;
+ unpacktext: fn(doc: self ref Doc, a: array of byte):
+ (string, string);
+ textlength: fn(doc: self ref Doc, a: array of byte): int;
+};
+
+init: fn(): string;
+
+filename: fn(s: string): string;
+dbname: fn(s: string): string;
+
+gets: fn(a: array of byte): string;
+puts: fn(a: array of byte, s: string);
+get2: fn(a: array of byte): int;
+get3: fn(a: array of byte): int;
+get4: fn(a: array of byte): int;
+put2: fn(a: array of byte, v: int);
+put3: fn(a: array of byte, v: int);
+put4: fn(a: array of byte, v: int);
+.EE
+.SH DESCRIPTION
+.B Palmfile
+provides read-only access to files in the Palmâ„¢ database and document formats.
+It currently handles three types of files:
+Palm Database
+.RB ( .pdb )
+files, which store data for applications;
+Palm Resource
+.RB ( .prc )
+files, which store code resources and user interface resource elements;
+and
+Palm Doc
+.RB ( .doc )
+files, which store compressed documents for the Palm document and e-book readers.
+Database and resource files have a similar structure, with slight differences
+in representation, and differing mainly in how the contents are used.
+.PP
+.B Init
+must be called before any other function in the file.
+It returns a diagnostic if it cannot initialise the module.
+.PP
+.B Pfile
+represents an open Palm file of any type:
+.TP
+.B open()
+Opens file
+.I name
+with the given
+.I mode
+(which must currently be
+.BR Sys->OREAD )
+and returns a tuple
+.RI ( pf , err ).
+.I Pf
+is a new
+.B Pfile
+instance giving access to the file,
+or nil if the open failed, in which case the
+.I err
+string contains a diagnostic.
+.TP
+.IB pf .close()
+Close the file (needed only when writing to a file is eventually supported).
+.TP
+.IB pf .read( index )
+Returns a tuple
+.RI ( rec,\ err )
+where
+.I rec
+is a
+.B Record
+containing the data of the record
+with the given
+.I index
+(origin 0), or
+nil if no such record index exists or it cannot be read.
+In the latter case,
+.I err
+is a diagnostic string.
+.TP
+.IB pf .stat()
+Return the database information for
+.IR pf .
+.TP
+.B entries
+An array of
+.B Entry
+values (see below), one per record.
+The length of the array is consequently the length of
+the file in records.
+It can be nil or empty.
+.TP
+.B appinfo
+Optional application-specific data (see
+.B Categories
+below).
+.TP
+.B sortinfo
+Optional application-specific data (typically
+an array of record IDs in a chosen sorting order).
+.TP
+.B fname
+File name given to
+.BR Pfile.open .
+.PP
+.B DBInfo
+gives the database information for a file:
+.TF creator
+.PD
+.TP
+.B name
+Database name used on the Palm, maximum of 31 characters.
+.TP
+.B attr
+A bit set of file attributes, containing the following values:
+.RS
+.TF Fappinfodirty
+.PD
+.TP
+.B Fresource
+File is a resource file
+.RB ( .prc )
+not a database file
+.RB ( .pdb ).
+.TP
+.B Fronly
+File is read only.
+.TP
+.B Fappinfodirty
+Application information has changed.
+.TP
+.B Fbackup
+No conduit program exists (the whole file must be backed up).
+.TP
+.B Foverwrite
+Overwrite older copy if present.
+.TP
+.B Freset
+Reset PDA after installing this file.
+.TP
+.B Fprivate
+Don't allow copy of this file to be beamed.
+.RE
+.TP
+.B dtype
+String identifying database type (up to 4 characters).
+It is usually the string
+\f5"appI"\fP for resource files.
+.TP
+.B version
+Identifies the version of the data format (application specific).
+.TP
+.B creator
+String identifying creating application (up to 4 characters).
+.TP
+.B ctime
+File creation time, in seconds from the Inferno epoch (see
+.IR daytime (2)).
+.TP
+.B mtime
+Time file last modified, in seconds from the epoch.
+.TP
+.B btime
+Time file last backed up, in seconds from the epoch.
+.TP
+.B uidseed
+Seed for generating unique record IDs (typically set to 0 for database files,
+always 0 for resource files).
+.TP
+.BI new( name,\ attr,\ dtype,\ creator )
+Return a new
+.B DBInfo
+with the given values.
+.PP
+In some applications, it is useful to use a data base name
+(ie,
+.BR DBInfo.name )
+as a component of an Inferno file name.
+The device allows space and slash characters in names, though,
+which makes it hard to use the name directly.
+.B Filename
+maps each space character
+in
+.I s
+to U+00A0 (unpaddable space)
+and each slash character to U+2215 (`division /'),
+and returns the result.
+.B Dbname
+maps the other way.
+.SS Entries and Records
+Each record in the file is represented by an
+.B Entry
+in memory, which holds the record's essential attributes,
+leaving the data on file.
+The meaning of some of the elements depends on whether
+the file is a data file or a resource file.
+.TF offset
+.PD
+.TP
+.B id
+Resource ID, 16 bits (resource file); unique record ID, 24 bits (data file).
+.TP
+.B offset
+Offset in file, in bytes.
+.TP
+.B size
+Size of record in bytes.
+.TP
+.B name
+Name of the resource (resource record only).
+.TP
+.B attrs
+Record attributes (data record only):
+.RS
+.TF Rarchive
+.PD
+.TP
+.B Rdelete
+Delete the record when file next synchronised.
+.TP
+.B Rdirty
+Record has been modified.
+.TP
+.B Rinuse
+Record in use (not typically used in Inferno).
+.TP
+.B Rsecret
+Record is secret (shown on the device only with use of a password).
+.TP
+.B Rarchive
+Archive this record when file next synchronised.
+.TP
+.B Rmcat
+Mask for the 4-bit category field (in
+.B Entry.attrs
+only).
+.RE
+.PP
+Records read from the file are represented by a
+.B Record
+adt containing its data and associated values.
+Some fields are valid only for particular classes of records.
+.TF index
+.PD
+.TP
+.B id
+Resource or record ID, as for
+.BR Entry .
+.TP
+.B index
+Index (origin 0) of the record in the file.
+.TP
+.B name
+Resource name (resource record only).
+.TP
+.B attr
+Record attributes, as above (data record only).
+.TP
+.B cat
+Record's category ID (data record only).
+.TP
+.B data
+The actual data.
+.SS Application data
+The contents of both the ``application information'' and ``sort information'' sections of the file
+are defined by an application in general.
+Even so, both have conventional uses with many Palm applications.
+The Palm software often assigns data records to particular categories (eg, ``Business'' or ``Personal''),
+and stores up to 16 category names and IDs in the application data in a fixed format
+(possibly followed by further data that is application specific).
+This is represented by an instance of
+.BR Categories ,
+which provides the following:
+.TF renamed
+.PD
+.TP
+.B renamed
+Bit set indicating which categories have been renamed (for category 0, bit
+.BR 1<<0 ,
+for 1, bit
+.BR 1<<1 ,
+and so on).
+.TP
+.B labels
+Array of 16 category labels.
+.TP
+.B uids
+Array of 16 category IDs, each in the range 0 to 255.
+(It is said that the Palm itself assigns 0 to 127 and desktop applications assign 128 to 255.)
+.TP
+.B lastuid
+Last unique category ID assigned.
+.TP
+.B appdata
+Any data that remained after unpacking the category data.
+.TP
+.BI new( labels )
+Return a new
+.B Categories
+value for the given array of
+.IR labels ,
+assigning unique IDs to each in turn, starting from 128.
+There can be at most 16 labels; if there are fewer, the remaining labels will be marked as unused
+(empty strings).
+.TP
+.BI unpack( a )
+Unpack the application data in array
+.I a
+(typically
+.IB pf .appinfo
+for some
+.B Pfile
+.IR pf ),
+returning a reference to a new
+.B Categories
+instance.
+A nil value is returned if the array is too short to hold valid category data.
+.TP
+.IB c .pack()
+Pack
+.I c
+into a form suitable for writing back to a file's application information area.
+.PP
+Binary data in Palm files is typically encoded in big-endian form.
+.B Palmfile
+functions account for that internally, but some Palm applications might use
+big-endian data in their own data records.
+Several functions are therefore provided to decode and encode big-endian data:
+.BI get n
+retrieves an integer from the first
+.I n
+bytes of array
+.IR a ;
+.BI put n
+stores a big-endian representation of the value
+.I v
+in the first
+.I n
+bytes of array
+.IR a .
+.PP
+Strings are stored in fixed-length arrays of bytes, always terminated by a zero byte.
+The character encoding is (apparently) Latin-1 (ISO 8859-1), not UTF-8,
+so functions
+.B gets
+and
+.B puts
+are provided to convert between that representation and a Limbo string.
+.SS Documents
+.B Doc
+provides read-only access to Palm documents and (unencrypted) e-books:
+.TF position
+.PD
+.TP
+.BI open( file )
+Given a
+.B Pfile
+.IR file ,
+return a tuple
+.RI ( doc,\ err )
+where
+.I doc
+is a new
+.B Doc
+instance giving access to the document contents in
+.IR file .
+If an error occurs, in particular if
+.I file
+does not appear to be a valid Palm document,
+.I doc
+is nil and the string
+.I err
+diagnoses the error.
+.TP
+.IB doc .iscompressed()
+Returns true (non-zero) if the document is compressed; returns false (zero) otherwise.
+.TP
+.IB doc .read( i )
+Read text record with index
+.I i
+(origin 0),
+returning a tuple
+.RI ( s,\ err )
+where
+.I s
+is the uncompressed text for record
+.IR i ,
+or nil if the record does not exist (or there is an error reading it).
+On any error,
+.I err
+is a diagnostic string.
+Note that
+.I i
+is an index into the set of text records, and is not an index into the set of all records.
+It must be no greater than
+.IB doc .nrec .
+.IB doc .unpacktext( a )
+Returns a tuple
+.RI ( s,\ err )
+where
+.I s
+is the text in array
+.IR a ,
+after uncompressing if
+.I doc
+contains compressed records.
+Following Palm conventions, the text is assumed to be written in the Latin-1 encoding (ISO-8859-1).
+If it is compressed but the data in
+.I a
+is corrupt (cannot be uncompressed),
+.I s
+is nil and
+.I err
+diagnoses the problem.
+.TP
+.IB doc .textlength( a )
+Returns the number of bytes required to store the text in array
+.I a
+once it has been uncompressed (if necessary).
+.TP
+.B version
+The document's version number.
+.TP
+.B length
+The length of the whole document in bytes, when uncompressed.
+.TP
+.B nrec
+Number of text records in the document.
+.TP
+.B recsize
+Size of uncompressed text records.
+.TP
+.B position
+Possibly records the position where reading last stopped.
+.TP
+.B sizes
+Array giving sizes of all text records, once uncompressed.
+.PP
+Most document-reading applications require only
+.B Doc.open
+and
+.BR Doc.read ,
+and perhaps
+.BR Doc.length
+to guide the construction of scroll bars (for instance).
+.SH SOURCE
+.B /appl/lib/palmfile.b
+.SH SEE ALSO
+.IR "Palm® File Format Specification" ,
+Gary Hillerson, Palm Inc.,
+Document Number 3008-004,
+1 May 2001.
+. br
+.IR "[Palm®] standard text document file format" ,
+Paul Lucas, 18 August 1998.
diff --git a/man/2/plumbmsg b/man/2/plumbmsg
new file mode 100644
index 00000000..9eba8c5c
--- /dev/null
+++ b/man/2/plumbmsg
@@ -0,0 +1,291 @@
+.TH PLUMBMSG 2
+.SH NAME
+plumbmsg \- plumbing message module
+.SH SYNOPSIS
+.EX
+include "plumbmsg.m";
+plumbmsg := load Plumbmsg Plumbmsg->PATH;
+Msg: import plumbmsg;
+
+Msg: adt
+{
+ src: string;
+ dst: string;
+ dir: string;
+ kind: string;
+ attr: string;
+ data: array of byte;
+ # used by applications
+ send: fn(msg: self ref Msg): int;
+ recv: fn(): ref Msg;
+ # used by plumb and send, recv
+ pack: fn(msg: self ref Msg): array of byte;
+ unpack: fn(b: array of byte): ref Msg;
+};
+
+Attr: adt
+{
+ name: string;
+ val: string;
+};
+
+init: fn(willsend: int, rcvport: string, maxdata: int): int;
+shutdown: fn();
+string2attrs: fn(s: string): list of ref Attr;
+attrs2string: fn(l: list of ref Attr): string;
+lookup: fn(attrs: list of ref Attr, name: string): (int, string);
+.EE
+.SH DESCRIPTION
+.B Plumbmsg
+is an interface for message-passing between applications
+via the
+.IR plumber (8).
+It allows applications to receive messages from the plumber on a logical input port,
+and send messages to other applications via the plumber.
+.PP
+.B Init
+must be called once when the application starts, to
+set up its plumbing connections.
+Applications can choose to send messages, receive them, or do both.
+Note that
+the plumber must be running before any of these functions are useful.
+Normally, that is done by the window system's initialisation procedure,
+but in specialised systems, plumbing can be used for attribute-oriented
+communication even without a window system.
+.PP
+If the application will be sending
+messages via the plumber, the value
+.I willsend
+must be non-zero, and
+.B init
+will open an appropriate channel to the plumber; if the application
+will not send messages, the value should be zero.
+.PP
+If the application is prepared to receive messages, the parameter
+.I rcvport
+names its logical input port,
+which must also be known to the plumber (ie, it must
+be named as a possible destination in
+.IR plumbing (6));
+.B init
+will open an appropriate channel to receive messages from the plumber.
+The parameter
+.I maxdata
+gives the size in bytes of the largest message
+the application is prepared to receive.
+Applications that only send messages set
+.I rcvport
+to nil.
+.PP
+.B Init
+returns returns -1 if for any reason either connection cannot be set up correctly,
+in particular if the plumber is not running or the input port is unknown.
+Otherwise it returns a non-negative value.
+.PP
+The following program fragment establishes input and output plumbing
+for an application `edit':
+.IP
+.EX
+plumbed := 0;
+plumbmsg = load Plumbmsg Plumbmsg->PATH;
+if(plumbmsg->init(1, "edit", 1000) >= 0)
+ plumbed = 1;
+.EE
+.PP
+The variable
+.B plumbed
+is set to allow the application to disable its plumbing user interface
+(and not attempt to send messages) if initialisation fails.
+.PP
+The
+.B Msg
+adt
+encapsulates the message data routed between applications and
+provides member functions to send and receive them.
+Its components are used as follows:
+.TF dataxx
+.PD
+.TP
+.B src
+The name of the program generating the message.
+.TP
+.B dst
+The output port to which the plumber should route the message.
+In practice, destination is often left empty, and
+the destination port will be determined by
+the plumber applying the automatic routing rules
+(cf.
+.IR plumbing (6))
+.TP
+.B dir
+The directory in which to interpret the data (eg, if the data is a local file name).
+.TP
+.B kind
+The format of the data.
+Currently,
+.RB ` text '
+is the only type that applications understand, but the plumbing system
+can route any kind of data.
+.TP
+.B attr
+A string containing
+.IB name = value
+pairs (eg,
+.BR click=7 ),
+separated by tabs.
+Normally the value should be created using
+.B attrs2string
+and parsed using
+.BR string2attrs ,
+described below.
+.TP
+.B data
+The message to be conveyed.
+If
+.B kind
+is
+.BR text ,
+and the message is a string
+.IR s ,
+.B data
+will be
+.RB ` array
+.B of
+.BI byte " s'"
+(ie, its UTF encoding).
+.PD
+.PP
+Plumbing messages are created directly using Limbo's
+.B ref
+operator, giving the desired value to each field.
+For example:
+.IP
+.EX
+ msg := ref Msg(
+ "WmSh",
+ "",
+ workdir->init(),
+ "text",
+ attr,
+ array of byte text);
+.EE
+.PP
+The plumbing messages are exchanged with
+the plumber
+using two member functions:
+.TP
+.IB m .send( msg )
+Writes a plumbing message to the
+plumber.
+It returns the number of bytes written (the result of
+.I write
+in
+.IR sys-read (2)
+which does the writing).
+It returns -1 if the plumber cannot route the message.
+.TP
+.B Msg.recv()
+Reads a plumbing message from the file
+representing the application's input port,
+previously opened by
+.BR init .
+It waits for a message, and returns a reference to a
+.B Msg
+that contains the message data.
+.PP
+.B Shutdown
+sends a message to the plumber
+that shuts down plumbing for the application's input port
+.IR rcvport .
+An application
+.I must
+call it before it exits if it has an active input port.
+.PP
+.B String2attrs
+takes a string containing a tab-separated list of attribute pairs and returns a list of references to
+.B Attr
+adts.
+.PP
+.B Attr2string
+converts a list of references to
+.B Attr
+adts into a string of the form
+.IB name = value name = value
+\&. . . .
+The
+.IB name = value
+pairs are separated by a single tab.
+.PP
+.B Lookup
+searches
+.I attrs
+for an attribute
+.IR name ,
+and if found, returns the tuple
+.BI (1, value ) .
+If
+.I name
+is not found,
+.B lookup
+returns
+.BR "(0, nil)" .
+.SS Packed message format
+The format of plumbing messages as transmitted, and member functions
+that encapsulate it, are documented here for completeness, and in case
+the details are useful in interpreting plumbing messages outside the Inferno environment.
+.PP
+Plumbing messages have a fixed structure: five lines of text
+giving UTF representations of the
+corresponding fields of
+.BR Msg ,
+then a line giving the length of
+.B data
+in decimal,
+followed by the bytes of
+.BR data :
+.IP
+.nf
+.IB source \en
+.IB destination \en
+.IB directory \en
+.IB kind \en
+.IB attributes \en
+.IB n \en
+.IB n " bytes"
+.fi
+.PP
+The details are encapsulated in two functions:
+.TP
+.IB m .pack()
+.B Pack
+packs the contents
+.B Msg
+.I m
+into an array of byte for subsequent transmission using
+.I write
+(see
+.IR sys-read (2)).
+.TP
+.BI Msg.unpack( b )
+Unpack unpacks an array of byte
+.I b
+to form a copy of the original
+.BR Msg ,
+which it returns.
+.SH FILES
+.TF /chan/plumb.rcvport
+.TP
+.B /chan/plumb.input
+file to send messages to the plumber
+.TP
+.BI /chan/plumb. rcvport
+file to receive messages routed to the logical name
+.I rcvport
+.SH SOURCE
+.B /appl/lib/plumbmsg.b
+.SH BUGS
+.I Shutdown
+should not be needed:
+the
+.IR plumber (8),
+as a file server, must know that a particular client has vanished.
diff --git a/man/2/pop3 b/man/2/pop3
new file mode 100644
index 00000000..6288bc2a
--- /dev/null
+++ b/man/2/pop3
@@ -0,0 +1,85 @@
+.TH POP3 2
+.SH NAME
+pop3 \- Post Office Protocol
+.SH SYNOPSIS
+.EX
+include "pop3.m";
+pop3 := load Pop3 Pop3->PATH;
+
+open: fn(user, password, server: string): (int, string);
+stat: fn(): (int, string, int, int);
+msglist: fn(): (int, string, list of (int, int));
+msgnolist: fn(): (int, string, list of int);
+top: fn(m: int): (int, string, string);
+get: fn(m: int): (int, string, string);
+delete: fn(m: int): (int, string);
+close: fn(): (int, string);
+.EE
+.SH DESCRIPTION
+.B Pop3
+provides an interface to the Post Office Protocol
+POP3 through a set of functions.
+.PP
+.B Open
+opens a connection to a POP3
+.IR server ,
+logging in as the specified
+.IR user
+with the given
+.IR password .
+If
+.I server
+is
+.IR nil ,
+.B open
+uses
+.BR $POPSERVER ,
+and if that is not defined, it
+uses
+.BR $MAILSERVER ,
+the default mail server, if set up in
+.LR /services/cs/db
+(see
+.IR db (6)).
+The remaining functions assume a successfully opened connection.
+.PP
+.B Stat
+returns the status of the user's mailbox.
+The third element of its return tuple is the number of
+messages and the fourth is the total number of bytes in the messages.
+.PP
+.B Msglist
+lists the user's mailbox. The third element in its return tuple gives a list of pairs of numbers
+comprising
+.RI ( "message number, bytes in message" ).
+.PP
+.B Msgnolist
+lists the user's mailbox as above but omits the bytes in each message.
+.PP
+.B Top
+returns the top of message
+.IR m .
+.PP
+.B Get
+returns the full text of message
+.IR m .
+.PP
+.B Delete
+deletes message
+.IR m .
+.PP
+.B Close
+closes the connection to the POP3 server.
+Note that subsequent reconnections to the server
+may renumber the messages in the mail box and will certainly do so if the last connection
+deleted messages.
+.PP
+Note also that a connection is static in the sense that mail messages entering the server during
+a connection will not be accessible. A reconnection is needed to see newly arrived messages.
+.SH SOURCE
+.B /appl/lib/pop3.b
+.SH SEE ALSO
+.IR acme (1)
+.SH DIAGNOSTICS
+All these functions return -1
+and an error message on failure as the first two entries in their return tuples.
diff --git a/man/2/popup b/man/2/popup
new file mode 100644
index 00000000..731ced36
--- /dev/null
+++ b/man/2/popup
@@ -0,0 +1,102 @@
+.TH POPUP 2
+.SH NAME
+Popup: mkbutton, changebutton, event, add \- popup list box pseudo-widget
+.SH SYNOPSIS
+.EX
+include "popup.m";
+popup := load Popup Popup->PATH;
+
+init: fn();
+mkbutton: fn(win: ref Tk->Toplevel, name: string,
+ items: array of string, n: int): chan of string;
+changebutton: fn(win: ref Tk->Toplevel, name: string,
+ items: array of string, n: int);
+event: fn(win: ref Tk->Toplevel, e: string,
+ items: array of string): int;
+add: fn(items: array of string, s: string):
+ (array of string, int);
+.EE
+.SH DESCRIPTION
+.B Popup
+implements popup list boxes as Tk pseudo-widgets.
+This module has since been superseded by
+.IR choicebutton (2)
+in Tk itself, but remains for the moment for compatibility.
+.PP
+.B Init
+must be called once to initialise the module.
+.PP
+.B Mkbutton
+creates a new button
+.IR name ,
+in Tk toplevel
+.IR win .
+It returns a channel on which it delivers events (see
+.BR event ,
+below).
+Once created,
+.I name
+can be packed like any other Tk widget.
+When the button is pressed with button 1,
+a menu pops up offering a choice from the given
+.IR items .
+The value
+.I n
+is the index in
+.I items
+of the button's initial value.
+The current choice is always displayed in the button.
+If
+.I items
+is nil or an empty array, the string
+.RB ` ----- '
+is displayed instead.
+.PP
+Having created a popup button, the application must receive values on
+the channel returned by
+.B mkbutton
+and pass each value it receives to
+.BR event
+(as parameter
+.IR e ).
+(Typically the application will receive on the channel in an
+.B alt
+statement that watches other channels too.)
+.B Event
+returns the result of a selection, or -1 if no selection was made.
+In either case, the text of the button
+.I name
+will reflect the currently active selection
+(the application can fetch it using
+.RB ` cget\ -text ').
+The
+.I items
+parameter must match that given to
+.B mkbutton
+(or most recently given to
+.BR changebutton ).
+.PP
+.B Changebutton
+changes the list of
+.I items
+in an existing popup button
+.IR name ,
+and sets its initial selection to the item with index
+.IR n .
+.PP
+.B Add
+adds string
+.I s
+to the array
+.IR items ,
+if it is not already there,
+and in either case returns the resulting new array and
+the index of
+.I s
+therein.
+It is useful for calculating a list of items dynamically.
+.SH SOURCE
+.B /appl/lib/popup.b
+.SH SEE ALSO
+.IR tabs (2),
+.IR tk (2)
diff --git a/man/2/prefab-0intro b/man/2/prefab-0intro
new file mode 100644
index 00000000..4d0d1776
--- /dev/null
+++ b/man/2/prefab-0intro
@@ -0,0 +1,75 @@
+.TH PREFAB-INTRO 2
+.SH NAME
+Prefab: intro \- Interactive TV tookit
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "prefab.m";
+prefab := load Prefab Prefab->PATH;
+.EE
+.SH DESCRIPTION
+The
+.B Prefab
+module contains components for building graphics objects suitable for
+Interactive Television (ITV) applications using infrared remote controls.
+Using the
+.B Draw
+module's operations
+for simple text and images
+(see
+.IR draw-intro (2)),
+the toolkit can group individual items,
+treat those groups as units, and then activate the
+items on command.
+The other user interface toolkit,
+.IR tk (2),
+provides facilities for keyboard- and mouse-driven applications.
+.PP
+The objects on the screen are of type
+.BR Compound ,
+each of which occupies a unique window on the
+display and contains objects of type
+.BR Element .
+An
+.B Element
+may be a single object or a list of further
+.BR Elements ,
+to build hierarchically structured components.
+.PP
+.B Prefab
+defines
+.B Environ
+and
+.B Style
+types that specify the appearance of objects: their colours, fonts,
+backgrounds, and so on.
+A
+.B Style
+gives font and colour information, while
+an
+.B Environ
+identifies the
+.B Screen
+upon which the items will be displayed and the
+.B Style
+in which they will be drawn.
+.PP
+Applications should allocate
+.B Elements
+and
+.B Compounds
+only through the appropriate member functions, as described in the corresponding
+sections of the manual.
+Items created with regular Limbo
+definitions will not work properly.
+Moreover, except where indicated,
+applications should not modify the data members directly.
+Although the type definitions make data members visible,
+the members should usually be treated as read-only data.
+.SH SOURCE
+.B /libinterp/prefab.c
+.br
+.B /libprefab/*.c
+.SH SEE ALSO
+.IR draw-intro (2),
+.IR ir (2)
diff --git a/man/2/prefab-compound b/man/2/prefab-compound
new file mode 100644
index 00000000..1ca41778
--- /dev/null
+++ b/man/2/prefab-compound
@@ -0,0 +1,262 @@
+.TH PREFAB-COMPOUND 2
+.SH NAME
+prefab: Compound \- windows for ITV toolkit
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "prefab.m";
+prefab := load Prefab Prefab->PATH;
+
+Compound: adt
+{
+ image: ref Draw->Image;
+ environ: ref Environ;
+ r: Draw->Rect;
+ title: ref Element;
+ contents: ref Element;
+
+ iconbox: fn(env: ref Environ,
+ p: Draw->Point, title: string, icon,
+ mask: ref Draw->Image):
+ ref Compound;
+ textbox: fn(env: ref Environ,
+ r: Draw->Rect, title, text: string):
+ ref Compound;
+ layoutbox: fn(env: ref Environ,
+ r: Draw->Rect, title: string, lay: list of Layout):
+ ref Compound;
+ box: fn(env: ref Environ,
+ p: Draw->Point, title, elist: ref Element):
+ ref Compound;
+ draw: fn(comp: self ref Compound);
+ redraw: fn(comp: self ref Compound, r: Draw->Rect);
+ scroll: fn(comp: self ref Compound, elem: ref Element,
+ d: Draw->Point);
+ show: fn(comp: self ref Compound, elem: ref Element): int;
+ select: fn(comp: self ref Compound,
+ elem: ref Element, i: int, c: chan of int):
+ (int, int, ref Element);
+ tagselect: fn(comp: self ref Compound,
+ elem: ref Element, i: int, c: chan of int):
+ (int, int, ref Element);
+ highlight: fn(comp: self ref Compound,
+ elem: ref Element, on: int);
+};
+.EE
+.SH DESCRIPTION
+.B Compound
+is the data type defining boxes drawn on the screen.
+Each appears in a new window,
+.BR Compound.image ,
+and holds a (possibly
+.BR nil )
+title
+.B Element
+and contents
+.BR Element .
+It occupies the space on
+the screen defined by
+.BR Compound.r .
+Allocating a
+.B Compound
+creates
+a window but does not draw it;
+after the
+.B Compound
+is built,
+.B Compound.draw
+must be called to make it visible.
+Compounds have a border around them, drawn in
+.B Style.edgecolor
+and contain from top to bottom the title (if any),
+a horizontal line (if there is a title), and the contents.
+.PP
+.TP
+.B "Compound.iconbox(\f2env\fP, \f2p\fP, \f2title\fP, \f2icon\fP, \f2mask\fP)
+Creates a
+.B Compound
+whose contents are made by calling
+.B Element.icon
+(see
+.IR prefab-element (2))
+using the
+.I icon
+and
+.IR mask .
+The
+.BR Compound 's
+upper left corner is at
+.IR p ;
+its size is determined by the size of the
+.I icon
+and
+.IR mask .
+.TP
+.B "Compound.textbox(\f2env\fP, \f2r\fP, \f2title\fP, \f2text\fP)
+Creates a
+.B Compound
+whose contents are made by calling
+.B Element.text
+using the supplied
+.IR text .
+As with
+.BR Element.text ,
+the resulting contents
+.B Element
+will be actually a list of text
+.B Elements
+if the text occupies multiple lines on the screen.
+The rectangle behaves as in
+.BR Element.text .
+.TP
+.B "Compound.layoutbox(\f2env\fP, \f2r\fP, \f2title\fP, \f2layoutlist\fP)
+Like
+.BR Compound.textbox ,
+but based on
+.B Element.layout
+rather than
+.BR Element.text .
+.TP
+.B "Compound.box(\f2env\fP, \f2p\fP, \f2title\fP, \f2element\fP)
+Creates a
+.B Compound
+whose contents are made from an existing
+.BR Element .
+To build complex structures, use the
+.BR Element -building
+functions,
+size the
+.B Element
+appropriately,
+and use
+.BR Compound.box .
+The result is positioned with its upper left corner at
+.IR p ,
+and with size determined by that of the
+.BR Element .
+.PP
+However a
+.B Compound
+is built,
+its size computation makes allowance for the border and title.
+Moreover, if the requested size and placement makes part
+appear offscreen, the result may be moved to display it better.
+.TP
+.B Compound.draw()
+This function
+uses the description of the title and contents to paint the
+on-screen image.
+It takes no arguments;
+all the information is included in the description.
+.TP
+.BI Compound.redraw( r )
+Like
+.BR Compound.draw ,
+but restricts the drawing to the specified
+.B Rect
+.IR r .
+.PP
+.TP
+.ft 5
+Compound.select( \f2element\fP, \f2index\fP, \f2c\fP ): (int, int, Element)
+.ft 1
+The channel
+.I c
+is a
+.B chan
+of
+.B int
+connected to an IR remote control interface, typically acquired through the program's
+.B Context
+(see
+.IR draw-context (2)).
+The
+.I element
+is contained in the
+.BR Compound ,
+and may be at any level of its structure.
+It
+is most usefully a list,
+but may be a singleton, in which case it behaves like a list of one element.
+The arrow keys on the remote control scroll through the members of the list,
+using the
+.B Style.highlightcolor
+associated with each member element to indicate selection.
+A
+.B Select
+key on the remote control triggers
+.B select
+to return a tuple
+.BI ( key ,
+.IB index ,
+.IB elem )\f1;
+.I key
+is the key code of the action (here
+.BR Select ),
+.I index
+is the number of the element in the list (ignoring separators),
+and
+.I elem
+is the list member highlighted when the key was hit.
+Any other key returns the same tuple with
+.I index
+\-1 and the value of the key.
+The
+.I elem
+returned is always the most recently highlighted,
+even if the result was not a selection.
+When
+.B select
+returns, it always restores the default appearance of the list.
+.PP
+.TP
+.ft 5
+Compound.tagselect( \f2element\fP, \f2index\fP, \f2c\fP): (int, int, Element)
+.ft 1
+Like
+.BR Compound.select ,
+but rather than selecting among all the elements
+of a list, it selects among only those elements with
+defined
+tags in the
+structure contained within the specified
+.IR element .
+.TP
+\f5Compound.highlight(\fP\f2element\fP\f5,\ \fP\f2on\fP\f5)\fP
+Set the highlighting to be ``on'' or ``off''
+for the
+.I element
+within the compound.
+.TP
+\f5Compound.scroll(\fP\f2element\fP\f5,\ \fP\f2d\fP\f5)\fP
+Like
+.BR Element.scroll :
+scroll the
+.I element
+within the compound.
+The updated image is redrawn after the scrolling.
+.TP
+.ft 5
+\f5Compound.show(\fP\f2element\fP\f5,\ \fP\f2d\fP\f5)\fP
+.ft 1
+Like
+.BR Element.show :
+make sure the
+.I element
+is visible
+within the rectangle of the top-level
+.B Element
+of the
+.BR Compound ,
+that is, in effect call
+.ft 5
+Element.show(Compound.contents, \f2element\fP);
+.ft 1
+.SH SOURCE
+.B /libinterp/prefab.c
+.br
+.B /libprefab/*.c
+.SH SEE ALSO
+.IR prefab-element (2),
+.IR prefab-environ (2),
+.IR prefab-style (2)
diff --git a/man/2/prefab-element b/man/2/prefab-element
new file mode 100644
index 00000000..ef35a604
--- /dev/null
+++ b/man/2/prefab-element
@@ -0,0 +1,468 @@
+.TH PREFAB-ELEMENT 2
+.SH NAME
+prefab: Element \- menu and display elements for ITV toolkit
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "prefab.m";
+prefab := load Prefab Prefab->PATH;
+
+# types of Elements
+EIcon: con 0;
+EText: con 1;
+ETitle: con 2;
+EHorizontal:con 3;
+EVertical: con 4;
+ESeparator: con 5;
+
+# first arg to Element.adjust: size of elements
+Adjpack: con 10; # leave alone, pack tightly
+Adjequal: con 11; # make equal
+Adjfill: con 12; # make equal, filling available space
+
+# second arg: position of element within space
+Adjleft: con 20;
+Adjup: con 20;
+Adjcenter: con 21;
+Adjright: con 22;
+Adjdown: con 22;
+
+Layout: adt
+{
+ font: ref Draw->Font;
+ color: ref Draw->Image;
+ text: string;
+ icon: ref Draw->Image;
+ mask: ref Draw->Image;
+ tag: string;
+};
+
+Element: adt
+{
+ kind: int;
+ r: Draw->Rect;
+ environ:ref Environ;
+ tag: string;
+
+ # different fields defined for different kinds of Elements
+ kids: cyclic list of ref Element; # children of elists
+ str: string; # text in an EText element
+ mask: ref Draw->Image; # part of Eicon, ESeparator
+ image: ref Draw->Image; # part of Eicon, ESeparator, EText, Etitle
+ font: ref Draw->Font; # part of EText, Etitle
+
+ icon: fn(env: ref Environ, r: Draw->Rect,
+ icon, mask: ref Draw->Image):
+ ref Element;
+ text: fn(env: ref Environ, text: string,
+ r: Draw->Rect, kind: int): ref Element;
+ layout: fn(env: ref Environ, lay: list of Layout,
+ r: Draw->Rect, kind: int): ref Element;
+ elist: fn(env: ref Environ, elem: ref Element, kind: int):
+ ref Element;
+ separator: fn(env:ref Environ, r: Draw->Rect,
+ icon, mask: ref Draw->Image): ref Element;
+
+ append: fn(elist: self ref Element, elem: ref Element): int;
+ adjust: fn(elem: self ref Element, equal: int, dir: int);
+ clip: fn(elem: self ref Element, r: Draw->Rect);
+ scroll: fn(elem:self ref Element, d: Draw->Point);
+ translate: fn(elem:self ref Element, d: Draw->Point);
+ show: fn(elist: self ref Element, elem: ref Element): int;
+};
+.EE
+.SH DESCRIPTION
+.B Prefab
+.B Elements
+are the building blocks of the ITV toolkit.
+They represent and display text and pictures that can be grouped in
+arbitrary two-dimensional menus to be walked by the infrared remote control.
+.B Elements
+are packaged within
+.B Compounds
+(see
+.IR prefab-compound (2))
+for display.
+.TF environ
+.PD
+.TP
+.B environ
+This specifies the element's environment.
+.TP
+.B image
+If the element needs an
+.B Image
+object (see
+.B kind
+below), this member specifies it.
+.TP
+.B kind
+The
+.B Prefab
+module defines six
+.B Element
+varieties, each labelled by a defined constant in the
+.B kind
+member.
+.RS
+.TP
+.B EIcon
+An image.
+.TP
+.B EHorizontal
+A horizontal list of elements.
+.TP
+.B ESeparator
+An
+.B Image
+object, like an
+.BR EIcon ,
+but intended to fill space in a list, rather than to serve
+as an element of the list.
+Separators are ignored when selecting or highlighting list elements.
+.TP
+.B EText
+A single line of text.
+Text for this element will be drawn with
+.B Style.textfont
+and
+.BR Style.textcolor .
+.TP
+.B ETitle
+A single line of text, usually giving the title of a
+.B Compound
+object.
+Text for this element will be drawn with
+.B Style.titlefont
+and
+.BR Style.titlecolor .
+.TP
+.B EVertical
+A vertical list of elements.
+.RE
+.TP
+.B mask
+When an element contains an
+.B Image
+object, the
+.B Image.draw
+function will be used to display it on the screen.
+The
+.B mask
+image is used as an argument to
+.BR Image.draw ;
+see
+.IR draw-intro (2)
+for more information.
+.TP
+.B r
+All
+.B Elements
+are rectangular, occupying the
+position on the display specified by
+.BR r.min .
+The size of the element also depends on
+.BR r .
+During creation,
+if the rectangle is degenerate (has
+zero size), the element takes its size from the
+sizes of its components:
+the image size for icons, text width for strings, etc.
+Otherwise, the element's size matches the rectangle.
+.TP
+tag
+The
+.B tag
+of an element serves two purposes: it allows an element to be labelled
+with arbitrary invisible text, and provides a mechanism to control which
+elements of a list may be selected: see the description of
+.B Compound.tagselect
+in
+.IR prefab-compound (2).
+The
+.B tag
+field of an element may be modified freely after the element is created.
+.TP
+.BI icon( env\fP,\fP\ r\fP,\fP\ icon\fP,\fP\ mask )
+Build one
+.B EIcon
+element to be drawn with the
+.I icon
+and
+.IR mask .
+The rectangle,
+.IR r ,
+gives the element's position and size.
+.TP
+.BI text( env\fP,\fP\ text\fP,\fP\ r\fP,\fP\ kind )
+Build a textual element or a list of textual elements.
+.I Kind
+may be
+.B EText
+or
+.BR ETitle ,
+determining the style of the drawn
+.IR text .
+The resulting
+.B Element
+object may be a single element or a
+.B EVertical
+list of the appropriate kind, if the text occupies
+more than one line.
+The text is folded as necessary to
+accommodate the available horizontal space; newlines in
+the text cause line breaks.
+The width of the
+text is determined by
+.IR r ,
+but if
+.I r
+has no width, it will be
+set by the text itself.
+The height of the Element is also
+determined by
+.IR r ;
+again, if the height of
+.I r
+is zero, the Element will be made as tall as necessary (if
+.I r
+is not tall enough, the rest of the text may be made visible
+by calls to
+.BR Element.scroll ).
+Thus one may choose
+a specific size or let the
+.I text
+determine the size by setting
+.I r
+suitably.
+.TP
+.BI layout( env\fP,\fP\ lay\fP,\fP\ r\fP,\fP\ kind )
+Like
+.BR Element.text ,
+but builds a structure using the contents of the list
+.I lay
+of
+.B Layout
+structures. The
+.B Layout
+type
+allows construction of a more general form of textual display
+by providing fine control over the font and colour in which to
+display text and the inclusion of images as textual elements.
+It also allows setting of the
+.B tag
+for each component of the resulting element or list of elements.
+If the
+.B Layout
+has a
+.RB non- nil
+.B image
+field, it is taken as a description of a
+picture to be incorporated in the text as an
+.B EIcon
+element (and the
+.B text
+field is ignored);
+otherwise the
+.B text
+field specifies the text to be drawn in the indicated
+.B font
+and
+.BR color .
+As with
+.BR Element.text ,
+.B Element.layout
+does all the geometry management, text line breaking and folding, etc.
+.TP
+.BI elist( env\fP,\fP\ elem\fP,\fP\ kind )
+Start a list of
+.B Element
+objects.
+The
+.I kind
+may be
+.B Prefab\->EHorizontal
+or
+.BR Prefab\->EVertical ,
+specifying the orientation of the list.
+.I Elem
+will be the first element of the list.
+It may be
+.BR nil ,
+which creates an empty list of the
+requested orientation.
+Subsequent
+.B Element.append
+calls build the list.
+.TP
+.BI separator( env\fP,\fP\ r\fP,\fP\ icon\fP,\fP\ mask )
+Build one
+.B ESeparator
+element to be drawn with the
+.I icon
+and
+.IR mask .
+The rectangle,
+.IR r ,
+gives the element's position and size.
+.TP
+.IB elist .append( elem )
+Append one
+.BR Element ,
+.IR elem ,
+to an existing list,
+.IR elist .
+The new element will appear after those already
+there, either to the right for
+.B EHorizontal
+or below for
+.B EVertical
+lists.
+.TP
+.IB elem .adjust( spacing\fP,\fP\ dir )
+Format the list so its elements abut.
+The list-building functions such as
+.B append
+attempt to build a sensible geometry.
+Alternatively, one can build a list using
+degenerate geometry and then let
+.B adjust
+compute the geometry for the whole list.
+For example, one could place all the elements
+at (0,\ 0) and then call
+.B adjust
+to decide where the elements belong.
+.IP ""
+.I Spacing
+specifies how the elements fit together:
+.RS
+.TP
+.B Adjequal
+Makes them all equal sized in the dimension of the list,
+but only as big as the largest element.
+For example, if the element is a horizontal list,
+all elements will be as wide as the widest item.
+If the list is too big for the allocated space,
+only some will be visible.
+.TP
+.B Adjfill
+Makes them all equal sized in the dimension of the list,
+expanding the elements to fit the space of the list's
+.BR Element.r .
+If the list is too big for the allocated space,
+only some will be visible.
+.TP
+.B Adjpack
+Packs elements as tightly as possible,
+using the ``natural'' size of each element
+and setting their rectangles against one another.
+.RE
+.IP ""
+.I Dir
+controls how each element is placed in its allotted space:
+.RS
+.TP
+.B Adjcenter
+Place each element in the middle of its space.
+.TP
+.B Adjdown
+In a vertical list, move each element to the bottom.
+.TP
+.B Adjleft
+In a horizontal list, move each element to the left.
+.TP
+.B Adjright
+In a horizontal list, move each element to the right.
+.TP
+.B Adjup
+In a vertical list, move each element to the top.
+.RE
+.TP
+.IB elem .clip( r )
+The drawing model for
+.B Element
+objects is that they occupy some space in
+the plane, which may be larger or smaller than the space occupied
+by its constituent text, icons, sub-elements, etc.
+The
+.I clip
+function sets the rectangle of
+.I elem
+to
+.IR r ,
+without changing its internal geometry.
+Any space made newly visible by this
+will be filled in by the list's
+.BR Style.elemcolor .
+For example, if
+.B e
+is an icon element just large enough to display its image,
+.B e.clip(e.r.inset(-2))
+will make a two-pixel-wide border around the icon when
+it is drawn.
+As another example, lists are scrolled by leaving their clip
+rectangle intact while translating the list elements' coordinates.
+.TP
+.IB elem .scroll( d )
+.I D
+is a
+.BR Point ,
+representing a vector;
+.I elem
+is an
+.B Element
+object to be scrolled.
+The
+.B scroll
+function leaves the element's
+.B r
+alone and translates all the constituent pieces of the list by
+.IR d ,
+causing a different portion of
+.I elem
+to be visible in its rectangle.
+.TP
+.IB elem .translate( d )
+Like
+.IB elem .scroll( d ),
+but moves
+.B r
+too, thus translating the entire
+.B Element
+rather than just the visible part within a fixed rectangle.
+.TP
+.IB elist .show( elem )
+.B Show
+does nothing if
+.I elem
+is not a list.
+If it is a list, the list is scrolled
+so
+.IR elem ,
+which must be a member of the list, is visible through
+.IR elist.r .
+.PP
+The geometry of elements and the membership of lists
+may be modified only through
+the provided functions; the Limbo-visible structure is
+(intended to be) read-only.
+Tags, text, and images may be modified freely
+by the application, but at the moment there is no way to recalculate
+the geometry if the components of an
+textual or image icon change size.
+.PP
+.B Element
+objects are never drawn explicitly, nor are they drawn after any
+.B Element
+operation.
+They are made visible only by calls to
+.BR Compound.draw ,
+described by
+.IR prefab-compound (2).
+.SH SOURCE
+.B /libinterp/prefab.c
+.B /libprefab/*.c
+.SH SEE ALSO
+.IR prefab-compound (2)
+.IR prefab-environ (2)
+.IR prefab-style (2)
diff --git a/man/2/prefab-environ b/man/2/prefab-environ
new file mode 100644
index 00000000..0f5a26e9
--- /dev/null
+++ b/man/2/prefab-environ
@@ -0,0 +1,54 @@
+.TH PREFAB-ENVIRON 2
+.SH NAME
+prefab: Environ \- environment for ITV toolkit
+to provide a graphics framework for a collection of items
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "prefab.m";
+prefab := load Prefab Prefab->PATH;
+
+Environ: adt
+{
+ screen: ref Draw->Screen;
+ style: ref Style;
+
+};
+.EE
+.SH DESCRIPTION
+The
+.B Environ
+type collects the
+.B Style
+and
+.B Screen
+types necessary to specify how and where to draw
+.B Prefab
+items.
+.TP 10
+.B screen
+Specifies the
+.B Screen
+upon which items will be displayed.
+.TP
+.B style
+Specifies the
+.B Style
+for items in an environment.
+To draw various items in different fonts or colors,
+the application should associate different
+.B Environ
+objects with the various.
+(But see also the
+.B layout
+functions in
+.IR prefab-element (2)
+and
+.IR prefab-compound (2)).
+.SH SOURCE
+.B /libinterp/prefab.c
+.B /libprefab/*.c
+.SH SEE ALSO
+.IR prefab-intro (2),
+.IR draw-screen (2),
+.IR prefab-style (2)
diff --git a/man/2/prefab-style b/man/2/prefab-style
new file mode 100644
index 00000000..d3b90153
--- /dev/null
+++ b/man/2/prefab-style
@@ -0,0 +1,95 @@
+.TH PREFAB-STYLE 2
+.SH NAME
+prefab: Style \- fonts and colours for ITV toolkit
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "prefab.m";
+prefab := load Prefab Prefab->PATH;
+
+Style: adt
+{
+ titlefont: ref Draw->Font;
+ textfont: ref Draw->Font;
+ elemcolor: ref Draw->Image;
+ edgecolor: ref Draw->Image;
+ titlecolor: ref Draw->Image;
+ textcolor: ref Draw->Image;
+ highlightcolor: ref Draw->Image;
+};
+.EE
+.SH DESCRIPTION
+The
+.B Style
+type collects the font and colour information for an application or a set of
+items within an application. Except when using the
+.B layout
+routines (see
+.IR prefab-compound (2)
+and
+.IR prefab-element (2)),
+the members of a
+.B Style
+are the only way to control the appearance of
+.B Prefab
+items.
+Note that although the
+.RB `... color'
+members of
+.B Style
+in practice often refer to a literal colour (a single replicated pixel of colour),
+they can be any image.
+.PP
+.B Styles
+are allocated by regular Limbo definitions; there is no allocation function.
+All the members of a
+.B Style
+must be defined.
+Although it will not cause errors to modify the members of a
+.B Style
+after it has been created and passed to a
+.B Prefab
+routine, the results may be unpredictable.
+.PP
+.TP 10
+.B edgecolor
+This
+.B Image
+specifies how to draw the edges, or borders, of compounds.
+.TP
+.B elemcolor
+This
+.B Image
+specifies how to draw the base, or background, of elements and compounds.
+.TP
+.B highlightcolor
+This
+.B Image
+specifies the colour to use to highlight a selected element.
+.TP
+.B textcolor
+This
+.B Image
+specifies the colour in which to draw an item's regular text.
+.TP
+.B textfont
+This
+.B Font
+specifies the font in which to draw an item's regular text.
+.TP
+.B titlecolor
+This
+.B Image
+specifies the colour in which to draw an item's title text.
+.TP
+.B titlefont
+This
+.B Font
+specifies the font in which to draw an item's title text.
+.SH SOURCE
+.B /libinterp/prefab.c
+.br
+.B /libprefab/*.c
+.SH SEE ALSO
+.IR prefab-intro (2),
+.IR prefab-environ (2)
diff --git a/man/2/print b/man/2/print
new file mode 100644
index 00000000..575ede77
--- /dev/null
+++ b/man/2/print
@@ -0,0 +1,341 @@
+.TH PRINT 2
+.SH NAME
+Print \- printing system
+.SH SYNOPSIS
+.EX
+include "print.m";
+print := load Print Print->PATH;
+
+Print: module
+{
+ PATH: con "/dis/lib/print/print.dis";
+ CONFIG_PATH: con "/lib/print/";
+
+ init: fn(): int;
+ set_printfd: fn(fd: ref Sys->FD);
+ print_image: fn(p: ref Printer, display: ref Draw->Display, im: ref Draw->Image, pcwidth: int): int;
+ print_textfd: fn(p: ref Printer, fd: ref Sys->FD, ps: real, pr: int, wrap: int): int;
+ get_defprinter: fn(): ref Printer;
+ set_defprinter: fn(p: ref Printer);
+ get_size: fn(p: ref Printer): (int, real, real); # dpi, xinches, yinches
+ get_printers: fn(): list of ref Printer;
+ get_papers: fn(): list of ref Paper;
+ save_settings: fn(): int;
+
+# Printer types
+
+Ptype: adt {
+ name: string;
+ modes: list of ref Pmode;
+ driver: string;
+ hpmapfile: string;
+};
+
+# Paper sizes
+
+Paper: adt {
+ name: string;
+ hpcode: string;
+ width_inches: real;
+ height_inches: real;
+};
+
+
+
+# Print modes
+
+Pmode: adt {
+ name: string;
+ desc: string;
+ resx: int;
+ resy: int;
+ blackdepth: int;
+ coldepth: int;
+ blackresmult: int;
+};
+
+# Print options
+
+Popt: adt {
+ name: string;
+ mode: ref Pmode;
+ paper: ref Paper;
+ orientation: int;
+ duplex: int;
+};
+
+# Printer instance
+
+PORTRAIT: con 0;
+LANDSCAPE: con 1;
+
+DUPLEX_OFF: con 0;
+DUPLEX_LONG: con 1;
+DUPLEX_SHORT: con 2;
+
+Printer: adt {
+ name: string;
+ ptype: ref Ptype;
+ device: string;
+ popt: ref Popt;
+ pdriver: Pdriver;
+};
+
+};
+
+
+Pdriver: module
+{
+ PATHPREFIX: con "/dis/lib/print/";
+ DATAPREFIX: con "/lib/print/";
+
+ init: fn(debug: int);
+ sendimage: fn(p: ref Print->Printer, tfd: ref Sys->FD, display: ref Draw->Display, im: ref Draw->Image, width: int, lmargin: int): int;
+ sendtextfd: fn(p: ref Print->Printer, pfd, tfd: ref Sys->FD, ps: real, pr: int, wrap: int): int;
+ printable_pixels: fn(p: ref Print->Printer): (int, int);
+
+};
+
+
+.EE
+.SH DESCRIPTION
+The
+.I Print
+module provides an interface to one or more printers.
+.SS "The Print module"
+.TP
+.BI init()
+.B Init
+must be called once to initialise the internal state of
+.BR Print .
+.TP
+.BI set_printfd( fd )
+.B set_printfd
+provides a file descriptor to be used for output. By default, output is sent to the file or device
+specified in the
+.B Printer
+adt.
+.TP
+.BI print_image( p, display, im, pcwidth )
+.B print_image
+prints a page containing a single image. The image is centred horizontally, and is scaled up to fill the percentage of the available
+width specified by
+.I pcwidth.
+.TP
+.BI print_textfd( p, fd, ps, pr, wrap )
+.B print_textfd
+prints one or more pages of text on printer
+.I p
+from the file open for reading on
+.I fd.
+The point size is controlled by
+.I p.
+If the printer does not support the specified point size an alternative size will be used.
+A point size of 0.0 can be used to select the printer's default size (usually 12 point).
+If
+.I pr is non-zero, a proportionally-spaced font will be used (if available).
+If
+.I wrap
+is non-zero, lines will be wrapped if they overflow the page width (if this feature is supported by the printer).
+.TP
+.BI get_defprinter( )
+.B get_defprinter
+returns the default printer (in
+.I /lib/print/defprinter).
+.TP
+.BI set_defprinter( p )
+.B set_defprinter
+sets the default printer (in
+.IR /lib/print/defprinter ).
+.TP
+.BI get_size( p )
+.B get_size
+returns the resolution in dots per inch and the total number of pixels available for printing in the x and y direction.
+Before calling this function the
+.I orientation
+should be set if required.
+.TP
+.BI get_printers( )
+.B get_printers
+returns a list of all available printers (in
+.I /lib/print/printer.cfg).
+.TP
+.BI get_papers( )
+.B get_papers
+returns a list of all available paper sizes (in
+.I /lib/print/paper.cfg).
+.SS "Data Structures"
+.TP
+.BI Ptype
+ - specifies a Printer Type, with fields:
+.RS
+.PD
+.TP
+.B name:
+Name used to refer to this printer type
+.TP
+.B desc
+Description
+.TP
+.B modes
+List of supported print modes
+.TP
+.B driver:
+The .dis file specification of the printer driver
+.TP
+.B hpmapfile:
+For HP printers, the name of the color map file
+.RE
+.TP
+.BI Paper
+ - specifies the dimensions of a type of paper
+.RS
+.PD
+.TP
+.B name:
+Name used to refer to this paper size
+.TP
+.B hpcode:
+For HP printers, PCL code used for this paper size
+.TP
+.B width_inches:
+Width of paper in inches
+.TP
+.B height_inches:
+Height of paper in inches
+.RE
+.TP
+.BI Pmode
+ - specifies a print mode
+.RS
+.PD
+.TP
+.B name:
+Name used to refer to this print mode
+.TP
+.B desc:
+Description
+.TP
+.B resx:
+X resolution in dots per inch
+.TP
+.B resx:
+Y resolution in dots per inch
+.TP
+.B blackdepth:
+Depth of black component in bytes
+.TP
+.B coldepth:
+Depth of color components in bytes
+.TP
+.B blackresmult:
+Resolution multiplier of black component (1 means same as base x resolution)
+.RE
+.TP
+.BI Popt
+ - specifies a set of Print Options
+.RS
+.PD
+.TP
+.B name:
+Name of a Printer to which these print options apply
+.TP
+.B mode:
+The name of a print mode
+.TP
+.B paper:
+The name of a paper size
+.TP
+.B orientation:
+Paper orientation - either PORTRAIT or LANDSCAPE
+.TP
+.B duplex (NB DUPLEX IS NOT CURRENTLY SUPPORTED):
+Duplex setting - DUPLEX_OFF or DUPLEX_SHORT or DUPLEX_LONG
+.RE
+.TP
+.BI Printer
+ - specifies a printer instance
+.RS
+.PD
+.TP
+.B name:
+Name used to refer to this printer
+.TP
+.B ptype:
+The printer type
+.TP
+.B device:
+The name of the file to be used for output (eg /dev/lpt1data)
+.TP
+.B popt:
+The print options
+.TP
+.B driver:
+The printer driver module handle
+.RE
+.SS "Configuration Files"
+.PP
+There are configuration files to initialize the Printer Types, Print Modes, Paper Sizes Printers and Print Modes.
+They all have a similar format, with fields corresponding to the relevant adt.
+Here is an extract from the
+.I paper.cfg
+file:
+.PP
+.EX
+A4=
+ hpcode=26
+ width_inches=8.3
+ height_inches=11.7
+A5=
+ hpcode=25
+ width_inches=4.15
+ height_inches=5.85
+.EE
+.PP
+Aliases can also be defined, such as
+.PP
+.EX
+myA4=A4
+.EE
+.PP
+The final configuration file,
+.B defprinter,
+just contains the name of the default printer.
+.SH FILES
+.TP
+.B /lib/print/*.map
+HP color maps.
+.TP
+.BI /lib/print/ptype.cfg
+Print Type configuration file.
+.TP
+.BI /lib/print/pmode.cfg
+Print Mode configuration file.
+.TP
+.BI /lib/print/paper.cfg
+Paper Size configuration file.
+.TP
+.BI /lib/print/printer.cfg
+Printer Instance configuration file.
+.TP
+.BI /lib/print/popts.cfg
+Print options configuration file.
+.TP
+.BI /lib/print/defprinter
+Holds the name of the default printer. Not needed if there is only one printer available.
+.SH SOURCE
+.TF /appl/lib/print/print.b
+.TP
+.B /appl/lib/print/print.b
+Implementation of the
+.B Print
+module.
+.TP
+.B /appl/lib/print/*_driver.b
+Printer-specific driver modules
+.TP
+.B /appl/lib/print/scaler.b
+Scaler module
+.SH SEE ALSO
+.IR draw-image (2),
+.IR image (6)
diff --git a/man/2/prof b/man/2/prof
new file mode 100644
index 00000000..a8d59966
--- /dev/null
+++ b/man/2/prof
@@ -0,0 +1,225 @@
+.TH PROFILE 2
+.SH NAME
+profile \- profiling library
+.SH SYNOPSIS
+.EX
+include "profile.m";
+
+profile := load Profile Profile->PATH;
+
+Range: adt{
+ l: int;
+ u: int;
+ f: int;
+ n: cyclic ref Range;
+};
+
+Funprof: adt{
+ name: string;
+ line: int;
+ count: int;
+ counte: int;
+};
+
+Modprof: adt{
+ name: string;
+ path: string;
+ srcpath: string;
+ rawtab: array of (int, int);
+ linetab: array of int;
+ rngtab: array of ref Range;
+ funtab: array of Funprof;
+ total: int;
+ totals: array of int;
+ covered: int;
+};
+
+Prof: adt{
+ mods: list of Modprof;
+ total: int;
+ totals: array of int;
+};
+
+Coverage: type list of (string, int, list of (list of (int, int, byte), string));
+
+MODULE: con 1; # give stats for each module
+FUNCTION: con 2; # give stats for each function
+LINE: con 4; # give stats for each line
+VERBOSE: con 8; # full stats
+FULLHDR: con 16; # file:lineno: on each line of output
+FREQUENCY: con 32; # show frequency rather than coverage
+
+init: fn(): int;
+profile: fn(m: string): int;
+sample: fn(i: int): int;
+start: fn(): int;
+stop: fn(): int;
+stats: fn() : Prof;
+show: fn(p: Prof, v: int): int;
+end: fn(): int;
+
+# coverage profiling specific functions
+
+cpstart: fn(pid: int): int;
+cpstats: fn(rec: int, v: int): Prof;
+cpfstats: fn(v: int): Prof;
+cpshow: fn(p: Prof, v: int): int;
+
+coverage: fn(p: Prof, v: int): Coverage;
+
+# memory profiling specific functions
+
+memstart: fn(): int;
+memstats: fn(): Prof;
+memshow: fn(p: Prof, v: int): int;
+
+lasterror: fn(): string;
+.EE
+.SH DESCRIPTION
+.B Profile
+provides an interface to the kernel profile device. It contains routines to start and stop
+profiling, to gather profiling statistics and to display these statistics in relation to the
+relevant limbo source code. All of these routines apart from
+.B lasterror
+return a negative integer if an error occurred during their execution. Once this
+happens, a call to
+.B lasterror
+will give the error message.
+.PP
+.B init
+initializes the module and binds the kernel profile device onto the /prof directory.
+It should be called before any other functions in this module.
+.PP
+.B profile
+takes a module name or a path name as its argument and indicates a module to be profiled.
+Repeated calls of this function allow a number of modules to be profiled together.
+In the absence of any calls to this routine, the profile device profiles all modules
+loaded by the kernel.
+.PP
+.B sample
+sets the sampling interval of the profiling. The argument is in ms. The default value
+in the profile device is 100ms.
+.PP
+.B start
+starts profiling.
+.PP
+.B stop
+stops profiling.
+.PP
+.B stats
+returns profiling statistics. It is recommended that this is called once profiling has
+been stopped, otherwise the results may be slightly inaccurate. It returns an adt
+of type
+.B Prof.
+Its first field
+.B mods
+is a list of profile statistics for each module under profile.
+Its second field
+.B total
+is the number of samples made altogether. The statistics for each module are
+represented in the
+.B Modprof
+adt. Its fields are
+.TP 10n
+.B name
+The name of the module.
+.TP 10n
+.B path
+The path of the module's corresponding dis file.
+.TP 10n
+.B srcpath
+The path of the module's corresponding source file.
+.TP 10n
+.B linetab
+The line frequency count table. The number of samples made on a particular line of
+the above source file is found by indexing this table.
+.TP 10n
+.B funtab
+The function frequency count table. This array of
+.B Funprof
+adt gives the name, line number and number of samples made for each function in
+the above source file.
+.TP 10n
+.B total
+The total number of samples made in this module.
+.PP
+.B stats
+will ignore modules if it fails to locate the symbol (.sbl) file for a particular dis file.
+.PP
+.B show
+simply prints out the profile information returned by
+.B stats.
+For each module it will print out either the line number statistics or the function
+statistics or both. The former gives the line number, percentage of time spent on
+this line and the source code for each line in the source file. The latter gives the
+line number, function name and percentage of time spent in this function for each
+function in the source file. The amount of output can be controlled by the second
+argument to
+.B show.
+The following should be ored together in the required combination to get the
+desired effect.
+.PP
+.TP 10n
+.B FUNCTION
+Print the function table.
+.TP 10n
+.B LINE
+Print the line number table.
+.TP 10n
+.B VERBOSE
+Normally lines and functions are not shown if the sample frequency for them is
+zero. This option prevents this.
+.TP 10n
+.B FULLHDR
+Prints the file name as well as the line number in a form that can be selected in
+.B acme
+to show that particular line in a window.
+.PP
+.B show
+will ignore modules if it fails to locate the source (.b) file for a particular dis file.
+.PP
+.B end
+ends the profiling session. This should be called when all statistics have been
+gathered in order to clean up the device profile's data structures.
+.PP
+In order to support coverage profiling as well the following new routines are
+provided.
+.PP
+.B cpstart
+Start coverage profiling on the process whose pid is given.
+.PP
+.B cpstats
+Returns coverage profiling statistics from the profile device. If the first argument is
+true, the raw results will be stored in a profile file whose name is <file>.prf where
+<file> is the prefix of the corresponding dis file.
+.PP
+.B cpfstats
+Returns coverage profiling statistics from any saved profile files.
+.PP
+.B cpshow
+Shows the coverage profiling statistics.
+.PP
+.B coverage
+Given the coverage profiler statistics this returns the list of modules profiled. Each module
+has a name, a boolean indicating whether all instructions in the module were executed and a
+list of lines. Each line consists of a list of ranges and the source code.
+The list of ranges contains the character positions on the line of code corresponding to instructions that were not executed and an indicator of whether
+partial execution was performed.
+.PP
+For the further support of memory profiling the following routines are available.
+.PP
+.B memstart
+Start memory profiling.
+.PP
+.B memstats
+Return the memory profile statisics.
+.PP
+.B memshow
+Send memory profile statistics to standard output.
+.PP
+.SH SOURCE
+.B /module/profile.m
+.br
+.B /appl/lib/profile.b
+.SH SEE ALSO
+.IR prof (3)
diff --git a/man/2/pslib b/man/2/pslib
new file mode 100644
index 00000000..47d04696
--- /dev/null
+++ b/man/2/pslib
@@ -0,0 +1,46 @@
+.TH PSLIB 2
+.SH NAME
+pslib - postscript generation
+.SH SYNOPSIS
+.EX
+include "pslib.m";
+pslib := load Pslib Pslib->PATH;
+
+init: fn(bufio: Bufio);
+writeimage: fn(f: ref Bufio->Iobuf,
+ img: ref Draw->Image, dpi: int): string;
+.EE
+.SH DESCRIPTION
+.B Pslib
+must first be initialised by calling
+.B Init
+with a loaded Bufio module.
+.B Writeimage
+writes a Postscript file containing the data within
+.I img
+to
+.IR f ,
+which should first have been opened for writing
+by
+.IR bufio .
+.I Dpi
+is a value specifying the pixel width of pixels in
+.IR img ;
+the width (and height) of
+.I dpi
+dots in
+.I img
+will be one inch when the Postscript is
+rendered.
+.SH SOURCE
+.B /appl/lib/pslib.b
+.SH SEE ALSO
+.IR bufio (2),
+.IR draw-image (2)
+.SH BUGS
+The resulting Postscript is really only suitable for
+use as encapsulated Postscript, as there's no way
+to set the destination paper size.
+.PP
+There should be many more useful functions
+in this module.
diff --git a/man/2/rand b/man/2/rand
new file mode 100644
index 00000000..a07a37fa
--- /dev/null
+++ b/man/2/rand
@@ -0,0 +1,35 @@
+.TH RAND 2
+.SH NAME
+rand \- pseudo random number generation
+.SH SYNOPSIS
+.EX
+include "rand.m";
+rand = load Rand Rand->PATH;
+
+init: fn(seed: int);
+rand: fn(modulus: int): int;
+bigrand: fn(modulus: big): big;
+.EE
+.SH DESCRIPTION
+.B Init
+initialises the pseudo-random number generator
+with
+.IR seed ;
+subsequent calls to
+.B rand
+and
+.B bigrand
+return a pseudo-random sequence of integers
+or bigs respectively, between 0 and
+.IR modulus \-1.
+.I Modulus
+should be a non-negative integer;
+for
+.BR bigrand ,
+it should be less than 2^53.
+.SH SOURCE
+.B /appl/lib/rand.b
+.SH SEE ALSO
+.IR security-random (2)
+.SH BUGS
+The quality of the algorithm currently used is questionable.
diff --git a/man/2/readdir b/man/2/readdir
new file mode 100644
index 00000000..c7acb7ec
--- /dev/null
+++ b/man/2/readdir
@@ -0,0 +1,101 @@
+.TH READDIR 2
+.SH NAME
+readdir \- read directory and sort files
+.SH SYNOPSIS
+.EX
+include "readdir.m";
+readdir := load Readdir Readdir->PATH;
+
+NAME, ATIME, MTIME, SIZE, NONE: con iota;
+COMPACT: con (1<<4);
+DESCENDING: con (1<<5);
+init: fn(path: string, sortkey: int): (array of ref Sys->Dir, int);
+readall: fn(fd: ref Sys->FD, sortkey: int): (array of ref Sys->Dir, int);
+sortdir: fn(a: array of ref Sys->Dir, key: int): (array of ref Sys->Dir, int);
+.EE
+.SH DESCRIPTION
+.B Readdir
+provides functions to read and sort the contents of a directory.
+Each function
+returns its result as a tuple that represents the
+directory contents as an array of references to
+.B Sys->Dir
+values, one per file
+(see
+.IR sys-stat (2)
+for a description of
+.BR Dir ).
+The integer element of the tuple is the number of entries
+returned, or \-1 if there was an error reading the directory.
+.B Readdir
+differs from
+.I sys-dirread (2)
+in returning the contents of the whole directory, not just a chunk of it,
+and in allowing the result to be sorted.
+.PP
+.B Init
+is most often used: it
+reads the contents of the directory
+.I path
+and sorts the resulting array according to
+.IR sortkey .
+.PP
+The sorting criteria for the returned array are based on
+.I sortkey
+as follows:
+.PP
+.TF MTIME
+.PD
+.TP
+.B NAME
+Sort files alphabetically by name.
+.TP
+.B ATIME
+Sort files by access time, most recently accessed first.
+.TP
+.B MTIME
+Sort files by modification time, most recently modified first.
+.TP
+.B SIZE
+Sort files by size, largest file first.
+.TP
+.B NONE
+Files are left in directory order, unsorted.
+.PP
+If the value
+.B DESCENDING
+is or'd into any of the values above, except
+.BR NONE ,
+the order of sorting is reversed.
+.PP
+The sort used is stable, of particular importance in the presence of
+duplicate names in a union mount.
+If the value
+.B COMPACT
+is or'd into any of the values above, including
+.BR NONE ,
+only the first (outermost) entry with a given name will be returned from reading
+a union mount, if names are duplicated in the union.
+.PP
+.B Readall
+reads file descriptor
+.I fd
+which must be open on a directory,
+and returns the contents after applying
+.I sortkey
+as described above for
+.BR init .
+.PP
+.B Sortdir
+sorts the array
+.I a
+according to the given
+.IR key ,
+as defined earlier, except that
+the
+.B COMPACT
+option has no effect.
+.SH SOURCE
+.B /appl/lib/readdir.b
+.SH SEE ALSO
+.IR sys-dirread (2)
diff --git a/man/2/regex b/man/2/regex
new file mode 100644
index 00000000..cddc08b5
--- /dev/null
+++ b/man/2/regex
@@ -0,0 +1,108 @@
+.TH REGEX 2
+.SH NAME
+regex \- regular expression recognizer module
+.SH SYNOPSIS
+.EX
+include "regex.m";
+regex := load Regex Regex->PATH;
+
+compile: fn(e: string, flag: int): (Re, string);
+execute: fn(x: Re; s: string): array of (int,int);
+executese: fn(x: Re, s: string, se: (int, int), bol: int, eol: int):
+ array of (int, int);
+.EE
+.SH DESCRIPTION
+Regular expressions are defined by
+.IR regexp (6).
+.B Compile
+returns (as the first element of the result tuple)
+a compiled form of the regular expression given in string
+.IR e .
+If
+.I e
+is not a valid regular expression,
+.B compile
+returns the tuple
+.BI "(nil" ", diag" )
+where
+.I diag
+is a diagnostic string.
+The effect of
+.I flag
+is described below.
+.PP
+.B Execute
+matches the compiled regular expression
+.I x
+against string
+.I s.
+It returns
+.B nil
+on no match, otherwise it returns an array.
+The element with index 0 gives the character positions
+of the first character of some longest leftmost match and
+the first character beyond the match.
+If the compilation
+.I flag
+was 0, there are no more elements.
+If
+.I flag
+was 1, there is one element for each pair of
+parentheses in the regular expression, counting
+left parentheses left to right starting at 1.
+The
+.IR n th
+element gives the position of the last match to the
+.IR n th
+parenthesized subexpression, or (\-1,\-1) if the subexpression
+does not participate in the overall match.
+.PP
+.B Executese
+is similar to
+.B execute
+but allows the start and end points in the string to be specified,
+as tuple
+.IR se :
+.BI ( "start , end" ) ,
+where
+.I start
+is the index in
+.I s
+of the initial character to be matched,
+and
+.I end
+is the index in
+.I s
+of the first character beyond the substring to be matched
+(and can be the length of
+.IR s ).
+If
+.I bol
+is non-zero, the
+initial character is at the beginning of a line,
+allowing an initial match by the regular expression operator
+.RB ` ^ ';
+if
+.I eol
+is non-zero, the
+last character is at the end of a line, allowing a match
+by the operator `\f5$\fP'.
+.SH EXAMPLES
+.EX
+(re, nil) := regex->compile("(thick )*(chocolate |raspberry )?"+
+ "(topp|fill)ing", 0);
+
+(re, nil) := regex->compile("[ABCb-z]+", 0);
+a := regex->execute(re, s:="aAbBcCdD");
+(beg, end) := a[0];
+s[beg:end] == "AbBcCd";
+
+(re, nil) := regex->compile("a*b*", 0);
+a := regex->execute(re, "bbaabb");
+(beg, end) := a[0];
+(beg, end) == (0,2);
+.EE
+.SH SOURCE
+.B /appl/lib/regex.b
+.SH SEE ALSO
+.IR regexp (6)
diff --git a/man/2/registries b/man/2/registries
new file mode 100644
index 00000000..526e1c13
--- /dev/null
+++ b/man/2/registries
@@ -0,0 +1,318 @@
+.TH REGISTRIES 2
+.SH NAME
+registries \- access services registry
+.SH SYNOPSIS
+.EX
+include "registries.m";
+registries := load Registries Registries->PATH;
+
+init: fn();
+
+Attributes: adt {
+ attrs: list of (string, string);
+
+ get: fn(a: self ref Attributes, attr: string): string;
+ set: fn(a: self ref Attributes, attr, val: string);
+ new: fn(attrs: list of (string, string)): ref Attributes;
+};
+
+Attached: adt {
+ fd: ref Sys->FD; # connection to the service
+ signerpkhash: string; # hash of signer's key
+ localuser: string; # user name here
+ remoteuser: string; # user name there
+};
+
+Service: adt {
+ addr: string; # dial this to connect to the service
+ attrs: ref Attributes; # service description
+
+ attach: fn(s: self ref Service, user: string,
+ keydir: string): ref Attached;
+};
+
+Registered: adt {
+ addr: string; # address where registered
+ reg: ref Registry; # registry where registered
+ fd: ref Sys->FD; # file representing registration entry
+};
+
+Registry: adt {
+ dir: string;
+
+ new: fn(dir: string): ref Registry;
+ connect: fn(svc: ref Service, user: string, keydir: string):
+ ref Registry;
+ services: fn(r: self ref Registry):
+ (list of ref Service, string);
+ find: fn(r: self ref Registry, a: list of (string, string)):
+ (list of ref Service, string);
+ register: fn(r: self ref Registry, addr: string,
+ attrs: ref Attributes, persist: int):
+ (ref Registered, string);
+ unregister: fn(r: self ref Registry, addr: string): string;
+};
+.EE
+.SH DESCRIPTION
+.B Registries
+helps access and update the contents of one or more
+.I registry (4)
+servers.
+Each registry lists services, each described by a set of attribute/value pairs.
+The attributes need not identify the service uniquely.
+.PP
+.B Init
+must be called before any other function in the module.
+.PP
+.B Attributes
+represents a set of attribute/value pairs;
+a given attribute name cannot appear more than once.
+It provides the following members and operations:
+.TF attrs
+.PD
+.TP
+.B attrs
+The current value of the set, as a list of
+.BI ( attr , value )
+tuples.
+.TP
+.BI Attributes.new( attrs )
+Return a new
+.B Attributes
+value given
+.IR attrs ,
+a list of
+.BI ( attr , value )
+tuples.
+.TP
+.IB a .get( attr )
+Return the value of
+.I attr
+in attribute set
+.IR a .
+.TP
+.IB a .set( attr\fB,\fP\ value )
+Set the
+.I value
+of
+.I attr
+in attribute set
+.IR a .
+.PP
+A
+.B Service
+value represents a service registered in some registry.
+It has the following members and operations:
+.TF attrs
+.PD
+.TP
+.B addr
+A string that represents where the service can be reached: it is often a
+.IR sys-dial (2)
+address string, but might be a name in the name space; the interpretation is internal to
+.BR Registries .
+.TP
+.B attrs
+The service's attributes (complete service description).
+.TP
+.IB svc .attach( user , keydir )
+Attempts to attach to the service
+.IR svc ,
+and if successful returns an
+.B Attached
+value to represent the connection;
+otherwise returns nil and sets the system error string.
+.I User
+is the local name of the user making the connection; if nil, the contents of
+.B /dev/user
+are used by default.
+.I Keydir
+is the name of a directory containing the
+.IR user 's
+certified keys for authentication; if nil, the default is
+.BI /usr/ user /keyring.
+If an error occurs, the return value is nil and the system error string contains a diagnostic.
+Not all services demand authentication, and either or both values can be nil to
+select suitable defaults.
+If authentication is done, the certified data determines the remote identity, not
+.IR user ,
+which is used only to help find a suitable set of keys and has no effect on security.
+.PP
+.B Attached
+holds data about an active connection to a particular service.
+(There can be several distinct connections to the same
+.BR Service .)
+It provides the following members:
+.TF attrs
+.PD
+.TP
+.B fd
+A file descriptor that can be read and written to exchange data with the service.
+The meaning of the data depends on the service (eg, it might be a Styx connection
+or a SOAP implementation).
+Typically an attribute of the service description hints at the protocol.
+.TP
+.B signerpkhash
+A hexadecimal string giving the SHA-1 hash of the key of the signer used for
+mutual authentication (ie, its thumbprint); if no authentication was needed or
+did not use public key methods, it is nil.
+.TP
+.B localuser
+If authentication was required, the name used as the local name for authentication;
+otherwise nil.
+.TP
+.B remoteuser
+If authentication was required, the remote identity for this connection; otherwise nil.
+.PP
+A service provider registers using one of the
+.B Registry
+functions listed below.
+An active registration is represented by a value of type
+.BR Registered :
+.TF attrs
+.PD
+.TP
+.B addr
+Location of service, as registered.
+.TP
+.B reg
+The registry that registered the service.
+.TP
+.B fd
+File descriptor open for on the service file in
+.IR registry (4)
+that holds the service description.
+Unless the service has a non-zero
+.B persist
+attribute, the service registration will be removed when this file is closed
+(eg, when this
+.B Registration
+value is freed by the garbage collector if there is no other copy of
+.BR fd ).
+The file can be written as described in
+.IR registry (4)
+to change the some or all of current set of attributes and/or values
+in the service description.
+.PP
+A
+.B Registry
+represents a connection to a single
+.IR registry (4)
+instance.
+It provides the following members and operations:
+.TF attrs
+.PD
+.TP
+.B dir
+Location of the registry in the name space.
+.TP
+.BI Registry.new( dir )
+Return a new
+.B Registry
+value for the registry located at
+.I dir
+in the name space; if
+.I dir
+is nil, the default is
+.BR /mnt/registry .
+.TP
+.BI Registry.connect( svc\fB,\fP\ user\fB,\fP\ keydir )
+Connect to the registry at the location determined by the service description
+.IR svc ;
+if
+.I svc
+is nil, the default is to try
+.IR sys-dial (2)
+to
+.BR net!$registry!registry ,
+the symbolic name of the default registry for the current host.
+(The registry might or might not be local.)
+Attributes of
+.I svc
+determine the method used to connect to the registry and whether authentication is required.
+.I User
+and
+.I keydir
+provide user name and certificate directory (see
+.IR getauthinfo (8))
+if authentication is required; either or both can be nil to select the defaults for the given authentication method.
+On successful connection,
+.B connect
+returns a
+.B Registry
+value that can subsequently be used to access that registry and its services.
+It returns nil on an error and sets the system error string.
+.TP
+.IB reg ".services()"
+Returns a tuple
+.BI ( svcs , err )
+where
+.I svcs
+is a list of
+.B Service
+values, one for each service registered by
+.I reg
+at time of asking.
+If no services are registered, both values are nil.
+If an error occurred,
+.I svcs
+is nil but
+.I err
+is a diagnostic string.
+.TP
+.IB reg .find( attrs )
+Return a tuple
+.BI ( svcs , err )
+where
+.I svcs
+is a list of
+.B Service
+values, one for each service registered by
+.I reg
+that (at time of asking) matched all of the attribute/value pairs in
+.IR attrs .
+A value of
+.B \&"*"
+matches any value.
+If no services matched, both values are nil.
+If an error occurred,
+.I svcs
+is nil but
+.I err
+is a diagnostic string.
+.TP
+.IB reg .register( addr\fB,\fP\ attrs\fB,\fP\ persist )
+Attempts to register with
+.I reg
+a service named
+.I addr
+and the given attributes
+.IR attrs ,
+and returns a tuple
+.BI ( r , err )
+where
+.I r
+is a non-nil
+.B Registration
+value for the entry if successful, and
+.I err
+is a diagnostic otherwise.
+.I Persist
+is non-zero if the service registration should survive the
+.B Registration
+value (connection); normally it is zero and the registry entry vanishes when
+the service frees the
+.B Registration
+value.
+.TP
+.IB reg .unregister( addr )
+Attempt to remove the registration entry at
+.I reg
+for the service named
+.IR addr .
+Only the service owner can do so.
+Returns nil on success and a diagnostic otherwise.
+.SH SEE ALSO
+.IR attrdb (2),
+.IR registry (4),
+.IR svc (8)
diff --git a/man/2/scsiio b/man/2/scsiio
new file mode 100644
index 00000000..0aa5e0ab
--- /dev/null
+++ b/man/2/scsiio
@@ -0,0 +1,144 @@
+.TH SCSIIO 2
+.SH NAME
+ScsiIO: Scsi \- SCSI device operations
+.SH SYNOPSIS
+.EX
+include "scsi.m";
+
+scsiio := load ScsiIO ScsiIO->PATH;
+Scsi: adt {
+ inquire: string;
+ rawfd: ref Sys->FD;
+ nchange: int;
+ changetime: int;
+
+ open: fn(devdir: string): ref Scsi;
+ rawcmd: fn(s: self ref Scsi, cmd: array of byte,
+ data: array of byte, io: int): int;
+ cmd: fn(s: self ref Scsi, cmd: array of byte,
+ data: array of byte, io: int): int;
+ ready: fn(s: self ref Scsi): int;
+};
+
+Sread, Swrite, Snone: con iota;
+
+scsierror: fn(asc: int, ascq: int): string;
+
+init: fn(verbose: int);
+.EE
+.SH DESCRIPTION
+.B ScsiIO
+provides a low-level interface to a SCSI or ATAPI device via
+.IR sd (3).
+.PP
+.B Init
+must be called before using any other operation of the module.
+If
+.I verbose
+is non-zero
+the module will produce a fair
+amount of debugging output on file descriptor 2
+when SCSI commands fail.
+.PP
+.B Scsi.open
+attempts to open the file
+.IB devdir /raw
+on which to send raw SCSI commands.
+On success, it reads the device's inquiry
+string and returns a reference to a
+.B Scsi
+value to represent the connection.
+It provides the following operations:
+.TP
+.IB s .ready()
+Sends the ``unit ready'' command up to three times,
+returning zero once the unit responds that it is ready,
+or \-1 on error.
+.TP
+.IB s .rawcmd( "cmd, data, io" )
+.PD 0
+.TP
+.IB s .cmd( "cmd, data, io" )
+Both these functions execute a single SCSI command on the named device.
+The command data is in the byte array
+.IR cmd .
+If
+.I io
+is
+.BR Sread ,
+a successful operation will store the resulting bytes in
+.IR data ,
+up to its length,
+returning the number of bytes stored.
+If
+.I io
+is
+.BR Swrite ,
+the bytes in
+.I data
+are transmitted as the data argument to
+the command, and the
+number of bytes written is returned.
+If
+.I io
+is
+.BR Snone ,
+.I data
+is ignored and may be nil.
+.B Rawcmd
+simply issues the command and
+returns the result;
+.B cmd
+works a bit harder and
+is the more commonly used routine.
+It attempts to send the commmand;
+if it is successful,
+.B cmd
+returns the result.
+Otherwise,
+.B cmd
+sends a request sense command to
+obtain the reason for the failure,
+sends a unit ready command in
+an attempt to bring the unit out of any
+inconsistent states, and tries again.
+It also accounts for media change.
+If the second try fails,
+.B cmd
+returns an error.
+On error, both functions return \-1 and set the system error string.
+.PD
+.PP
+The
+.B nchange
+and
+.B changetime
+elements of
+.B Scsi
+the number of times a media
+change has been detected, and the
+first time the current media was detected (the
+first time a SCSI command was issued
+after it was inserted).
+They are maintained by
+.BR Scsi.cmd .
+The initial SCSI inquiry result is kept in
+.BR inquire .
+.PP
+.I Scsierror
+returns a textual description of the SCSI status
+denoted by the ASC and ASCQ sense codes.
+The description is found by consulting
+.BR /lib/scsicodes .
+.SH FILES
+.TF
+.TP
+.B /lib/scsicodes
+List of textual messages corresponding to SCSI error codes;
+consulted by
+.BR scsierror .
+.SH SOURCE
+.B /appl/lib/scsiio.b
+.SH SEE ALSO
+.IR disks (2),
+.IR sd (3)
diff --git a/man/2/secstore b/man/2/secstore
new file mode 100644
index 00000000..2a14b67a
--- /dev/null
+++ b/man/2/secstore
@@ -0,0 +1,250 @@
+.TH SECSTORE 2
+.SH NAME
+secstore \- fetch data from Plan 9's secure storage service
+.SH SYNOPSIS
+.EX
+include "secstore.m";
+secstore := load Secstore Secstore->PATH;
+
+Maxfilesize: con 128*1024; # default
+
+init: fn();
+privacy: fn(): int;
+cansecstore: fn(addr: string, user: string): int;
+mkseckey: fn(pass: string): array of byte;
+dial: fn(addr: string): ref Sys->Connection;
+auth: fn(conn: ref Sys->Connection, user: string, seckey: array of byte):
+ (string, string);
+connect: fn(addr: string, user: string, seckey: array of byte):
+ (ref Sys->Connection, string, string);
+sendpin: fn(conn: ref Sys->Connection, pin: string): int;
+files: fn(conn: ref Sys->Connection):
+ list of (string, int, string, string, array of byte);
+getfile: fn(conn: ref Sys->Connection, name: string,
+ maxsize: int): array of byte;
+.\"putfile: fn(conn: ref Sys->Connection, name: string, data: array of byte,): int;
+remove: fn(conn: ref Sys->Connection, file: string): int;
+bye: fn(conn: ref Sys->Connection);
+
+mkfilekey: fn(pass: string): array of byte;
+decrypt: fn(data: array of byte, filekey: array of byte): array of byte;
+.\"encrypt: fn(data: array of byte, filekey: array of byte): array of byte;
+erasekey: fn(key: array of byte);
+
+lines: fn(file: array of byte): list of array of byte;
+.EE
+.SH DESCRIPTION
+.B Secstore
+establishes a secure authenticated connection with a Plan 9
+.I secstore
+service (or equivalent, such as Plan 9 from User Space),
+that can then be used to fetch and decrypt data files, such as the
+.B factotum
+file containing the initial keys for an instance of
+.IR factotum (4).
+The module's functions hold the file descriptors for the connection in a
+.BR Sys->Connection
+value,
+as returned by
+.IR sys-dial (2).
+The
+.I addr
+parameter that gives the network address of the
+.I secstore
+service is also as defined in
+.IR sys-dial (2).
+A nil value defaults to
+.BR "net!$auth!secstore" ,
+for translation in the usual way by
+.IR cs (8).
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+.PP
+.B Privacy
+ensures the memory of the calling process cannot be read, for instance by
+.IR prog (3).
+It returns zero on success and a negative value on failure.
+.PP
+.B Cansecstore
+returns true if a connection can be made to a
+.I secstore
+at network address
+.IR addr ,
+and the given
+.I user
+has a
+.I secstore
+account;
+it returns false otherwise.
+.PP
+Users authenticate themselves to the service using a secret key and a special protocol that does not
+reveal the key itself to the remote service.
+The textual secret (eg, password or pass phrase) is not used directly by the following functions,
+but only after transformation by
+.BR mkseckey ,
+which hashes it into an array of bytes.
+That is the
+.I key
+parameter to the functions.
+.PP
+.B Dial
+dials the
+.I secstore
+at network address
+.I addr
+(as defined by
+.IR sys-dial (2))
+and returns a reference to the resulting
+.BR Sys->Connection .
+It returns nil on an error and sets the error string.
+.PP
+.B Auth
+authenticates a fresh connection as belonging to a given
+.I user
+of the service.
+The parameter
+.I conn
+refers to the
+.B Sys->Connection
+value representing the connection.
+.I User
+names a user registered with the service.
+The parameter
+.I seckey
+is the result of applying
+.B mkseckey
+to the user's secret.
+.I Auth
+returns a tuple
+.BI ( srvname,\ diag ).
+.I Srvname
+is the service name configured in the remote host (often simply
+.BR secstore ).
+On an error,
+.I srvname
+is nil, and
+.I diag
+is a diagnostic.
+If the remote service
+has been configured to demand extra authentication data, then
+.I diag
+contains a demand for it.
+Currently the only such value is
+.RB ` need pin ';
+call
+.B sendpin
+to provide it to the connection.
+If
+.B sendpin
+succeeds, it returns zero, and
+.I conn
+can be used normally; on error,
+.B sendpin
+returns -1 and the connection cannot be used.
+.PP
+.B Connect
+combines the actions of
+.B dial
+and
+.BR auth :
+dials the
+.I secstore
+at
+.IR addr ,
+and mutually authenticates the server and the given
+.I user
+using the user's secret
+.I key
+for that service.
+It returns a tuple
+.BI ( conn,\ srvname,\ diag ),
+where each component is as described for
+.B dial
+and
+.B auth
+above.
+On an error,
+.I conn
+is nil, and
+.I diag
+contains a diagnostic.
+.PP
+.B Getfile
+retrieves the file
+.I name
+from the secure store, and returns its contents as an array of bytes.
+.I Maxsize
+gives the largest acceptable file size; if the value is zero or negative,
+a large value is used by default.
+The files stored on the service are separately encrypted under the user's secret key.
+.B Mkfilekey
+takes a textual secret
+.I key
+and returns a hash of it as an array of bytes,
+suitable for use as the
+.I filekey
+parameter in subsequent calls to
+.BR decrypt .
+(The
+.I filekey
+is not the same value as the
+.I seckey
+used for initial authentication, although the secret text is the same.)
+.PP
+.B Remove
+deletes the given
+.I file
+from the server.
+It returns 0 on success and a negative value on error.
+.PP
+.B Decrypt
+decrypts the
+.I data
+previously fetched from a file on the secure store.
+It uses the
+.I filekey
+produced by
+.B mkfilekey
+to decrypt the data in place (ie, modifying the contents of
+.IR data )
+and returns a slice of
+.I data
+that excludes any headers and trailers in the encoding.
+It returns nil if the file could not be decrypted (usually because the
+.I key
+value is not actually the encryption key).
+.PP
+.B Erasekey
+clears the bytes of
+.I key
+to zero; it should be called on every value produced by
+.B mkfilekey
+and
+.BR mkseckey ,
+after use,
+but can also be used on the data arrays returned by
+.B getfile
+and
+.BR decrypt .
+.PP
+.B Lines
+returns a list of slices of
+.IR file ,
+representing each line of
+.I file
+in turn (including newline).
+.IR Factotum (4)
+for instance requires keys to be written to its control file one at a time.
+.PP
+.B Bye
+closes the connection to the
+.IR secstore .
+.SH SOURCE
+.B /appl/lib/secstore.b
+.SH DIAGNOSTICS
+As well as returning the error values described above, functions set the system error string.
+.SH SEE ALSO
+.IR crypt (1),
+.IR factotum (2),
+.IR factotum (4)
diff --git a/man/2/security-0intro b/man/2/security-0intro
new file mode 100644
index 00000000..a7d0d6e2
--- /dev/null
+++ b/man/2/security-0intro
@@ -0,0 +1,162 @@
+.TH SECURITY-INTRO 2
+.SH NAME
+intro \- introduction to security
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+include "security.m";
+.EE
+.SH DESCRIPTION
+This is an introduction to some of the principals behind computer security as well as a description of how these principals are used in Inferno. More detailed descriptions of the methods and principals for ensuring secure communications on computers can be found in texts such as
+.I "Applied Cryptography"
+by Bruce Schneier (published 1996, J. Wiley & Sons, Inc.).
+.PP
+Inferno provides several levels of security:
+.IP \(bu
+Mutual authentication means that two users or applications that want to communicate can establish that they are who they say they are. It is the basic level of security provided by Inferno. Thus, for example, when a user connects to
+an Inferno service, they can and must establish that they are a legitimate user.
+.IP \(bu
+Message digesting is a technique to ensure that an interloper cannot modify messages sent between users.
+.IP \(bu
+Encryption protects the confidentiality of messages so that only the party or parties for whom the messages are intended can decrypt and read them.
+Inferno makes it easy to enforce any one or all of these levels of security.
+.SS "Mutual Authentication"
+Authentication requires a combination of elements: a third party that each user can trust, an algorithm or mathematical method to secure messages between users, and a protocol for exchanging messages that ensures that a third party or intruder cannot pretend to be one of the users, or use some other method to undermine their communication.
+.PP
+One important method for authenticating users in Inferno is the use of digital signatures. Like signing a letter a digital signature testifies to the identity of the sender. Fortunately, it is much more difficult to forge a digital signature.
+.PP
+Even after users are authenticated to each other, it is possible for someone `listening' to their communication to read and possibly modify their messages without the users knowing it. So authentication solves one security requirement, but not all of them.
+.SS "Message Digesting"
+Message digesting uses a mathematical hashing algorithm to convert a message
+into an indecipherable string of fixed length (a digest).
+By appending the hashed value to the message,
+the authenticity of the message can be verified.
+The recipient takes the message, applies the same hashing algorithm used by the sender, and compares the value to the one sent.
+If the values are the same, then the message received must be the same as the one that was sent.
+.PP
+Inferno includes a counter in the digest to check that messages were received in the correct order and
+that no messages were inserted by a third party listening in on the line.
+A secret key is also included in the digest to verify the identity of the sender.
+.PP
+A message digest ensures that no one has tampered with a message.
+It does not prevent someone from reading it.
+.SS "Message Encryption"
+The traditional notion of encryption is translating a message, called a plaintext in cryptography, into something unreadable, called a ciphertext. Its most obvious use is to provide confidentiality. Only someone able to decrypt the message, or translate it back to its original form, can interpret it.
+.PP
+A mathematical algorithm is used to both encrypt and decrypt a message. Encryption algorithms depend on keys or bit strings of a specified length for encryption and decryption. The nature of an algorithm and the size of the key determine the degree of security.
+.PP
+Two basic types of algorithms are used in cryptography: private key (or symmetric key) and public key algorithms. With symmetric algorithms the same key is used to encrypt and decrypt a message. This key must be a secret, known only to the users who want to communicate. It is often called a private or secret key.
+.PP
+A public key algorithm may use a private or secret key to encrypt a message and a public key to decrypt it, or vice-versa. The private or secret key is known only to one user. The public key, however, does not have to be kept secret and may be distributed to anyone the user wishes to communicate with.
+.PP
+Inferno uses a public key algorithm for digital signatures and symmetric key algorithms for encryption.
+.PP
+A user can encrypt a message with or without appending a message digest.
+.PP
+.SS "Algorithms Supplied With Inferno"
+Some of the considerations when choosing algorithms are speed, degree of security, and
+political restrictions on export.
+The algorithms used in Inferno are well known and rigorously tested.
+.TP
+One-way hashing algorithms
+SHA1 and MD5 are well known (in cryptographic circles) one-way hashing algorithms. MD5 is a high-speed, 128-bit hash. SHA1 is a somewhat slower but more secure 160-bit hash.
+.TP
+Elgamal and RSA public key signature algorithms
+Elgamal is a public key system widely used for creating digital signatures. It uses a private key for signing a message and a public key for verifying it.
+Inferno also supports the widely-used RSA and DSS-1 signature algorithms.
+Because Inferno initially used Elgamal
+keys, it does not assume that either a private or public key can be used for encryption or decryption. With constant advances in the field of cryptography, one of the design goals of Inferno is to create a security component that will be easy to enhance as new algorithms are developed.
+.TP
+Encryption algorithms
+DES (the Data Encryption Standard) was adopted by the US government in 1976 as a standard encryption/decryption system for unclassified data in the United States. It is widely used, especially by the financial services industry. Two types of DES are offered: DES-ECB and DES-CBC. ECB or Electronic Code Book and CBC or Chain Block Coding are part of the ANSI Banking Standard. CBC is more complex and less vulnerable than ECB. Both versions of DES provide 56-bit keys.
+.RS
+.PP
+RC4 is a symmetric or private key system that is about 10 times faster than DES.
+.RE
+.TP
+Diffie-Hellman key exchange algorithm
+Diffie-Hellman is an algorithm for creating a secret key to be shared by users for encrypting messages (sometimes called a shared secret). It requires each user to exchange certain information with the other. This information can be exchanged in the open, that is, without encryption. Each user is able to create the same, secret key from this information. However, no one else listening to their exchange would be able to create or determine the secret key.
+.SS "Security Protocols"
+Cryptanalysis is the study of how to break cryptographic systems. Attempts to disrupt or listen to confidential communications are called attacks. Usually the objective of an attack is to figure out the secret key, decrypt a message, or add or modify messages in some way.
+.PP
+There are many methods or strategies for attacking a confidential communication. One method is called a man-in-the-middle attack, where someone listening to a communication pretends to be one of the parties; another is a replay attack, where an interloper reuses messages that have already been exchanged in an attempt to discover a pattern.
+.PP
+In order to thwart such attacks and establish some level of trust between communicating parties, it is necessary to employ certain protocols.
+Inferno uses two well-established protocols to permit keys to be exchanged
+and to permit
+mutual authentication of the identities of two communicating parties.
+.PP
+A
+.I "digital signature"
+is one way to guarantee that a message sent by a user is indeed from that user and not someone else. A signature does not require that a message be encrypted. It can be appended to a message in order to guarantee the identity of the sender. With Elgamal, creating a signature requires that the user have a secret or private key. Uniquely associated with the private key is another key that can be distributed publicly. This public key is used along with the private key to create a signature, and is used by others to verify the signature.
+.PP
+To create a signature the Elgamal algorithm is applied to a combination of the private key, the public key, and the message to be signed. The output of the algorithm is the signature.
+.PP
+To verify the signature the receiver applies the Elgamal algorithm to the public key and the signature. If the output is the same message that was sent with the signature, then the signature is valid. This method ensures that the user receiving a message is indeed communicating with someone who owns the public key.
+.PP
+The next step is to determine who the owner of the public key is, and to ensure that it belongs to the user that the receiver wants to communicate with. This is accomplished by having a third party create a
+.I "certificate"
+testifying to the identity of the owner of the public key. This third party is called a certifying authority (CA). If a user trusts the certifying authority, a copy of a certificate is sufficient to determine the ownership of a public key, and therefore, the signature and identity of the user sending a message.
+.PP
+A certificate includes a variety of information: a user's public key, the identity of the user, Diffie-Hellman parameters, an expiration time for the certificate, and the signature of the CA. The CA's public key is sent to the user along with the certificate to verify the CA's signature.
+.PP
+Inferno provides two different methods for obtaining a certificate depending on whether a user has access to a keyboard or not. For users with a keyboard, Inferno offers a variation of the Encrypted-Key-Exchange (EKE) protocol,
+described in
+.IR login (6).
+The protocol depends on establishing trust between a user and a CA
+using a shared secret (password).
+The secret must initially be established at the CA by some secure means:
+typing a password on a secure console at the CA, or transmitting the
+password securely off-line, perhaps by unintercepted letter or untapped phone call.
+To obtain a certificate, a user can subsequently enter
+the secret on the client machine's keyboard; the protocol obtains
+a certificate without revealing the secret.
+.PP
+For an application or user on a set-top box, which normally does not have a keyboard, entering a password would be difficult. Therefore, Inferno provides a different method to establish trust. When the set-top box is turned on, it creates a private/public key pair and dials the service provider's CA to get a certificate. The CA returns a certificate blinded or scrambled with a random bit string known only to the CA. A hashed version of the string is displayed on the user's screen. The user telephones the CA and compares what is displayed with what the CA has sent. If they match, and the user can prove his or her identity, the CA makes the random bit string known to the user, so the certificate can be unscrambled.
+.SS "Authentication"
+Mutual authentication in Inferno requires that two parties who want to communicate must have a certificate from the same CA. As described above, the public key of the CA is used to check the certificate sent by the other user. The certificate is used to verify that the public key belongs to the party that the user wants to communicate with.
+.PP
+If a user can trust the public key, then the key can be used to check the signature sent by the other party. If the public key unlocks the signature, then whoever sent the signature must have the corresponding secret key, and therefore, must be the owner of the public key.
+.PP
+The default protocol provided by Inferno for mutual authentication is
+the station-to-station protocol described in
+.IR auth (6).
+It has the property that both parties can derive the
+same key from exchanged and validated data but no eavesdropper
+can determine the key.
+.SS "Security at the Application Layer"
+An application can make use of the algorithms and protocols described previously by using only a few library routines such as:
+.IR security-login (2),
+.IR security-auth (2)
+and
+.IR connect
+(see
+.IR security-ssl (2)).
+The
+.B Login
+module enables an application that shares a password with a server acting as the CA to obtain a certificate. After obtaining certificates, two applications establish a mutually authenticated connection by calling
+.IR auth .
+.I Auth
+performs the entire STS protocol.
+.I Connect
+connects an application to an SSL (security sockets layer) device. Each application can create message digests or encrypt messages by writing to this device. Messages are received and decrypted by reading from the SSL device.
+.PP
+Although Inferno provides these routines to make it easy to establish secure communications, an application is not restricted to their use. Lower-level routines used by
+.I login
+and
+.I auth
+are also available to an application. These routines enable an application to create alternate methods for establishing security, or to perform specialized functions like signing files.
+.PP
+Inferno also provides security routines tailored for set-top boxes. For example, a set-top-box can use
+.IR register (8)
+instead of
+.I login
+(see
+.IR security-login (2)).
+.I Register
+obtains a certificate without requiring a user to enter a password.
+.PP
+There are also commands in section 8 that establish a server as a Certifying Authority or `signer'. For example, a CA needs a key and password to create a certificate. These can be created on the server using the commands
+.IR changelogin (8)
+and
+.IR createsignerkey (8).
diff --git a/man/2/security-auth b/man/2/security-auth
new file mode 100644
index 00000000..045db64e
--- /dev/null
+++ b/man/2/security-auth
@@ -0,0 +1,157 @@
+.TH SECURITY-AUTH 2
+.SH NAME
+Auth: init, client, server \- authenticated connections between client and server
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+include "security.m";
+auth := load Auth Auth->PATH;
+
+init: fn(): string;
+client: fn(alg: string, ai: ref Keyring->Authinfo,
+ fd: ref Sys->FD): (ref Sys->FD, string);
+server: fn(algs: list of string, ai: ref Keyring->Authinfo,
+ fd: ref Sys->FD, setid: int): (ref Sys->FD, string);
+.EE
+.SH DESCRIPTION
+.B Auth
+establishes authenticated connections using the station to station protocol described
+in
+.IR auth (6).
+It encapsulates the use of the primitives of
+.IR keyring-auth (2)
+and
+.IR security-ssl (2)
+for the particular case where the stations
+play the rôles of `client' and `server'.
+The underlying primitives must still be accessed directly in some cases,
+for instance when completely symmetric authentication is needed between peers.
+.PP
+.B Init
+must be called before using any other functions in
+.BR Auth ;
+it returns nil if successful, and a diagnostic message otherwise.
+.PP
+.B Client
+authenticates a connection with the server on
+.I fd
+using the authentication data in
+.IR ai .
+If successful, and
+.I alg
+is neither
+.B nil
+nor the value
+.B
+"none"\c
+,
+.B client
+will set the connection to digest or encrypt the data,
+using the
+digest or encryption algorithm specified in
+.IR alg .
+It returns the file descriptor for the connection,
+and a string with information about the connection.
+If an authenticated connection cannot be established,
+.B client
+returns a nil file descriptor and an error message.
+.PP
+.B Server
+authenticates a client connection
+.IR fd ,
+as described in
+.IR keyring-auth (2),
+using the server's authentication data in
+.IR ai .
+If successful, and the client requested the use of a digest or
+encryption algorithm, and that algorithm is listed in
+.IR algs ,
+.B server
+enables the security layer
+.IR ssl (3)
+using the selected algorithm.
+Furthermore, if
+.I setid
+is non-zero, the current user name is set to the
+newly authenticated name.
+.B Server
+returns a file descriptor for the connection,
+and a string with information about the connection.
+If an authenticated connection cannot be established,
+or the client's chosen algorithm is not listed,
+.B server
+returns a nil file descriptor and an error message.
+.PP
+Any string acceptable to
+.IR ssl (3),
+including
+.B
+"clear"\c
+, can be given as an
+.I alg
+to
+.BR client ,
+or listed in
+.I algs
+for
+.BR server .
+Furthermore, the special string
+.B
+"none"
+tells both functions
+that
+.IR ssl (3)
+should not be used at all on a connection.
+.SH EXAMPLE
+This selection from
+.B /appl/cmd/mount.b
+illustrates client-side use.
+.PP
+.EX
+ au := load Auth Auth->PATH;
+ err := au->init();
+ if(err != nil){
+ sys->fprint(stderr, "mount: %s\en", err);
+ exit;
+ }
+ fd: ref Sys->FD;
+ (fd, err) = au->client("none", ai, c.dfd);
+ if(fd == nil){
+ sys->fprint(stderr, "mount: authentication failed: %s\en", err);
+ exit;
+ }
+ dir := hd argv;
+ ok = sys->mount(fd, dir, flags, "");
+ if(ok < 0)
+ sys->fprint(stderr, "mount: %r\en");
+.EE
+.PP
+The following example from
+.B /appl/lib/styxd.b
+shows server-side use;
+note that
+.B readauthinfo
+is called first to fetch the authentication data to pass to
+.BR server .
+.PP
+.EX
+ kr := load Keyring Keyring->PATH;
+ ...
+ ai := kr->readauthinfo("/usr/"+user+"/keyring/default");
+ auth->init();
+ (fd, info_or_err) := auth->server(argv, ai, stdin, 1);
+ if(fd == nil){
+ sys->fprint(stderr, "styxd: %s\en", info_or_err);
+ exit;
+ }
+ sys->pctl(Sys->FORKNS, nil);
+ if(sys->export(fd, Sys->EXPASYNC) < 0)
+ sys->fprint(stderr, "styxd: file export: %r\en");
+.EE
+.SH SOURCE
+.B /appl/lib/auth.b
+.SH "SEE ALSO"
+.IR keyring-auth (2),
+.IR security-ssl (2),
+.IR ssl (3),
+.IR auth (6)
diff --git a/man/2/security-login b/man/2/security-login
new file mode 100644
index 00000000..cc831319
--- /dev/null
+++ b/man/2/security-login
@@ -0,0 +1,93 @@
+.TH SECURITY-LOGIN 2
+.SH NAME
+login \- verify credentials
+.SH SYNOPSIS
+.EX
+include "keyring.m";
+include "security.m";
+login := load Login Login->PATH;
+
+login: fn(name, password, addr: string):
+ (string, ref Keyring->Authinfo);
+.EE
+.SH DESCRIPTION
+The
+.BR Login
+module is provided for use by a client of
+a certifying authority (CA) or `signer'.
+The
+.B login
+function communicates
+with a certifying authority (CA)
+in order to create a
+.B Keyring->Authinfo
+adt
+which contains a public/private key pair and a certificate
+signed by the CA
+(see
+.IR keyring-intro (2)).
+The public/private key pair is generated by
+.B login
+using the same parameters as those in the signer's key
+(eg, algorithm and key length);
+see
+.IR keyring-gensk (2).
+The procedure assumes a secret, i.e. a
+password, has already been established
+between the user and the CA.
+See
+.IR changelogin (8)
+and
+.IR keyfs (4)
+for how this password is managed at the
+CA.
+.PP
+.B Login
+connects, using
+.IR sys-dial (2),
+to the signer at network address
+.IR addr ,
+which is any form accepted by
+.IR cs (8),
+including the special address
+.BR $SIGNER ,
+which
+.IR cs
+will translate to the client's default signer (if there is one).
+Normally the incoming call will be given to
+.IR logind (8)
+by
+.IR svc (8).
+.PP
+.B Login
+sends the user
+.I name
+and
+.IR password ,
+using the protocol described in
+.IR login (6),
+to justify the server's
+issuing a certificate, which is returned in a
+.B Keyring->Authinfo
+adt on success.
+The certificate can if desired be stored by
+.BR Keyring->writeauthinfo ;
+see
+.IR keyring-auth (2).
+The password is used by the encrypted
+key exchange protocol to establish
+a secure channel between user and CA.
+.SH SOURCE
+.B /appl/lib/login.b
+.SH SEE ALSO
+.IR getauthinfo (8),
+.IR keyring-auth (2),
+.IR login (6),
+.IR createsignerkey (8),
+.IR logind (8)
+.SH DIAGNOSTICS
+.B Login
+returns nil in the string component
+on success and a diagnostic string on error (with a nil
+.B Keyring->Authinfo
+reference).
diff --git a/man/2/security-random b/man/2/security-random
new file mode 100644
index 00000000..60ff3f7c
--- /dev/null
+++ b/man/2/security-random
@@ -0,0 +1,43 @@
+.TH SECURITY-RANDOM 2
+.SH NAME
+random: randomint, randombuf \-
+random number generation
+.SH SYNOPSIS
+.EX
+include "security.m";
+random := load Random Random->PATH;
+
+randomint: fn(which: int): int;
+randombuf: fn(which, n: int): array of byte;
+.EE
+.SH DESCRIPTION
+.B Randomint
+and
+.B randombuf
+return random or not-quite-random data
+obtained from
+.B /dev/random
+or
+.BR /dev/notquiterandom .
+.B Randomint
+returns a random integer;
+.B randombuf
+returns an array of length
+.I n
+filled with random bytes.
+In both functions,
+.I which
+may be either
+.B ReallyRandom
+or
+.B NotQuiteRandom
+to select the random data source.
+.SH FILES
+.B /dev/random
+.br
+.B /dev/notquiterandom
+.SH SOURCE
+.B /appl/lib/random.b
+.SH SEE ALSO
+.IR rand (2),
+.IR cons (3)
diff --git a/man/2/security-ssl b/man/2/security-ssl
new file mode 100644
index 00000000..7b54f2af
--- /dev/null
+++ b/man/2/security-ssl
@@ -0,0 +1,76 @@
+.TH SECURITY-SSL 2
+.SH NAME
+ssl: connect, secret \- interface to the Secure Sockets Layer
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "security.m";
+ssl := load SSL SSL->PATH;
+
+connect: fn(fd: ref Sys->FD): (string, ref Sys->Connection);
+secret: fn(c: ref Sys->Connection, secretin,
+ secretout: array of byte): string;
+.EE
+.SH DESCRIPTION
+.B SSL
+provides an interface to the secure sockets layer device
+.IR ssl (3).
+.PP
+.B Connect
+allocates a new
+.IR ssl (3)
+connection directory.
+It pushes
+file descriptor
+.I fd
+into the
+.B data
+file of that connection, and if successful,
+returns a reference to a
+.B Connection
+adt describing the connection.
+The
+.B Connection
+adt has its members set as follows:
+.B dir
+names the resulting connection directory;
+.B cfd
+is open on the connection's
+control file; and
+.B dfd
+is open on the connection's
+.B data
+file,
+which is read and written to exchange data on the original
+.I fd
+using SSL.
+.PP
+.B Secret
+writes
+.I secretin
+and
+.I secretout
+to
+.IB c .dir/secretin
+and
+.IB c .dir/secretout
+where
+.I n
+is obtained from the
+.B Connection
+adt
+.IR c .
+The string returned describes errors encountered, if any; otherwise it is nil.
+.PP
+.SH SOURCE
+.B /appl/lib/ssl.b
+.SH "SEE ALSO"
+.IR security-auth (2),
+.IR ssl (3)
+.SH DIAGNOSTICS
+.B Connect
+returns a tuple containing a string and a
+.B Connection
+reference.
+On success the string is nil, and the connection reference is not nil;
+on error, the string contains a diagnostic, and the connection reference is nil.
diff --git a/man/2/selectfile b/man/2/selectfile
new file mode 100644
index 00000000..7b28b236
--- /dev/null
+++ b/man/2/selectfile
@@ -0,0 +1,57 @@
+.TH SELECTFILE 2
+.SH NAME
+selectfile \-
+file browser
+.SH SYNOPSIS
+.EX
+include "selectfile.m";
+selectfile := load Selectfile Selectfile->PATH;
+
+init: fn();
+filename: fn(ctxt: ref Draw->Context, parent: ref Draw->Image,
+ title: string,
+ pat: list of string,
+ dir: string): string;
+.EE
+.SH DESCRIPTION
+.B Selectfile
+provides an interactive file browser for use by a
+.IR wm (1)
+application.
+It allows a user to browse the
+file system to select a file of a give type.
+.PP
+.B Init
+should be called once to initialise the module's internal state.
+.PP
+.B Filename
+makes a dialog panel for selecting a file.
+It is created in the graphics context
+.IR ctxt ,
+near the northeast corner of a given parent window,
+.IR parent ,
+represented by that window's Image.
+(If the parent window is a Tk Toplevel
+.IR t ,
+for instance, the appropriate value is
+.IB t .image \f1.)\fP
+If
+.I parent
+is nil, the panel is centred on the screen.
+.I Dir
+gives the directory where the file search should begin.
+Only files that match
+.I pat
+are displayed.
+The returned string is the name of the selected file,
+or the empty string if no file was selected.
+.SH SOURCE
+.B /appl/lib/selectfile.b
+.SH SEE ALSO
+.IR dialog (2),
+.IR dividers (2),
+.IR draw-context (2),
+.IR tabs (2),
+.IR tk (2),
+.IR wmlib (2)
+
diff --git a/man/2/sets b/man/2/sets
new file mode 100644
index 00000000..6c0fcaf9
--- /dev/null
+++ b/man/2/sets
@@ -0,0 +1,226 @@
+.TH SETS 2
+.SH NAME
+Sets \-
+sets of non-negative integers
+.SH SYNOPSIS
+.EX
+include "sets.m";
+\fIOR\fP include "sets32.m";
+sets := load Sets Sets->PATH;
+A, B: import Sets;
+
+Sets: adt {
+ init: fn();
+ set: fn(): Set;
+ str2set: fn(str: string): Set;
+ bytes2set: fn(d: array of byte): Set;
+ Set: adt {
+ # opaque data
+
+ X: fn(s1: self Set, op: int, s2: Set): Set;
+ add: fn(s: self Set, n: int): Set;
+ addlist: fn(s: self Set, ns: list of int): Set;
+ del: fn(s: self Set, n: int): Set;
+ invert: fn(s: self Set): Set;
+
+ eq: fn(s1: self Set, s2: Set): int;
+ holds: fn(s: self Set, n: int): int;
+ isempty: fn(s: self Set): int;
+ msb: fn(s: self Set): int;
+ limit: fn(s: self Set): int;
+
+ str: fn(s: self Set): string;
+ bytes: fn(s: self Set, n: int): array of byte;
+ };
+};
+.EE
+.SH DESCRIPTION
+.PP
+The
+.B Sets
+module provides routines for manipulating sets
+of small non-negative integers. There are currently
+two implementations available:
+the implementation declared in
+.B sets32.m
+stores sets of numbers from 0 to 31 inclusive;
+the implementation in
+.B sets.m
+stores arbitrary sets of non-negative integers.
+The description given is for the more general
+implementation; behaviour of the other is undefined
+if an integer higher than 31 is used.
+.PP
+.B Init
+must be called first, to allow
+.B Sets
+to initialise its internal state.
+.B Set
+returns a new set, containing nothing.
+.B Str2set
+converts a string to a new set; the string
+should have been created with
+.BR Set.str() .
+.B Bytes2set
+converts an array of bytes,
+.IR d ,
+as returned by
+.BR Set.bytes() ,
+to a new set.
+.PP
+Note that all set operations are copy operations;
+none change an existing set.
+.TP 10
+.IB s1 .X(\fIop\fP,\ \fIs2\fP)
+Returns a new set, the result of combining
+.I s1
+and
+.I s2
+according to boolean operator
+.IR op .
+.I Op
+can be any bitwise boolean combination of the
+two constants
+.B A
+and
+.BR B ,
+defined in the module. Notionally, each
+set is an infinitely long string of bits, each
+bit representing a non-negative integer:
+zero if the integer is present, and one if absent.
+For each corresponding bit in
+.I s1
+and
+.IR s2 ,
+.B X
+sets a corresponding bit in the returned set
+according to the calculation
+.IR "s1 op s2" .
+.TP
+.IB s .add(\fIn\fP)
+Returns the set
+.I s
+with
+.I n
+added.
+.TP
+.IB s .addlist(\fIns\fP)
+.B Addlist
+is the same as calling
+.B add
+on each member of the list
+.IR ns ,
+but somewhat more efficient.
+.TP
+.IB s .del(\fIn\fP)
+Returns
+.I s
+with
+.I n
+removed.
+.TP
+.IB s .invert()
+.B Invert
+returns a set holding all non-negative integers
+other than those already in
+.IR s .
+Hence
+.B set().invert()
+holds all non-negative integers.
+.TP
+.IB s1 .eq(\fIs2\fP)
+Returns non-zero if
+.I s1
+is identical to
+.IR s2 .
+.TP
+.IB s .holds(\fIn\fP)
+Returns non-zero if
+.I s
+holds
+.I n
+as a member.
+.TP
+.IB s .isempty()
+Returns non-zero if
+.I s
+holds no members.
+.TP
+.IB s .msb()
+Returns the "most significant bit": the membership
+status of all members that have not been explicitly
+set. For example,
+.B set().msb()
+is 0;
+.B set().invert().msb()
+is 1.
+.TP
+.IB s .limit()
+If
+.IB s .msb()
+is zero,
+.IB s .limit()
+returns one more than the largest member contained in
+.IR s ,
+otherwise it returns one more than the largest member
+.I not
+contained in
+.IR s .
+Thus
+.B set().limit()
+yields 0,
+and
+.B set().invert().del(5).limit()
+yields 6.
+.TP
+.IB s .str()
+Returns a string corresponding to
+.IR s .
+The format is
+.IB hexdigits : msb\fR,\fP
+where
+.I hexdigits
+give the least significant members of the set,
+most significant on the left, in hexadecimal format;
+.I msb
+gives the padding bit that fills the rest of the set.
+Note that this format is compatible between the
+two implementations.
+.TP
+.IB s .bytes(\fIn\fP)
+Returns a packed byte representaton of
+.I s .
+The array is held in little-endian order,
+with the topmost bit of the top byte
+holding the msb of the set.
+The array returned will contain at least
+.I n
+bytes.
+.SH EXAMPLES
+Given two sets,
+.I s1
+and
+.IR s2 ,
+.IB s1 ".X(A&B," " s2" )
+gives their intersection;
+.IB s1 ".X(A|B," " s2" )
+their union;
+.IB s1 ".X(A&~B," " s2" )
+gives the set of all members of
+.I s1
+that aren't in
+.IR s2 ;
+.IB s1 ".X(~(A|B), " s2 )
+gives the set of all integers in neither
+.I s1
+nor
+.IR s2 .
+.PP
+.EX
+ sys->print("%s\en", set().addlist(1::2::5::nil)
+ .invert().X(A|B, set().add(2)).str());
+.EE
+produces the string
+.RB `` dd:1 '',
+corresponding to the set of all non-negative
+integers except 1 and 5.
diff --git a/man/2/sexprs b/man/2/sexprs
new file mode 100644
index 00000000..e06b06cf
--- /dev/null
+++ b/man/2/sexprs
@@ -0,0 +1,362 @@
+.TH SEXPRS 2
+.SH NAME
+Sexprs: Sexp \- S-expressions
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+include "sexprs.m";
+sexprs := load Sexprs Sexprs->PATH;
+
+Sexp: adt {
+ pick {
+ String =>
+ s: string;
+ hint: string;
+ Binary =>
+ data: array of byte;
+ hint: string;
+ List =>
+ l: cyclic list of ref Sexp;
+ }
+
+ read: fn(b: ref Bufio->Iobuf): (ref Sexp, string);
+ parse: fn(s: string): (ref Sexp, string, string);
+ pack: fn(e: self ref Sexp): array of byte;
+ packedsize: fn(e: self ref Sexp): int;
+ text: fn(e: self ref Sexp): string;
+ b64text: fn(e: self ref Sexp): string;
+ unpack: fn(a: array of byte): (ref Sexp, array of byte, string);
+
+ eq: fn(e: self ref Sexp, t: ref Sexp): int;
+ copy: fn(e: self ref Sexp): ref Sexp;
+
+ astext: fn(e: self ref Sexp): string;
+ asdata: fn(e: self ref Sexp): array of byte;
+
+ islist: fn(e: self ref Sexp): int;
+ els: fn(e: self ref Sexp): list of ref Sexp;
+ op: fn(e: self ref Sexp): string;
+ args: fn(e: self ref Sexp): list of ref Sexp;
+};
+
+init: fn();
+.EE
+.SH DESCRIPTION
+.B Sexprs
+provides a data type and I/O for S-expressions, or `symbolic expressions',
+which represent complex data as trees.
+This implementation provides the variant defined by
+Rivest in Internet Draft
+.L draft-rivest-sexp-00.txt
+(4 May 1997),
+as used for instance by the Simple Public Key Infrastructure (SPKI).
+It offers a basic set of operations on the internal representation,
+and input and output in both canonical and advanced transport encodings.
+.I Canonical
+form conveys binary data directly and efficiently (unlike some
+other schemes such as XML).
+Canonical encoding must be used when exchanging S-expressions between computers,
+and when digitally signing an expression.
+.I Advanced
+encoding is a more elaborate
+form similar to that used by Lisp interpreters, typically using
+only printable characters: representing any binary data in hexadecimal or base 64 encodings,
+and quoting strings containing special characters, using escape sequences as required.
+Unquoted text is called a
+.IR token ,
+restricted by the standard to a specific alphabet:
+it must start with a letter or a character from the set
+.LR "-./_:*+=" ,
+and contain only letters, digits and characters from that set.
+Upper- and lower-case letters are distinct.
+See
+.IR sexprs (6)
+for a precise description.
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+.PP
+.B Sexp
+is the internal representation of S-expression data, as lists and non-list values (atoms) that
+in general can form a tree structure;
+that is, a list may contain not just atoms but other lists as its elements, and so on recursively.
+The atoms are strings of text or binary.
+A well-formed S-expression might be a tree, but cannot contain cycles.
+.PP
+For convenience in processing,
+.B Sexp
+distinguishes three variants represented in a pick adt:
+.TP
+.B Sexp.String
+An atom that can be represented as a textual string
+.IR s ,
+including all tokens but also any other data that contains no characters outside the 7-bit ASCII
+set and no control-characters other than space.
+.I Hint
+is the `display hint', typically nil (see the Internet Draft for its intended use).
+.TP
+.B Sexp.Binary
+An atom that must be represented as an array of bytes
+.I data
+(typically because it is purely binary data or contains non-space control-characters).
+.I Hint
+again is the display hint.
+.TP
+.B Sexp.List
+A list of S-expression values,
+.IR l .
+.PP
+.B Sexp
+provides the following operations for input and output, using
+.IR bufio (2)'s
+buffered channels (directly or indirectly):
+.TP
+.BI read( b )
+Read one S-expression (a list or a single token) from
+.B Iobuf
+.IR b .
+Return a tuple of the form
+.RI ( e , err ),
+where
+.I e
+is the
+.B Sexp
+representing the data just read, and
+.I err
+is nil on success;
+.I b
+is positioned at the first character after the end of the S-expression.
+On an error,
+.I e
+is nil, and
+.I err
+contains the diagnostic string.
+On end-of-file, both
+.I e
+and
+.I err
+are nil.
+.TP
+.BI parse( s )
+Parse the first S-expression in string
+.IR s ,
+and return a tuple
+.RI ( e , t , err ),
+where
+.I e
+is the
+.B Sexp
+representating that expression,
+.I t
+is the unparsed tail of string
+.IR s ,
+and
+.I err
+is a diagnostic string that is nil on success.
+On an error,
+.I e
+is nil,
+.I t
+is as before, and
+.I err
+contains the diagnostic.
+.TP
+.IB e .pack()
+Return an array of byte that represents
+.B Sexp
+.I e
+as an S-expression in canonical transport form.
+.TP
+.IB e .packedsize()
+Return the size in bytes of the canonical transport representation of
+.IR e .
+.TP
+.IB e .b64text()
+Return a string that contains the base-64 representation of the canonical representation of
+.IR e ,
+surrounded by braces.
+.TP
+.IB e .text()
+Return a string that represents
+.I e
+as an S-expression in advanced (`human-readable') transport form containing no newlines.
+The result of
+.B text
+can always be interpreted by
+.B Sexp.read
+and
+.BR Sexp.parse ,
+and furthermore
+.BI "Sexp.parse(" e ".text())"
+yields the same tree value as
+.I e
+(similarly for
+.BR Sexp.read ).
+.TP
+.BI unpack( a )
+Parse the first S-expression in array of byte
+.IR a ,
+and return a tuple
+.RI ( e , r , err ),
+where
+.I e
+is the
+.B Sexp
+representing the S-expression,
+.I r
+is a slice of
+.I a
+giving the portion of
+.I a
+after the S-expression, and
+.I err
+is nil on success.
+On error,
+.I e
+is nil,
+.I r
+is as before,
+and
+.I err
+contains a diagnostic string.
+The data in
+.I a
+is typically in canonical transport form, read from a file or network connection.
+.PP
+All input functions accept S-expression in either canonical or advanced form, or
+any legal mixture of forms.
+Expressions can cross line boundaries.
+For output in canonical form, use
+.BR pack ;
+for output in advanced form (similar to Lisp's S-expressions), use
+.BR text .
+.PP
+.B Sexp
+provides a further small collection of operations:
+.TP
+.IB e1 .eq( e2 )
+Return non-zero if expression
+.I e1
+and
+.I e2
+are identical (isomorphic in tree structure and atoms in corresponding positions in
+.I e1
+and
+.I e2
+equal);
+return 0 otherwise.
+.TP
+.IB e .copy()
+Return a new
+.B Sexp
+value equal to
+.IR e ,
+but sharing no storage with it.
+(In other words, it returns a copy of the
+whole tree
+.IR e ).
+.TP
+.IB e .islist()
+Return true iff
+.I e
+is a list
+(ie, a value of type
+.BR Sexp.List ).
+.PP
+Two operations provide a shorthand for fetching the value of an atom, returning nil if
+applied to a list:
+.TP
+.IB e .astext()
+Return the value of
+.I e
+as a
+.BR string ;
+binary data is assumed to be a string in
+.IR utf (6)
+representation.
+.TP
+.IB e .asdata()
+Return the value of
+.I e
+as an array of bytes.
+A
+.B String
+value will be converted to an array of bytes giving its
+.IR utf (6).
+.PP
+The remaining operations extract values from lists,
+and return nil if applied to an atom:
+.TP
+.IB e .els()
+Return the elements of list
+.IR e ;
+return nil if
+.I e
+is not a list.
+.TP
+.IB e .op()
+Return the first token of list
+.IR e ,
+if it is a string; return nil if it is not a string or
+.I e
+is not a list.
+The first token of a list often gives an operation name.
+.TP
+.IB e .args()
+Return a list containing the second and subsequent values in list
+.IR e ;
+useful when the first value is an operation name and the rest represent parameters
+(arguments) to that operation.
+.SH EXAMPLES
+The following S-expression is in advanced transport form:
+.IP
+.EX
+(snicker "abc" (#03# |YWJj|))
+.EE
+.PP
+It represents a list of three elements: the token
+.LR snicker ,
+the token
+.LR abc ,
+and a sub-list with two elements (a hexadecimal constant
+representing the byte
+.LR 03 ,
+and a base-64 constant
+.L YWjj
+that represents the bytes
+.LR abc ).
+.PP
+Here is another in advanced form with two sublists:
+.IP
+.EX
+(certificate
+ (issuer bob)
+ (subject "alice b"))
+.EE
+.PP
+Its equivalent in canonical form (as produced by
+.BR pack )
+is shown below:
+.IP
+.EX
+(11:certificate(6:issuer3:bob)(7:subject7:alice b))
+.EE
+.PP
+Nesting parentheses
+still mark the start and end of lists, but there is no other punctuation or white space, and
+the byte sequence representing each atom
+is preceded by a decimal count, so that binary values appear unencoded,
+and for instance the space
+in the last string is not a delimiter but part of the token.
+.SH SOURCE
+.B /appl/lib/sexprs.b
+.SH SEE ALSO
+.IR bufio (2),
+.IR xml (2),
+.IR sexprs (6)
+.PP
+R. Rivest, ``S-expressions'', Network Working Group Internet Draft,
+.L http://theory.lcs.mit.edu/~rivest/sexp.txt
+(4 May 1997),
+reproduced in
+.BR /lib/sexp .
diff --git a/man/2/sh b/man/2/sh
new file mode 100644
index 00000000..ebe82f15
--- /dev/null
+++ b/man/2/sh
@@ -0,0 +1,561 @@
+.TH SH 2
+.SH NAME
+Sh \- module interface to the shell
+.SH SYNOPSIS
+.EX
+.ps -1
+.vs -1
+include "sh.m";
+sh := load Sh Sh->PATH;
+Context, Listnode: import sh;
+
+system: fn(drawctxt: ref Draw->Context, cmd: string): string;
+run: fn(drawctxt: ref Draw->Context, argv: list of string): string;
+parse: fn(s: string): (ref Cmd, string);
+cmd2string: fn(c: ref Cmd): string;
+list2stringlist: fn(nl: list of ref Listnode): list of string;
+stringlist2list: fn(sl: list of string): list of ref Listnode;
+
+Context: adt {
+ new: fn(drawcontext: ref Draw->Context): ref Context;
+ get: fn(c: self ref Context,
+ name: string): list of ref Listnode;
+ set: fn(c: self ref Context,
+ name: string,
+ value: list of ref Listnode);
+ setlocal: fn(c: self ref Context,
+ name: string,
+ value: list of ref Listnode);
+ envlist: fn(c: self ref Context):
+ list of (string, list of ref Listnode);
+ push, pop: fn(c: self ref Context);
+ copy: fn(c: self ref Context, copyenv: int): ref Context;
+ run: fn(c: self ref Context,
+ args: list of ref Listnode,
+ last: int): string;
+ addmodule: fn(c: self ref Context, name: string,
+ mod: Shellbuiltin);
+ addbuiltin: fn(c: self ref Context, name: string,
+ mod: Shellbuiltin);
+ removebuiltin: fn(c: self ref Context, name: string,
+ mod: Shellbuiltin);
+ addsbuiltin: fn(c: self ref Context, name: string,
+ mod: Shellbuiltin);
+ removesbuiltin: fn(c: self ref Context, name: string,
+ mod: Shellbuiltin);
+ fail: fn(c: self ref Context, ename, msg: string);
+ options: fn(c: self ref Context): int;
+ setoptions: fn(c: self ref Context, flags, on: int): int;
+};
+
+Listnode: adt {
+ cmd: ref Cmd;
+ word: string;
+};
+
+Cmd: adt {
+ # private data
+};
+
+Shellbuiltin: module {
+ initbuiltin: fn(ctxt: ref Context, sh: Sh): string;
+ whatis: fn(ctxt: ref Sh->Context, sh: Sh,
+ name: string, wtype: int): string;
+ runbuiltin: fn(ctxt: ref Context, sh: Sh,
+ cmd: list of ref Listnode,
+ last: int): string;
+ runsbuiltin: fn(ctxt: ref Context, sh: Sh,
+ cmd: list of ref Listnode): list of ref Listnode;
+ getself: fn(): Shellbuiltin;
+};
+
+.ps +1
+.vs +1
+.EE
+.SH DESCRIPTION
+.I Sh
+is a command-line interpreter and a scripting language;
+it also presents a module interface to allow Limbo
+modules to access its functionality at a lower level.
+The
+.B Sh
+module can be used in several different ways.
+At the simplest level, it can be run as a command-line
+program; for details of this, see
+.IR sh (1).
+The simplest access at the Limbo level is through
+the
+.B system
+function, which given a
+.I draw
+.B Context
+(see
+.IR draw-context (2))
+and a string
+executes the
+.I sh
+command contained in
+.I s
+and returns its result. It catches any exceptions raised by the command.
+Almost as simple is
+.BR exec ,
+which runs
+.I argv
+as a command, taking the first word as the command to be
+executed (it can be a braced block) and giving the rest as arguments,
+catching any exceptions raised.
+.PP
+Although program arguments are passed to external programs
+as lists of strings, at the
+.B Sh
+module level, an argument list is held as a
+.BR "list of ref Listnode" .
+A
+.B Listnode
+holds either a simple string, or a braced block
+that has been parsed by the shell. Sometimes it can hold
+both; in this case the string and the block both represent
+the same thing.
+.B Parse
+converts from a string to a
+.B Cmd
+(a braced block). It returns a tuple
+.RI ( cmd ,\ error )
+where
+.I cmd
+holds the parsed block,
+and
+.I error
+is non-empty if an error has occurred doing so.
+.B Cmd2string
+performs the opposite conversion; it returns
+a string that when parsed will yield the same command
+block it was passed.
+The utility functions
+.B List2stringlist
+and
+.B stringlist2list
+convert from and to a
+.B list of ref Listnode
+to or from a
+.B list of string
+respectively.
+.PP
+A
+.B Context
+holds all the state information needed by a currently running
+.I sh
+process; this adt holds current values of environment variables
+and a list of currently loaded modules and builtin commands.
+It is specific to the process within which it was created.
+If it is desired to run
+.I sh
+commands in a newly spawned process, a new
+.B Context
+must be created, or a copy of an existing Context made (making
+sure to synchronise access until the copy has been made).
+.TP 10
+.BI Context.new( drawcontext )
+.B New
+creates a new context.
+.I Drawcontext
+represents the current graphics context
+within which
+.I sh
+commands will be run
+(see
+.IR draw-context (2)).
+.TP
+.IB ctxt .get(\fPname\fP)
+.B Get
+retrieves the value of environment variable
+.I name
+from
+.IR ctxt .
+It is retrieved from the innermost scope in which
+a value for
+.I name
+has been set.
+.TP
+.IB ctxt .set(\fPname\fP,\ \fPvalue\fP)
+.B Set
+sets the value of environment variable
+.I name
+in
+.IR ctxt
+to
+.IR value .
+It is set in the innermost scope in which a value
+for
+.I name
+has been set, or the outermost level if it has
+not been set.
+.TP
+.IB ctxt .setlocal(\fPname\fP,\ \fPvalue\fP)
+Similar to
+.B set()
+except that the value is set in the innermost scope
+that has been pushed.
+.TP
+.IB ctxt .envlist()
+.B Envlist
+retrieves the list of all the environment variables
+currently in scope, and their values.
+It returns a list of
+.RI ( name ,\ value )
+tuples, where
+.I name
+is the name of the variable and
+.I value
+is its value.
+.TP
+.IB ctxt .push()
+.B Push
+creates a new innermost environment variable scope.
+.TP
+.IB ctxt .pop()
+.B Pop
+discards the current innermost scope, losing the
+values of all variables that have been defined there.
+It is an error to
+.B pop
+a context that has not been pushed.
+Care must be taken to ensure that a
+.B push
+is always matched by a
+.BR pop.
+In particular, exceptions should be caught,
+the context popped, and the exception re-raised.
+.TP
+.IB ctxt .copy(\fPcopyenv\fP)
+The shell's
+.B Context
+is associated with a particular process;
+.B copy
+returns a copy of
+.I ctxt
+associated with the current process. If
+.I copyenv
+is non-zero, the whole environment will be copied - this
+should be set if the new process is to run asynchronously - i.e.
+if there is a chance that there might be two processes accessing the
+context in parallel. It is an error to copy a context if not
+within a new process.
+.TP
+.IB ctxt .run(\fPargs\fP,\ \fPlast\fP)
+.B Run
+executes a
+.I sh
+command.
+.I Last
+should be non-zero if this is the last time
+that
+.B run
+will be called, so
+.I sh
+does not have to spawn a new process in order
+to hide file redirection side-effects.
+.TP
+.IB ctxt .addmodule(\fPname\fP,\ \fPmod\fP)
+.B Addmodule
+adds the
+.B Shellbuiltin
+module
+.I mod
+to its list of builtin modules.
+The module will be initialised as described in
+``Builtin modules'', below.
+.TP
+.IB ctxt .addbuiltin(\fPname\fP,\ \fPmod\fP)
+.B Addbuiltin
+may be called by a module that has previously
+been loaded by
+.B addmodule
+or by the
+.B load
+.I sh
+command to add a new builtin command
+to the shell. Any subsequent invocation of
+.I name
+within
+.I ctxt
+will result in a call of
+.B runbuiltin()
+to
+.IR mod .
+Any attempt to redefine the command
+.RB `` builtin ''
+will be ignored.
+.TP
+.IB ctxt .removebuiltin(\fPname\fP,\ \fPmod\fP)
+.B Removebuiltin
+removes
+.I name
+from the list of builtin commands in
+.IR ctxt .
+If
+.I name
+had not previously been defined by
+.IR mod ,
+or had subsequently been replaced, then
+this function does nothing.
+.TP
+.IB ctxt .addsbuiltin(\fPname\fP,\ \fPmod\fP)
+.B Addsbuiltin
+may be called by a module that has previously
+been loaded by
+.B addmodule
+or by the
+.B load
+.I sh
+command to add a new builtin substitution operator
+to the shell.
+Any subsequent invocation of
+.BI ${ name }
+within
+.I ctxt
+will result in a call of
+.B runsbuiltin()
+to
+.IR mod .
+.TP
+.IB ctxt .removesbuiltin(\fPname\fP,\ \fPmod\fP)
+.B Removesbuiltin
+removes
+.I name
+from the list of builtin substitution operators in
+.IR ctxt .
+If
+.I name
+had not previously been defined by
+.IR mod ,
+or had subsequently been replaced, then
+this function does nothing.
+.TP
+.IB ctxt .fail(\fPename\fP,\ \fPmsg\fP)
+.B Fail
+prints
+.I msg
+to the standard error if message printing
+is currently enabled, and raises
+the exception
+.BI fail: ename\f1.\fP
+.TP
+.IB ctxt .options()
+.B Options
+returns a bitmask of the options currently enabled in
+.IR ctxt .
+The bits are defined by constants declared within
+.BR Context .
+They include:
+.RS
+.TP
+.IB ctxt .INTERACTIVE
+.I Sh
+is currently being run from an interactive command-line.
+.TP
+.IB ctxt .VERBOSE
+Message printing is currently enabled.
+.TP
+.IB ctxt .EXECPRINT
+Commands are printed to standard error
+as they are executed.
+.TP
+.IB ctxt .ERROREXIT
+An exception will be raised when the first
+simple command returns an error status.
+.PP
+Options are defined in the innermost scope
+of
+.I ctxt
+and will be lost when it is
+.BR pop ped.
+.RE
+.TP
+.IB ctxt .setoptions(\fPflags\fP,\ \fPon\fP)
+.B Setoptions
+sets the specified
+.I flags
+within
+.IR ctxt .
+.I Flags
+is a bitmask of options, as described in
+.BR options ,
+above. If
+.I on
+is non-zero, the specified bits will be set;
+otherwise they will be reset.
+.B Setoptions
+returns the previously set options bitmask.
+.SS Builtin modules
+.B Shellbuiltin
+specifies the interface to a loadable
+.I sh
+builtin module. Any Limbo module
+.I mod
+adhering to this
+interface may be loaded into the shell.
+.TP 10
+.IB mod ->initbuiltin(\fPctxt\fP,\ \fPsh\fP)
+.B Initbuiltin
+is called when
+.I sh
+loads
+.I mod
+either via the
+.B load
+command, or via the
+.B loadmodule()
+function.
+.I Ctxt
+is the context within which the builtin has been
+loaded, and
+.I sh
+is the
+.B Sh
+module itself. When
+.B initbuiltin
+is called,
+.I mod
+is expected to call
+.IB ctxt .addbuiltin
+and
+.IB ctxt .addsbuiltin
+to define any builtin commands and builtin substitution
+operators that it wants. If an error occurs on
+initialisation,
+.B initbuiltin
+should return a non-nil value; this will cause the load to fail.
+.TP
+.IB mod ->runbuiltin(\fPctxt\fP,\ \fPsh\fP,\ \fPcmd\fP,\ \fPlast\fP)
+.B Runbuiltin
+is invoked when
+.I sh
+executes a command that has previously been
+defined as a builtin command by
+.IR mod .
+.I Ctxt
+is the current execution context (which may not be
+the original context passed to
+.BR initbuiltin() ),
+.I sh
+is the running
+.B Sh
+module, and
+.I cmd
+is the command to be executed.
+.I Last
+is true if this is the last command to be executed
+in the current process; it can be passed to
+.IB ctxt .run()
+as appropriate.
+The name of the command can be found in
+.BR "(hd cmd).word" .
+.B Runbuiltin
+returns its exit status; by convention this
+is the exit status of the last command executed.
+A non-nil exit status is usually treated as false.
+By convention, if an invalid set of arguments are
+passed to a builtin command, a
+.B usage
+exception is raised by calling
+.IB ctxt .fail
+with
+.B "usage"
+and an explanatory usage message as arguments.
+.TP
+.IB mod ->runsbuiltin(\fPctxt\fP,\ \fPsh\fP,\ \fPcmd\fP)
+Similar to
+.BR runbuiltin ,
+.B runsbuiltin
+is called when
+.I sh
+encounters a builtin substitution operator
+that has previously been defined by
+.IR mod .
+It returns the list of values that will be
+substituted in place of the operator.
+.TP
+.IB mod ->getself()
+.B Getself
+should return the
+.B Shellbuiltin
+module handle for
+.IR mod ,
+usually obtained by invoking
+.BR "load $self" .
+N.B. it is important that the value returned
+by
+.B getself
+is the same as that passed to
+.B addbuiltin
+or
+.BR addsbuiltin .
+As the Limbo
+.B load
+operator returns a different value each time,
+the value to be returned by
+.B getself()
+should be initialised once,
+during the call to
+.BR initbuiltin() .
+.TP 10
+.IB mod ->whatis(\fPctxt\fP,\ \fPsh\fP,\ \fPname\fP,\ \fPwtype\fP)
+.B Whatis
+is called by the shell's
+.B whatis
+command to query the definition of a name.
+.I Wtype
+gives the type of name that is being asked about; it can be
+.B BUILTIN
+(conventional commands),
+.BR SBUILTIN
+(substitution builtins),
+or
+.BR OTHER
+(any other names that the module defines).
+Return
+.B nil
+to get the usual default behaviour. The
+.B std
+module, for example, uses this feature to
+display the definition of a shell function
+correctly.
+.SS Exceptions
+The exceptions used within
+.I sh
+are exactly the same as those used within Limbo,
+except that all exceptions generated by the
+shell are prefixed by the string
+.RB `` fail: '',
+and any exception caught with the prefix
+.B fail:
+has its first 5 characters removed before
+being made available to the
+.I sh
+script.
+This adheres to the convention defined by
+other shells within Inferno that a process
+that raises an exception with a
+.B fail:
+prefix is just returning a non-zero exit status,
+and should not be left in a Broken state.
+It also means that the number of bytes available
+for the exception string is reduced by 5
+(to 59). Care must therefore be taken to avoid
+generating an exception with a name that is too long;
+.I sh
+takes the pragmatic approach of truncating any
+exception string that is too long.
+.SH FILES
+.TP 10
+.BI /prog/ pid /wait
+The file used by the shell to wait for dead child processes.
+.SH SOURCE
+.B /appl/cmd/sh/sh.y
+.SH SEE ALSO
+.IR sh (1),
+.IR sh-std (1),
+.IR sh-expr (1),
+.IR sh-tk (1),
+.IR sys-exception (2)
diff --git a/man/2/smtp b/man/2/smtp
new file mode 100644
index 00000000..16cde120
--- /dev/null
+++ b/man/2/smtp
@@ -0,0 +1,58 @@
+.TH SMTP 2
+.SH NAME
+smtp \- Simple Mail Transfer Protocol
+.SH SYNOPSIS
+.EX
+include "smtp.m";
+smtp := load Smtp Smtp->PATH;
+
+open: fn(server: string): (int, string);
+sendmail: fn(fromwho: string,
+ towhom: list of string,
+ cc: list of string,
+ msg: list of string): (int, string);
+close: fn(): (int, string);
+.EE
+.SH DESCRIPTION
+.B Smtp
+provides an interface to the mail transport protocol SMTP.
+.PP
+.B Open
+opens a connection to the given SMTP
+.IR server .
+If
+.I server
+is nil,
+.B open
+uses the
+default mail server
+.B $MAILSERVER
+if set up in
+.BR /services/cs/db ;
+see
+.IR db (6).
+It returns -1 and an error message if the connection fails.
+.PP
+.B Sendmail
+sends mail to the SMTP server for subsequent delivery.
+The first argument names the sender, the list
+.I towhom
+names the
+recipients,
+.I cc
+is a list of CC's,
+and
+.I msg
+has the text of the message. The latter
+may simply be a list of one item containing the whole message, a list of lines of the message
+or any intermediate format. It returns -1 and an error message on failure.
+.PP
+.B Close
+closes the connection to the SMTP server.
+.SH SOURCE
+.B /appl/lib/smtp.b
+.SH SEE ALSO
+.IR sendmail (1),
+.IR acme (1)
+.SH BUGS
+Too much copying of strings is done, especially with large messages.
diff --git a/man/2/spki b/man/2/spki
new file mode 100644
index 00000000..dc7badb3
--- /dev/null
+++ b/man/2/spki
@@ -0,0 +1,446 @@
+.TH SPKI 2
+.SH NAME
+SPKI: Cert, Hash, Key, Name, Seqel, Signature, Subject, Toplev, Valid \- simple public key infrastructure
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+include "sexprs.m";
+include "keyring.m";
+include "spki.m";
+spki := load SPKI SPKI->PATH;
+
+Hash: adt {
+ alg: string;
+ hash: array of byte;
+
+ sexp: fn(h: self ref Hash): ref Sexprs->Sexp;
+ text: fn(h: self ref Hash): string;
+ eq: fn(h1: self ref Hash, h2: ref Hash): int;
+};
+
+Key: adt {
+ pk: ref Keyring->PK; # either pk/sk or hash might be nil
+ sk: ref Keyring->SK;
+ halg: string;
+ hash: ref Hash;
+
+ hashed: fn(k: self ref Key, alg: string): array of byte;
+ sigalg: fn(k: self ref Key): string;
+ text: fn(k: self ref Key): string;
+ sexp: fn(k: self ref Key): ref Sexprs->Sexp;
+ eq: fn(k1: self ref Key, k2: ref Key): int;
+};
+
+Name: adt {
+ principal: ref Key;
+ names: list of string;
+
+ isprincipal: fn(n: self ref Name): int;
+ local: fn(n: self ref Name): ref Name;
+ islocal: fn(n: self ref Name): int;
+ isprefix: fn(n1: self ref Name, n2: ref Name): int;
+ text: fn(n: self ref Name): string;
+ sexp: fn(n: self ref Name): ref Sexprs->Sexp;
+ eq: fn(n1: self ref Name, n2: ref Name): int;
+};
+
+Cert: adt {
+ e: ref Sexprs->Sexp; # S-expression, if originally parsed
+ issuer: ref Name;
+ subject: ref Subject;
+ valid: ref Valid;
+ pick {
+ A or KH or O => # auth, keyholder or object
+ delegate: int;
+ tag: ref Sexprs->Sexp;
+ N => # name
+ }
+
+ text: fn(c: self ref Cert): string;
+ sexp: fn(c: self ref Cert): ref Sexprs->Sexp;
+};
+
+Subject: adt {
+ pick{
+ P =>
+ key: ref Key;
+ N =>
+ name: ref Name;
+ O =>
+ hash: ref Hash;
+ KH =>
+ holder: ref Name;
+ T =>
+ k, n: int;
+ subs: cyclic list of ref Subject;
+ }
+
+ eq: fn(s1: self ref Subject, s2: ref Subject): int;
+ principal: fn(s: self ref Subject): ref Key;
+ text: fn(s: self ref Subject): string;
+ sexp: fn(s: self ref Subject): ref Sexprs->Sexp;
+};
+
+Signature: adt {
+ hash: ref Hash;
+ key: ref Key; # find by hash if necessary
+ sa: string;
+ sig: list of (string, array of byte);
+
+ sexp: fn(s: self ref Signature): ref Sexprs->Sexp;
+ text: fn(s: self ref Signature): string;
+};
+
+Seqel: adt {
+ pick{
+ C =>
+ c: ref Cert;
+ K =>
+ k: ref Key;
+ O =>
+ op: string;
+ args: list of ref Sexprs->Sexp;
+ S =>
+ sig: ref Signature;
+ E =>
+ exp: ref Sexprs->Sexp;
+ }
+
+ text: fn(se: self ref Seqel): string;
+};
+
+Valid: adt {
+ notbefore: int;
+ notafter: int;
+
+ intersect: fn(a: self Valid, b: Valid): (int, Valid);
+ text: fn(a: self Valid): string;
+ sexp: fn(a: self Valid): ref Sexprs->Sexp;
+};
+
+Toplev: adt {
+ pick {
+ C =>
+ v: ref Cert;
+ Sig =>
+ v: ref Signature;
+ K =>
+ v: ref Key;
+ Seq =>
+ v: list of ref Seqel;
+ }
+};
+
+init: fn();
+date2epoch: fn(s: string): int; # YYYY-MM-DD_HH:MM:SS
+epoch2date: fn(t: int): string;
+time2secs: fn(s: string): int; # HH:MM:SS
+secs2time: fn(t: int): string;
+
+# parse structures
+parse: fn(s: ref Sexprs->Sexp): (ref Toplev, string);
+parseseq: fn(s: ref Sexprs->Sexp): list of ref Seqel;
+parsecert: fn(s: ref Sexprs->Sexp): ref Cert;
+parsesig: fn(s: ref Sexprs->Sexp): ref Signature;
+parsename: fn(s: ref Sexprs->Sexp): ref Name;
+parsekey: fn(s: ref Sexprs->Sexp): ref Key;
+parsehash: fn(s: ref Sexprs->Sexp): ref Hash;
+parsecompound: fn(s: ref Sexprs->Sexp): ref Name;
+
+# tags
+maketag: fn(e: ref Sexprs->Sexp): ref Sexprs->Sexp;
+tagintersect: fn(t1: ref Sexprs->Sexp, t2: ref Sexprs->Sexp):
+ ref Sexprs->Sexp;
+tagimplies: fn(t1: ref Sexprs->Sexp, t2: ref Sexprs->Sexp): int;
+
+# hash canonical s-expression
+hashbytes: fn(a: array of byte, alg: string): array of byte;
+hashexp: fn(e: ref Sexprs->Sexp, alg: string): array of byte;
+.EE
+.SH DESCRIPTION
+.B SPKI
+provides data types and operations to help build implementations of the Simple Public Key Infrastructure
+(SPKI).
+It provides types for hash values, public and private keys, local and extended names,
+principals and compound principles, certificates, validity periods, signatures, and proof sequences.
+It also provides operations on authorisation tags.
+Externally, SPKI represents all such things as particular forms of S-expression, internally represented using
+.B Sexprs->Sexp
+from
+.IR sexprs (2).
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+.PP
+Most types defined here provide several common operations:
+.TP
+.IB t1 .eq( t2 )
+Return true iff values
+.I t1
+and
+.I t2
+are equal.
+.TP
+.IB t .sexp()
+Return an S-expression
+.I s
+representing the value of
+.IR t .
+Subsequently, the
+.B Sexp
+operation
+.IR s .pack()
+will yield an array of bytes containing the value
+.I t
+in SPKI's canonical S-expression form.
+.TP
+.IB t .text()
+Return a textual representation of the value
+.IR t ;
+it is often just the textual representation of the corresponding S-expression.
+.PP
+.B Hash
+is the internal representation of hash values,
+containing an
+algorithm name
+.B alg
+and the
+.B hash
+itself as an array of bytes.
+A
+.B Hash
+value can be created from an S-expression representing a SPKI
+.B <hash>
+element
+by
+.BR parsehash .
+It returns nil if the S-expression was ill-formed.
+.PP
+.B Key
+represents public and private keys,
+with an optional associated hash algorithm when signing, and
+an optional hash of the key itself.
+SPKI identifies principals and public keys, thus each instance of a principal
+in the other data structures is represented by a
+.B Key
+giving the corresponding public key, or its hash, or both.
+Currently the public and private (secret) key values have types defined by
+.IR keyring-intro (2).
+A
+.B Key
+value can be created from an S-expression representing a SPKI
+.B <public-key>
+element by
+.BR parsekey .
+It returns nil if the S-expression was ill-formed.
+.PP
+.B Name
+represents both local and extended names, and simple principals consisting of just a key.
+The field
+.B principal
+gives the key that defines the name space in which the list of names is interpreted.
+For simple principles, the list of
+.B names
+is nil.
+A local name has exactly one name in the list.
+Two parsing functions convert to
+.B Name
+from S-expressions.
+.B Parsename
+parses a SPKI
+.B <name>
+element:
+.BI (name
+[
+.I principal
+]
+.I name
+\&...
+.BR ),
+where
+.I principal is either a
+.B <public-key>
+or a
+.B <hash>
+element.
+.B Parsecompound
+accepts either a
+.B <name>
+element as above, or a
+.B <public-key>
+or its
+.BR <hash> .
+Both functions return nil if the S-expression is ill-formed.
+.PP
+.B Subject
+represents the subjects of SPKI name and authorisation certificates.
+It has several variants in a
+.B pick
+adt, with suitable fields for each variant:
+.TP
+.B Subject.P
+A simple principal: a
+.BR key .
+.TP
+.B Subject.N
+A group of principals or a delayed binding to a principal: a
+.BR name .
+.TP
+.B Subject.O
+The
+.B hash
+of an object.
+.TP
+.B Subject.KH
+A keyholder certificate, that says something about a key's
+.B holder
+(represented by a
+.BR Name ).
+.TP
+.B Subject.T
+A
+.I threshold
+subject, used only in authorisation certificates.
+The
+.I n
+subsidiary subjects are listed in
+.BR subs ;
+of those, at least
+.I k
+must sign a request for it to be authorised.
+.TP
+.B Subject
+provides the common operations
+.BR eq ,
+.B sexp
+and
+.BR text ,
+and a further operation:
+.TP
+.IB s .principal()
+If
+.I s
+is a simple principal or a name, return the
+.B Key
+defining the principal, if known; return nil otherwise.
+.PP
+Subjects appear only as a subsidiary item in certificates and do not have a parsing function.
+.PP
+.B Cert
+represents SPKI certificates.
+There are four variants, represented by a pick adt:
+.B Cert.A
+(authorisation);
+.B Cert.KH
+(keyholder);
+.B Cert.O
+(object); and
+.B Cert.N
+(name).
+The following fields and operations are common to all variants:
+.TP
+.B e
+original S-expression (if created by
+.BR parsecert )
+to allow hashes and signatures to be computed on the SPKI canonical form of the certificate
+.TP
+.B issuer
+The simple principal (represented as a name) that issued an authorisation, keyholder or object certificate,
+or the
+.B <issuer-name>
+of a name certificate (allowing both local and extended names not just simple principals).
+.TP
+.B subject
+The
+.B Subject
+of the certificate.
+Name certificates may not have threshold subjects.
+.TP
+.B valid
+Optional restriction on the certificate's validity
+(see
+.B Valid
+for details).
+.PP
+Name certificates have only the fields above; the others have several more fields:
+.TP
+.B
+delegate
+True iff the certificate carries delegation rights (ie,
+.B (propagate)
+in the S-expression representation).
+.TP
+.B tag
+An S-expression that expresses the authority granted by the certificate.
+The expression
+.B "(tag (*))"
+means `all permissions'.
+.PP
+A
+.B Cert
+value
+can be created from an S-expression representing a SPKI
+.B <cert>
+element by
+.BR parsecert .
+It returns nil if the expression was ill-formed.
+.PP
+SPKI
+.B tag
+expressions, represented internally by
+.B Sexprs->Sexpr
+trees, form a partial order,
+including the pattern operations
+.BR (*) ,
+.BR "(* set " ...
+.BR ),
+.BR "(* prefix " ...
+.BR ),
+.BR "(* range " ...
+.BR ),
+and as an extension,
+.BR "(* suffix " ...
+.BR ).
+Given two tag expressions
+.I t1
+and
+.IR t2 ,
+.I tagintersect
+returns a tag expression representing
+.I t1
+∩
+.IR t2 ;
+.B tagimplies
+returns true iff tag
+.I t1
+implies tag
+.IR t2 :
+(\fIt1\fP∩\fIt2\fP)=\fIt2\fP.
+Both functions work correctly when
+.I t1
+and
+.I t2
+contain any legal combination of pattern operations.
+.PP
+SPKI structures are converted to a canonical form of S-expression to be hashed or signed
+(with or without hashing).
+.B Hashbytes
+returns an array of bytes containing the result of hashing array
+.I a
+using hash algorithm
+.I alg
+(either
+.B sha1
+or
+.BR md5 ).
+.B Hashexp
+returns an array of bytes containing the hash of the canonical form of expression
+.I e
+using hash algorithm
+.IR alg .
+.SH SOURCE
+.B /appl/lib/spki.b
+.SH SEE ALSO
+.IR bufio (2),
+.IR sexprs (2),
+.IR spki-verifier (2)
diff --git a/man/2/spki-verifier b/man/2/spki-verifier
new file mode 100644
index 00000000..0218c75a
--- /dev/null
+++ b/man/2/spki-verifier
@@ -0,0 +1,91 @@
+.TH SPKI-VERIFIER 2
+.SH NAME
+verifier: verify \- verify sequence of SPKI elements
+.SH SYNOPSIS
+.EX
+include "bufio.m";
+include "sexprs.m";
+include "spki.m";
+
+sexprs := load Sexprs Sexprs->PATH;
+Sexp: import sexprs;
+
+spki := load SPKI SPKI->PATH;
+Name, Seqel, Subject, Valid: import spki;
+
+verifier := load Verifier Verifier->PATH;
+
+Speaksfor: adt {
+ subject: ref Subject;
+ name: ref Name;
+ regarding: ref Sexp;
+ valid: ref Valid;
+};
+
+init: fn();
+verify: fn(seq: list of ref Seqel):
+ (ref Speaksfor, list of ref Seqel, string);
+.EE
+.SH DESCRIPTION
+.B Verifier
+checks SPKI proof sequences.
+This initial implementation provides a single basic operation.
+Further work will allow (via channels and processes) verification
+to detect and refresh expired credentials, to support `pull' authentication,
+for instance.
+.PP
+.B Init
+must be called before any other operation of the module.
+.PP
+A
+.B Speaksfor
+value represents a claim that a given
+.I subject
+entity
+speaks for (on behalf of) a given
+.I name
+regarding a set of statements, with validity optionally limited to a given period.
+That is, when during the agreed time,
+.I subject
+makes a statement that is in the agreed sete, it is treated
+as if
+.I name
+had said it directly.
+The set of statements is defined by a SPKI `tag' expression, represented as
+an S-expression.
+In particular, the
+.B "(tag (*))"
+means that
+.I subject
+speaks for
+.I name
+about everything.
+A claim can be taken as true if supported by acceptable evidence,
+for instance a collection of signed certificates.
+.PP
+.B Verify
+does the actual verification of a sequence
+.I seq
+of SPKI certificates, signatures and operations
+that makes and supports a claim that an entity speaks for another.
+It returns a tuple
+.BI ( claim,\ badel,\ err ) .
+On success,
+.I claim
+refers to a
+.B Speaksfor
+value that summaries the statement verified by the sequence.
+On failure,
+.I claim
+is nil,
+.I badel
+is a list of sequence elements headed by the first element of
+.I seq
+that failed verification, and
+.I err
+is the reason it failed.
+.SH SOURCE
+.B /appl/lib/spki/verifier.b
+.SH SEE ALSO
+.IR sexprs (2),
+.IR spki (2)
diff --git a/man/2/spree b/man/2/spree
new file mode 100644
index 00000000..1cd517b3
--- /dev/null
+++ b/man/2/spree
@@ -0,0 +1,604 @@
+.TH SPREE 2
+.SH NAME
+Spree \- distributed interactive sessions.
+.SH SYNOPSIS
+.EX
+.ps -1
+.vs -1
+include "sys.m";
+include "draw.m";
+include "sets.m";
+include "spree.m";
+spree := load Spree Spree->PATH;
+Range, Object, Clique, Member: import spree;
+Set: import Sets;
+Archive: import Archives;
+
+Range: adt {
+ start: int;
+ end: int;
+};
+
+Object: adt {
+ transfer: fn(o: self ref Object,
+ r: Range, dst: ref Object, i: int);
+ setvisibility: fn(o: self ref Object,
+ visibility: Set);
+ setattrvisibility: fn(o: self ref Object,
+ name: string, visibility: Set);
+ setattr: fn(o: self ref Object,
+ name: string, val: string, vis: Set);
+ getattr: fn(o: self ref Object, name: string): string;
+ delete: fn(o: self ref Object);
+ deletechildren: fn(o: self ref Object, r: Range);
+
+ id: int;
+ parentid: int;
+ children: array of ref Object;
+ objtype: string;
+ visibility: Set;
+ # ...private data
+};
+
+Clique: adt {
+ new: fn(parent: self ref Clique, archive: ref Archive,
+ owner: string): (int, string, string);
+ newobject: fn(clique: self ref Clique, parent: ref Object,
+ visibility: int, objtype: string): ref Object;
+ action: fn(clique: self ref Clique, cmd: string,
+ objs: list of int, rest: string, whoto: int);
+ member: fn(clique: self ref Clique, id: int): ref Member;
+ start: fn(clique: self ref Clique);
+ breakmsg: fn(clique: self ref Clique, whoto: Sets->Set);
+ members: fn(clique: self ref Clique): list of ref Member;
+ owner: fn(clique: self ref Clique): string;
+ hangup: fn(clique: self ref Clique);
+ notify: fn(clique: self ref Clique, cliqueid: int, msg: string);
+
+ objects: array of ref Object;
+ cliqueid: int;
+ # ...private data
+};
+
+Member: adt {
+ obj: fn(m: self ref Member, id: int): ref Object;
+ del: fn(m: self ref Member, suspend: int);
+
+ id: int;
+ name: string;
+ # ...private data
+};
+
+Engine: module {
+ init: fn(srvmod: Spree, clique: ref Clique, argv: list of string): string;
+ command: fn(member: ref Member, e: string): string;
+ join: fn(member: ref Member , e: string, suspended: int): string;
+ leave: fn(member: ref Member): int;
+ notify: fn(fromid: int, s: string);
+ readfile: fn(f: int, offset: big, count: int): array of byte;
+};
+
+Archives: module {
+ Archive: adt {
+ argv: list of string; # how to restart the session.
+ members: array of string; # members involved.
+ info: list of (string, string); # any other information.
+ objects: array of ref Object;
+ };
+ init: fn(mod: Spree);
+ write: fn(clique: ref Clique, info: list of (string, string), file: string, members: Set): string;
+ read: fn(file: string): (ref Archive, string);
+ readheader: fn(file: string): (ref Archive, string);
+};
+
+rand: fn(n: int): int;
+.ps +1
+.vs +1
+.EE
+.SH DESCRIPTION
+.I Spree
+provides a general server interface that allows sets of distributed
+clients,
+.IR cliques ,
+to interact in a controlled manner, with the
+interaction mediated
+by Limbo modules, known as
+.IR engines .
+Each engine decides on the rules
+of its particular clique; the engine interface is described
+at the end of this manual page, under
+``Module Interface''.
+.PP
+This manual page describes the
+interface as presented to an engine
+once it has been loaded by
+.IR spree .
+A loaded instance of an engine is responsible for a particular
+.IR clique ,
+in which one or more
+.I members
+participate. Messages sent by members
+are interpreted by the engine, which
+responds by making changes to the hierarchical
+.I object
+database held by the clique.
+Behind the scenes
+.I spree
+distributes updates to this database to members
+of the clique as appropriate (see
+.IR spree (4)
+for details).
+.SS "Objects and visibility"
+Objects hold a clique's visible state. An object
+has a unique integer
+.IR id ,
+which is an index into the array
+.IB clique .objects\fR;\fP
+it also holds a set of attribute-value pairs, a type, and
+zero or more child objects. Together, all the objects
+in the clique form a hierarchical tree, rooted at
+the
+.IR "root object"
+(id 0), which always exists.
+Each attribute and each object also has an associated
+.IR "visibility set" ,
+the set of member that sees updates to the attributes or the children
+of the object. Each member has a unique id;
+in a visibility set (see
+.IR sets (2)),
+a member is ``visible'' if the set contains the member's id.
+.PP
+Note that the visibility set of an object does not alter the visibility
+of that object's attributes, but only that of its children (and of
+their children: in general an object is visible to a member if the
+intersection of all its ancestors' visibility sets contains that
+member).
+.PP
+Objects can be transferred inside the hierarchy from one parent to
+another. If an object is moved to a parent whose visibility conceals it
+from a member, then it will appear to that member to have been deleted;
+if it is later made visible, then it will be recreated for that
+member.
+A clique engine can almost always ignore this technicality,
+except for one thing: the identifier used by a particular member to
+identify an object is not necessarily the same as that used by the clique
+engine. Thus when an engine receives an object id in a member's
+message, it should convert it using the
+.IB member .obj()
+function.
+.SS \fBClique\fP
+The
+.B Clique
+type holds all the objects in a clique. It allows the
+creation of new objects, and provides a way of communicating
+with members directly.
+All data members of a
+.B Clique
+should be treated as read-only.
+.TP 10
+.IB clique .objects
+This array holds the objects in the clique. An object with
+identifier
+.I id
+is found at
+.IB clique .objects[ id ]\fR.\fP
+.TP
+.IB clique .new(\fIarchive\fP, \fIowner\fP)
+.B New
+creates a new clique.
+.I Archive
+is an archive of the game to be created;
+.IB archive \.argv
+should be non-nil; its first element should name
+the engine to be loaded (as a path relative to the
+engine module directory, and without the
+.B .dis
+extension).
+.TP
+.IB clique .newobject(\fIparent\fP,\ \fIvisibility\fP,\ \fIobjtype\fP)
+.B Newobject
+creates a new object at the end
+of
+.IR parent 's
+children;
+If
+.I parent
+is nil, the new object is created under the root object.
+The new object has visibility
+.IR visibility ,
+and type
+.IR objtype .
+An object's type cannot be changed once
+it has been created.
+.TP
+.IB clique .action(\fIcmd\fP,\ \fIobjs\fP,\ \fIrest\fP,\ \fIwhoto\fP)
+.B Action
+sends a message to some members without affecting
+the object hierarchy. It can be used to send transient
+events that have no meaning when stored statically
+(for example, network latency probes).
+The message is sent to the set of members given by
+.IR whoto .
+.I Objs
+is assumed to be a list of object ids, which are
+converted appropriately for each member
+receiving the message; the final
+message is a string built by concatenating
+.IR cmd ,
+the list of object ids, and
+.IR rest ,
+separated by spaces.
+.TP
+.IB clique .breakmsg(\fIwhoto\fP)
+Messages are usually sent to clients in an uninterrupted
+stream (as documented in
+.IR spree (4)),
+with a single read returning a potentially large
+set of messages.
+.B Breakmsg
+arranges that subsequent messages received by the members specified in
+.I whoto
+will see not be merged with messages sent prior to the call to
+.BR breakmsg .
+This is used to enable a new client module to be started
+without needing to pass it data received in the previous read.
+.TP
+.IB clique .member(\fIid\fP)
+.B Member
+yields the member corresponding to identifier
+.IR id ,
+or
+.B nil
+if there is none.
+.TP
+.IB clique .membernamed(\fIname\fP)
+.B Membernamed
+searches for a member of
+.I clique
+named
+.I name
+and returns it if it finds it, otherwise
+.BR nil .
+.TP
+.IB clique .members()
+.B Members
+returns a list of all the members of
+.IR clique ,
+including those that have been suspended.
+.TP
+.IB clique .owner()
+.B Owner
+returns the name of the owner of the clique;
+i.e. the user that created it.
+.TP
+.IB clique .hangup()
+.B Hangup
+terminates a game and informs all the
+players of that fact.
+.TP
+.IB clique .notify(\fIcliqueid\fP, \fImsg\fP)
+.B Notify
+sends an informational message to another clique.
+The clique so referenced must be either the parent
+or a child of
+.IR clique .
+The message is not sent synchronously,
+and care should be taken not to send messages that
+can cause an indefinite recursion.
+.SS Member
+The
+.B Member
+type represents a member of a clique.
+.TP 10
+.IB member .id
+The member's identifier is an integer unique across all current members
+of the clique,
+but ids of members that have left the clique will
+be reused.
+There may not be two members of the same name in the
+same clique.
+.TP
+.IB member .name
+.B Name
+holds the authenticated name of the member.
+This is necessarily unique over the members
+of a clique.
+.TP
+.IB member .obj(\fIid\fP)
+.B Obj
+converts from a member's external object
+identifier to the clique's local
+.B Object
+that it represents. It returns
+.B nil
+if there is no such object.
+.TP
+.IB member .del(\fIsuspend\fP)
+.B Del
+deletes
+.I member
+from the clique;
+no more requests from
+.I member
+will be received by the clique engine.
+If
+.I suspend
+is non-zero, if a member of the same name joins again
+it will be allocated the same object id, allowing a member
+to leave and join again without losing state.
+.SS \fBObject\fP
+The
+.B Object
+type is the basic unit of clique engine state.
+An object's children can be selectively concealed
+from members; it holds a set of
+.RI ( attribute ,\ value )
+pairs, each of which can be concealed likewise.
+Where an argument
+.IR r ,
+of
+.B Range
+type is used, it refers to a range of an object's
+children starting at index
+.IB r .start\fR,\fP
+and finishing at
+.IB r .end-1\fR.\fP
+All the data members of an
+.B Object
+should be treated as read-only.
+.TP 10
+.IB obj .setattr(\fIname\fP,\ \fIval\fP,\ \fIvis\fP)
+.B Setattr
+sets attribute
+.I name
+in
+.I obj
+to
+.IR val.
+If the attribute is being created for the
+first time, then it will be given visibility
+.IR vis .
+.I Name
+should be non-empty, and should not
+contain any space characters.
+Note that it is not possible for an attribute
+to refer directly to an object by its identifier;
+if this facility is needed, another identifying
+scheme should be used. This also applies
+to member identifiers, which will change
+if the clique is saved and loaded again.
+.TP
+.IB obj .getattr(\fIname\fP)
+.B Getattr
+yields the current value of the
+attribute
+.I name
+in
+.IR obj .
+If an attribute is not set, it yields
+.BR nil .
+.TP
+.IB obj .delete()
+.B Delete
+removes
+.I obj
+from the object
+hierarchy.
+.TP
+.IB obj .deletechildren(\fIr\fP)
+.B Deletechildren
+deletes children in range
+.I r
+from
+.IR obj .
+.TP
+.IB obj .transfer(\fIr\fP,\ \fIdst\fP,\ \fIi\fP)
+.B Transfer
+transfers the children in range
+.I r
+from
+.I obj
+to just before the object at index
+.I i
+in
+.IR dst .
+It is permissible for
+.I obj
+and
+.I dst
+to be the same object.
+.TP
+.IB obj .setvisibility(\fIvisibility\fP)
+.B Setvisibility
+allows the set of members
+given in
+.I visibility
+to see the children of
+.IR obj ,
+and denies access to all others.
+Members are notified of the change.
+.TP
+.IB obj .setattrvisibility(\fIname\fP,\ \fIvisibility\fP)
+.B Setattrvisibility
+allows the set of members
+given in
+.I visibility
+to see the value of
+.IR obj 's
+attribute
+.IR name ,
+and denies access to all others.
+Members are not notified of the change;
+if there is a need to communicate
+the fact of an attribute becoming invisible to
+members, it should be done by using another
+(visible) attribute to communicate the change.
+.SS "Archives"
+The
+.B Archives
+module provides a means of committing a clique
+to permanent storage and retrieving it later.
+It should first be initialised by calling
+.BR init ,
+passing the
+.B Spree
+module in
+.IR mod .
+.B Write
+writes
+.I clique
+to the file
+.IR file .
+.I Info
+gives a set of attributes and values associated with the clique;
+.I members
+gives the set of clique members for which visibility information
+will be archived; visibility information for other members is forgotten.
+.PP
+.B Read
+opens
+.I file
+and returns it as an
+.B Archive
+adt, say
+.IR a .
+.IB A .argv
+holds the command line arguments to the clique module
+(including the name of the module, its first element);
+.IB a .members
+gives the names of all archived members - the id
+of an archived member is given by its index in the array;
+.IB a .info
+gives the list of attributes an values as stored by
+.BR write ;
+.IB a .objects
+holds the clique objects.
+.B Readheader
+is just like
+.B read
+except that it parses the header only, so will return an
+.B Archive
+adt such that
+.IB a .objects
+is nil.
+.SS "Module Interface"
+An engine module,
+.IR mod ,
+must implement the
+following functions. Where a function returns a string,
+it is interpreted as an error response to the member
+responsible for the request; an empty string signifies
+no error.
+.TP
+.IB mod ->init(\fIsrvmod\fP, \fIclique\fP, \fIargv\fP)
+.B Init
+initialises the clique engine.
+.I Clique
+is the clique that the engine is controlling,
+and
+.I srvmod
+is the
+.B Spree
+module holding its associated data.
+An error response from this function
+causes the clique to be aborted.
+.I Argv
+gives a list of arguments to the engine, starting
+with its module name.
+.TP
+.IB mod ->join(\fImember\fP, \fIe\fP, \fIsuspended\fP)
+.I Member
+has made a request to join the clique;
+an error response causes the request to be
+refused, otherwise the member joins the
+clique.
+.I E
+is a message from the client about how it would like to
+join the clique (e.g.
+.BR join ,
+.BR watch ,
+etc).
+.I Suspended
+is non-zero if the member was previously suspended from the clique.
+.TP
+.IB mod ->leave(\fImember\fP)
+.I Member
+has left the clique.
+If
+.B leave
+returns zero, the member will not be deleted from the
+clique, but merely suspended until they should join again.
+.TP
+.IB mod ->command(\fImember\fP,\ \fIe\fP)
+.I Member
+has sent the command
+.IR e .
+The command usually follows
+the simple message conventions
+used in
+.IR spree (4),
+i.e. simple space-separated tokens.
+.TP
+.IB mod ->notify(\fIcliqueid\fP, \fIs\fP)
+A notification,
+.IR s ,
+has been posted to
+the current clique
+by the clique identified by
+.IR cliqueid .
+The posting clique is either a parent or a child of the current clique.
+.TP
+.IB mod .
+.SH EXAMPLE
+The following is a small, but working example
+of a clique engine that acts as a chat server
+(parsing error checking omitted, and white-space
+compressed to save paper):
+.PP
+.EX
+.ps -1
+.vs -1
+implement Cliquemodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "../spree.m";
+ spree: Spree;
+ Clique, Member: import spree;
+clique: ref Clique;
+clienttype(): string
+{
+ return "chat";
+}
+init(g: ref Clique, srvmod: Spree): string
+{
+ (sys, clique, spree) = (load Sys Sys->PATH, g, srvmod);
+ return nil;
+}
+join(nil: ref Member): string
+{
+ return nil;
+}
+leave(nil: ref Member)
+{
+}
+command(member: ref Member, cmd: string): string
+{
+ clique.action("say " + string member.id + " " + cmd, nil, nil, ~0);
+ return nil;
+}
+.ps +1
+.vs +1
+.EE
+.SH SOURCE
+.B /appl/cmd/cliques/spree.b
+.SH "SEE ALSO"
+.IR spree (4),
+.IR spree-objstore (2),
+.IR spree-cardlib (2),
+.IR spree-allow (2),
+.SH BUGS
+The reuse of object ids can lead to
+problems when objects are deleted and
+recreated on the server before clients become
+aware of the changes.
diff --git a/man/2/spree-allow b/man/2/spree-allow
new file mode 100644
index 00000000..6265c9ca
--- /dev/null
+++ b/man/2/spree-allow
@@ -0,0 +1,129 @@
+.TH SPREE-ALLOW 2
+.SH NAME
+Allow \- filter client actions
+.SH SYNOPSIS
+.EX
+include "spree.m";
+include "spree/allow.m";
+Clique, Member, Object: import Spree;
+allow := load Allow Allow->PATH;
+
+init: fn(m: Spree, c: ref Clique);
+add: fn(tag: int, member: ref Member, pattern: string);
+del: fn(tag: int, member: ref Member);
+action: fn(member: ref Member, cmd: string): (string, int, list of string);
+archive: fn(archiveobj: ref Object);
+unarchive: fn(archiveobj: ref Object);
+.EE
+.SH DESCRIPTION
+A
+.IR spree (2)
+client can send arbitrary actions to a running
+engine. The
+.B Allow
+module enables an engine to filter clients'
+actions, permitting only actions matching
+certain provided patterns to get through.
+.PP
+An action is conventionally formatted as
+a sequence of space-separated words.
+A
+.I pattern
+is a string consisting of a sequence of such words.
+For a pattern to match a client's action, each word in the pattern
+must match each word in the action.
+Most pattern words are not special: they must match
+literally. The exceptions are:
+.TP
+.B *
+An asterisk matches any single word.
+.TP
+.B "&"
+An ampersand matches any set of words.
+Any words in the pattern after this are ignored.
+.TP
+.B %d
+Matches a decimal integer.
+.TP
+.B %p
+Matches a valid player id (decimal integer).
+.TP
+.B %o
+Matches any valid object id (decimal integer).
+The corresponding word in the list returned by
+.B action
+will be changed to the local object id from
+the member's external representation.
+.PP
+.B Init
+must be called first with the spree module,
+.IR m ,
+and the current clique,
+.IR c ,
+to initialise the module.
+.PP
+.B Add
+adds the new
+.I pattern
+to the list of allowed actions;
+.I tag
+is an integer tag that the caller can later use to identify the
+action, and
+I member
+is the clique member that is allowed to perform the action
+(if nil, then any member will be allowed to perform the action).
+.B Del
+deletes patterns tagged with
+.I tag
+from the list of allowed actions.
+If
+.I member
+is non-nil, then only patterns specific to
+that member will be deleted.
+.PP
+.B Action
+matches
+.IR
+.IR cmd ,
+an action performed by
+.IR member ,
+against the list of all the allowed patterns.
+It returns a tuple, say
+.RI ( err\fR,\ \fItag\fR,\ \fItoks\fR).
+If
+.I cmd
+does not match any pattern, then
+.I err
+will be non-nil and holds a string describing the
+nature of the failure.
+If a match is made, then
+.I tag
+holds the matched pattern's tag, as passed to
+.BR add ,
+and
+.I toks
+holds the list of words in the action, with
+object ids matched by
+.B %o
+changed to their local representation using
+.IB member .obj\fR.
+.PP
+.B Archive
+stores all the
+.I allow
+module's internal state as attributes on
+.I archiveobj
+(for card game engines, this is usually the
+object returned from
+.B cardlib->archive
+(see
+.IR cardlib (2))).
+.B Unarchive
+reverses this, restoring the module's internal state from
+.IR archiveobj .
+.SH SOURCE
+/appl/spree/lib/allow.b
+.SH "SEE ALSO"
+.IR spree (2) ,
+.IR spree-cardlib (2) ,
+.IR spree-objstore (2)
diff --git a/man/2/spree-cardlib b/man/2/spree-cardlib
new file mode 100644
index 00000000..6c495902
--- /dev/null
+++ b/man/2/spree-cardlib
@@ -0,0 +1,628 @@
+.TH SPREE-CARDLIB 2
+.SH NAME
+Cardlib \- support for card games in Spree engines.
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "draw.m";
+include "sets.m";
+include "spree.m";
+include "spree/cardlib.m";
+
+Object: import Spree;
+cardlib := load Cardlib Cardlib->PATH;
+
+init: fn(spree: Spree, clique: ref Clique, archived: int);
+selection: fn(stack: ref Object): ref Selection;
+
+makecard: fn(deck: ref Object, c: Card, rear: string): ref Object;
+makecards: fn(stack: ref Object, r: Range, rear: string);
+getcard: fn(card: ref Object): Card;
+getcards: fn(stack: ref Object): array of Card;
+setface: fn(card: ref Object, face: int);
+flip: fn(stack: ref Object);
+shuffle: fn(stack: ref Object);
+discard: fn(stk, pile: ref Object, facedown: int);
+deal: fn(stack: ref Object, n: int, stacks: array of ref Object, first: int);
+sort: fn(stack: ref Object, rank, suitrank: array of int);
+
+addlayframe: fn(name: string, parent: string, layout: ref Layout, packopts: int, facing: int);
+addlayobj: fn(name: string, parent: string, layout: ref Layout, packopts: int, obj: ref Object);
+dellay: fn(name: string, layout: ref Layout);
+maketable: fn(parent: string);
+
+newstack: fn(parent: ref Object, p: ref Member, spec: Stackspec): ref Object;
+
+archive: fn(): ref Object;
+unarchive: fn(): ref Object;
+setarchivename: fn(o: ref Object, name: string);
+archivearray: fn(a: array of ref Object, name: string);
+getarchiveobj: fn(name: string): ref Object;
+getarchivearray: fn(name: string): array of ref Object;
+
+nmembers: fn(): int;
+
+Layout: adt {
+ lay: ref Object;
+};
+
+Stackspec: adt {
+ style: string;
+ maxcards: int;
+ title: string;
+ conceal: int;
+};
+
+Card: adt {
+ suit: int;
+ number: int;
+ face: int;
+};
+
+# a member currently playing
+Cmember: adt {
+ ord: int;
+ id: int;
+ p: ref Member;
+ obj: ref Object;
+ layout: ref Layout;
+ sel: ref Selection;
+
+ join: fn(p: ref Member, ord: int): ref Cmember;
+ index: fn(ord: int): ref Cmember;
+ find: fn(p: ref Member): ref Cmember;
+ findid: fn(id: int): ref Cmember;
+ leave: fn(cp: self ref Cmember);
+ next: fn(cp: self ref Cmember, fwd: int): ref Cmember;
+ prev: fn(cp: self ref Cmember, fwd: int): ref Cmember;
+};
+
+Selection: adt {
+ stack: ref Object;
+ ownerid: int;
+ isrange: int;
+ r: Range;
+ idxl: list of int;
+
+ set: fn(sel: self ref Selection, stack: ref Object);
+ setexcl: fn(sel: self ref Selection, stack: ref Object): int;
+ setrange: fn(sel: self ref Selection, r: Range);
+ addindex: fn(sel: self ref Selection, i: int);
+ delindex: fn(sel: self ref Selection, i: int);
+ isempty: fn(sel: self ref Selection): int;
+ isset: fn(sel: self ref Selection, index: int): int;
+ transfer: fn(sel: self ref Selection, dst: ref Object, index: int);
+ owner: fn(sel: self ref Selection): ref Cmember;
+};
+.EE
+.SH DESCRIPTION
+.I Cardlib
+provides facilities to help in the implementation
+of
+.I spree (2)
+engines that implement the
+.IR spree-cards (4)
+interface.
+Facilities include the layout of clients' cards,
+support for card selections, and card manipulation.
+.PP
+.B Init
+must be called first to initialise the
+.I Cardlib
+module, giving it the
+.I spree
+module and the current clique.
+.I Archived
+should be non-zero if the card game is being restored from
+an archive.
+.SS Cards
+The value of a playing card is represented by the
+.B Card
+adt, having attributes
+.IR suit ,
+.IR number ,
+and
+.IR face .
+.I Suit
+ranges from 0 to 3 inclusive, representing clubs,
+diamonds, hearts and spades respectively;
+.I number
+ranges from 0 to 12 inclusive for the standard cards,
+with ace low and king high - a joker is represented
+by a number greater than 12;
+.I face
+represents whether the card is face up or face down
+(0 is face down).
+.PP
+A actual card is represented by an object in the object hierarchy
+of type
+.BR card ,
+with attributes
+.BR number ,
+.BR face ,
+and
+.BR rear .
+.B Number
+is the suit/number of the card (held as
+.IR n ,
+where
+.IR n %4
+gives the suit, and
+.IR n /4
+the rank).
+.B Face
+is as held in the
+.B Card
+adt, and
+.B rear
+is a number that represents the pattern on the
+back of the card (numbered from 0 upwards).
+Conventionally the
+.B number
+attribute is made invisible to all players when
+the
+.B face
+attribute is set to zero.
+.PP
+.B Makecard
+creates a new card of value
+.IR c ,
+placing the new card object at the end of
+.IR deck ,
+and setting the
+.B rear
+attribute to
+.I rear
+if it is non-nil.
+.B Makecards
+makes a set of cards, all face down,
+in all four suits, having numbers within the range
+.IR r .
+.PP
+.B Getcard
+gets the value representation of a card from object
+.IR card ;
+.B getcards
+gets the values of all the card objects within
+.IR stack .
+.B Setface
+sets of
+.I card
+to
+.IR face ;
+the visibility of the card's number is changed appropriately.
+.PP
+The following few routines operate on stacks of cards: objects
+which contain only card objects:
+.B flip
+reverses a stack of cards, reversing their faces as it does so;
+.B shuffle
+shuffles a stack of cards, and
+.B sort
+sorts a stack of cards by suit and then number, according to
+.I rank
+and
+.IR suitrank .
+.I Rank
+and
+.I suitrank
+are permutations mapping number/suit to sort precedence (0 low).
+If either of these are nil, then a default ranking scheme is chosen
+(two low, ace high for number).
+.B Discard
+moves all the cards in
+.I stk
+onto
+.IR pile ,
+turning them face down if
+.I facedown
+is non-zero.
+.B Deal
+deals out all the cards in
+.I stack
+as evenly as possible amongst
+.IR stacks ,
+dealing to
+.IB stacks [ first ]
+first.
+.SS Members and card selection
+.I Cardlib
+keeps a record of the current players of the game;
+a player is represented by a
+.B Cmember
+adt; the players are assumed to sit in a circle,
+numbered from 0 updwards;
+.B nmembers
+gives the number of current players.
+Each player has a unique integer id, and an
+associated selection
+and card layout.
+.TP 10
+.IB m .join(\fIm\fP,\ \fIord\fP)
+Join a new player to the game;
+.I m
+is the clique member that's joining, and
+.I ord
+is where to slot the player in the circle of existing players.
+If
+.I ord
+is -1, the player will be added at the end.
+.TP
+.IB m .leave()
+Remove
+.I m
+from the list of current players.
+.TP
+.IB m .index(\fIord\fP)
+.B Index
+returns the
+.IR ord th
+player around the table.
+.TP
+.IB m .find(\fIm\fP)
+Find the
+.B Cmember
+corresponding to member
+.IR m .
+.TP
+.IB m .findid(\fIid\fP)
+Find the
+.B Cmember
+with identifier
+.IR id ,
+and return it.
+.IB m .next(\fIfwd\fP)
+.B Next
+returns the next player around the table
+from
+.IR m .
+If
+.I fwd
+is non-zero, it counts upwards, otherwise it counts
+downwards.
+.IB m .prev(\fIfwd\fP)
+.B Prev
+is the opposite of
+.BR next .
+If
+.I fwd
+is non-zero, it counts downwards, otherwise it
+counts upwards.
+.SS Selection
+Each
+.B Cmember
+.I m
+has an associated selection,
+.IB m .sel\fR,
+which consists of a selection
+of some cards from a single stack of cards.
+A selection can consist of either a range of cards within
+a stack, or an arbitrary set of cards within a stack.
+A stack can only be the subject of one selection; the
+member that has that selection is known as its
+owner.
+.TP 10
+.IB sel .set(\fIstack\fP)
+.B Set
+makes
+.I stack
+(an object containing only card objects)
+the subject of
+.IR sel 's
+selection. If
+.I stack
+is nil, the selection is cleared.
+.TP
+.IB sel .setexcl(\fIstack\fP)
+.B Setexcl
+is the same as
+.B set
+except that it will fail if the stack is owned
+by a different player. It returns 0 if it fails,
+otherwise non-zero.
+.TP
+.IB sel .setrange(\fIr\fP)
+.B Setrange
+sets the selection
+.I sel
+to be a range of cards within its stack.
+If the selection had been of distinct cards (set using
+.BR addindex ),
+it is first cleared.
+.TP
+.IB sel .addindex(\fIi\fP)
+.B Addindex
+adds the card at index
+.I i
+to the selection
+.IR sel .
+If a range had previously been selected,
+it is first cleared.
+.TP
+.IB sel .delindex(\fIi\fP)
+.B Delindex
+deletes the card at index
+.I i
+from the selection.
+If the selection was previously a range,
+this is a no-op.
+.TP
+.IB sel .isempty()
+.B Isempty
+returns non-zero if
+.I sel
+holds an empty selection.
+.TP
+.IB sel .isset(\fIindex\fP)
+.B Isset
+returns non-zero if the card at index
+.I index
+is contained within the selection
+.IR sel .
+.TP
+.IB sel .transfer(\fIdst\fP,\ \fIindex\fP)
+.B Transfer
+moves all the cards in the selection
+.I sel
+to just before
+.I index
+within the stack
+.IR dst .
+.IB sel .owner()
+.B Owner
+returns the
+.B Cmember
+that owns the selection
+.IR sel .
+.SS Layout
+Creating a stack of cards does not specify how it is to be displayed
+to members of the game. Each member has a
+.I layout
+object which defines which objects are to be displayed to
+that member, and how they are to be laid out.
+Any member must see at most one layout object
+(it is conventional to make a layout object visible only to
+its owner).
+Objects are laid out using tk-like
+.IR pack (9)
+semantics:
+.I frames
+pack together display objects or other frames.
+A display object can lay out anything the card client knows
+how to display (see ``Display Objects'', below).
+.PP
+.B Addlayframe
+adds a new frame named
+.I name
+within
+a layout frame named
+.IR parent ,
+specific to
+.IR layout .
+If
+.I parent
+is nil, the frame is added to the root of the hierarchy.
+If
+.I layout
+is nil, a frame is added to
+.I parent
+for each member that has a layout frame of that name.
+.I Packopts
+specifies how the frame is to be packed within its parent:
+it is a bitmask, specifying the side of the cavity against which it is to be packed,
+the place it is to be anchored should the cavity be bigger than its requested size,
+how to fill its cavity, whether to expand its requested size to fill extra available space.
+See
+.IR pack (9)
+for details of the packing algorithm.
+The packing direction is specified with one of
+.BR dTOP ,
+.BR dLEFT ,
+.BR dBOTTOM
+or
+.BR dRIGHT .
+The anchor direction is specified with one of
+.BR aCENTRE ,
+.BR aUPPERCENTRE ,
+.BR aUPPERLEFT ,
+.BR aCENTRELEFT ,
+.BR aLOWERLEFT ,
+.BR aLOWERCENTRE ,
+.BR aLOWERRIGHT ,
+.BR aCENTRERIGHT ,
+or
+.BR aUPPERRIGHT .
+.B FILLX
+and
+.B FILLY
+specify how to fill unused space in its cavity
+(not mutually exclusive),
+and
+.B EXPAND
+requests unused space.
+.I Facing
+influences direction that objects are packed in
+underneath the frame. It should be one of the
+pack direction constants specified above
+(e.g.
+.BR dTOP ).
+For instance, if
+.B dRIGHT
+is specified, then all objects packed underneath
+have their attributes modified 90° clockwise,
+as if the player in question was sitting on the
+left of the table, looking right.
+This feature means that it is possible
+to set up a ``table'' in which layout objects
+can be added to all players at the same time, but
+which nonetheless looks different to each player
+around the table.
+.PP
+.B Maketable
+creates such a ``table'' for between 0 and 4 players.
+It creates a frame for each player, named
+.BI p n\fR,
+where
+.I n
+is the ordinal number of the player around the table;
+and an inner space, named
+.BR public .
+The
+.I parent
+argument to
+.B maketable
+gives the frame within which the table is to be created.
+.PP
+.B Addlayobj
+adds a new display object
+.I obj to the layout hierarchy.
+.IR Name ,
+.IR parent ,
+.IR layout ,
+and
+.I packopts
+are the same as for
+.B addlayframe
+except that
+if it is a stack object, then
+.I packopts also specifies the
+orientation of the stack, with one of the constants
+.BR oRIGHT ,
+.BR oUP ,
+.BR oLEFT ,
+or
+.BR oDOWN ,
+giving the direction in which cards are laid out
+within the stack.
+.PP
+.B Dellay
+deletes the object named
+.I name
+from the layout hierarchy. If
+.I layout
+is nil, it is deleted from all layouts,
+otherwise from
+.I layout
+only.
+.SS "Display Objects"
+Currently, two kinds of objects can be displayed: stacks and
+widgets. A stack has object type
+.BR stack ,
+and contains only cards objects.
+Attributes on the stack object define its appearance:
+.B maxcards
+gives the default size of the stack;
+.B style
+gives the style of stack layout,
+currently one of
+.B pile
+(all the cards piled directly on top of one another),
+or
+.B display
+(cards are spread out in the direction specified by
+the orientation given in the packing options, see
+Layout, above);
+.B title
+gives a title to display with the stack.
+.PP
+.B Newstack
+creates a new stack according to the specifications in
+.IR spec ,
+where
+.I spec
+is an adt that holds
+.BR style ,
+.BR maxcards ,
+and
+.BR title ,
+as described above.
+If
+.IB spec .conceal
+is non-zero, the contents of the new stack will be made
+invisible to all (except
+.IR owner ,
+if
+.I owner
+is non-nil).
+.PP
+Widgets are created by making an object
+of type
+.RB `` widget
+.IR type '',
+where
+.I type
+is one of
+.BR button ,
+.BR entry , or
+.BR menu .
+The
+.B text
+attribute controls the text that is displayed in the widget;
+.B command
+gives the text that will be sent to the engine
+when the widget is activated,
+and
+.B width
+specifies the widget of the widget, in multiples of the width
+of the ``0'' character.
+.PP
+Entries can be made in a menu widget
+by creating new objects of type
+.B menuentry
+inside a menu object. The
+.B text
+and
+.B command
+attributes have the usual meaning here.
+.SS Archival
+Engines that use
+.I cardlib
+should not use
+.IR spree-objstore (2)
+to archive their objects:
+.I cardlib
+provides an interface to do this,
+and also knows how to archive and unarchive its own
+internal state.
+.PP
+.B Archive
+commits all the internal state of
+.I cardlib
+to the object hierarchy, prior to archival.
+It returns an ``archive'' object
+that can be used as a convenient place to put
+attributes that need archiving but are not associated with
+any particular object.
+.B Setarchivename
+associates
+.I name
+with the object
+.I o
+such that it can be retrieved when
+unarchiving by calling
+.B getarchiveobj
+with the same name.
+Similarly
+.B Archivearray
+associates a name with each object in the array
+.I a
+such that the array can be retrieved when unarchiving
+by calling
+.B getarchivearray
+with the same name.
+.I Name
+should not end in a decimal digit.
+.B Unarchive
+unarchives
+.IR cardlib 's
+internal state. It returns the same archive object
+that was returned by
+.BR archive .
+.SH SOURCE
+.B /appl/spree/lib/cardlib.b
+.SH "SEE ALSO"
+.IR spree (2),
+.IR spree-allow (2),
+.IR spree-objstore (2)
+.SH BUGS
+This interface is not complete and is liable to change.
diff --git a/man/2/spree-gather b/man/2/spree-gather
new file mode 100644
index 00000000..b4b4aeab
--- /dev/null
+++ b/man/2/spree-gather
@@ -0,0 +1,105 @@
+.TH SPREE-GATHER 2
+.SH NAME
+Gatherengine \- module interface for pre-assembled groups.
+.SH SYNOPSIS
+.EX
+implement Gatherengine;
+
+include "spree.m";
+include "spree/gather.m";
+Clique, Member: import Spree;
+
+init: fn(m: Spree, c: ref Clique, argv: list of string, archived: int): string;
+clienttype: fn(): string;
+maxmembers: fn(): int;
+propose: fn(members: array of string): string;
+start: fn(members: array of ref Member, archived: int);
+command: fn(member: ref Member, c: string): string;
+archive: fn();
+readfile: fn(f: int, offset: big, n: int): array of byte;
+.EE
+.SH DESCRIPTION
+When implementing a
+.IR spree (2)
+engine, it is common to have the requirement that a certain number
+of members are grouped together before actually starting the
+engine.
+.I Spree
+provides no support for this directly; instead the
+.I gather
+module acts as an intermediate layer: engines that wish
+this functionality should implement the
+.B Gatherengine
+interface.
+The
+.I gather
+module also provides facilities for the automatic suspension and resumption
+of players, clique archival, and members that watch but do not
+participate.
+.PP
+.B Init
+is called first, with
+.IR m ,
+the
+.I spree
+module, and
+.IR c ,
+the new clique.
+.I Argv
+gives a list of arguments to the engine (the first being
+the name of the engine itself);
+.I archived
+is non-zero if the engine has been restored from an archive.
+If
+.B init
+returns a non-nil string, it is taken to describe an error, and the
+engine will be discarded.
+.B Maxmembers
+should return the maximum number of members that the engine
+can accept;
+.B clienttype
+should return the kind of client that is expected by the
+engine (e.g.
+.B cards
+for a card game engine).
+.PP
+.B Propose
+proposes that a clique consisting of
+.I members
+(the names of the proposed members)
+be started. It returns an error string: if this is non-nil, then
+the clique is not started, otherwise the proposed
+members are accepted into the clique,
+and
+.B start
+is called, where
+.I members
+is the array of actual members (corresponding to the
+members passed to
+.BR propose ),
+and
+.I archived
+is non-zero if the clique is being restored from an archive
+(same as passed to
+.BR init ).
+.PP
+Once a clique has been successfully started,
+.B command
+is called when a member sends a command to the
+engine;
+.I member
+has sent the command,
+and
+.I c
+is the command itself.
+.B Command
+should return a non-nil error string if the command fails.
+.PP
+When a clique is being archived,
+.B archive
+will be called to request the engine to store all its
+internal state into the object hierarchy (this is the moment,
+for instance, to call
+.BR cardlib->archive ).
+.SH "SEE ALSO"
+.IR spree (2) ,
diff --git a/man/2/spree-objstore b/man/2/spree-objstore
new file mode 100644
index 00000000..6a6be763
--- /dev/null
+++ b/man/2/spree-objstore
@@ -0,0 +1,63 @@
+.TH SPREE-OBJSTORE 2
+.SH NAME
+Objstore \- support for object archiving in Spree engines.
+.SH SYNOPSIS
+.EX
+include "spree.m";
+include "spree/objstore.m";
+Object: import Spree;
+objstore := load Objstore Objstore->PATH;
+
+init: fn(m: Spree, c: ref Clique);
+setname: fn(o: ref Object, name: string);
+unarchive: fn();
+get: fn(name: string): ref Object;
+.EE
+.SH DESCRIPTION
+The
+.IR spree (2)
+module provides an
+.B Archives
+module to allow storage of an engine's object hierarchy to a persistent
+medium. This does not store the state internal to an engine that
+is not reflected in the object hierarchy, e.g. global variables.
+In particular, if an engine holds a variable referring to an object,
+it is not able to reset that variable correctly when the archive is
+later restored.
+The
+.B Objstore
+module provides some support for the naming of objects
+before archival, and for their retrieval by name, in order to enable this.
+.PP
+.B Init
+must be called first with the spree module,
+.IR m ,
+and the current clique,
+.IR c .
+When a module is archiving itself, it should name each object
+that it wishes to retrieve, using
+.BR setname .
+It is permissible for a single object to be given multiple
+names: the object will later be retrievable under any of its given
+names.
+.PP
+When restoring from an archive, a module should call
+.BR unarchive ,
+which scans through the object hierarchy looking
+for named objects and storing their names.
+After this,
+.BI get( name )
+will return the object,
+.IR o ,
+that was named
+.IR name
+by a previous
+.BI setname( o ,\ name )\fR,
+or
+.B nil
+if there was none such.
+.PP
+The names for an object are stored in the attribute ``§'',
+which is cleared when
+.B unarchive
+is called.
diff --git a/man/2/srv b/man/2/srv
new file mode 100644
index 00000000..f217a0d9
--- /dev/null
+++ b/man/2/srv
@@ -0,0 +1,66 @@
+.TH SRV 2
+.SH NAME
+srv \- network name and address translation when hosted
+.SH SYNOPSIS
+.EX
+include "srv.m"
+srv := load Srv Srv->PATH;
+Srv: module
+{
+ init: fn();
+ iph2a: fn(host: string): list of string;
+ ipa2h: fn(addr: string): list of string;
+ ipn2p: fn(protocol, service: string): string;
+};
+.EE
+.SH DESCRIPTION
+.B Srv
+provides access to the host operating system's
+name and address translation when Inferno is running hosted.
+The module's implementation is usually built-in to
+.IR emu (1),
+and then only on some platforms.
+It uses the Internet name resolution services of the host operating system
+(eg,
+.B gethostbyname
+on Unix systems).
+Its services are normally only used internally by
+.IR cs (8)
+and
+.IR dns (8),
+and even they give priority to data in
+.IR services (6)
+and
+.IR dns (6)
+if available.
+Other Inferno applications normally give network addresses to the functions of
+.IR sys-dial (2),
+and they are then translated automatically, using the services of
+.IR cs (8).
+.PP
+.B Init
+must be called before any other function is used.
+.PP
+Given a host name,
+.B iph2a
+returns a list of its Internet addresses (if any).
+Given an Internet address,
+.B ipa2h
+returns a list of host names (if any) that have that address.
+The results are only as accurate as the host system's name service.
+.PP
+.B Ipn2p
+returns the port number (as a string) for the given
+.I service
+when accessed using a particular protocol
+.I protocol
+(typically
+.B tcp
+or
+.BR udp ).
+.SH SOURCE
+.B /emu/port/srv.c
+.SH SEE ALSO
+.IR sys-file2chan (2),
+.IR cs (8),
+.IR dns (8)
diff --git a/man/2/string b/man/2/string
new file mode 100644
index 00000000..7d1c4298
--- /dev/null
+++ b/man/2/string
@@ -0,0 +1,177 @@
+.TH STRING 2
+.SH NAME
+string: append, drop, in, prefix, quoted, splitl, splitr, splitstrl,
+splitstrr, take, tobig, toint, tolower, toupper, unquoted \- string operations
+.SH SYNOPSIS
+.EX
+include "string.m";
+str := load String String->PATH;
+
+append: fn(s: string, l: list of string): list of string;
+drop: fn(s, cl: string): string;
+in: fn(c: int, cl: string): int;
+prefix: fn(pre, s: string): int;
+splitl: fn(s, cl: string): (string, string);
+splitr: fn(s, cl: string): (string, string);
+splitstrl: fn(s, t: string): (string, string);
+splitstrr: fn(s, t: string): (string, string);
+take: fn(s, cl: string): string;
+tobig: fn(s: string, base: int): (big, string);
+toint: fn(s: string, base: int): (int, string);
+tolower: fn(s: string): string;
+toupper: fn(s: string): string;
+quoted: fn(args: list of string): string;
+unquoted: fn(s: string): list of string;
+.EE
+.SH DESCRIPTION
+The
+.I cl
+argument to some of these functions is a character class in which
+a
+.B -
+between any two characters indicates a range and a
+.B ^
+in the first position means
+.I not in
+the class.
+Example of classes are
+.B \&"a-zA-Z"
+and
+.B
+\&"^acg-mr"\c
+\&.
+.PP
+.B Append
+appends string
+.I s
+to the end of string list
+.IR l .
+.PP
+.B Drop
+removes the maximal prefix of string
+.I s
+that is in class
+.IR cl .
+.PP
+.B In
+returns 1 if
+character
+.I c
+is in class
+.I cl
+and 0 if it is not.
+.PP
+.B Prefix
+returns 1 if string
+.I pre
+is a prefix of string
+.I s
+and 0 if it is not.
+.PP
+.B Splitl
+splits string
+.I s
+just before the first character in class
+.IR cl .
+.PP
+.B Splitr
+splits string
+.I s
+just after the last character in class
+.IR cl .
+.PP
+.B Splitstrl
+splits string
+.I s
+just before the leftmost segment of string
+.I s
+that consists entirely of string
+.IR t ,
+and returns a tuple with the resulting pair of strings.
+If
+.I t
+does not occur in
+.IR s ,
+the result is
+.RI ( s , nil ).
+.PP
+.B Splitstrr
+splits string
+.I s
+just after the rightmost segment of string
+.I s
+that consists entirely of string
+.IR t ,
+and returns a tuple with the resulting pair of strings.
+If
+.I t
+does not occur in
+.IR s ,
+the result is
+.RI ( nil, s ).
+.PP
+.B Take
+returns the maximal prefix of string
+.I s
+that is in class
+.IR cl .
+.PP
+.B Toint
+returns as an integer the value represented by the string
+.IR s .
+The string is scanned up to the first character inconsistent
+with
+.IR base .
+The first inconsistent character marks the beginning of the
+returned string.
+Leading white-space characters are ignored.
+The
+.I base
+can be any integer in the range 2 to 36, inclusive;
+or 0 in which case the base can be specified as part
+of the string, in Limbo style (e.g. 16rffff).
+.PP
+.B Tobig
+has the same specification as
+.B toint
+except that converts to 64-bit
+.BR big .
+.PP
+.B Tolower
+converts all upper case letters in the string
+.I s
+to lower case letters.
+.PP
+.B Toupper
+converts all lower case letters in the string
+.I s
+to upper case letters.
+.PP
+.B Quoted
+takes a list of strings,
+.IR args ,
+and returns a single string with the value of each element of
+.I args
+separated from the next by a single space.
+When forming the string, the text of any element that
+contains white space or single quotes is first quoted by
+surrounding it by single quotes
+.RB ( ' ... ' )
+within which each existing single quote is doubled
+.RB ( '' ),
+following the conventions of
+.IR sh (1).
+.PP
+.B Unquoted
+takes a string
+.IR s ,
+quoted according to the conventions of
+.BR quoted ,
+and splits it into separate strings.
+It splits the string at each maximal sequence of
+unquoted white space (blank, newline or tab),
+stripping single quotes except where paired,
+to form the corresponding list of strings,
+which it returns.
+.SH SOURCE
+.B /appl/lib/string.b
diff --git a/man/2/stringinttab b/man/2/stringinttab
new file mode 100644
index 00000000..1dbf5c66
--- /dev/null
+++ b/man/2/stringinttab
@@ -0,0 +1,87 @@
+.TH STRINGINTTAB 2
+.SH NAME
+stringinttab \- string table lookup module
+.SH SYNOPSIS
+.EX
+include "strinttab.m";
+StringInt: import StringIntTab;
+
+strinttab := load StringIntTab StringIntTab->PATH;
+
+StringInt: adt{
+ key: string;
+ val: int;
+};
+
+lookup: fn(tab: array of StringInt, key: string) : (int, int);
+revlookup: fn(tab: array of StringInt, val: int) : string;
+.EE
+.SH DESCRIPTION
+.B Stringinttab
+provides functions that perform forward and reverse searches of an ordered table of
+.I key\-value
+pairs.
+.PP
+A table should be constructed as an array of
+.B StringInt
+entries, ordered by increasing
+.I key
+value. Keys ordering is determined by comparison of the Unicode
+value of their characters.
+.PP
+.B Lookup
+performs a binary search of
+.I tab
+for the
+.B StringInt
+entry whose
+.B key
+field has a value equal to
+.I key
+and returns a tuple: an
+.B int
+whose value is non-zero if a match has been found and zero otherwise,
+and an
+.B int
+whose value is equal to the
+.B val
+field of the matching
+.B StringInt
+entry.
+.PP
+.B Revlookup
+searches
+.I tab
+for the first
+.B StringInt
+entry whose
+.B val
+field has a value equal to
+.I val
+and returns the corresponding
+.B key
+string.
+.SH EXAMPLES
+.EX
+T := load StringIntTab StringIntTab->PATH;
+
+fmtstringtab := array[] of { Strinttab->StringInt
+ ("html", FHtml),
+ ("latex", FLatex),
+ ("latexbook", FLatexBook),
+ ("latexpart", FLatexPart),
+ ("latexproc", FLatexProc),
+ ("latexslides", FLatexSlides),
+};
+
+(fnd, fmt) := T->lookup(fmtstringtab, "latexbook");
+fmtstring := T->revlookup(fmtstringtab, FLatex);
+.EE
+.SH SOURCE
+.B /appl/lib/strinttab.b
+.SH SEE ALSO
+.IR hash (2)
+.SH BUGS
+.B Revlookup
+performs a sequential search of the table.
+
diff --git a/man/2/styx b/man/2/styx
new file mode 100644
index 00000000..d7208d00
--- /dev/null
+++ b/man/2/styx
@@ -0,0 +1,416 @@
+.TH STYX 2
+.SH NAME
+Styx: Rmsg, Tmsg, dir2text, istmsg, packdir, packdirsize, readmsg, qid2text, unpackdir \- interface to Styx file protocol
+.SH SYNOPSIS
+.EX
+include "styx.m";
+styx := load Styx Styx->PATH;
+
+Tmsg: adt {
+ tag: int;
+ pick {
+ Readerror =>
+ error: string; # tag is unused in this case
+ Version =>
+ msize: int;
+ version: string;
+ Auth =>
+ afid: int;
+ uname, aname: string;
+ Attach =>
+ fid, afid: int;
+ uname, aname: string;
+ Flush =>
+ oldtag: int;
+ Walk =>
+ fid, newfid: int;
+ names: array of string;
+ Open =>
+ fid, mode: int;
+ Create =>
+ fid: int;
+ name: string;
+ perm, mode: int;
+ Read =>
+ fid: int;
+ offset: big;
+ count: int;
+ Write =>
+ fid: int;
+ offset: big;
+ data: array of byte;
+ Clunk or
+ Stat or
+ Remove =>
+ fid: int;
+ Wstat =>
+ fid: int;
+ stat: Sys->Dir;
+ }
+
+ read: fn(fd: ref Sys->FD, msize: int): ref Tmsg;
+ unpack: fn(a: array of byte): (int, ref Tmsg);
+ pack: fn(nil: self ref Tmsg): array of byte;
+ packedsize: fn(nil: self ref Tmsg): int;
+ text: fn(nil: self ref Tmsg): string;
+ mtype: fn(nil: self ref Tmsg): int;
+};
+
+Rmsg: adt {
+ tag: int;
+ pick {
+ Readerror =>
+ error: string; # tag is unused in this case
+ Version =>
+ msize: int;
+ version: string;
+ Auth =>
+ aqid: Sys->Qid;
+ Attach =>
+ qid: Sys->Qid;
+ Flush =>
+ Error =>
+ ename: string;
+ Clunk or
+ Remove or
+ Wstat =>
+ Walk =>
+ qids: array of Sys->Qid;
+ Create or
+ Open =>
+ qid: Sys->Qid;
+ iounit: int;
+ Read =>
+ data: array of byte;
+ Write =>
+ count: int;
+ Stat =>
+ stat: Sys->Dir;
+ }
+
+ read: fn(fd: ref Sys->FD, msize: int): ref Rmsg;
+ unpack: fn(a: array of byte): (int, ref Rmsg);
+ pack: fn(nil: self ref Rmsg): array of byte;
+ packedsize: fn(nil: self ref Rmsg): int;
+ text: fn(nil: self ref Rmsg): string;
+ mtype: fn(nil: self ref Rmsg): int;
+};
+
+init: fn();
+
+readmsg: fn(fd: ref Sys->FD, msize: int): (array of byte, string);
+istmsg: fn(f: array of byte): int;
+
+compatible: fn(t: ref Tmsg.Version, msize: int, version: string): (int, string);
+
+packdirsize: fn(d: Sys->Dir): int;
+packdir: fn(d: Sys->Dir): array of byte;
+unpackdir: fn(f: array of byte): (int, Sys->Dir);
+dir2text: fn(d: Sys->Dir): string;
+qid2text: fn(q: Sys->Qid): string;
+
+VERSION: con "9P2000";
+MAXWELEM: con 16;
+NOTAG: con 16rFFFF;
+NOFID: con ~0;
+IOHDRSZ: con \fIimplementation-defined\f5;
+MAXRPC: con \fIimplementation-defined\f5;
+.EE
+.SH DESCRIPTION
+.B Styx
+provides a Limbo interface to send and receive messages of the Styx file service protocol,
+described by Section 5 of this manual (a thorough reading of which
+is advised before using this module).
+.B Init
+must be called before using any other function in the module.
+.PP
+A Styx client transmits requests to a server as `T-messages'
+and receives replies in matching `R-messages'.
+A T-message is here represented by values of the type
+.BR Tmsg ,
+and an R-message by values of type
+.BR Rmsg .
+Every message has a
+.B tag
+value, and the alternatives of the pick adt represent the possible operation types of a T-message,
+generally with parameter names and types corresponding to those described in section 5.
+The exceptions are:
+.B Tmsg.Write
+and
+.B Rmsg.Read
+contain an array of byte,
+.BR data ,
+to hold the data for the corresponding message, and the `count' parameter of the message is simply the length of that array;
+and there is an alternative labelled
+.B Readerror
+that does not appear in the protocol but is used to represent input errors as described below.
+Also note that values that are `unsigned' integers in the protocol are typically given signed integer
+types in the Limbo representation (in particular, fids, qid paths, counts and offsets), and applications
+should take appropriate care when manipulating them.
+.PP
+The following functions are provided by
+.BR Tmsg:
+.TP
+.BI read( fd\fP,\fP\ msize )
+Read file descriptor
+.I fd
+to obtain exactly one T-message and return (a reference to) the corresponding
+.BR Tmsg .
+A nil value is returned on end of file.
+Otherwise, if the read fails or the data read does not form a valid T-message,
+the value returned will be a
+.B Tmsg.Readerror
+value in which the
+.B error
+member describes the error.
+.I Msize
+gives the maximum number of bytes in any acceptable T-message,
+and should be the value negotiated in the exchange of
+.B version
+messages;
+any incoming message larger than that will result in a diagnostic as a
+.B Tmsg.Readerror
+value.
+An
+.I msize
+of 0 means `no limit negotiated' and should (only) be used until a message size
+has been negotiated by exchange of
+.IR version (5)
+messages.
+.TP
+.IB t .pack()
+Return an array of bytes containing the value of
+.I t
+in the machine-independent format described in Section 5.
+It can return nil only if the message
+.I t
+is itself nil or has an invalid type.
+.TP
+.BI unpack( a )
+The array
+.I a
+is assumed to contain zero or more T-messages.
+.B Unpack
+attempts to unpack the first message, and returns a tuple of the form
+.RI ( n , v ).
+If successful,
+.I n
+is the number of bytes at the start of
+.I a
+used by the message, and
+.I v
+is the corresponding
+.B Tmsg
+value.
+If
+.I a
+contains the prefix of a valid message but more data is required to complete it,
+.I n
+is zero (and
+.I v
+is nil); the caller will typically read more data, append it to
+.IR a ,
+and try again.
+If the message is invalid,
+.I n
+is -1
+and
+.I v
+is nil.
+.TP
+.IB t .packedsize()
+Return the number of bytes required for the value of
+.I t
+when packed in its machine-independent format.
+(Zero is returned if
+.I t
+is invalid.)
+.TP
+.IB t .text()
+Return a printable string showing the contents of
+.IR t ,
+for tracing or debugging.
+.TP
+.IB t .mtype()
+Return the Styx message type of the message.
+.PP
+An R-message is represented by
+.BR Rmsg .
+Its member functions behave exactly as those for
+.BR Tmsg ,
+except that they operate on R-messages not T-messages.
+.PP
+When a client reads a directory, the data returned in the reply must be formatted
+as described in
+.IR read (5):
+an array of directory entries, one per file, with each entry formatted in
+a machine-independent format.
+An appropriate array value can be produced by
+.B packdir
+from a
+.B Sys->Dir
+structure, as used by
+.IR sys-stat (2).
+The space that packed representation will take can be calculated beforehand by
+.BR packdirsize .
+The server will usually fill the buffer for the reply to the read
+with as many entries as will fit,
+checking the space remaining against the result of
+.B packdirsize
+and if the value will fit, storing the result of
+.BR packdir .
+Given an array
+.I a
+containing at most one packed directory value (as produced by
+.BR packdir ),
+.B unpackdir
+returns a tuple
+.RI ( n,\ d )
+where
+.I n
+is \-1 if
+.I a
+is illegally formatted;
+.I n
+is zero if
+.I a
+does not contain a complete directory entry value;
+and otherwise
+.I n
+is the number of bytes of
+.I a
+used to produce the unpacked
+.B Dir
+value
+.I d .
+.PP
+The functions
+.B dir2text
+and
+.B qid2text
+produce printable strings showing the contents of the corresponding data structures,
+for use when tracing or debugging.
+.PP
+Applications that acts as file servers will read T-messages and
+reply with R-messages.
+They can use
+.B Tmsg.read
+to read each T-message, build an
+.B Rmsg
+reply value
+.IR r ,
+and use
+.IB r .pack
+to produce an array of bytes to be written in reply by
+.B Sys->write
+(see
+.IR sys-read (2)).
+.PP
+A few specialised programs might need the lower-level function
+.B readmsg
+that underlies
+.B Tmsg.read
+and
+.BR Rmsg.read .
+It reads a single message, which can be either a T-message or R-message,
+and returns it as an array of bytes,
+which can then be unpacked using
+.B Tmsg.unpack
+or
+.BR Rmsg.unpack .
+.I Msize
+is the negotiated message size, or 0 meaning `no limit'.
+The predicate
+.B istmsg
+returns true if the contents of array
+.I f
+looks like a packed representation of a T-message,
+judging only by its
+.I type
+byte.
+.PP
+When generating the
+.B version
+message (see
+.IR version (5)),
+the constant
+.B NOTAG
+can be used in
+.B Tmsg.tag
+and
+.B Rmsg.tag
+to represent `no tag value'.
+The constant
+.B VERSION
+names the current version of the protocol, and can be
+used as the value of
+.BR Tmsg.version .
+.PP
+.B Compatible
+can be used by a server to
+compare its
+.I msize
+and
+.I version
+(which is typically
+.BR VERSION )
+to those in the
+.B Tmsg.Version
+message received from a client, to decide its reply,
+following the rules in
+.IR version (5).
+It returns a tuple
+.RI ( m ", " v )
+with values for use in the
+.B Rmsg.Version
+reply.
+.I M
+is the lesser of
+.I msize
+and
+.IB t .msize ,
+and
+.I v
+is the negotiated protocol version, or the value \f5"unknown"\f1
+if no version could be agreed.
+The constant
+.B MAXRPC
+is a reasonable value for
+.I msize
+on current systems.
+The resulting value
+.I m
+can subsequently be given to the various read functions as the limit
+.IR msize .
+The constant
+.B IOHDRSZ
+gives the amount to allow for protocol overhead, when limiting data size for
+.B Tmsg.Write
+and
+.BR Rmsg.Read .
+.PP
+The constant
+.B NOFID
+can be used as the value of
+.B afid
+of the
+.B attach
+message when authentication is not required (see
+.IR attach (5)).
+.PP
+The constant
+.B MAXWELEM
+gives the protocol-defined limit on the length of the arrays
+.B Tmsg.names
+and
+.BR Rmsg.qids .
+For specialised applications, the module defines constants
+.BR Tversion ,
+.BR Rversion ,
+etc. for the message types of the protocol, and the
+other constants mentioned in Section 5.
+.SH SOURCE
+.B /appl/lib/styx.b
+.SH SEE ALSO
+.IR styxservers (2),
+.IR intro (5)
diff --git a/man/2/styxconv b/man/2/styxconv
new file mode 100644
index 00000000..ca5d9f49
--- /dev/null
+++ b/man/2/styxconv
@@ -0,0 +1,77 @@
+.TH STYXCONV 2
+.SH NAME
+styxconv \- convert between old and new Styx
+.SH SYNOPSIS
+.EX
+include "styxconv.m";
+styxconv := load Styxconv Styxconv->PATH;
+
+init: fn();
+styxconv: fn(to: ref Sys->FD, from: ref Sys->FD, pid: chan of int);
+.EE
+.SH DESCRIPTION
+.B Styxconv
+converts between the previous version of the Styx protocol,
+as used for instance in Inferno's Third Edition and earlier,
+and the current version of the protocol,
+based on 9P2000 and defined by
+.IR intro (5).
+.PP
+.B Init
+must be called before any other function in the module.
+.PP
+The function
+.B styxconv
+takes two file descriptors.
+.I From
+must be a connection to a file server that serves the original, older
+version of Styx.
+.I To
+is a connection, perhaps a pipe, to something that requires the current protocol;
+.B Sys->mount
+for instance
+(see
+.IR sys-bind (1)).
+.B Styxconv
+is spawned by the caller, to create a process that copies messages between
+.I from
+and
+.IR to ,
+converting as required as it goes.
+Its process ID is the only message sent on
+channel
+.IR pidc ;
+it must be received by
+.BR styxconv 's
+caller.
+See the example below.
+.SH EXAMPLE
+Apply
+.B styxconv
+to file descriptor
+.I fd
+connected to an old Styx server:
+.IP
+.EX
+cvstyx(fd: ref Sys->FD): ref Sys->FD
+{
+ styxconv := load Styxconv Styxconv->PATH;
+ if(styxconv == nil)
+ return nil;
+ p := array[2] of ref Sys->FD;
+ if(sys->pipe(p) < 0)
+ return nil;
+ styxconv->init();
+ pidc := chan of int;
+ spawn styxconv->styxconv(p[1], fd, pidc);
+ <-pidc;
+ return p[0];
+}
+.EE
+.SH SOURCE
+.B /appl/lib/styxconv
+.SH SEE ALSO
+.IR bind (1),
+.IR sys-bind (2),
+.IR sys-pipe (2),
+.IR intro (5)
diff --git a/man/2/styxpersist b/man/2/styxpersist
new file mode 100644
index 00000000..60f370bf
--- /dev/null
+++ b/man/2/styxpersist
@@ -0,0 +1,80 @@
+.TH STYXPERSIST 2
+.SH NAME
+styxpersist \- persistent Styx connection
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "styxpersist.m";
+styxpersist := load Styxpersist Styxpersist->PATH;
+
+init: fn(clientfd: ref Sys->FD, usefac: int, keyspec: string)
+ : (chan of chan of ref Sys->FD, string);
+.EE
+.SH DESCRIPTION
+.I Styxpersist
+tries to maintain a persistent Styx connection for its client.
+.B Init
+starts a process to serve Styx for the client on
+.IR clientfd .
+If
+.I usefac
+is non-zero,
+.I styxpersist
+will use
+.IR factotum (2)
+to do plan 9-style authentication if necessary,
+and
+.I keyspec
+gives attribute-value pairs to pass to
+.IR factotum 's
+.B proxy
+function.
+.PP
+.B Init
+returns a tuple, say
+.RI ( c ,\ err ).
+If things have started successfully,
+.I c
+holds a channel that
+.I styxpersist
+uses to request a new connection to the server.
+The caller of
+.B init
+should arrange that a process is ready to repeatedly receive on this channel,
+dial the server, and send the resulting file descriptor (or
+.B nil
+if the connection was unsuccessful)
+on the channel received,
+.PP
+If
+.B init
+failed,
+.I c
+will be
+.B nil
+and
+.I err
+describes the error.
+.PP
+If the server goes down, it redials as above, and tries to
+re-open all the files that were open in the previous connection.
+In the meantime all client access to the namespace is blocked.
+.PP
+Note that this service should only be used on conventional
+file servers, where most reads and writes are idempotent.
+.SH SOURCE
+.B /appl/lib/styxpersist.b
+.SH BUGS
+Even on a conventional fileserver, some operations are non-idempotent;
+namely create, rename, remove, and write to an append-only file.
+If a fileserver dies while such a request is outstanding, it is unclear
+what it should do. Currently it returns an error to the client if such a sitution occurs.
+.PP
+.I Styxpersist
+is dependent on the capabilities of the local factotum to re-authenticate
+Plan 9 style. If a client uses an external factotum with different keys,
+.I styxpersist
+may be unable to re-authenticate.
+.SH "SEE ALSO"
+.IR mount (1),
+.IR sys-dial (2)
diff --git a/man/2/styxservers b/man/2/styxservers
new file mode 100644
index 00000000..fca2748a
--- /dev/null
+++ b/man/2/styxservers
@@ -0,0 +1,902 @@
+.TH STYXSERVERS 2
+.SH NAME
+styxservers \-
+Styx server implementation assistance
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "styx.m";
+Tmsg, Rmsg: import Styx;
+include "styxservers.m";
+styxservers := load Styxservers Styxservers->PATH;
+Styxserver, Fid, Navigator: import styxservers;
+
+Styxserver: adt {
+ fd: ref Sys->FD; # file server end of connection
+ t: ref Navigator; # name space navigator for this server
+ msize: int; # negotiated Styx message size
+
+ new: fn(fd: ref Sys->FD, t: ref Navigator, rootpath: big)
+ :(chan of ref Tmsg, ref Styxserver);
+ reply: fn(srv: self ref Styxserver, m: ref Rmsg): int;
+
+ # protocol operations
+ attach: fn(srv: self ref Styxserver, m: ref Tmsg.Attach): ref Fid;
+ clunk: fn(srv: self ref Styxserver, m: ref Tmsg.Clunk): ref Fid;
+ walk: fn(srv: self ref Styxserver, m: ref Tmsg.Walk): ref Fid;
+ open: fn(srv: self ref Styxserver, m: ref Tmsg.Open): ref Fid;
+ read: fn(srv: self ref Styxserver, m: ref Tmsg.Read): ref Fid;
+ remove: fn(srv: self ref Styxserver, m: ref Tmsg.Remove): ref Fid;
+ stat: fn(srv: self ref Styxserver, m: ref Tmsg.Stat);
+ default: fn(srv: self ref Styxserver, gm: ref Tmsg);
+
+ # check validity
+ cancreate: fn(srv: self ref Styxserver, m: ref Tmsg.Create)
+ :(ref Fid, int, ref Sys->Dir, string);
+ canopen: fn(srv: self ref Styxserver, m: ref Tmsg.Open)
+ :(ref Fid, int, ref Sys->Dir, string);
+ canread: fn(srv: self ref Styxserver, m: ref Tmsg.Read)
+ :(ref Fid, string);
+ canwrite: fn(srv: self ref Styxserver, m: ref Tmsg.Write)
+ :(ref Fid, string);
+
+ # fid management
+ getfid: fn(srv: self ref Styxserver, fid: int): ref Fid;
+ newfid: fn(srv: self ref Styxserver, fid: int): ref Fid;
+ delfid: fn(srv: self ref Styxserver, c: ref Fid);
+ allfids: fn(srv: self ref Styxserver): list of ref Fid;
+
+ iounit: fn(srv: self ref Styxserver): int;
+};
+
+Fid: adt {
+ fid: int; # client's fid
+ path: big; # file's 64-bit unique path
+ qtype: int; # file's qid type (eg, Sys->QTDIR if directory)
+ isopen: int; # non-zero if file is open
+ mode: int; # if open, the open mode
+ uname: string; # user name from original attach
+ param: string; # attach aname from original attach
+ data: array of byte; # application data
+
+ clone: fn(f: self ref Fid, nf: ref Fid): ref Fid;
+ open: fn(f: self ref Fid, mode: int, qid: Sys->Qid);
+ walk: fn(f: self ref Fid, qid: Sys->Qid);
+};
+
+Navop: adt {
+ reply: chan of (ref Sys->Dir, string); # channel for reply
+ path: big; # file or directory path
+ pick {
+ Stat =>
+ Walk =>
+ name: string;
+ Readdir =>
+ offset: int; # index (origin 0) of first entry to return
+ count: int; # number of directory entries requested
+ }
+};
+
+Navigator: adt {
+ new: fn(c: chan of ref Navop): ref Navigator;
+ stat: fn(t: self ref Navigator, path: big): (ref Sys->Dir, string);
+ walk: fn(t: self ref Navigator, parent: big, name: string)
+ : (ref Sys->Dir, string);
+ readdir:fn(t: self ref Navigator, path: big,
+ offset, count: int): array of ref Sys->Dir;
+};
+
+init: fn(styx: Styx);
+traceset: fn(on: int);
+
+readbytes: fn(m: ref Styx->Tmsg.Read, d: array of byte):
+ ref Styx->Rmsg.Read;
+readstr: fn(m: ref Styx->Tmsg.Read, s: string):
+ ref Styx->Rmsg.Read;
+openok: fn(uname: string, omode,
+ perm: int, funame, fgname: string): int;
+openmode: fn(o: int): int;
+.EE
+.SH DESCRIPTION
+When writing a Styx file server, there are some
+commonly performed tasks that are
+fiddly or tedious to implement each time.
+.B Styxservers
+provides a framework to automate some of these
+routine tasks.
+In particular, it helps manage the fid space,
+implements common default processing for protocol messages,
+and assists walking around the
+directory hierarchy and reading of directories. Other
+tasks, such as defining the structure of the
+name space, and reading and writing files in it, are
+left to the file server program itself.
+Familiarity with Section 5 of the manual which defines the protocol
+(see
+.IR intro (5)),
+and with the representation of Styx messages in Limbo
+(see
+.IR styx (2)),
+is a prerequisite for use of this module.
+.PP
+.B Styxservers
+does not define or store any of the directory hierarchy itself;
+instead it queries an external process for information
+when necessary, through a value of type
+.BR Navigator ,
+which encapsulates communication with that process.
+That process must be started up
+independently of each
+.BR Styxserver ;
+a channel to such a process should be provided
+when starting a new
+.BR Styxserver .
+The channel carries messages of type
+.BR Navop .
+.IR Styxservers-nametree (2)
+provides a ready-made
+implementation of such a process that is sufficient for many applications.
+.PP
+.B Styxserver
+keeps tabs on the fids that are currently in use, and remembers
+some associated information, such as the Qid path
+of the file, whether it has been opened, etc.
+It does this using values of type
+.BR Fid .
+.PP
+Once the
+.B Styxservers
+module has been loaded,
+the
+.B init
+function must be called before anything else,
+to initialise its internal state. The
+.I styx
+argument should be an implementation of
+the
+.IR styx (2)
+module, which will be used to translate messages.
+Individual
+.B Styxserver
+instances do not share state, and are therefore
+independently thread-safe.
+.SS Fid representation
+.B Styxservers
+represents each active fid as a
+.B Fid
+value,
+which has the following public members:
+.TF param
+.TP
+.B fid
+The integer
+.I fid
+value provided by the client to refer to an active instance of a file in the file server,
+as described in
+.IR intro (5).
+.TP
+.B path
+The 64-bit qid path that uniquely identifies the file on the file server,
+as described in
+.IR intro (5).
+It is set by
+.IB f .walk
+and
+.IB f .open
+(see below).
+.TP
+.B qtype
+The file's qid type; it is
+.B Sys->QTDIR
+if and only if the fid refers to a directory.
+The value is set by
+.IB f .walk
+and
+.IB f .open
+(see below).
+.TP
+.B isopen
+Non-zero if and only if the fid has been opened by an
+.IR open (5)
+message.
+It is initially zero, and set by
+.IB f .open
+(see below).
+.TP
+.B mode
+Valid only if the fid has been opened.
+It has one of the values
+.BR Sys->OREAD ,
+.BR Sys->OWRITE ,
+.BR Sys->ORDWR ,
+possibly ORed with
+.BR Sys->ORCLOSE ,
+corresponding to the mode with which the file was opened.
+It is set by
+.IB f .open
+(see below).
+.TP
+.B uname
+The name of the user that created the fid.
+.TP
+.B param
+Set by
+.B Styxservers
+to the
+.B aname
+of the initial
+.IR attach (5)
+message,
+and subsequently inherited by each new fid created by
+.IR walk (5),
+but not otherwise used by
+.B Styxservers
+itself, and may be changed by the application.
+.TP
+.B data
+Unused by
+.BR Styxservers ;
+for application use.
+It might be used, for instance, to implement a file that gives different
+data to different clients.
+.TP
+.IB f .clone( nf )
+Copy the current state of all members of
+.I f
+except
+.IB f .fid\f1,\fP
+into
+.IR nf ,
+and return
+.IR nf .
+Used by
+.BR Styxserver.walk ,
+and is needed by an application only if it replaces that function.
+.TP
+.IB f .walk( qid )
+Make
+.I f
+refer to the file with the given
+.IR qid :
+set
+.IB f .path
+and
+.IB f .qtype
+from
+.IB qid .path
+and
+.IB qid .qtype .
+Used by
+.IB Styxserver.walk
+and is needed by an application only if it replaces that function.
+.TP
+.IB f .open( mode,\ qid )
+Mark
+.I f
+as `open',
+set
+.IR f .mode
+to
+.IR mode ,
+and set
+.B path
+and
+.B qtype
+to the path and type of
+.IR qid .
+Used by the
+implementations of
+.B open
+and
+.B create
+messages.
+The default implementation of
+.IR open (5)
+in
+.B Styxserver
+obtains the value of
+.I mode
+from
+.B Styxserver.canopen
+(below),
+and
+obtains the value of
+.I qid
+by querying the application's navigator.
+.SS Styxserver and file server state
+Each
+.B Styxserver
+value holds the state for a single file server, including its active fids,
+the link to the external name space process, and other internal data.
+Most of the state is manipulated through the member functions described below.
+The exceptions are two read-only values:
+the
+.B Navigator
+reference
+.IB srv .t
+which can be used to access that navigator; and
+the file descriptor
+.IB srv .fd
+that is the file server's end of the connection to the Styx client.
+Both values are initially provided by the file serving application,
+but can be accessed through the
+.B Styxserver
+value for convenience.
+The file descriptor value is normally used only through
+.BR Styxserver.reply ,
+but will be needed directly if the caller needs the file descriptor value
+as a parameter to
+.IR sys-pctl (2)
+when insulating the serving process's file descriptors from the surrounding environment.
+.PP
+The first set of functions in
+.B Styxserver
+provides common and default actions:
+.TP
+.B Styxserver.new(\fIfd\fP,\ \fIt\fP,\ \fIrootpath\fP)
+Create a new
+.BR Styxserver .
+It returns a tuple, say
+.RI ( c ", " srv ),
+and spawns a new process, which uses
+.IR styx (2)
+to read and parse Styx messages read
+from
+.IR fd ,
+and send them down
+.IR c ;
+.I t
+should be a
+.B Navigator
+adt which the
+.B Styxserver
+can use to answer queries
+on the name space (see ``Navigating file trees'', below).
+.I Rootpath
+gives the Qid path of the root of the served name space.
+.TP
+.IB srv .reply(\fIm\fP)
+Send a reply (R-message) to a client. The various utility methods,
+listed below, call this function to make their response.
+.TP
+.IB srv .attach(\fIm\fP)
+Respond to an
+.IR attach (5)
+message
+.IR m ,
+creating a new fid in the process, and returning it.
+Returns
+.B nil
+if
+.IB m .fid
+is a duplicate of an existing fid.
+The value of the attach parameter
+.IB m .aname
+is copied into the new fid's
+.B param
+field, as is the attaching user name,
+.IB m .uname .
+.TP
+.IB srv .clunk(\fIm\fP)
+Respond to a
+.IR clunk (5)
+message
+.IR m ,
+and return the old
+.BR Fid .
+Note that this does nothing about remove-on-close
+files; that should be programmed explicitly if needed.
+.TP
+.IB srv .walk(\fIm\fP)
+Respond to a
+.IR walk (5)
+message
+.IR m ,
+querying
+.IB srv . t
+for information on existing files.
+.TP
+.IB srv .open(\fIm\fP)
+Respond to an
+.IR open (5)
+message
+.IR m .
+This will allow a file to be opened if its permissions allow the
+specified mode of access.
+.TP
+.IB srv .read(\fIm\fP)
+Respond to a
+.IR read (5)
+message
+.IR m .
+If a directory is being read, the appropriate reply
+is made; for files, an error is given.
+.TP
+.IB srv .remove(\fIm\fP)
+Respond to a
+.IR remove (5)
+message
+.IR m
+with an error, clunking the fid as it does so,
+and returning the old
+.BR Fid .
+.TP
+.IB srv .stat(\fIm\fP)
+Respond to a
+.IR stat (5)
+message
+.IR m .
+.TP
+.IB srv .default(\fIgm\fP)
+Respond to an arbitrary T-message,
+.IR gm ,
+as appropriate (eg, by calling
+.IB srv .walk
+for a
+.IR walk (5)
+message).
+It responds appropriately to
+.IR version (5),
+and replies to
+.B Tauth
+(see
+.IR attach (5))
+stating that authentication is not required.
+Other messages without an associated
+.B Styxserver
+function are generally responded to
+with a ``permission denied'' error.
+.PP
+All the functions above check the validity of the fids, modes, counts and offsets
+in the messages, and automatically reply to the client with a suitable
+.IR error (5)
+message on error.
+.PP
+The following further
+.B Styxserver
+operations are useful
+in applications that override all or part of the default handling
+(in particular,
+to process read and write requests):
+.TP
+.IB srv .canopen( m )
+Check whether it is legal to open a file as requested by message
+.IR m :
+the fid is valid but not already open, the corresponding file exists and its
+permissions allow access in the requested mode, and if
+.B Sys->ORCLOSE
+is requested, the parent directory is writable (to allow the file to be removed when closed).
+.B Canopen
+returns a tuple, say
+.RI ( f ,\ mode ,\ d,\ err\ \fP).
+If the open request was invalid,
+.I f
+will be nil, and the string
+.I err
+will diagnose the error (for return to the client in an
+.B Rmsg.Error
+message).
+If the request was valid:
+.I f
+contains the
+.B Fid
+representing the file to be opened;
+.I mode
+is the access mode derived from
+.IB m .mode ,
+.BR Sys->OREAD ,
+.BR Sys->OWRITE ,
+.BR Sys->ORDWR ,
+ORed with
+.BR Sys->ORCLOSE ;
+.I d
+is a
+.B Dir
+value giving the file's attributes, obtained from the navigator;
+and
+.I err
+is nil.
+Once the application has done what it must to open the file,
+it must call
+.IB f .open
+to mark it open.
+.TP
+.IB srv .cancreate( m )
+Checks whether the
+creation of the file requested by
+message
+.I m
+is legal:
+the fid is valid but not open, refers to a directory,
+the permissions returned by
+.IR srv .t.stat
+show that directory is writable by the requesting user,
+the name does not already exist in that directory,
+and the mode with which the new file would be opened is valid.
+.B Cancreate
+returns a tuple, say
+.RI ( f ,\ mode,\ d,\ err\ \fP).
+If the creation request was invalid,
+.I f
+will be nil, and the string
+.I err
+will diagnose the error, for use in an error reply to the client.
+If the request was valid:
+.I f
+contains the
+.B Fid
+representing the parent directory;
+.I mode
+is the open mode as defined for
+.B canopen
+above;
+.I d
+is a
+.B Dir
+value containing some initial attributes for the new file or directory;
+and
+.I err
+is nil.
+The initial attributes set in
+.I d
+are:
+.IB d .name
+(the name of the file to be created);
+.IB d .uid
+and
+.IB d .muid
+(the user that did the initial attach);
+.IB d .gid ,
+.IB d .dtype ,
+.IB d .dev
+(taken from the parent directory's attributes);
+and
+.IB d .mode
+holds the file mode that should be attributed to the new
+file (taking into account the parent mode, as
+described in
+.IR open (5)).
+The caller must supply
+.IB d .qid
+once the file has successfully been created,
+and
+.IB d .atime
+and
+.IB d .mtime ;
+it must also call
+.IB f .open
+to mark
+.I f
+open and set its path to the file's path.
+If the file cannot be created successfully, the application should reply with
+an
+.IR error (5)
+message and leave
+.I f
+untouched.
+The
+.B Fid
+.I f
+will then continue to refer to the original directory, and remain unopened.
+.TP
+.IB srv .canread( m )
+Checks whether
+.IR read (5)
+message
+.I m
+refers to a valid fid that has been opened for reading,
+and that the count and file offset are non-negative.
+.B Canread
+returns a tuple, say
+.RI ( f ,\ err );
+if the attempted access is illegal,
+.I f
+will be nil, and
+.I err
+contains a description of the error,
+otherwise
+.I f
+contains the
+.B Fid
+corresponding to the file in question.
+It is typically called by an application's implementation of
+.B Tmsg.Read
+to obtain the
+.B Fid
+corresponding to the fid in the message, and check the access.
+.TP
+.IB srv .canwrite( m )
+Checks whether
+message
+.I m
+refers to a valid fid that has been opened for writing,
+and that the file offset is non-negative.
+.B Canwrite
+returns a tuple, say
+.RI ( f ,\ err );
+if the attempted access is illegal,
+.I f
+will be nil, and
+.I err
+contains a description of the error,
+otherwise
+.I f
+contains the
+.B Fid
+corresponding to the file in question.
+It is typically called by an application's implementation of
+.B Tmsg.Write
+to obtain the
+.B Fid
+corresponding to the fid in the message, and check the access.
+.TP
+.IB srv .iounit()
+Return an appropriate value for use as the
+.I iounit
+element in
+.B Rmsg.Open
+and
+.B Rmsg.Create
+replies,
+as defined in
+.IR open (5),
+based on the message size negotiated by the initial
+.IR version (5)
+message.
+.PP
+The remaining functions are normally used only by servers that need to
+override default actions.
+They maintain and access the mapping between a client's fid values presented in
+.B Tmsg
+messages and the
+.B Fid
+values that represent the corresponding files internally.
+.TP
+.IB srv .newfid(\fIfid\fP)
+Create a new
+.B Fid
+associated with number
+.I fid
+and return it.
+Return nil if the
+.I fid
+is already in use (implies a client error if the server correctly clunks fids).
+.TP
+.IB srv .getfid(\fIfid\fP)
+Get the
+.B Fid
+data associated with numeric id
+.IR fid ;
+return nil if there is none such (a malicious or erroneous client
+can cause this).
+.TP
+.IB srv .delfid(\fIfid\fP)
+Delete
+.I fid
+from the table of fids in the
+.BR Styxserver .
+(There is no error return.)
+.TP
+.IB srv .allfids()
+Return a list of all current fids (ie, the files currently active on the client).
+.PP
+.B Newfid
+is required when processing
+.IR auth (5),
+.IR attach (5)
+and
+.IR walk (5)
+messages to create new fids.
+.B Delfid
+is used to clunk fids when processing
+.IR clunk (5),
+.IR remove (5),
+and in a failed
+.IR walk (5)
+when it specified a new fid.
+All other messages should refer only to already existing fids, and the associated
+.B Fid
+data is fetched by
+.BR getfid .
+.SS Navigating file trees
+When a
+.B Styxserver
+instance needs to know about the namespace,
+it queries an external process through a channel
+by sending a
+.B Navop
+request;
+each such request carries with it a
+.B reply
+channel through which the
+reply should be made.
+The reply tuple has a reference to a
+.B Sys->Dir
+value that is non-nil on success, and a diagnostic string
+that is non-nil on error.
+.PP
+Files in the tree are referred to
+by their Qid
+.BR path .
+The requests are:
+.TF Walk
+.TP
+.BR Stat
+.br
+Find a file in the hierarchy by its
+.BR path ,
+and reply with the corresponding
+.B Dir
+data if found (or a diagnostic on error).
+.TP
+.BR Walk
+.br
+Look for file
+.B name
+in the directory with the given
+.BR path .
+.TP
+.BR Readdir
+.br
+Get information on selected files in the directory with the given
+.BR path .
+In this case, the reply channel is used to send
+a sequence of values, one for each entry in the directory, finishing with a tuple value
+.BR (nil,nil) .
+The entries to return are those selected by an
+.B offset
+that is the index (origin 0) of the first directory entry to return,
+and a
+.B count
+of a number of entries to return starting with that index.
+Note that both values are expressed in units of directory entries, not as byte counts.
+.PP
+.B Styxserver
+provides a
+.B Navigator
+adt to enable convenient access to this functionality; calls
+into the
+.B Navigator
+adt are bundled up into requests on the channel, and the
+reply returned.
+The functions provided are:
+.TP 10
+.BI Navigator.new( c )
+Create a new
+.BR Navigator ,
+sending requests down
+.IR c .
+.TP
+.IB t .stat(\fIpath\fP)
+Find the file with the given
+.IR path .
+Return a tuple
+.RI ( d ,\ err ),
+where
+.I d
+holds directory information for the file
+if found; otherwise
+.I err
+contains an error message.
+.TP
+.IB t .walk(\fIparent\fP,\ \fIname\fP)
+Find the file with name
+.I name
+inside parent directory
+.IR parent .
+Return a tuple as for
+.BR stat .
+.TP
+.IB t .readdir(\fIpath\fP,\ \fIoffset\fP,\ \fIcount\fP)
+Return directory data read from directory
+.IR path ,
+starting at entry
+.I offset
+for
+.I count
+entries.
+.SS Other functions
+The following functions provide some commonly used functionality:
+.TP 10
+.BI readbytes( m ,\ d )
+Assuming that the file in question contains data
+.IR d ,
+.B readbytes
+returns an appropriate reply to
+.IR read (5)
+message
+.IR m ,
+taking account of
+.IB m .offset
+and
+.IB m.count
+when extracting data from
+.IR d .
+.TP 10
+.BI readstr( m ,\ s )
+Assuming that the file in question contains string
+.IR s ,
+.B readstr
+returns an appropriate reply to
+.IR read (5)
+message
+.IR m ,
+taking account of
+.IB m .offset
+and
+.IB m.count
+when extracting data from the UTF-8 representation of
+.IR s .
+.TP
+.BI openok (\fIuname\fP,\ \fIomode\fP,\ \fIperm\fP,\ \fIfuid\fP,\ \fIfgid\fP)
+Does standard permission checking, assuming user
+.I uname
+is trying to open a file with access mode
+.IR omode ,
+where the file is owned by
+.IR fuid ,
+has group
+.IR fgid ,
+and permissions
+.IR perm .
+Returns true (non-zero) if permission would be granted, and false (zero) otherwise.
+.TP
+.BI openmode( o )
+Checks to see whether the open mode
+.I o
+is well-formed; if it is not,
+.B openmode
+returns -1; if it is, it returns the mode
+with OTRUNC and ORCLOSE flags removed.
+.TP
+.BI traceset( on )
+If
+.I on
+is true (non-zero),
+will trace Styx requests and replies, on standard error.
+This option must be set before creating a
+.BR Styxserver ,
+to ensure that it preserves its standard error descriptor.
+.SS Constants
+.B Styxservers
+defines a number of constants applicable to the writing
+of Styx servers, including:
+.TP
+.BR Einuse\fP,\fP\ Ebadfid\fP,\fP\ Eopen\fP,\fP\ Enotfound\fP,\fP\ Enotdir\fP,\fP\ Eperm\fP,\fP\ Ebadarg\fP,\fP\ Eexists
+These provide standard strings for commonly used error conditions,
+to be used in
+.B Rmsg.Error
+replies.
+.SS Authentication
+If authentication is required beyond that provided at the link level
+(for instance by
+.IR security-auth (2)),
+the server application must handle
+.B Tauth
+itself,
+remember the value of
+.I afid
+in that message, and generate an
+.B Rauth
+reply with a suitable Qid referring to a file with
+.B Qid.qtype
+of
+.BR QTAUTH .
+Following successful authentication by read and write on that file,
+it must associate that status with the
+.IR afid .
+Then, on a subsequent
+.B Tattach
+message, before calling
+.I srv .attach
+it must check that the
+.BR Tattach 's
+.I afid
+value corresponds to one previously authenticated, and
+reply with an appropriate error if not.
+.SH SOURCE
+.B /appl/lib/styxservers.b
+.SH SEE ALSO
+.IR styxservers-nametree (2),
+.IR sys-stat (2),
+.IR intro (5)
diff --git a/man/2/styxservers-nametree b/man/2/styxservers-nametree
new file mode 100644
index 00000000..f64e519a
--- /dev/null
+++ b/man/2/styxservers-nametree
@@ -0,0 +1,180 @@
+.TH STYXSERVERS-NAMETREE 2
+.SH NAME
+Styxservers: nametree \-
+hierarchical name storage for use with Styxservers.
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "styx.m";
+include "styxservers.m";
+nametree := load Nametree Nametree->PATH;
+ Tree: import nametree;
+
+Tree: adt {
+ create: fn(t: self ref Tree, parentpath: big, d: Sys->Dir): string;
+ remove: fn(t: self ref Tree, path: big): string;
+ wstat: fn(t: self ref Tree, path: big, d: Sys->Dir);
+ quit: fn(t: self ref Tree);
+};
+init: fn();
+start: fn(): (ref Tree, chan of ref Styxservers->Navop);
+.EE
+.SH DESCRIPTION
+.B Nametree
+provides the storage for a hierarchical namespace
+to be used by
+.IR styxservers (2).
+After the module is loaded, the
+.B init
+function should be called to
+initialise the module's internal variables.
+.B Start
+spawns a new
+.B nametree
+process; it returns a tuple, say
+.RI ( tree ,\ c ),
+where c is a channel that can be used to create
+an instance of
+.BR Styxservers->Navigator ,
+to access files inside
+.BR nametree ,
+and
+.I tree
+is an adt that allows creation and removal of those files.
+On failure, these functions return a string describing
+the error.
+.PP
+Note that the full set of operations on
+.B Nametree
+(i.e. stat, walk, readdir, wstate, create and remove),
+is only available in conjunction with
+.BR Styxserver 's
+.B Navigator
+interface.
+Files in the name space are ultimately identified by a 64-bit
+.I path
+value, which forms the path component of the file's Qid.
+(See
+.IR intro (5)
+for a description of the system's interpretation of Qids.)
+.PP
+The
+.B Tree
+operations
+are:
+.TP 10
+.IB t .create(\fIparentpath\fP,\ \fId\fP)
+Create a new file or directory.
+.I D
+gives the directory information that will be stored
+for the file, including its own path value,
+given by
+.IB d .qid.path .
+If the file referenced by
+.I parentpath
+does not exist, creation will not be allowed,
+other than in the special case when
+.IB d .qid.path
+is equal to
+.IR parentpath ,
+in which case it is assumed to be a root directory
+and may be created. This potentially allows a single
+.B Nametree
+instance to hold many distinct directory hierarchies.
+Note that no attempt is made to ensure that
+.I parentpath
+refers to a directory; the check is assumed to have
+been made previously.
+When a hierarchy is traversed,
+.B Nametree
+interprets the name
+.RB ` .. '
+itself as `parent directory', and that name should not be created explicitly.
+.TP
+.IB t .remove(\fIpath\fP)
+Remove the file referred to by
+.IR path ,
+and all its descendants.
+.TP
+.IB t .wstat(\fIpath\fP,\ \fId\fP)
+Change the directory information held on file
+.IR path .
+The Qid path itself cannot be changed by
+.IR d .
+.TP
+.IB t .quit()
+Shut down the
+.B nametree
+process.
+.SH EXAMPLE
+Here is a complete example that uses
+.B Nametree
+in conjunction with
+.B Styxservers
+in order to serve two files
+.B data
+and
+.BR ctl " ..."
+and do nothing with them:
+.EX
+implement Tst;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "styx.m";
+include "styxservers.m";
+ styxservers: Styxservers;
+ Styxserver, Navigator: import styxservers;
+ nametree: Nametree;
+ Tree: import nametree;
+
+Tst: module
+{
+ init: fn(nil: ref Draw->Context, argv: list of string);
+};
+
+Qroot, Qctl, Qdata: con big iota; # paths
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ styx := load Styx Styx->PATH;
+ styx->init();
+ styxservers = load Styxservers Styxservers->PATH;
+ styxservers->init(styx);
+ nametree = load Nametree Nametree->PATH;
+ nametree->init();
+ sys->pctl(Sys->FORKNS, nil);
+ (tree, treeop) := nametree->start();
+ tree.create(Qroot, dir(".", 8r555|Sys->DMDIR, Qroot));
+ tree.create(Qroot, dir("ctl", 8r666, Qctl));
+ tree.create(Qroot, dir("data", 8r444, Qdata));
+ (tchan, srv) := Styxserver.new(sys->fildes(0),
+ Navigator.new(treeop), Qroot);
+ while((gm := <-tchan) != nil) {
+ # normally a pick on gm would act on
+ # Tmsg.Read and Tmsg.Write at least
+ srv.default(gm);
+ }
+ tree.quit();
+}
+
+dir(name: string, perm: int, qid: big): Sys->Dir
+{
+ d := sys->zerodir;
+ d.name = name;
+ d.uid = "me";
+ d.gid = "me";
+ d.qid.path = qid;
+ if (perm & Sys->DMDIR)
+ d.qid.qtype = Sys->QTDIR;
+ else
+ d.qid.qtype = Sys->QTFILE;
+ d.mode = perm;
+ return d;
+}
+.EE
+.SH SOURCE
+.B /appl/lib/nametree.b
+.SH SEE ALSO
+.IR styxservers (2),
+.IR intro (5)
diff --git a/man/2/sys-0intro b/man/2/sys-0intro
new file mode 100644
index 00000000..c5c90b47
--- /dev/null
+++ b/man/2/sys-0intro
@@ -0,0 +1,302 @@
+.TH SYS-INTRO 2
+.SH NAME
+Sys: intro \- introduction to the
+.B Sys
+module
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+.EE
+.SH DESCRIPTION
+Inferno system calls are provided by the built-in module declared by
+.BR sys.m .
+It contains the fundamental system data structures and interfaces.
+There are currently 42 calls, providing: file access; basic I/O;
+name space manipulation; formatted output
+for Limbo; and basic character and string manipulation.
+.SS "File Name Space"
+Files are collected into a hierarchical organization called a
+.I file
+.I tree
+starting in a
+.I directory
+called the
+.IR root.
+.IR Filenames ,
+also called
+.IR paths ,
+consist of a number of
+.BR / -separated
+.I "path elements
+with the slashes corresponding to directories.
+A path element must contain only printable
+characters (those outside ASCII and Latin-1 control space).
+A path element cannot contain a space, slash, or
+.BR # .
+The path element
+.B \&..
+refers to the parent directory of the directory containing that element.
+.PP
+When a process presents a file name to Inferno,
+it is
+.I evaluated
+by the following algorithm.
+.TP
+1.
+Start with a directory that depends on the first character of the path:
+.B /
+means the root of the main hierarchy,
+.B #
+means the separate root of a kernel device's file tree
+(see Section 3),
+and anything else means the process's current working directory.
+.TP
+2.
+For each path element, look up the element
+in the directory, advance to that directory,
+do a possible translation (see below).
+.TP
+3.
+Repeat.
+The last step may yield a directory or regular file.
+.PP
+The collection of files reachable from the root is called the
+.I "name space
+of a process.
+.PP
+A program can use
+.B bind
+or
+.B mount
+(see
+.IR sys-bind (2))
+to say that whenever a certain (specified) file is reached during an evaluation,
+that evaluation continues instead from some other (specified) file.
+.PP
+Also, these same calls create
+\f2union directories\fP,
+which are concatenations of ordinary directories
+that are searched sequentially until the desired element is found.
+.PP
+The result of evaluating
+.B \&..
+in a union directory is undefined.
+.PP
+Using
+.B bind
+and
+.B mount
+to do name space adjustment affects only
+the current name space group (see below, and
+.IR sys-pctl (2)).
+.PP
+Certain conventions about the layout of the name space should be preserved;
+see
+.IR namespace (4).
+.SS "File I/O"
+Files are opened for input or output
+by
+.B open
+or
+.B create
+(see
+.IR sys-open (2)).
+These calls return a reference to an object of type
+.B FD
+(file descriptor)
+that identifies the file to subsequent I/O calls,
+notably
+.B read
+and
+.B write
+(see
+.IR sys-read (2)).
+When the last reference to an
+.B FD
+disappears, the file descriptor is released\(emclosed, in Unix parlance.
+The
+.B FD
+contains an integer file descriptor, similar to those in Unix, but the
+.B FD
+type is the one passed to Limbo I/O routines.
+.PP
+Integer file descriptor values range from 0 to
+.I n
+in the current system, where the upper bound
+depends on the underlying operating system.
+The system allocates the numbers by selecting the lowest unused descriptor.
+They may be reassigned using
+.B dup
+(see
+.IR sys-dup (2)).
+Integer file descriptor values are indices into a
+kernel-resident
+.IR "file descriptor table" ,
+which is inherited from the parent when a process is created by a Limbo
+.B spawn
+operation.
+A set of processes, called a
+.IR "file descriptor group" ,
+shares that table, so files opened by one process may be
+read and written by other processes in the group. See
+.IR sys-pctl (2)
+for more information.
+.PP
+By convention,
+file descriptor 0 is the standard input,
+1 is the standard output,
+and 2 is the standard error output.
+The operating system is unaware of these conventions;
+it is permissible to close file 0,
+or even to replace it by a file open only for writing,
+but many programs will be confused by such chicanery.
+.PP
+Files are normally read or written in sequential order.
+The I/O position in the file is called the
+.IR "file offset"
+and may be set arbitrarily using the
+.B seek
+system call
+.RI ( sys-seek (2)).
+.PP
+Directories may be opened and read
+much like regular files (see
+.IR sys-dirread (2)).
+They contain an integral number of records,
+called
+.IR "directory entries" .
+Each entry is a machine-independent representation of
+the information about an existing file in the directory,
+including the
+name,
+ownership,
+permission,
+access dates,
+and so on.
+.PP
+The entry
+corresponding to an arbitrary file can be retrieved by
+.B stat
+or
+.B fstat
+(see
+.IR sys-stat (2));
+.B wstat
+and
+.B fwstat
+write back entries, thus changing the properties of a file.
+.PP
+New files are made with
+.B create
+and deleted with
+.B remove
+(see
+.IR sys-open (2)
+and
+.IR sys-remove (2)).
+.PP
+Directories are manipulated by
+.BR create ,
+.BR remove ,
+.BR wstat ,
+and
+.BR fwstat ;
+they may not directly be written.
+.PP
+Inferno provides no guarantee of consistency should
+several processes access a file concurrently.
+Guaranteed synchronous writes are not available.
+Nor is file locking from underlying file systems supported by Inferno.
+Processes can coordinate their file operations by other mechanisms.
+.PP
+Atomicity is guaranteed for byte counts smaller than the
+.I Styx
+message size;
+see
+.IR read (5).
+.SS "Process execution and control"
+A Limbo
+.IR process ,
+also called a
+.IR thread ,
+is the basic unit of computation for Limbo application programming
+in the Inferno operating system.
+.PP
+A newly spawned thread shares the same
+.I "address space
+as that of its creator thread.
+That is, the set of global variables that is in scope to
+one is in scope to the other.
+A change made by one can be detected by the other.
+Since they are scheduled independently,
+they should synchronize their
+actions to share this data coherently.
+.PP
+The newly created thread also shares the same set of open file descriptors
+and the current working directory.
+.PP
+Processes are also organized into
+.I "process groups
+.RB ( pgrps )
+that represent the set of threads of a single
+application and can be terminated by a single kill request; see
+.IR prog (3).
+.PP
+A newly-spawned thread automatically inherits the following attributes:
+file name space (including shared
+current directory); file descriptor group; and process group.
+A thread can subsequently
+acquire a new, independent name space, new or modified file descriptor group,
+or new process group.
+See
+.IR sys-pctl (2).
+.SS "User/Group Identity"
+The Inferno operating system maintains user identifier
+.RB ( uid )
+and group identifier
+.RB ( gid )
+strings
+for each process.
+These values are also attributes of files and directories.
+See
+.IR sys-stat (2)
+and
+.IR stat (5).
+A comparison of process and file identities take place when a process
+attempts to open or create a file.
+.PP
+When a pathname crosses from one server to another the process identities are
+mapped by each server receiving a file request.
+.PP
+The
+.B uid
+and
+.B gid
+strings are assigned to the thread created
+when a user logs into Inferno and cannot be changed.
+.SH SOURCE
+.B /emu/port/inferno.c
+.br
+.B /os/port/inferno.c
+.SH DIAGNOSTICS
+System calls often return an integer status, or tuples containing results and
+an integer status,
+and follow the convention that a status of -1 is returned when an error occurred;
+a non-negative value (usually 0) is returned on success.
+If an error occurred, a detailed error message can be obtained for the
+most recent error, using the
+.RB ` %r '
+format of
+.IR sys-print (2).
+Exceptions to this general rule are noted in the
+`DIAGNOSTICS' sections.
+.PP
+From Limbo, system calls that return values on the heap, for instance strings in
+.B Dir
+structures returned by
+.IR sys-stat (2),
+and arrays of directory entries returned by
+.IR sys-readdir (2),
+can also raise ``out of memory: heap'' exceptions when attempting
+to create the return value.
diff --git a/man/2/sys-bind b/man/2/sys-bind
new file mode 100644
index 00000000..b03379c0
--- /dev/null
+++ b/man/2/sys-bind
@@ -0,0 +1,201 @@
+.TH SYS-BIND 2
+.SH NAME
+bind, mount, unmount \- change file name space
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+bind: fn(name, old: string, flag: int): int;
+mount: fn(fd: ref FD; afd: ref FD, old: string, flag: int, aname: string):
+ int;
+unmount: fn(name, old: string): int;
+.EE
+.SH DESCRIPTION
+.B Bind
+and
+.B mount
+modify the file name space of the current process and its name space group.
+For both calls,
+.I old
+is the name of an existing file or directory in the
+current name space where the modification is to be made.
+The name
+.I old
+is
+evaluated
+as described in
+.IR sys-intro (2)
+except that no translation of the final path element is done.
+.PP
+For
+.BR bind ,
+.I name
+is the name of another (or possibly the same)
+existing file or directory in
+the current name space.
+After a successful
+.B bind
+call, the file name
+.I old
+is an alias for the object originally named by
+.IR name ;
+if the modification does not hide the original,
+.I name
+will also still refer to its original file.
+The evaluation of
+.I name
+happens at the time of the
+.BR bind ,
+not when the binding is later used.
+.PP
+The
+.I fd
+argument to
+.B mount
+is a file descriptor of an open pipe or network connection
+to a file server ready to receive Styx messages.
+The
+.I old
+file must be a directory.
+After a successful
+.BR mount ,
+the file tree
+.I served
+(see below) by
+.I fd
+will be visible with its root directory having name
+.IR old .
+If the requested service requires authentication, the file descriptor
+.I afd
+must be open on an authentication file for the
+requested service;
+otherwise it should be
+.BR nil .
+.PP
+The
+.I flag
+controls details of the modification made to the name space.
+In the following,
+.I new
+refers to the file
+as defined by
+.I name
+or the root directory served by
+.IR fd .
+Either both
+.I old
+and new files must be directories,
+or both must not be directories.
+.I Flag
+can be one of:
+.TF Sys->MBEFORE
+.TP
+.B Sys->MREPL
+Replace the
+.I old
+file by the new one.
+Henceforth, an evaluation of
+.I old
+will be translated to the new file.
+If they are directories (for
+.BR mount ,
+this condition is true by definition),
+.I old
+becomes a
+.I "union directory"
+consisting of one directory (the new file).
+.TP
+.B Sys->MBEFORE
+Both the
+.I old
+and new files must be directories.
+Add the constituent files of the new directory
+to the union directory at
+.I old
+so its contents appear first in the union.
+After a
+.B Sys->MBEFORE
+.B bind
+or
+.BR mount ,
+the new directory will be searched first when evaluating file names
+in the union directory.
+.TP
+.B Sys->MAFTER
+Like
+.B Sys->MBEFORE
+but the new directory goes at the end of the union.
+.PD
+.PP
+In addition, there is a
+.B Sys->MCREATE
+flag that can be OR'd with any of the above.
+When a
+.B create
+call (see
+.IR sys-open (2))
+attempts to create in a union directory, and the file does not exist,
+the elements of the union are searched in order until one is found
+with
+.B Sys->MCREATE
+set.
+The file is created in that directory; if that attempt fails,
+the
+.B create
+fails.
+.PP
+With
+.BR mount ,
+the file descriptor
+.I fd
+must be open for reading and writing
+and connected to a file server.
+After the
+.BR mount ,
+the file tree starting at
+.I old
+is served by a kernel
+.IR mnt (3)
+device.
+That device will turn operations in the tree into messages to the server on
+.IR fd .
+.I Aname
+selects among different
+file trees on the server; the
+empty (or nil)
+string chooses the default tree.
+.PP
+The effects of
+.B bind
+and
+.B mount
+can be undone by
+.BR unmount .
+If
+.I name
+is
+.BR nil ,
+everything bound to or mounted upon
+.I old
+is unbound or unmounted.
+If
+.I name
+is not
+.BR nil ,
+it is evaluated as described above for
+.BR bind ,
+and the effect of binding or mounting that particular result on
+.I old
+is undone.
+.SH SEE ALSO
+.IR sys-intro (2)
+.SH DIAGNOSTICS
+The return value is a positive integer (a unique sequence number) for
+success, \-1 for failure.
+.SH BUGS
+.B Mount
+will not return until it has successfully attached
+to the file server, so the thread doing a
+.B mount
+cannot be the one serving.
diff --git a/man/2/sys-byte2char b/man/2/sys-byte2char
new file mode 100644
index 00000000..70aeb015
--- /dev/null
+++ b/man/2/sys-byte2char
@@ -0,0 +1,68 @@
+.TH SYS-BYTE2CHAR 2
+.SH NAME
+byte2char, char2byte \- convert between bytes and characters
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+byte2char: fn(buf: array of byte, n: int): (int, int, int);
+char2byte: fn(c: int, buf: array of byte, n: int): int;
+.EE
+.SH DESCRIPTION
+.B Byte2char
+converts a byte sequence to one Unicode character.
+.I Buf
+is an array of bytes and
+.I n
+is the index of the first byte to examine in the array.
+The returned tuple, say
+.BI ( c ,
+.IB length ,
+.IB status )\f1,
+specifies the result of the translation:
+.I c
+is the resulting Unicode character,
+.I status
+is non-zero if the bytes are a valid UTF sequence and zero otherwise,
+and
+.I length
+is set to the number of bytes consumed by the translation.
+If the input sequence is not long enough to determine its validity,
+.B byte2char
+consumes zero bytes;
+if the input sequence is otherwise invalid,
+.B byte2char
+consumes one input byte and generates an error character
+.RB ( Sys->UTFerror ,
+.BR 16r80 ),
+which prints in most fonts as a boxed question mark.
+.PP
+.B Char2byte
+performs the inverse of
+.BR byte2char .
+It translates a Unicode character,
+.IR c ,
+to a UTF byte sequence, which
+is placed in successive bytes starting at
+.IR buf [\c
+.IR n ].
+The longest UTF sequence for a single Unicode character is
+.B Sys->UTFmax
+(3) bytes.
+If the translation succeeds,
+.B char2byte
+returns the number of bytes placed in the buffer.
+If the buffer is too small to hold the result,
+.B char2byte
+returns zero and leaves the array unchanged.
+.SH SOURCE
+.B /libinterp/runt.c
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-utfbytes (2),
+.IR utf (6)
+.SH DIAGNOSTICS
+A run-time error occurs if
+.I n
+exceeds the bounds of the array.
diff --git a/man/2/sys-chdir b/man/2/sys-chdir
new file mode 100644
index 00000000..8604d7f9
--- /dev/null
+++ b/man/2/sys-chdir
@@ -0,0 +1,40 @@
+.TH SYS-CHDIR 2
+.SH NAME
+chdir \- change working directory
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+chdir: fn(path: string): int;
+.EE
+.SH DESCRIPTION
+.B Chdir
+changes the working directory
+of the invoking process and its file name space group to
+.IR path .
+.PP
+The working directory is the starting point for
+evaluating file names that do not begin with
+.B /
+or
+.BR # ,
+as explained in
+.IR sys-intro (2).
+.PP
+When Inferno boots,
+the initial process has
+.B /
+for its working directory.
+.PP
+Applications that invoke
+.B chdir
+normally use the
+.B FORKNS
+option of
+.IR sys-pctl (2)
+to prevent the change from affecting the surrounding environment.
+.SH DIAGNOSTICS
+Returns 0 on success; -1 on failure.
+.SH SEE ALSO
+.IR sys-intro (2)
diff --git a/man/2/sys-dial b/man/2/sys-dial
new file mode 100644
index 00000000..4626f557
--- /dev/null
+++ b/man/2/sys-dial
@@ -0,0 +1,247 @@
+.TH SYS-DIAL 2
+.SH NAME
+announce, dial, listen \- make network connections
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+Connection: adt
+{
+ dfd: ref FD; # data file
+ cfd: ref FD; # control file
+ dir: string; # pathname of line directory
+};
+
+announce: fn(addr: string): (int, Connection);
+dial: fn(addr, local: string): (int, Connection);
+listen: fn(c: Connection): (int, Connection);
+.EE
+.SH DESCRIPTION
+These routines establish network connections.
+Their description uses the following definitions:
+.TF network
+.PD
+.TP
+.I addr
+is a network address in one of the following forms:
+.br
+.IP
+.IB network ! netaddr ! service\f1
+.br
+.IB network ! netaddr\f1
+.br
+.IR netaddr
+.TP
+.I network
+Any directory listed in
+.B /net
+(eg,
+.BR tcp ),
+or the special token,
+.BR net .
+The name
+.B net
+acts as a free variable that stands for any network in common
+between the source and
+.IR netaddr .
+A network name can be preceded by the full path name of a directory
+of networks, using the form
+.I /dir/network
+(eg,
+.BR /net.alt/tcp ).
+.TP
+.I netaddr
+A host name, a domain name, a network address,
+or a meta-name of the form
+.BI $ attribute\f1,
+which
+is replaced by
+.I value
+from the corresponding attribute-value pair
+in the connection server data base (see
+.IR db (6)).
+.PP
+The functions
+.B dial
+and
+.B announce
+translate a given
+.I addr
+to an actual network address using
+the connection server
+.IR cs (8).
+If a logical name
+.I addr
+corresponds to several network addresses,
+for instance if a destination machine has several interfaces,
+.I cs
+will return them all.
+In particular, if
+.I addr
+is
+.BR net ,
+.I cs
+will return addresses on
+all networks that are common to source and destination.
+The translation procedure accesses
+.I cs
+using its interface file
+.BR cs ,
+which is sought as follows:
+first, in an explicit directory
+.BI / dir
+if one was given in
+.IR network ;
+second, in the standard directory
+.BR /net ;
+and finally in the directory
+.BR /net.alt
+.RB ( dial
+only).
+If the connection server cannot be found,
+the
+.I addr
+is used as-is.
+.PP
+If a connection attempt is successful, the
+.B dir
+member of the resulting
+.B Connection
+will be
+the path name of a
+.I line directory
+that has files for accessing the connection.
+One line directory exists for each possible connection.
+The
+.B data
+file in the line directory is opened to
+make a connection, and read and written to communicate with the destination.
+The
+.B ctl
+file in the line directory can be used to send commands to the line.
+See
+.IR ip (3)
+for messages that can be written to the
+.B ctl
+file.
+The last close of the
+.B data
+or
+.B ctl
+file will close the connection.
+The
+.B remote
+file in the line directory contains the address called; the file
+.B local
+contains the local address assigned.
+.PP
+The
+.B dial
+routine
+makes a call to destination
+.I addr
+on a multiplexed network.
+If the connection server returns several addresses,
+.B dial
+tries each in turn, until a connection is made
+or no addresses remain to be tried.
+It returns a
+.B Connection
+containing a file descriptor
+.B dfd
+open for reading and writing the
+.B data
+file in the line directory,
+and a file descriptor
+.B cfd
+open for reading and writing the
+.B ctl
+file.
+If
+.IR local
+is non-empty, and
+the network allows the local address to be set,
+as is the case with UDP and TCP port numbers,
+the local address will be set to
+.IR local .
+.PP
+.B Announce
+and
+.B listen
+are the complements of
+.BR dial .
+.B Announce
+establishes a network name to which incoming calls can be made.
+In
+.IR addr ,
+.I netaddr
+gives the name or address of one of the local host's interfaces on which to listen for
+calls to the given
+.IR service ;
+it can be
+.B *
+to listen for calls on any interface on
+.IR network .
+.B Announce
+returns a
+.B Connection
+structure in which only the
+.B cfd
+descriptor is open, on the control file representing the announcement.
+.B Listen
+takes as its only argument the
+.B Connection
+structure of a successful call to
+.BR announce .
+When a call is received,
+.B listen
+returns an open
+.B Connection
+structure as if from
+.BR dial ,
+except that only the
+.B cfd
+descriptor is open,
+.B dfd
+is nil,
+and the caller must open the data file for itself.
+.SH EXAMPLES
+.PP
+Make a call and return an open file descriptor to
+use for communications:
+.IP
+.EX
+callkremvax(): (int, Connection)
+{
+ return sys->dial("tcp!kremvax!80", nil);
+}
+.EE
+.PP
+Call the local certificate signer:
+.IP
+.EX
+dialsigner(service: string): (int, Connection)
+{
+ return sys->dial("net!$SIGNER!inflogin", nil);
+}
+.EE
+.SH SOURCE
+.B /emu/port/inferno.c
+.br
+.B /emu/port/dial.c
+.br
+.B /os/port/inferno.c
+.br
+.B /os/port/dial.c
+.SH DIAGNOSTICS
+The integer valued functions return 0 on success and -1 on error;
+the system error string is set.
+The integer component of the tuple returned by the other functions
+follows the same convention.
+.SH BUGS
+Note that
+.B listen
+does not open the
+.B data
+file.
diff --git a/man/2/sys-dirread b/man/2/sys-dirread
new file mode 100644
index 00000000..1599d58b
--- /dev/null
+++ b/man/2/sys-dirread
@@ -0,0 +1,59 @@
+.TH SYS-DIRREAD 2
+.SH NAME
+dirread \- read directory
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+dirread: fn(fd: ref FD): (int, array of Dir);
+.EE
+.SH DESCRIPTION
+.B Dirread
+reads the contents of the directory pointed to by the open file descriptor
+.IR fd ,
+returning a tuple containing an array
+with one
+.B Dir
+structure for each directory entry read.
+These
+.B Dir
+structures are equivalent to the result of a
+.B stat
+call on each file in the directory.
+See
+.IR sys-stat (2)
+for a description of
+.B stat
+and
+.BR Dir .
+.PP
+A successful
+.B dirread
+returns a tuple giving the number of entries read and the resulting array.
+A return of (0,nil) indicates the end of the directory.
+Directory entries are variable length in general;
+the file offset is advanced by the number of bytes actually read.
+.PP
+Seeks (see
+.IR sys-seek (2))
+are allowed on directories only to seek to the start.
+.PP
+In general, several calls to
+.B dirread
+will be needed to read the whole directory.
+.I Readdir (2)
+provides functions that return all the directory entries at once,
+optionally sorted.
+.SH SEE ALSO
+.IR readdir (2),
+.IR sys-intro (2),
+.IR sys-open (2),
+.IR sys-read (2),
+.IR sys-seek (2),
+.IR sys-stat (2)
+.SH DIAGNOSTICS
+The integer in
+.BR dirread 's
+return tuple has a value of -1 on error, and 0 on end of file.
+The array element of the tuple is nil in both cases.
diff --git a/man/2/sys-dup b/man/2/sys-dup
new file mode 100644
index 00000000..7b96b47a
--- /dev/null
+++ b/man/2/sys-dup
@@ -0,0 +1,62 @@
+.TH SYS-DUP 2
+.SH NAME
+dup, fildes \- duplicate an open file descriptor
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+dup: fn(oldfd, newfd: int): int;
+fildes: fn(fd: int): ref FD;
+.EE
+.fi
+.SH DESCRIPTION
+The Limbo programming language and its libraries
+manage I/O via references to instances of abstract data type,
+.BR FD ,
+called a
+.IR "Limbo file descriptor",
+or simply `file descriptor' when the context is understood.
+.B FD
+holds an integer-valued file descriptor, the form used
+by the operating system, in a structure that can be reference counted
+and garbage collected.
+There are occasions when a program must access the underlying
+integer file descriptor, such as when rearranging the standard input
+and output for a new subprocess.
+.PP
+The
+.B dup
+call takes a valid integer file descriptor,
+.IR oldfd ,
+referring to an open file,
+and
+returns a new integer file descriptor referring to the same file.
+If
+.I newfd
+is in the range of legal file descriptors,
+.B dup
+will use that for the new file descriptor
+(closing any old file associated with
+.IR newfd );
+if
+.I newfd
+is \-1 the system chooses the lowest available file descriptor.
+If a suitable file descriptor cannot be found,
+.B dup
+returns \-1.
+.PP
+.B Fildes
+uses the integer file descriptor
+.B fd
+to create a new Limbo
+file descriptor, suitable for other
+.B Sys
+module functions.
+It returns
+.B nil
+if it cannot convert
+.IR fd .
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-open (2)
diff --git a/man/2/sys-export b/man/2/sys-export
new file mode 100644
index 00000000..00ca7cf3
--- /dev/null
+++ b/man/2/sys-export
@@ -0,0 +1,116 @@
+.TH SYS-EXPORT 2
+.SH NAME
+export \- export a name space
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+export: fn(fd: ref FD, dir: string, flag: int): int;
+.EE
+.SH DESCRIPTION
+.B Export
+receives and replies
+to Styx requests from a client on a connection represented by
+.IR fd ,
+for file operations on the part of the current file name space
+rooted at
+.IR dir ,
+which is thus exported.
+This is the server end of the client's
+.B mount
+call.
+Names presented by the client are interpreted relative to directory
+.IR dir ,
+which can be adjusted using
+.IR sys-pctl (2)
+and
+.IR sys-bind (2)
+before export.
+The file descriptor
+.I fd
+must be open for reading and writing, and neither mounted elsewhere nor already exported.
+.PP
+Commonly,
+.BR export 's
+first argument is a file descriptor open on the data file in the
+.B dir
+of a
+.B Connection
+returned by
+.B listen
+(see
+.IR sys-dial (2)).
+Before calling
+.BR export ,
+the connection on
+.I fd
+can optionally be authenticated and set for encryption or digesting using the
+functions in
+.IR security-auth (2).
+.PP
+The
+.B export
+function takes two mutually exclusive flags:
+.TP
+.B Sys->EXPWAIT
+.B Export
+blocks until all client requests are complete.
+.TP
+.B Sys->EXPASYNC
+Client requests are handled by a background (kernel) process.
+.B Export
+returns immediately.
+The serving process terminates when the client hangs up.
+.SH EXAMPLES
+.PP
+Export a given directory on
+.BR fd ,
+protecting it from subsequent changes:
+.IP
+.EX
+exportdir(fd: ref Sys->FD, dir: string, pid: chan of int)
+{
+ pid <-= sys->pctl(Sys->FORKNS|Sys->FORKENV|Sys->NEWFD, fd.fd :: nil);
+ sys->export(fd, dir, Sys->EXPWAIT);
+}
+.EE
+.PP
+The
+.B FORKNS
+given to
+.B pctl
+forks the name space, and
+prevents the
+.B sys->export
+from seeing the effects of subsequent mounts by the process
+that calls or spawns
+.BR exportdir .
+The
+.B exportdir
+function above might be called using:
+.IP
+.EX
+pid := chan of int;
+spawn export(fd, "/", pid);
+expid := <-pid;
+.EE
+.PP
+Service will stop automatically when the connection
+.B fd
+returns end-of-file (eg, when it hangs up),
+but it can also be stopped locally by killing
+.BR expid .
+.EE
+.SH SOURCE
+.B /emu/port/inferno.c
+.br
+.B /emu/port/exportfs.c
+.br
+.B /os/port/inferno.c
+.br
+.B /os/port/exportfs.c
+.SH DIAGNOSTICS
+.B Export
+returns a non-negative value on success and -1 on error;
+the system error string is set.
diff --git a/man/2/sys-fauth b/man/2/sys-fauth
new file mode 100644
index 00000000..8e06d6ac
--- /dev/null
+++ b/man/2/sys-fauth
@@ -0,0 +1,61 @@
+.TH SYS-FAUTH 2
+.SH NAME
+fauth \- set up authentication on a file descriptor to a file server
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+fauth: fn(fd: ref FD, aname: string): ref FD;
+.EE
+.SH DESCRIPTION
+.B Fauth
+provides a means for the current user to authenticate to access
+resources available through the Styx connection represented by
+.IR fd .
+The return value is a file descriptor, conventionally called
+.IR afd ,
+that is subsequently used to execute the authentication protocol
+for the server.
+After successful authentication,
+.I afd
+may be passed as the second argument to a subsequent
+.B mount
+call (see
+.IR sys-bind (2)),
+with the same
+.IR aname,
+as a ticket-of-entry for the user.
+.PP
+If
+.B fauth
+returns nil, the error case, that means the file server does not require
+authentication for the connection, and
+.I afd
+should be nil
+in the call to
+.BR mount.
+.ig
+.PP
+It is rare to use
+.IR fauth
+directly; more commonly
+.I amount
+(see
+.IR auth (2))
+is used.
+..
+.SH SEE ALSO
+.IR attach (5),
+.IR security-auth (2)
+.ig
+(particularly
+.BR amount ),
+.IR authsrv (6)
+..
+.SH DIAGNOSTICS
+The system error string is set on error,
+including the server not requiring authentication,
+and
+.B fauth
+returns nil.
diff --git a/man/2/sys-fd2path b/man/2/sys-fd2path
new file mode 100644
index 00000000..4890e0fb
--- /dev/null
+++ b/man/2/sys-fd2path
@@ -0,0 +1,46 @@
+.TH FD2PATH 2
+.SH NAME
+fd2path \- return file name associated with file descriptor
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+fd2path(fd: ref FD): string;
+.EE
+.SH DESCRIPTION
+As described in
+.IR intro (2),
+the kernel stores a rooted path name with every open file or directory;
+typically, it is the name used in the original access of the file.
+.B Fd2path
+returns the path name associated with open file descriptor
+.IR fd .
+(It returns nil if an error occurs.)
+.PP
+Changes to the underlying name space do not update the path name
+stored with the file descriptor.
+Therefore,
+the path returned by
+.B fd2path
+may no longer refer to the same file (or indeed any file)
+after some component directory or file in the path has been removed, renamed
+or rebound.
+.PP
+As an example,
+.IR workdir (2)
+is implemented by opening
+.B .
+and executing
+.B fd2path
+on the resulting file descriptor.
+.SH SEE ALSO
+.IR bind (1),
+.IR ns (1),
+.IR sys-bind (2),
+.IR sys-intro (2),
+.IR workdir (2),
+.IR prog (3)
+.SH DIAGNOSTICS
+.B Fd2path
+returns nil on error and sets the system error string.
diff --git a/man/2/sys-file2chan b/man/2/sys-file2chan
new file mode 100644
index 00000000..dc4088b0
--- /dev/null
+++ b/man/2/sys-file2chan
@@ -0,0 +1,158 @@
+.TH SYS-FILE2CHAN 2
+.SH NAME
+file2chan \- create file connected to Limbo channel
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+Rread: type chan of (array of byte, string);
+Rwrite: type chan of (int, string);
+FileIO: adt
+{
+ read: chan of (int, int, int, Rread);
+ write: chan of (int, array of byte, int, Rwrite);
+};
+
+file2chan: fn(dir, file: string): ref FileIO;
+.EE
+.fi
+.SH DESCRIPTION
+.B File2chan
+presents an interface for binding Limbo channels to files in the file name space.
+A
+.I server
+program calls
+.B file2chan
+to create a
+.I file
+in a directory
+.IR dir ,
+which must be a directory on which device
+.RB ` #s '
+has been bound
+(see
+.IR srv (3)).
+A
+.I client
+program can open the file for reading or writing (see
+.IR sys-open (2)
+and
+.IR sys-read (2))
+to communicate with the server.
+.PP
+.B File2chan
+returns a
+.B FileIO
+type holding two channels used to deliver tuples representing
+the contents of the
+.B Tread
+and
+.B Twrite
+Styx messages received by the system on the server's behalf; see
+.IR intro (5).
+.PP
+When the client invokes the
+.B read
+system call on the file, the server
+receives a tuple, say
+.BI ( offset\fP,\fP\ count\fP,\fP\ fid\fP,\fP\ rc )\f1,
+on the
+.B read
+channel.
+The request asks for
+.I count
+bytes of data, starting at
+.I offset
+bytes from the beginning of the file
+associated with
+.IR fid .
+The server sends its reply to the client by transmitting a tuple, say
+.BI ( data\fP,\fP\ error )\f1,
+that contains the
+.I data
+for the
+.BR read ,
+on the channel
+.I rc
+received as part of the
+.B read
+tuple.
+If the request was successful, the
+.I error
+string should be
+.BR nil .
+If an error occurred,
+.I error
+should be a diagnostic string,
+and the
+.I data
+array should be
+.BR nil .
+The client blocks in the
+.B read
+system call until the server sends its reply.
+The client receives only
+.I count
+bytes even if
+.I data
+is larger.
+.PP
+When the client does a
+.B write
+system call on the file,
+the server receives a tuple,
+.BI ( offset\fP,\fP\ data\fP,\fP\ fid\fP,\fP\ wc )\f1,
+on the
+.B write
+channel.
+A
+.BI ( count\fP,\fP\ error )
+response is sent back on the
+.I wc
+channel received in the
+.B write
+tuple:
+.I count
+gives the number of bytes written (zero if an error occurs), and
+.I error
+is an empty or
+.B nil
+string or an explanation of the problem.
+.PP
+If the client closes the file for reading (writing), the server will receive a
+.B read
+.RB ( write )
+message with a
+.B nil
+.I rc
+.BI ( wc )\f1.
+The server can use these signals to determine when to stop processing.
+The
+.I fid
+received by the server can be used to manage the multiplexing of multiple
+active clients sharing a single file; see
+.IR intro (5)
+for details.
+.SH SOURCE
+.B /emu/port/devsrv.c
+.br
+.B /os/port/devsrv.c
+.SH SEE ALSO
+.IR sh-file2chan (1),
+.IR sys-intro (2),
+.IR sys-open (2),
+.IR sys-read (2),
+.IR sys-bind (2),
+.IR intro (5)
+.SH BUGS
+.B Read
+and
+.B write
+system calls for the file will not return until the
+server sends its reply on the appropriate channel,
+so the process doing the
+.B read
+or
+.B write
+cannot be the one serving.
diff --git a/man/2/sys-fversion b/man/2/sys-fversion
new file mode 100644
index 00000000..200a4f04
--- /dev/null
+++ b/man/2/sys-fversion
@@ -0,0 +1,71 @@
+.TH SYS-FVERSION 2
+.SH NAME
+fversion \- initialize Styx connection and negotiate version
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+fversion: fn(fd: ref FD, bufsize: int, version: string): (int, string);
+.EE
+.SH DESCRIPTION
+.B Fversion
+initialises the Styx connection represented by
+.I fd
+and negotiates the maximum message size and the version of the protocol to be used.
+.PP
+The
+.I bufsize
+determines the size of the I/O buffer used to stage Styx requests to the server,
+subject to the constraints of the server itself.
+The
+.I version
+is a text string that represents the highest version level the protocol will support.
+.PP
+.B Fversion
+returns a tuple
+.RI ( n , useversion )
+where
+.I n
+is -1 if the request was rejected, and otherwise
+.I n
+is
+.I bufsize
+and
+.I useversion
+is a string representing the negotiated, possibly lower, version of the protocol.
+.PP
+Default values of zero for
+.I bufsize
+and the empty string for
+.I version
+will negotiate sensible defaults for the connection.
+.PP
+The interpretation of the version strings is defined in
+.IR version (5).
+.PP
+It is rare to use
+.BR fversion
+directly; usually the default negotiation performed
+by the kernel during
+.B mount
+(see
+.IR sys-bind (2))
+is sufficient.
+.SH SEE ALSO
+.IR sys-fauth (2),
+.IR intro (5),
+.IR version (5).
+.SH DIAGNOSTICS
+.B Fversion
+returns a value of -1 for
+.I n
+on error, including failure to negotiate acceptable values,
+and sets the system error string.
+.SH BUGS
+The returned value of
+.I n
+when no error occurs should be the negotiated message size
+but is currently the original
+.I bufsize
+parameter.
diff --git a/man/2/sys-iounit b/man/2/sys-iounit
new file mode 100644
index 00000000..0f8ef118
--- /dev/null
+++ b/man/2/sys-iounit
@@ -0,0 +1,35 @@
+.TH SYS-IOUNIT 2
+.SH NAME
+iounit \- return size of atomic I/O unit for file descriptor
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+iounit: fn(fd: ref FD): int;
+.EE
+.SH DESCRIPTION
+Reads and writes of files are transmitted using the Styx protocol (see
+.IR intro (5))
+and in general, operations involving large amounts of data must be
+broken into smaller pieces by the operating system.
+The `I/O unit' associated with each file descriptor records the maximum
+size, in bytes, that may be read or written without breaking up the transfer.
+.PP
+The
+.B iounit
+system call returns the I/O unit size for the open file
+.IR fd .
+Certain file descriptors, particularly those associated with devices, may
+have no specific I/O unit, in which case
+.B iounit
+will return zero.
+.SH SOURCE
+.B /emu/port/inferno.c
+.br
+.B /os/port/inferno.c
+.SH SEE ALSO
+.IR sys-dup (2),
+.IR read (5)
+.SH DIAGNOSTICS
+Returns zero if any error occurs or if the I/O unit size of the fd is unspecified or unknown.
diff --git a/man/2/sys-millisec b/man/2/sys-millisec
new file mode 100644
index 00000000..d8e7d0bb
--- /dev/null
+++ b/man/2/sys-millisec
@@ -0,0 +1,24 @@
+.TH SYS-MILLISEC 2
+.SH NAME
+millisec \- millisecond timer
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+millisec: fn(): int;
+.EE
+.SH DESCRIPTION
+.B Millisec
+returns the value of an internal system clock, in milliseconds.
+The actual resolution of the clock is a property of the underlying
+system and may be coarser than a millisecond.
+The epoch is arbitrary, so
+.B millisec
+is useful for measuring durations but not absolute time.
+If the system operates continuously, the millisecond counter overflows
+every few months;
+a reboot resets the epoch.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-sleep (2)
diff --git a/man/2/sys-open b/man/2/sys-open
new file mode 100644
index 00000000..5795ce32
--- /dev/null
+++ b/man/2/sys-open
@@ -0,0 +1,135 @@
+.TH SYS-OPEN 2
+.SH NAME
+open, create \- open a file for reading or writing, create file
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+create: fn(file: string, omode, perm: int): ref FD;
+open: fn(file: string, omode: int): ref FD;
+.EE
+.SH DESCRIPTION
+.B Open
+opens the
+.I file
+for I/O and returns an associated file descriptor.
+.I Omode
+is one of
+.BR Sys->OREAD ,
+.BR Sys->OWRITE ,
+or
+.BR Sys->ORDWR ,
+asking for permission to read, write, or read and write, respectively.
+There are two values that can be OR'd with those to form
+.IR omode :
+.B Sys->OTRUNC
+says to truncate the file before opening it, which requires write permission
+even if
+.I omode
+is
+.BR Sys->OREAD ;
+and
+.B Sys->ORCLOSE
+says to remove the file when it is closed (ie, when the last reference
+to this file descriptor goes away).
+.PP
+.B Open
+returns
+.B nil
+if the file does not exist, if the file name is unacceptable, if the user does not have
+permission to open it as requested
+(see
+.IR sys-stat (2)
+for a description of permissions),
+or if any other error occurs.
+.PP
+.B Create
+creates a new
+.I file
+or prepares to rewrite an existing
+.IR file ,
+opens it according to
+.I omode
+(as described for
+.BR open ),
+and returns an associated file descriptor.
+.PP
+If the file is new,
+the owner is set to the
+.I "user id
+of the creating process group,
+the group to that of the containing directory,
+and the permissions to
+.I perm
+ANDed with the permissions of the containing directory.
+The bits in
+.I perm
+are the same as those
+in the file mode returned by
+.IR sys-stat (2).
+.PP
+If the file already exists,
+it is truncated to 0 length,
+but the permissions, owner, and group remain unchanged.
+.PP
+The created file will be a directory if the
+.B Sys->DMDIR
+bit is set in
+.IR perm ,
+and
+.I omode
+is
+.BR Sys->OREAD .
+The file will be exclusive-use if the
+.B Sys->DMEXCL
+bit is set in
+.I perm
+and the underlying file server supports it;
+see
+.IR open (5)
+for details.
+It will be append-only if the
+.B Sys->DMAPPEND
+bit is set, and the underlying file server supports it.
+.PP
+.B Create
+returns
+.B nil
+if the path up to the last element of
+.I file
+cannot be evaluated, if the file name is unacceptable,
+if the user does not have write permission in the final directory,
+if the file already exists and does not permit the access defined by
+.IR omode,
+or if any other error occurs.
+.PP
+If the file is new and the directory in which it is created is
+a union directory (see
+.IR sys-intro (2))
+then the constituent directory where the file is created
+depends on the structure of the union: see
+.IR sys-bind (2).
+.PP
+Since create may succeed even if the file exists, a special mechanism
+is necessary for applications that require an atomic create operation.
+If the
+.B Sys->OEXCL
+bit is set in the mode for a create, the call succeeds only if
+the file does not already exist; see
+.IR open (5)
+for details.
+.PP
+There is no explicit ``close'' routine:
+when the last reference to the file descriptor is released,
+the system closes the associated file.
+For devices and network protocols where shutdown must be guaranteed,
+write a
+.B hangup
+message to the associated control file and use the return value of the
+.B write
+to verify closure.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-bind (2),
+.IR sys-stat (2)
diff --git a/man/2/sys-pctl b/man/2/sys-pctl
new file mode 100644
index 00000000..1df73829
--- /dev/null
+++ b/man/2/sys-pctl
@@ -0,0 +1,142 @@
+.TH SYS-PCTL 2
+.SH NAME
+pctl \- process control
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+pctl: fn(flags: int, movefd: list of int): int;
+.EE
+.SH DESCRIPTION
+A newly spawned Limbo process (also known as a thread)
+shares with its parent process a number of resources and properties,
+such as file name space, open file descriptors, current working directory,
+and so on.
+.B Pctl
+controls this sharing, allowing a process to gain a copy of a resource
+rather than to share it, to start with a null resource, and so on.
+.PP
+The set of processes sharing a property are called a group;
+for example the set of processes sharing a name space are called a name space group.
+Each process is a member of a
+.IR "process group" ,
+typically the set of threads functioning as a single program.
+All the members of a process group
+may be terminated at once using the
+.B killgrp
+control message in the
+.IR prog (3)
+device.
+.PP
+A call to
+.B pctl
+affects the calling process and, indirectly according to
+.IR flags ,
+any other processes sharing properties with it.
+The
+.I flags
+to
+.B pctl
+are:
+.TF FORKENV
+.PD
+.TP
+.B NEWFD
+Give the process a new file descriptor group.
+All file descriptors are closed except those listed in
+.IR movefd ,
+which are preserved in the new group.
+After this call, changes the process makes to its set of open file descriptors
+will not be visible to other processes.
+.TP
+.B FORKFD
+Place the process in a new file descriptor group
+containing a copy
+of the current set of file descriptors.
+The file descriptors listed in
+.I movefd
+are closed in the
+.I old
+group.
+After this call, changes the process makes to its set of open file descriptors
+will not be visible to other processes.
+.TP
+.B NEWNS
+Place the process in a new file name space group in which the current directory
+is made the root directory,
+.LR / ,
+of the new name space.
+The current directory is unaffected by this call.
+.TP
+.B FORKNS
+Place the process in a new file name space group
+containing a copy
+of the current name space.
+After this call, changes the process makes to its name space, including
+.B chdir
+calls,
+will not affect other processes.
+.TP
+.B NODEVS
+Set the current file name space group to prevent subsequent access to
+the roots of file trees implemented by a device driver (ie, the use of path
+names beginning with
+.BR # ,
+as described by
+.IR intro (3)).
+Even after
+.B NODEVS
+the following devices can be attached, which are either
+private or can be separately controlled:
+.IR pipe (3) ,
+.IR env (3),
+.IR srv (3)
+and
+.IR ssl (3).
+.TP
+.B NEWENV
+Place the process in a new empty environment group containing
+no environment variables.
+After this call, changes the process makes to its environment will
+not affect other processes.
+.TP
+.B FORKENV
+Place the process in a new environment group containing
+a copy of the current environment variables.
+After this call, changes the process makes to its environment will
+not affect other processes.
+.TP
+.B NEWPGRP
+Establish a new process group with a group id equal to that of the pid
+of the calling process.
+.PP
+The Inferno shell
+.IR sh (1)
+uses
+.B FORKFD
+when starting a command;
+its
+.I pctl
+built-in (see
+.IR sh-std (1))
+can invoke the other effects when needed.
+The window manager
+.IR wm (1)
+uses
+.B NEWPGRP|FORKFD
+when starting a window manager application.
+.IR Srv (8)
+uses
+.B NEWGRP|FORKNS|FORKFD
+to insulate itself completely from services it starts.
+.PP
+The return value of
+.B pctl
+is the numerical process id of the calling process, which can be used for example to
+access its
+.IR prog (3)
+files.
+.SH SEE ALSO
+.IR sh-std (1),
+.IR sys-intro (2)
diff --git a/man/2/sys-pipe b/man/2/sys-pipe
new file mode 100644
index 00000000..6fb3a25e
--- /dev/null
+++ b/man/2/sys-pipe
@@ -0,0 +1,45 @@
+.TH SYS-PIPE 2
+.SH NAME
+pipe \- create an interprocess channel
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+pipe: fn(fds: array of ref FD): int;
+.EE
+.SH DESCRIPTION
+.B Pipe
+creates a buffered channel for interprocess I/O via file descriptors.
+It allocates a pipe from the pipe device and returns in the array
+.B fds
+file descriptors for the two pipe ends. Both returned file descriptors are opened for both reading and writing
+.RB ( Sys->ORDWR ).
+Data written on one file descriptor can be read from the other.
+The details of flow control and buffering are given in
+.IR pipe (3).
+When no references remain to the file descriptor representing
+one end of a pipe, and all remaining data has been read at the other end,
+subsequent reads at that end will return 0 bytes.
+Writes to a pipe with no reader produce an exception.
+.PP
+The array
+.B fds
+passed to the system call must have a length of at least 2;
+only entries 0 and 1 are updated.
+.PP
+Limbo applications typically use typed Limbo channels, not pipes, for efficient
+communication by cooperating processes.
+Pipes are still useful, however,
+to connect applications that do not (or cannot) share such channels,
+or when a system interface requires a file descriptor.
+For instance, a process that serves the Styx protocol can
+pass the file descriptor for one end of a pipe to
+.B Sys->mount
+(see
+.IR sys-bind (2)),
+and read and write Styx messages on the other end of the pipe.
+.SH DIAGNOSTICS
+Returns 0 on success; -1 on failure.
+.SH "SEE ALSO"
+.IR pipe (3)
diff --git a/man/2/sys-print b/man/2/sys-print
new file mode 100644
index 00000000..c499ad43
--- /dev/null
+++ b/man/2/sys-print
@@ -0,0 +1,271 @@
+.TH SYS-PRINT 2
+.SH NAME
+print, fprint, sprint \- print formatted output
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+fprint: fn(fd: ref FD, format: string, *): int;
+print: fn(format: string, *): int;
+sprint: fn(format: string, *): string;
+.EE
+.SH DESCRIPTION
+These functions format and print their arguments as
+.SM UTF
+text.
+.B Print
+writes text to the standard output.
+.B Fprint
+writes to the named output
+file descriptor.
+.B Sprint
+places text
+in a string, which it returns.
+.B Print
+and
+.B fprint
+return the number of bytes transmitted
+or
+a negative value if an error was encountered when writing the output.
+.PP
+Each of these functions
+converts, formats, and prints its
+trailing arguments
+under control of a
+.IR format
+string.
+The
+format
+contains two types of objects:
+plain characters, which are simply copied to the
+output stream,
+and conversion specifications,
+each of which results in fetching of
+zero or more
+arguments.
+The Limbo compiler recognizes calls to these functions
+and checks that the arguments match the format specifications in number and type.
+.PP
+Each conversion specification has the following format:
+.IP
+.BI "%" " \fR[\fPflags\fR]\fP verb"
+.PP
+The verb is a single character and each flag is a single character or a
+(decimal) numeric string.
+Up to two numeric strings may be used;
+the first is called
+.IR f1 ,
+the second
+.IR f2 .
+They can be separated by
+.RB ` . ',
+and if one is present, then
+.I f1
+and
+.I f2
+are taken to be zero if missing, otherwise they are considered `omitted'.
+Either or both of the numbers may be replaced with the character
+.BR * ,
+meaning that the actual number will be obtained from the argument list
+as an integer.
+The flags and numbers are arguments to
+the
+.I verb
+described below.
+.PP
+.TP
+.BR d ", " o ", " x ", " X
+The numeric verbs
+.BR d ,
+.BR o ,
+and
+.B x
+format their
+.B int
+arguments in decimal, octal, and hexadecimal (with hex digits in lower-case).
+The flag
+.B b
+is required when the corresponding value is a Limbo
+.BR big ,
+not an
+.BR int .
+Arguments are taken to be signed, unless the
+.B u
+flag is given, to force them to be treated as unsigned.
+Each interprets the flags
+.B \- ,
+.B , ,
+and
+.B #
+to mean left justified, commas every three digits, and alternative format.
+If
+.I f2
+is not omitted, the number is padded on the left with zeros
+until at least
+.I f2
+digits appear.
+Then, if alternative format is specified
+for
+.B x
+conversion, the number is preceded by
+.BR 0x .
+Finally, if
+.I f1
+is not omitted, the number is padded on the left (or right, if
+left justification is specified) with enough blanks to
+make the field at least
+.I f1
+characters long.
+The verb
+.B X
+is similar to
+.BR x ,
+except that the hexadecimal digits are displayed in upper-case,
+and in alternative format, the number is preceded by
+.BR 0X .
+.PP
+.TP
+.BR e ", " f ", " g
+The floating point verbs
+.BR e ,
+.BR f ,
+and
+.BR g
+take a
+.B real
+argument.
+Each interprets the flags
+.BR + ,
+.BR \- ,
+and
+.B #
+to mean
+always print a sign,
+left justified,
+and
+alternative format.
+.I F1
+is the minimum field width and,
+if the converted value takes up less than
+.I f1
+characters, it is padded on the left (or right, if `left justified')
+with spaces.
+.I F2
+is the number of digits that are converted after the decimal place for
+.BR e
+and
+.B f
+conversions,
+and
+.I f2
+is the maximum number of significant digits for
+.B g
+conversions.
+The
+.B f
+verb produces output of the form
+.RB [ \- ]\c
+.IR digits [\c
+.BI \&. digits\fR].
+The
+.B e
+conversion appends an exponent
+.BR e [ \- ]\c
+.IR digits .
+The
+.B g
+verb will output the argument in either
+.B e
+or
+.B f
+with the goal of producing the smallest output.
+Also, trailing zeros are omitted from the fraction part of
+the output, and a trailing decimal point appears only if it is followed
+by a digit.
+When alternative format is specified, the result will always contain a decimal point,
+and for
+.B g
+conversions, trailing zeros are not removed.
+.TP
+.BR E ", " G
+These are the same as
+.B e
+and
+.B g
+respectively, but use
+.B E
+not
+.B e
+to specify an exponent when one appears.
+.TP
+.B c
+The
+.B c
+verb converts a single Unicode character
+from an
+.B int
+argument to a UTF encoding,
+justified within a field of
+.I f1
+characters as described above.
+.TP
+.B r
+The
+.B r
+verb takes no arguments; it prints the error string
+associated with the most recent system error.
+.TP
+.B s
+The
+.B s
+verb copies a
+.B string
+to the output.
+The number of characters copied
+.RI ( n )
+is the minimum
+of the size of the string and
+.IR f2 .
+These
+.I n
+characters are justified within a field of
+.I f1
+characters as described above.
+.TP
+.B q
+The
+.B q
+verb copies a
+.B string
+to the output as for
+.BR s ,
+but quotes the string in the style of
+.IR sh (1)
+only if necessary to avoid ambiguity (for instance
+if the string contains quotes or spaces).
+If the format string, however, includes the specifier
+.B #
+(for example
+.BR %#q ),
+the printed string will always be quoted.
+.SH SOURCE
+.B /libinterp/runt.c:/^xprint
+.br
+.B /os/port/print.c
+.br
+.B /lib9/print.c
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-open (2)
+.SH BUGS
+The
+.B x
+verb does not apply the
+.B 0x
+prefix when
+.I f2
+is present.
+The prefix should probably be
+.B 16r
+anyway.
diff --git a/man/2/sys-read b/man/2/sys-read
new file mode 100644
index 00000000..38df696d
--- /dev/null
+++ b/man/2/sys-read
@@ -0,0 +1,94 @@
+.TH SYS-READ 2
+.SH NAME
+read, write, pread, pwrite, stream \- read or write file
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+read: fn(fd: ref FD, buf: array of byte, nbytes: int): int;
+write: fn(fd: ref FD, buf: array of byte, nbytes: int): int;
+
+pread: fn(fd: ref FD, buf: array of byte, nbytes: int,
+ offset: big): int;
+pwrite: fn(fd: ref FD, buf: array of byte, nbytes: int,
+ offset: big): int;
+
+stream: fn(src, dst: ref FD, bufsiz: int): int;
+.EE
+.SH DESCRIPTION
+.B Read
+reads
+.I nbytes
+bytes of data from the offset in the file
+associated with
+.I fd
+into memory at
+.IR buf .
+The file offset is advanced by the number of bytes read.
+It is not guaranteed
+that all
+.I nbytes
+bytes will be read; for example
+if the file refers to the console, at most one line
+will be returned.
+In any event the number of bytes read is returned.
+A return value of
+0 is conventionally interpreted as end of file.
+.PP
+.B Write
+writes
+.I nbytes
+bytes of data starting at
+.I buf
+to the file associated with
+.I fd
+at the file offset.
+The offset is advanced by the number of bytes written.
+The number of bytes actually written is returned.
+It should be regarded as an error
+if this is not the same as requested.
+.PP
+.B Pread
+and
+.B pwrite
+take an explicit file
+.I offset
+as a parameter, leaving
+.IR fd 's
+current offset untouched;
+they are otherwise identical in behaviour to
+.B read
+and
+.BR write .
+They are particulary useful when several processes must access the same
+.I fd
+concurrently and it is inconvenient or undesirable to synchronise their activity
+to avoid interference.
+.PP
+.B Stream
+continually reads data from
+.IR src ,
+using a buffer of
+.I bufsiz
+bytes, and writes the data to
+.IR dst .
+It copies data
+until a read fails (returning
+zero bytes or an error) or a write fails.
+.B Stream
+returns the number of bytes actually copied.
+The implementation may be more efficient than a
+.BR read / write
+loop in the application, but is otherwise
+equivalent to calling
+.B read
+and
+.B write
+directly.
+.SH SEE ALSO
+.IR bufio (2),
+.IR sys-intro (2),
+.IR sys-dup (2),
+.IR sys-open (2),
+.IR read (5)
diff --git a/man/2/sys-remove b/man/2/sys-remove
new file mode 100644
index 00000000..083ec6b4
--- /dev/null
+++ b/man/2/sys-remove
@@ -0,0 +1,23 @@
+.TH SYS-REMOVE 2
+.SH NAME
+remove \- remove a file
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+remove: fn(file: string): int;
+.EE
+.SH DESCRIPTION
+.B Remove
+removes
+.I file
+from the directory containing it and discards the contents of the file.
+The user must have write permission in the containing directory.
+If
+.I file
+is a directory, it must be empty.
+.B Remove
+returns zero if it deletes the file, \-1 otherwise.
+.SH SEE ALSO
+.IR sys-intro (2)
diff --git a/man/2/sys-seek b/man/2/sys-seek
new file mode 100644
index 00000000..15124007
--- /dev/null
+++ b/man/2/sys-seek
@@ -0,0 +1,48 @@
+.TH SYS-SEEK 2
+.SH NAME
+seek \- change file offset
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+seek: fn(fd: ref FD, off: big, start: int): big;
+.EE
+.SH DESCRIPTION
+.B Seek
+sets the 64-bit offset for the file
+associated with
+.I fd
+as follows:
+.IP
+If
+.I start
+is
+.BR Sys->SEEKSTART ,
+the offset is set to
+.I off
+bytes.
+.IP
+If
+.I start
+is
+.BR Sys->SEEKRELA ,
+the pointer is set to its current location plus
+.IR off .
+.IP
+If
+.I start
+is
+.BR Sys->SEEKEND ,
+the pointer is set to the size of the
+file plus
+.IR off .
+.PP
+The new file offset value is returned.
+.PP
+Seeking in a pipe is not allowed.
+Seeking in a directory is allowed only if the new offset is zero.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-open (2),
+.IR bufio (2),
diff --git a/man/2/sys-self b/man/2/sys-self
new file mode 100644
index 00000000..777cca2e
--- /dev/null
+++ b/man/2/sys-self
@@ -0,0 +1,83 @@
+.TH SYS-SELF 2
+.SH NAME
+SELF \- reference self as a compatible module type
+.SH SYNOPSIS
+.B
+include "sys.m";
+.br
+.BI "me := load" " Module " SELF;
+.SH DESCRIPTION
+An instance of
+a module of one type can acquire a reference to itself as any compatible module type,
+using the Limbo
+.B load
+operator with the special built-in module name
+.BR $self .
+Normally, applications use a synonym, the constant
+.BR SELF ,
+which is defined by
+.B sys.m
+.I outside
+the declaration of the
+.B Sys
+module
+(so that it need not be imported).
+Note that the result of the
+.B load
+refers to the same instance
+that is currently executing (ie, the same module data).
+.PP
+This mechanism is most often used to obtain a reference to the current module
+instance with a
+.I restriction
+of its module type to a compatible subtype (eg, containing a subset
+of the current module's declarations).
+For example, given modules of the following types:
+.IP
+.EX
+T: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+ special: fn(a, b: int);
+};
+S: module
+{
+ special: fn(x, y: int);
+};
+G: module
+{
+ init: fn(v: S);
+};
+.EE
+.PP
+an instance of module
+.B T
+can execute both the following:
+.IP
+.EX
+t := load T SELF;
+s := load S SELF;
+.EE
+.PP
+but a module of type
+.B S
+could not load itself as type
+.BR T .
+.PP
+The result might typically be assigned to a module variable of that type
+(including passing as a parameter or storing in an adt), as in:
+.IP
+.EX
+g := load G "g.dis";
+g->init(s);
+.EE
+.PP
+See the definition and use of
+.B BufioFill
+in
+.IR bufio (2)
+and
+.IR bufio-chanfill (2)
+for a practical example.
+.SH SEE ALSO
+``The Limbo Programming Language'', Volume 2.
diff --git a/man/2/sys-sleep b/man/2/sys-sleep
new file mode 100644
index 00000000..d8b91a56
--- /dev/null
+++ b/man/2/sys-sleep
@@ -0,0 +1,29 @@
+.TH SYS-SLEEP 2
+.SH NAME
+sleep \- delay
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+sleep: fn(period: int): int;
+.EE
+.SH DESCRIPTION
+.B Sleep
+suspends the current thread for
+.I period
+milliseconds.
+The actual suspension time may be a little more or less than
+the requested time.
+If
+.I period
+is 0, the process
+gives up the CPU if another process is waiting to run, returning
+immediately if not.
+.PP
+.B Sleep
+normally returns 0. In hosted Inferno it may return -1 to indicate that
+it was not possible to sleep (eg if no more threads are available).
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-millisec (2)
diff --git a/man/2/sys-stat b/man/2/sys-stat
new file mode 100644
index 00000000..a5ca67da
--- /dev/null
+++ b/man/2/sys-stat
@@ -0,0 +1,283 @@
+.TH SYS-STAT 2
+.SH NAME
+fstat, fwstat, stat, wstat \- get and put file status
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+fstat: fn(fd: ref FD): (int, Dir);
+fwstat: fn(fd: ref FD; d: Dir): int;
+stat: fn(name: string): (int, Dir);
+wstat: fn(name: string, d: Dir): int;
+
+nulldir: con Dir(\fIspecial don't care values\fP);
+zerodir: con Dir(\fIall elements set to zero\fP);
+.EE
+.SH DESCRIPTION
+Given a file's
+.IR name ,
+or an open file descriptor
+.IR fd ,
+these routines retrieve or modify file status information.
+.B Stat
+and
+.B fstat
+retrieve information about
+.I name
+or
+.I fd
+into the
+.B Dir
+member of the return tuple.
+The
+.B int
+member will be zero for success and \-1 for failure.
+.B wstat
+and
+.B fwstat
+write information back, thus changing file attributes according to
+.IR d .
+Both functions return zero for success and \-1 for failure.
+.PP
+File status is recorded as a
+.B Dir
+type:
+.IP
+.PP
+.EX
+Qid: adt
+{
+ path: big; # unique id for file on server
+ vers: int; # write version number
+ qtype: int; # file type (see below)
+};
+
+Dir: adt
+{
+ name: string; # last element of path
+ uid: string; # owner name
+ gid: string; # group name
+ muid: string; # last modifier name
+ qid: Qid; # unique id from server
+ mode: int; # permissions
+ atime: int; # last read time
+ mtime: int; # last write time
+ length: big; # file length
+ dtype: int; # server type
+ dev: int; # server subtype
+};
+.EE
+.PP
+If the file resides on permanent storage and is not a directory,
+the
+.B length
+field returned in
+.B Dir
+by
+.B stat
+is the number of bytes in the file.
+For directories, the length returned is zero.
+Some devices, in particular files that are
+streams such as pipes and network connections,
+report a length that is the number of bytes that
+may be read from the device without blocking.
+.PP
+Each file is the responsibility of some
+.IR server :
+it could be a file server, a kernel device, or a user process.
+.B Dtype
+identifies the server type, and
+.B dev
+says which of a group of servers of the same type is the one
+responsible for this file.
+.B Qid
+is a type containing
+.BR path ,
+.B vers
+and
+.B qtype
+members, each an integer:
+.B path
+is guaranteed to be
+unique among all path names currently on the file server;
+.B vers
+changes each time the file is modified;
+and
+.B qtype
+gives the file's characteristics (eg, directory or file).
+The
+.B path
+is 64 bits
+.RB ( big ),
+and the
+.B vers
+is 32 bits
+.RB ( int ).
+Thus, if two files have the same
+.BR dtype ,
+.BR dev ,
+and
+.BR qid ,
+they are the same file.
+(Except when checking that the contents
+are the same, as in a file cache, the version is often considered irrelevant in that comparison.)
+The bits in
+.B qtype
+are defined by
+.IP
+.EX
+16r80 # directory (Sys->QTDIR)
+16r40 # append-only (Sys->QTAPPEND)
+16r20 # exclusive-use (Sys->QTEXCL)
+16r08 # authentication file (Sys->QTAUTH)
+16r00 # any other file (Sys->QTFILE)
+.EE
+.PP
+(They are the top 8 bits of
+.B Dir.mode
+for the file, as discussed below.)
+.B Sys
+defines constants for the bits:
+.BR Sys->QTDIR ,
+.BR Sys->QTAPPEND ,
+and so on, as shown above.
+The value
+.B Sys->QTFILE
+is not a particular bit; it is defined to be zero, to allow
+a symbolic name to be used when creating
+.B Qid
+values for ordinary files.
+.PP
+The bits in
+.B mode
+are defined by
+.IP
+.EX
+16r80000000 #directory (Sys->DMDIR)
+16r40000000 #append-only (Sys->DMAPPEND)
+16r20000000 #exclusive-use (Sys->DMEXCL)
+16r08000000 #authentication file (Sys->DMAUTH)
+ 8r400 #read permission by owner
+ 8r200 #write permission by owner
+ 8r100 #execute permission (search on directory) by owner
+ 8r070 #read, write, execute (search) by group
+ 8r007 #read, write, execute (search) by others
+.EE
+.PP
+There are constants defined in
+.B Sys
+for the first four bits:
+.BR Sys\->DMDIR ,
+.B Sys\->DMAPPEND
+and
+.B Sys\->DMEXCL
+for normal files, and
+.B Sys\->DMAUTH
+only for the special authentication file opened by
+.IR sys-fauth (2).
+.PP
+The two time fields are measured in seconds since the epoch
+(Jan 1 00:00 1970 GMT).
+.B Mtime
+is the time of the last change of content.
+Similarly,
+.B atime
+is set whenever the contents are accessed;
+also, it is set whenever
+.B mtime
+is set.
+.PP
+.B Uid
+and
+.B gid
+are the names of the owner and group (of owners) of the file;
+.B muid
+is the name of the user that last modified the file (setting
+.BR mtime ).
+Groups are also users, but each server is free to associate
+a list of users with any user name
+.IR g ,
+and that list is the
+set of users in the group
+.IR g .
+When an initial attachment is made to a server,
+the user string in the process group is communicated to the server.
+Thus, the server knows, for any given file access, whether the accessing
+process is the owner of, or in the group of, the file.
+This selects which sets of three bits in
+.B mode
+is used to check permissions.
+.PP
+Only some of the fields may be changed by
+.B wstat
+calls.
+The
+.B name
+can be changed by anyone with write permission in the parent directory.
+The
+.B mode
+and
+.B mtime
+can be changed by the owner or the group leader of the file's current
+group.
+The
+.B gid
+can be changed by the owner if he or she is a member of the new group.
+The
+.B gid
+can be changed by the group leader of the file's current group
+if he or she is the leader of the new group.
+The
+.B length
+can be changed by anyone with write permission, provided the operation
+is implemented by the server.
+(See
+.IR intro (5)
+and
+.IR stat (5)
+for more information about permissions, and
+.IR users (6)
+for how to configure users and groups
+when using
+.IR kfs (4)).
+.PP
+Special values in the fields of the
+.B Dir
+passed to
+.I wstat
+indicate that the field is not intended to be changed by the call.
+The values are the maximum unsigned integer of appropriate size
+for integral values (usually
+.BR ~0 ,
+but beware of conversions and size mismatches
+when comparing values) and the empty or nil string for string values.
+The constant
+.B nulldir
+in
+.B Sys
+has all its elements initialised to these ``don't care'' values.
+Thus one may change the mode, for example, by assigning
+.B sys->nulldir
+to initialize a
+.BR Dir ,
+then setting the mode, and then doing
+.IR wstat ;
+it is not necessary to use
+.I stat
+to retrieve the initial values first.
+.PP
+The constant
+.B zerodir
+has all its elements initialised to zero.
+It can be used to initialise a
+.B Dir
+structure, for use with
+.IR styx (2)
+or
+.IR styxservers-nametree (2),
+for instance.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-dirread (2),
+.IR sys-open (2)
diff --git a/man/2/sys-tokenize b/man/2/sys-tokenize
new file mode 100644
index 00000000..38c04598
--- /dev/null
+++ b/man/2/sys-tokenize
@@ -0,0 +1,56 @@
+.TH SYS-TOKENIZE 2
+.SH NAME
+tokenize \- split string into words
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+tokenize: fn(s, delim: string): (int, list of string);
+.EE
+.SH DESCRIPTION
+.B Tokenize
+breaks
+.I s
+into words separated by characters in
+.IR delim .
+The returned tuple holds the number of words
+and an ordered list of those words (whose
+.B hd
+gives the leftmost word from
+.IR s ).
+.PP
+Words are delimited by the maximal sequences of any
+character from the
+.I delim
+string.
+.B Tokenize
+skips delimiter characters at the beginning and end of
+.IR s ,
+so each element in the returned list has non-zero length.
+.PP
+If
+.I s
+is
+.B nil
+or contains no words,
+.B tokenize
+returns a count of zero and a
+.B nil
+list.
+.PP
+.I Delim
+may be
+.B nil
+or the empty string, specifying no delimiter characters.
+The resulting word list will be
+.B nil
+(if
+.I s
+is
+.B nil
+or the empty string)
+or a single-item list with a copy of
+.IR s .
+.SH SEE ALSO
+.IR sys-intro (2)
diff --git a/man/2/sys-utfbytes b/man/2/sys-utfbytes
new file mode 100644
index 00000000..2ad42489
--- /dev/null
+++ b/man/2/sys-utfbytes
@@ -0,0 +1,28 @@
+.TH SYS-UTFBYTES 2
+.SH NAME
+utfbytes \- compute UTF length of complete Unicode characters in a UTF byte sequence
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+utfbytes: fn(buf: array of byte, n: int): int;
+.EE
+.SH DESCRIPTION
+.B Utfbytes
+examines the
+.IR n -byte
+UTF sequence in
+.IR buf
+and returns the number of bytes representing complete Unicode characters.
+The value will be less than
+.I n
+when the region inspected ends with an incomplete UTF sequence.
+.SH DIAGNOSTIC
+A bounds check error results if
+.I n
+exceeds the length of the array.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-byte2char (2),
+.IR utf (6)
diff --git a/man/2/sys-werrstr b/man/2/sys-werrstr
new file mode 100644
index 00000000..add8206d
--- /dev/null
+++ b/man/2/sys-werrstr
@@ -0,0 +1,26 @@
+.TH SYS-WERRSTR 2
+.SH NAME
+werrstr \- set the system error string
+.SH SYNOPSIS
+.EX
+include "sys.m";
+sys := load Sys Sys->PATH;
+
+werrstr(s: string): int;
+.EE
+.SH DESCRIPTION
+When a system call fails, it returns an error value (often -1)
+and records a string describing the error in a per-process location.
+The verb
+.B r
+in
+.IR sys-print (2)
+outputs the error string.
+.B Werrstr
+sets the process's error string to
+.IR s ,
+to allow a function in a module to mimic the error reporting
+interface of a system call.
+.SH SEE ALSO
+.IR sys-intro (2),
+.IR sys-print (2)
diff --git a/man/2/tabs b/man/2/tabs
new file mode 100644
index 00000000..eae441de
--- /dev/null
+++ b/man/2/tabs
@@ -0,0 +1,74 @@
+.TH TABS 2
+.SH NAME
+tabs: mktabs, tabsctl \-
+tabbed notebook pseudo-widget
+.SH SYNOPSIS
+.EX
+include "tabs.m";
+tabs := load Tabs Tabs->PATH;
+
+init: fn();
+
+mktabs: fn(p: ref Tk->Toplevel, book: string,
+ tabs: array of (string, string), dflt: int):
+ chan of string;
+
+tabsctl: fn(p: ref Tk->Toplevel, book: string,
+ tabs: array of (string, string), curid: int,
+ newid: string): int;
+.EE
+.SH DESCRIPTION
+.B Tabs
+implements a Tk extension:
+a user-interface device that looks like a tabbed notebook.
+.PP
+.B Init
+should be called once to initialise the internal state.
+.PP
+.B Mktabs
+creates a tabbed notebook pseudo widget,
+.IR book ,
+for insertion into Tk
+widget
+.IR p .
+Once created,
+.I book
+can be packed like any other Tk widget.
+Information for specific tab pages is contained in the
+.I tabs
+array.
+For each page,
+.I tabs
+contains the name displayed in the tab and a Tk widget name.
+Whenever a page is selected, its widget is
+packed in
+.I book
+and displayed.
+The notebook will initially display the page
+indexed by
+.IR dflt .
+.B Mktabs
+returns a Tk event channel.
+Messages received on this channel should be passed as the
+.I newid
+argument to
+.BR tabsctl .
+.PP
+.B Tabsctl
+controls a tabbed notebook.
+.I Curid
+is the index of the page currently selected
+in the notebook.
+.I Newid
+is a string containing the index of the new
+page to be displayed; this is usually the information received on
+the tabs channel.
+The index of the newly selected page is returned.
+.SH SOURCE
+.B /appl/lib/tabs.b
+.SH SEE ALSO
+.IR dividers (2),
+.IR draw-context (2),
+.IR tk (2),
+.IR wmlib (2)
+
diff --git a/man/2/tftp b/man/2/tftp
new file mode 100644
index 00000000..d5a2a236
--- /dev/null
+++ b/man/2/tftp
@@ -0,0 +1,54 @@
+.TH TFTP 2
+.SH NAME
+tftp \- Trivial File Transfer Protocol
+.SH SYNOPSIS
+.EX
+tftp := load Tftp Tftp->PATH;
+Tftp: module
+{
+ init: fn(progress: int);
+ receive: fn(host: string, filename: string,
+ fd: ref Sys->FD): string;
+};
+.EE
+.SH DESCRIPTION
+.B Tftp
+fetches files from an Internet TFTP server.
+It is typically used only to fetch kernels or configuration files when booting.
+Only one transfer can be active at any given time.
+.PP
+.B Init
+must be called once before using any other function of the module.
+If
+.I progress
+is non-zero,
+.B receive
+will periodically print a character as blocks are received:
+.RB ` . '
+for every 25 blocks,
+.RB ` S '
+for a sequence error,
+.RB ` T '
+for a timeout.
+.PP
+.B Receive
+attempts to fetch the contents of
+.I filename
+from
+.I host
+and writes the blocks of data to
+.I fd
+as they are received.
+It returns when the file transfer has completed,
+returning a nil string on success or a diagnostic string otherwise.
+When booting,
+.I fd
+is typically open on the
+.B kexec
+file of
+.IR boot (3).
+.SH SOURCE
+.B /appl/lib/tftp.b
+.SH SEE ALSO
+.IR ip (2),
+.IR bootpd (8)
diff --git a/man/2/timers b/man/2/timers
new file mode 100644
index 00000000..4e1c8f52
--- /dev/null
+++ b/man/2/timers
@@ -0,0 +1,89 @@
+.TH TIMERS 2
+.SH NAME
+timers \- interval timers
+.SH SYNOPSIS
+.EX
+include "timers.m";
+timers := load Timers Timers->PATH;
+
+Timer: adt
+{
+ timeout: chan of int;
+ start: fn(msec: int): ref Timer;
+ stop: fn(t: self ref Timer);
+};
+
+init: fn(minms: int): int;
+shutdown: fn();
+.EE
+.SH DESCRIPTION
+.B Timers
+provides simple interval timing.
+Timeouts are notified by a message sent on a channel,
+allowing them to provide timeouts in
+.B alt
+statements.
+.PP
+The module must first be initialised by calling
+.BR init ,
+which starts a process to manage the interval timers and returns its process ID.
+Before exit, the caller must shut the timing process down either by calling
+.BR shutdown ,
+which stops it synchronously; by using the process ID returned by
+.B init
+to kill it;
+or by killing the process group of the process that
+called
+.BR init
+(since the timing processes remain in that group).
+.I Minms
+gives the minimum granularity of timing requests in milliseconds.
+.TP
+.BI Timer.start( msec )
+Returns a
+.B Timer
+that will expire in
+.I msec
+milliseconds,
+measured with the granularity of either
+.IR sys-sleep (2)
+or the granularity set by
+.BR init ,
+whichever is greater.
+.TP
+.IB t .timeout
+An arbitrary integer value is sent on this channel when the timer
+.I t
+expires.
+.TP
+.IB t .stop()
+The timer
+.I t
+is stopped
+and removed from the interval timing queue,
+if it has not already expired.
+.PP
+Each
+.B Timer
+value times a single interval.
+When a timer
+.I t
+expires, the timing process attempts, at that and each subsequent timing interval, to send on
+.IB t .channel
+until the expiry message is delivered or the timer is stopped.
+.SH EXAMPLE
+Wait for data to be sent on an input channel, but give up if it does not arrive within 600 milliseconds:
+.IP
+.EX
+t := Timer.start(600);
+alt {
+data := <-input =>
+ t.stop();
+ # process the data
+<-t.timeout =>
+ # request timed out
+}
+.EE
+.SH SEE ALSO
+.IR sys-millisec (2),
+.IR sys-sleep (2)
diff --git a/man/2/tk b/man/2/tk
new file mode 100644
index 00000000..07774801
--- /dev/null
+++ b/man/2/tk
@@ -0,0 +1,270 @@
+.TH TK 2
+.SH NAME
+Tk: toplevel, namechan, cmd, pointer, keyboard, imageget, imageput, quote \- graphics toolkit
+.SH SYNOPSIS
+.EX
+include "draw.m";
+include "tk.m";
+tk := load Tk Tk->PATH;
+Image: import Draw;
+
+Toplevel: adt
+{
+ display: ref Draw->Display;
+ wreq: chan of string;
+ image: ref Image;
+ ctxt: ref Draw->Wmcontext;
+ screenr: Draw->Rect;
+};
+
+toplevel: fn(display: ref Draw->Display, arg: string): ref Toplevel;
+namechan: fn(top: ref Toplevel, c: chan of string, n: string): string;
+cmd: fn(top: ref Toplevel, arg: string): string;
+pointer: fn(top: ref Toplevel, p: Draw->Pointer);
+keyboard: fn(top: ref Toplevel, key: int);
+getimage: fn(top: ref Toplevel, name: string):
+ (ref Image, ref Image, string);
+putimage: fn(top: ref Toplevel, name: string, i, m: ref Image): string;
+rect: fn(top: ref Toplevel, name: string, flags: int): Draw->Rect;
+quote: fn(s: string): string;
+color: fn(s: string): int;
+.EE
+.SH DESCRIPTION
+The
+.B Tk
+module provides primitives for building user interfaces, based on
+Ousterhout's Tcl/TK.
+The interface to the toolkit itself is primarily the passing of strings
+to and from the elements of the toolkit using the
+.B cmd
+function; see section 9 of this manual for more information
+about the syntax of those strings.
+.IR Tkclient (2)
+is conventionally used to create tk windows
+that interact correctly with a running window manager.
+.PP
+.B Toplevel
+creates a new window
+called a
+.BR Toplevel ,
+which is under the control of the
+.B Tk
+toolkit,
+on an existing
+.IR display ,
+usually one inherited from the graphics
+.B Context
+(see
+.IR draw-context (2)).
+The
+.B Toplevel
+is passed to
+.B cmd
+and
+.B namechan
+.RI ( q.v. )
+to drive the widgets in the window.
+.I Arg
+is a string containing creation options (such as
+.BR "-borderwidth 2" )
+that are applied when creating the toplevel window.
+.PP
+.B Cmd
+passes command strings to the widgets in the
+.B Toplevel
+.I t
+and returns the string resulting from their execution.
+For example, given a canvas
+.B .c
+in the
+.B Toplevel
+.BR t ,
+.EX
+ x := int tk->cmd(t, ".c cget -actx");
+.EE
+returns the integer
+.I x
+coordinate of the canvas.
+.PP
+Bindings can be created in a
+.B Toplevel
+that trigger strings to be sent on Limbo channels.
+Such channels must be declared to the
+.B Tk
+module using
+.BR namechan .
+For example, to create a button that sends the word
+.B Ouch
+when it is pressed:
+.EX
+ hitchannel := chan of string;
+ tk->namechan(t, hitchannel, "channel");
+ tk->cmd(t,
+ "button .b.Hit -text Hit -command {send channel Ouch}");
+ expl := <-hitchannel; # will see Ouch when button pressed
+.EE
+.PP
+.B Pointer
+and
+.B keyboard
+pass mouse and keyboard events to a
+.BR Tk
+window
+for delivery to widgets; they must be called by each application,
+which usually receives them via a
+.B Wmcontext
+structure (see
+.IR draw-context (2))
+obtained from the window manager, often via
+.IR tkclient (2).
+.PP
+.B Putimage
+passes an image and a mask into Tk.
+If
+.I name
+is the name of a Tk widget, it must be either a
+.IR panel (9)
+widget, or a top level widget (ie,
+.RB `` . '')
+.BR "" "`"` . "'')"
+or a menu widget,
+in which case the associated image
+or window image is set to
+.IR i .
+.RI ( m
+is ignored for menu and top-level widgets.)
+Otherwise,
+.I name
+must be the name of an existing
+.IR image (9)
+which has its image and mask
+set to copies of
+.I i
+and
+.I m
+respectively.
+.PP
+Initially, a Tk toplevel has no image to draw on.
+Tk uses
+.B wreq
+to request new images of an external authority, and to inform
+said authority when the images are to be deleted.
+The requests are formatted as per
+.B quoted
+in
+.IR string (2),
+and hold one of the following:
+.TP
+.B !reshape \fIname\fP \fIreqid\fP \fIminx miny maxx maxy\fP
+A new image for
+.I name
+is requested
+.RI ( name
+is either the toplevel widget or a menu).
+The desired rectangle for the new image is given
+by
+.RI [ "minx miny maxx maxy" ],
+and the application should respond by creating a new
+image and using
+.B putimage
+to pass it to Tk.
+.I Reqid
+is used by Tk to filter out responses to out-of-date
+requests; when responding to a reshape
+request, the
+.I name
+passed to
+.B putimage
+should have a space and
+.I reqid
+appended.
+.IR Tkclient (2)
+usually deals with the details of this.
+.TP
+.B delete \fIname\fP
+The image
+.I name
+has been deleted. This is generated for
+.IR menu (9)
+widgets when they are unmapped.
+.TP
+.B raise \fIname\fP
+Tk widget
+.I name
+should be raised above other windows on the same screen.
+.TP
+.B lower \fIname\fP
+Tk widget
+.I name
+should be lowered beneath other windows on the same screen.
+.PP
+.B Wreq
+may be set to nil if an application is not prepared to
+read requests sent on this channel.
+.PP
+.B Rect
+returns the bounding rectangle of
+widget
+.I name
+in
+.IR top .
+.I Flags
+determines the form of rectangle returned.
+If
+.I flags
+is zero, the actual rectangle of
+.I name
+in screen coordinates, not including its border,
+is returned. The bitmask flags that can change this are:
+.TP
+.B Border
+Include the widget's border.
+.TP
+.B Required
+Return the rectangle required by the widget, rather
+than the rectangle that has been actually allocated to it.
+.TP
+.B Local
+Return the rectangle in coordinates relative
+to the logical origin of the actual top level image.
+.PP
+.B Quote
+returns a string that is the same as its arguments, but enclosed
+in curly braces and with internal curly braces escaped.
+This can be used to make an arbitrary string into a
+.I word
+suitable as an argument to a Tk function.
+.PP
+.B Color
+returns a colour in 32-bit RGBA format corresponding to the
+tk colour name
+.IR s .
+(see
+.IR types (9)
+for details).
+.PP
+.B Screenr
+gives the rectangle of the screen containing the toplevel window.
+Tk has no
+.I "a priori"
+way of knowing what this is; it is initially set to the rectangle of the
+display image, and may be set by the application if it knows better
+(e.g. from the
+.B wmrect
+file served by
+.IR wm (1)).
+.SH SOURCE
+.B /libinterp/tk.c
+.br
+.B /libtk/*.c
+.SH SEE ALSO
+.IR intro (9),
+.IR image (9),
+.IR panel (9),
+.IR tkcmd (1),
+.IR sh-tk (1),
+.IR draw-context (2),
+.IR tkclient (2),
+.IR wmlib (2)
+.br
+`An Overview of Limbo/Tk', this manual, Volume 2.
diff --git a/man/2/tkclient b/man/2/tkclient
new file mode 100644
index 00000000..c8bf5091
--- /dev/null
+++ b/man/2/tkclient
@@ -0,0 +1,229 @@
+.TH TKCLIENT 2
+.SH NAME
+tkclient: makedrawcontext, toplevel, onscreen, startinput,
+wmctl, settitle, handler, snarfput, snarfget \-
+window manager interface for Tk applications.
+.SH SYNOPSIS
+.EX
+include "tkclient.m";
+tkclient := load Tkclient Tkclient->PATH;
+
+Resize,
+Hide,
+Help,
+OK,
+Plain: con 1 << iota;
+
+Appl: con Resize | Hide;
+
+init: fn();
+makedrawcontext: fn(): ref Draw->Context;
+toplevel: fn(ctxt: ref Draw->Context, topconfig: string,
+ title: string, buts: int): (ref Tk->Toplevel, chan of string);
+onscreen: fn(top: ref Tk->Toplevel, how: string);
+startinput: fn(top: ref Tk->Toplevel, devs: list of string);
+wmctl: fn(top: ref Tk->Toplevel, request: string): string;
+settitle: fn(top: ref Tk->Toplevel, name: string): string;
+handler: fn(top: ref Tk->Toplevel, stop: chan of int);
+
+snarfput: fn(buf: string);
+snarfget: fn(): string;
+.EE
+.SH DESCRIPTION
+The
+.B Tkclient
+module provides routines for making windows controlled by
+.IR wm (1)
+containing
+.IR tk (2)
+widgets.
+.PP
+.B Init
+should be called once to initialise the internal state of
+.BR tkclient .
+.PP
+.B Makedrawcontext
+establishes an initial connection with the window manager,
+creating a new
+.B Draw
+context suitable for creating new windows. It is only
+necessary to call this if the application has not already
+been provided with a context.
+.PP
+.B Toplevel
+creates a new window through
+.IR ctxt .
+.I Topconfig
+gives a list of
+.IR frame (9)
+options that are applied to the
+new tk window, as described in
+.IR tk (2).
+.I Title
+gives a label that will be displayed in the title bar
+of the window;
+.I buts
+determines which buttons are created in the titlebar,
+a bitwise combination of the constants
+.BR Resize ,
+.BR Help ,
+.BR OK,
+and
+.BR Hide .
+If
+.B Plain
+is given, the window is given no decoration at all.
+.B Toplevel
+returns a tuple, say
+.RI ( top ,\ ctl ),
+where
+.I top
+is the newly created top level tk window,
+and
+.I ctl
+is a channel down which requests from the
+title bar are sent.
+Messages received on
+.I ctl
+should be processed
+by the application or passed to the
+.B wmctl
+function. Requests are formatted
+as with
+.B quoted
+in
+.IR string (2).
+The messages include:
+.TP
+.B exit
+The window should be closed.
+.B Wmctl
+will kill all processes in the current
+process group.
+.TP
+.B !move \fIx\fP \fIy\fP
+The user has started to try to drag the window.
+.I X
+and
+.I y
+give the location of the initial pointer click.
+.TP
+.B !size
+The user wishes to resize the window.
+.TP
+.B help
+The help button has been clicked.
+.TP
+.B ok
+The OK button has been clicked.
+.TP
+.B hide
+The Hide button has been clicked.
+The window will be deleted, and an entry
+shown on the toolbar.
+.PP
+In order to function correctly, an application
+should process not only events from the
+title bar channel, but also events from
+the Tk toplevel
+.I wreq
+channel, those received from the window
+manager itself (via
+.IB top .ctxt.ctl\fR),\fP
+and pointer and keyboard events received from
+the window manager (via
+.IB top .ctxt.ptr
+and
+.IB top .ctxt.kbd
+respectively).
+Control events can be passed to
+.BR wmctl ;
+pointer and keyboard events should be
+passed to their respective functions
+in
+.IR tk (2).
+.PP
+When created, the window is not visible
+and will not receive pointer or keyboard events.
+.B Onscreen
+makes it visible, and possibly chooses a
+position and a size for it.
+.I How
+specifies what sort of placement is required
+for the window; it can be one of
+.TP
+.B place
+tries to choose a suitable place on the screen
+with respect to other windows; it may size the
+window as it feels appropriate. This the default
+(if
+.I how
+is nil).
+.TP
+.B onscreen
+tries to keep the position and size the same
+as specified on the window, adjusting them only
+to bring the window fully on screen, and making sure
+that the window is no bigger than the entire display.
+.TP
+.B exact
+does not change the specified size or position
+of the window unless absolutely necessary.
+.PP
+.B Startinput
+informs the window manager that the window is
+ready to the event types specified in
+.IR devs .
+Currently understood are
+.B kbd
+for keyboard events, and
+.B ptr
+for pointer events.
+.PP
+The simplest well-behaved
+.I wm (1)
+client will therefore contain:
+.PP
+.EX
+ (top, ctl) := tkclient->toplevel(ctxt, nil, "My Program", Tkclient->Appl);
+ # ... populate the window with tk widgets
+ tkclient->startinput(top, "ptr" :: "kbd" :: nil);
+ tkclient->onscreen(top, nil);
+ for(;;){
+ alt{
+ s := <-ctl or
+ s = <-top.ctxt.ctl or
+ s = <-top.wreq =>
+ tkclient->wmctl(top, s);
+ p := <-top.ctxt.ptr =>
+ tk->pointer(top, *p);
+ c := <-top.ctxt.kbd =>
+ tk->keyboard(top, c);
+ }
+ }
+.EE
+.PP
+.B Settitle
+changes the name displayed in the title bar
+and the window's name when it is in the task bar.
+.PP
+.B Snarfget
+and
+.B snarfput
+retrieve and replace the contents of the window
+manager's snarf buffer.
+.SH FILES
+.TF /chan/snarf
+.TP
+.B /chan/snarf
+snarf buffer maintained by
+.IR wm (1)
+.TP
+.B /chan/wm
+channel for interaction with
+.IR wm (1)
+.SH SOURCE
+.B /appl/lib/tkclient.b
+.SH SEE ALSO
+.IR wm (1),
+.IR tk (2)
diff --git a/man/2/translate b/man/2/translate
new file mode 100644
index 00000000..87e0ca1b
--- /dev/null
+++ b/man/2/translate
@@ -0,0 +1,135 @@
+.TH TRANSLATE 2
+.SH NAME
+translate: opendict, opendicts, mkdictname \- translation dictionaries
+.SH SYNOPSIS
+.EX
+include "translate.m";
+translate := load Translate Translate->PATH;
+
+Dict: adt {
+ new: fn(): ref Dict;
+ add: fn(d: self ref Dict, file: string): string;
+ xlate: fn(d: self ref Dict, s: string): string;
+ xlaten: fn(d: self ref Dict, s: string, note: string): string;
+};
+
+init: fn();
+opendict: fn(file: string): (ref Dict, string);
+opendicts: fn(files: list of string): (ref Dict, string);
+mkdictname: fn(locale, app: string): string;
+.EE
+.SH DESCRIPTION
+The
+.B Translate
+module provides access to the translation dictionaries
+defined by
+.IR translate (6),
+intended for the translation of
+text from one natural language to another.
+.PP
+.B Init
+should be called before using any of these functions.
+.PP
+.B Opendict
+opens a dictionary
+.I file
+(of the format defined below) and returns a tuple:
+a reference to a
+.B Dict
+that represents it and a diagnostic string (which is nil if no error occurred).
+.B Opendicts
+is similar, but loads each of the
+.I files
+in turn into the same
+.BR Dict ,
+producing a composite dictionary in which translations in later files can override
+translations in earlier ones;
+the diagnostic string summarises all errors (if any).
+.PP
+.B Mkdictname
+returns the conventional name of a dictionary file given
+locale and application names.
+The
+.I locale
+is normally
+.B nil
+to use the current locale, which is formed by
+binding the desired locale directory (or directories) onto
+.BR /lib/locale .
+.PP
+.B Dict.new
+returns an empty dictionary.
+.B Dict.add
+loads the given dictionary
+.I file
+into an existing dictionary, returning a non-nil diagnostic string on error.
+Translations are made by
+.B Dict.xlate
+and
+.BR Dict.xlaten :
+they look for a string
+.I s
+(eg, text in one language),
+optionally qualified by a
+.IR note ,
+and return the corresponding translation text from the dictionary.
+If no such translation exists, they return the original text
+.IR s .
+.SH EXAMPLE
+The following shows one possible style of use:
+.PP
+.EX
+.ta 4n 8n 12n 16n 20n
+include "translate.m";
+ translate: Translate;
+ Dict: import translate;
+
+dict: ref Dict;
+
+X(s: string): string
+{
+ if(dict == nil)
+ return s;
+ return dict.xlate(s);
+}
+
+init(ctxt: ref Draw->Context, args: list of string)
+{
+ ...
+ translate = load Translate Translate->PATH;
+ if(translate != nil){
+ translate->init();
+ (dict, nil) = translate->opendict(
+ translate->mkdictname("", "vmail"));
+ }
+ ...
+ optioncfg := array [] of {
+ "frame .op -relief flat -borderwidth 8",
+ "frame .op.lbs",
+ "label .op.lbs.a -text {" +
+ X("Voice Mail Active") + ":}",
+ "label .op.lbs.g -text {" +
+ X("Answer Calls With") + ":}",
+ "label .op.lbs.r -text {" +
+ X("Rings before Answering") + ":}",
+ "label .op.lbs.l -text {" +
+ X("Length of Incoming Messages") + ":}}",
+ ...
+ };
+ ...
+ wmlib->tkcmds(top, optioncfg);
+}
+.EE
+.PP
+The intermediate function
+.B X
+is defined to allow the program to be used (albeit with text in English) even
+when the
+.B Translate
+module cannot be loaded.
+.SH FILES
+.BI /locale/ locale /dict/ app
+.SH SOURCE
+.B /appl/lib/translate.b
+.SH SEE ALSO
+.IR translate (6)
diff --git a/man/2/ubfa b/man/2/ubfa
new file mode 100644
index 00000000..46f6a763
--- /dev/null
+++ b/man/2/ubfa
@@ -0,0 +1,273 @@
+.TH UBFA 2
+.SH NAME
+ubfa: readubf, writeubf, UValue \- read, write and represent values in a UBF(A) data transport encoding
+.SH SYNOPSIS
+.EX
+include "ubfa.m";
+ubfa := load UBFa UBFa->PATH;
+
+UValue: adt {
+ pick{
+ Atom =>
+ name: string;
+ Int =>
+ value: int;
+ String =>
+ s: string;
+ Binary =>
+ a: array of byte;
+ Tuple =>
+ a: cyclic array of ref UValue; # tree
+ List =>
+ l: cyclic list of ref UValue; # tree
+ Tag =>
+ name: string;
+ o: cyclic ref UValue;
+ }
+ isatom: fn(o: self ref UValue): int;
+ isstring: fn(o: self ref UValue): int;
+ isint: fn(o: self ref UValue): int;
+ istuple: fn(o: self ref UValue): int;
+ isop: fn(o: self ref UValue, op: string, arity: int): int;
+ islist: fn(o: self ref UValue): int;
+ isbinary: fn(o: self ref UValue): int;
+ istag: fn(o: self ref UValue): int;
+ eq: fn(o: self ref UValue, v: ref UValue): int;
+ op: fn(o: self ref UValue, arity: int): string;
+ args: fn(o: self ref UValue, arity: int):
+ array of ref UValue;
+ els: fn(o: self ref UValue): list of ref UValue;
+ val: fn(o: self ref UValue): int;
+ binary: fn(o: self ref UValue): array of byte;
+ objtag: fn(o: self ref UValue): string;
+ obj: fn(o: self ref UValue): ref UValue;
+ text: fn(o: self ref UValue): string;
+};
+
+init: fn(bufio: Bufio);
+readubf: fn(input: ref Iobuf): (ref UValue, string);
+writeubf: fn(output: ref Iobuf, v: ref UValue): int;
+uniq: fn(s: string): string;
+
+uvatom: fn(s: string): ref UValue.Atom;
+uvint: fn(i: int): ref UValue.Int;
+uvstring: fn(s: string): ref UValue.String;
+uvbinary: fn(a: array of byte): ref UValue.Binary;
+uvtuple: fn(a: array of ref UValue): ref UValue.Tuple;
+uvlist: fn(l: list of ref UValue): ref UValue.List;
+uvtag: fn(name: string, o: ref UValue): ref UValue.Tag;
+.EE
+.SH DESCRIPTION
+.B UBFa
+provides value representations, and encoding and decoding operations for Armstrong's UBF(A) data transport
+format, defined by
+.IR ubfa (6).
+.PP
+.B Init
+must be called before invoking any other operation of the module.
+The
+.I bufio
+parameter must refer to the instance of
+.IR bufio (2)
+that provides the
+.B Iobuf
+parameters used for input and output.
+.PP
+.B UValue
+is the internal representation of values that can be transmitted by the UBF(A) encoding.
+The various sorts of values are distinguished in a pick adt:
+.TP
+.B UValue.Atom
+Represents an
+.IR atom :
+a symbolic constant, for example the name of an operation or an enumeration literal.
+The string
+.B name
+gives the spelling of the constant's name.
+.TP
+.B UValue.Int
+Represents an integer value (eg, a Limbo
+.BR int )
+with the given
+.BR value .
+.TP
+.B UValue.String
+Represents a character string (eg, a Limbo
+.BR string )
+with the value
+.BR s .
+.TP
+.B UValue.Binary
+Represents binary data as a sequence of bytes in the array
+.BR a .
+.TP
+.B UValue.Tuple
+Represents a compound value that contains a fixed number of component values,
+given by successive elements of the array
+.BR a .
+UBF tuples correspond to tuples or non-pick
+.B adt
+values in Limbo.
+.TP
+.B UValue.List
+Represents a compound value containing a variable number of component values,
+given by successive elements of the list
+.BR l .
+.TP
+.B UValue.Tag
+Associates an application-specific
+.B tag
+with another
+.B UValue
+referenced by
+.BR o .
+.PP
+.B Readubf
+reads a single value in
+.IR ubfa (6)
+format from the
+.I input
+stream and returns a tuple
+.BI ( val,\ err ).
+On success,
+.I val
+is a
+.B UValue
+that represents that value.
+If an error occurs,
+.I val
+is nil and
+.I err
+contains a diagnostic.
+.PP
+.B Writeubf
+writes a
+.IR ubfa (6)
+representation of the value
+.I v
+to the
+.I output
+stream.
+It returns 0 on success and -1 on error (setting the system error string).
+.PP
+The easiest way to create a new
+.B UValue
+for subsequent output is with one of the module-level functions
+.BR uvatom ,
+.BR uvint ,
+.BR uvstring ,
+and so on.
+As values of a pick adt, a
+.B UValue
+can be inspected using Limbo's
+.B tagof
+operator and the appropriate variant accessed using a
+.B pick
+statement.
+.B UValue
+also supports several groups of common operations, for smaller, tidier code.
+First, the set of enquiry functions
+.IB u .is X ()
+return true if the value
+.I u
+is an instance of the UBF type
+.I X
+.RI ( atom ,
+.IR int ,
+.IR string ,
+.IR binary ,
+.IR tuple ,
+etc).
+The other operations are:
+.TP
+.IB u .eq( v )
+Return true if the values of
+.I u
+and
+.I v
+are equal, including the values of corresponding subcomponents, recursively
+.TP
+.IB u .isop( op,\ n )
+Return true if
+.I u
+is a tuple having
+.I n
+components, and its first component is an atom or string with the value
+.IR op .
+.TP
+.IB u .op( n )
+If
+.I u
+is a tuple with
+.I n
+components, and the first component is an atom or string, return its value.
+Otherwise, return nil.
+.TP
+.IB u .args( n )
+If
+.I u
+is a tuple with
+.I n
+components, return an array containing the values of all but the first component.
+Otherwise, return nil.
+.TP
+.IB u .els()
+If
+.I u
+is a list, return a Limbo list of its elements (ie,
+.IB u .l\fR)\fP.
+Otherwise, return nil.
+.TP
+.IB u .val()
+If
+.I u
+is an integer, return its value.
+Otherwise return zero.
+.TP
+.IB u .binary()
+If
+.I u
+is a binary value, return the corresponding array of bytes; if
+.I u
+is an atom or string, return an array of bytes containing its value;
+otherwise, return nil.
+.TP
+.IB u .objtag()
+If
+.I u
+is a tag, return the name of the tag.
+Otherwise, return nil.
+.TP
+.IB u .obj()
+If
+.I u
+is a tag, return the tagged value.
+Otherwise, return
+.I u
+itself.
+.TP
+.IB u .text()
+Return a printable representation of the value
+.IR u ,
+mainly intended for debugging and tracing.
+.PP
+One difference between atoms and strings is that
+all atoms with identical spellings refer to the same string in the implementation's storage.
+Given an atom name,
+.B uniq
+returns the corresponding string, stored in an internal dictionary.
+It is used by
+.B UBFa
+to create the strings
+.BR UValue.Atom.s ,
+and can be put to similar use directly by applications.
+It should only be applied to values that are small in number (as with symbolic constants).
+.SH SOURCE
+.B /appl/lib/ubfa.b
+.SH SEE ALSO
+.IR sexprs (2),
+.IR ubfa (6)
+.br
+J L Armstrong, ``Getting Erlang to talk to the outside world'',
+.I "ACM SIGPLAN Erlang workshop 2002" ,
+Pittsburg, PA USA
diff --git a/man/2/venti b/man/2/venti
new file mode 100644
index 00000000..fdb0d2ac
--- /dev/null
+++ b/man/2/venti
@@ -0,0 +1,107 @@
+.TH VENTI 2
+.SH NAME
+Venti \- access to Venti content-addressed filestore.
+.SH SYNOPSIS
+.EX
+include "venti.m";
+venti := load Venti Venti->PATH;
+Session: import venti;
+
+init: fn();
+unpackentry: fn(d: array of byte): ref Entry;
+unpackroot: fn(d: array of byte): ref Root;
+
+Session: adt {
+ new: fn(fd: ref Sys->FD): ref Session;
+ read: fn(s: self ref Session, score: Venti->Score, etype: int, maxn: int): array of byte;
+ write: fn(s: self ref Session, etype: int, buf: array of byte): (int, Venti->Score);
+ sync: fn(s: self ref Session): int;
+};
+
+Score: adt {
+ a: array of byte;
+ eq: fn(a: self Score, b: Score): int;
+ text: fn(a: self Score): string;
+ parse: fn(s: string): (int, Score);
+ zero: fn(): Score;
+};
+
+.EE
+.SH DESCRIPTION
+.I Venti
+is a block storage server intended for archival applications.
+The
+.I Venti
+module provides low-level access to a Venti server.
+The module assumes that the physical connection
+to the server has already been established
+(for example, by
+.IR dial (2)).
+On a Venti server, a block is addressed by the SHA1 hash of
+the contents of that block, known as a
+.IR score ,
+and represented as a
+.B Score
+adt.
+Blocks are additionally tagged with a
+.IR type ,
+facilitating recovery in the event of corruption.
+A
+.B Session
+represents an session with a Venti server.
+.TP
+.IB s .new(\fIfd\fP)
+.B New
+performs the initial handshake with the Venti server,
+returning established
+.BR Session .
+.TP
+.IB s .read(\fIscore\fP,\ \fIetype\fP,\ \fImaxn\fP)
+.B Read
+tries to retrieve the block
+corresponding to
+.IR score ,
+and of type
+.IR etype .
+The block must be no longer than
+.I maxn
+bytes.
+.I Etype
+is conventionally one of the constants
+.BR Roottype ,
+.BR Dirtype ,
+.BR Datatype
+or
+.BR Pointertype [0-9],
+where the different
+.BR Pointertype s
+represent different depth levels within a Venti tree.
+.TP
+.IB s .write(\fIetype\fP,\ \fIbuf\fP)
+.B Write
+writes the data in
+.I buf
+to the Venti server.
+The block will be tagged with type
+.IR etype .
+It returns a tuple, say
+.RI ( ok ,\ score );
+on error,
+.I ok
+is -1, otherwise
+.I ok
+is 0 and
+.I score
+contains the Venti score for the block that has been written.
+.TP
+.IB s .sync()
+.B Sync
+tells the Venti server to make sure that all data is committed to
+active storage.
+.SH SOURCE
+.B /appl/lib/venti.b
+.SH BUGS
+to do:
+Score adt
+entry packing/unpacking
+other Vmsgs, Session.rpc()?
diff --git a/man/2/virgil b/man/2/virgil
new file mode 100644
index 00000000..5a7cd347
--- /dev/null
+++ b/man/2/virgil
@@ -0,0 +1,54 @@
+.TH VIRGIL 2
+.SH NAME
+virgil \- pose question to name resolver
+.SH SYNOPSIS
+.EX
+include "security.m";
+virgil := load Virgil Virgil->PATH;
+
+virgil: fn(args: list of string): string;
+.EE
+.SH DESCRIPTION
+.B Virgil
+provides a client side interface for interactions with the
+name resolution service
+.IR virgild (8).
+.PP
+.I Args
+is a command line of the form:
+.IP
+.BR virgil " [" -v
+.IR address ]
+.RI [ name ]
+.PP
+.I Name
+is the host name to be resolved to a network address.
+Normally the request is broadcast to any and all
+.I virgild
+servers on the network, which
+.B virgil
+expects to find on UDP/IP port 2202.
+The
+.B -v
+option instead directs the request to the given numeric IP
+.IR address .
+.PP
+.B Virgil
+waits up to 5 seconds for a reply, retransmitting the request once a second.
+It accepts and returns the first answer it receives.
+.SH SOURCE
+.B /appl/lib/virgil.b
+.SH SEE ALSO
+.IR sys-dial (2),
+.IR cs (8),
+.IR register (8),
+.IR virgild (8)
+.SH DIAGNOSTICS
+.B Virgil
+returns
+.L nil
+for invalid arguments and if the name was not resolved.
+.SH BUGS
+The
+.I virgild
+port is hard coded.
diff --git a/man/2/volume b/man/2/volume
new file mode 100644
index 00000000..58b5d61f
--- /dev/null
+++ b/man/2/volume
@@ -0,0 +1,51 @@
+.TH VOLUME 2 mux
+.SH NAME
+volume \- volume control for an infrared interface
+.SH SYNOPSIS
+.EX
+include "volume.m";
+vctl := load Volumectl Volumectl->PATH;
+
+volumectl: fn(ctxt: ref Draw->Context, ch: chan of int,
+ device: string);
+.EE
+.SH DESCRIPTION
+.B Volumectl
+should be spawned as a separate process from any process that desires volume control via an infrared interface.
+.I Ctxt
+provides
+.B volumectl
+with access to the display,
+on which it displays a slider widget.
+The slider automatically disappears after several seconds of inactivity.
+.B Volumectl
+receives input from the infrared controller on channel
+.IR ch .
+The values recognized are:
+.TF Enter
+.PD
+.TP
+.B VolUP
+increase volume
+.TP
+.B VolDN
+decrease volume
+.TP
+.B Enter
+exit
+.PP
+.I Device
+is a string used as a prefix to commands to the device;
+for example
+.B
+"audio out"
+.ft P
+for
+.IR audio (3).
+.SH FILES
+.B /dev/volume
+.SH SOURCE
+.B /appl/lib/volume.b
+.SH "SEE ALSO"
+.IR ir (2),
+.IR prefab-intro (2)
diff --git a/man/2/w3c-css b/man/2/w3c-css
new file mode 100644
index 00000000..44a1ebfc
--- /dev/null
+++ b/man/2/w3c-css
@@ -0,0 +1,349 @@
+.TH W3C-CSS 2
+.SH NAME
+w3c-css \- cascading style sheet parser
+.SH SYNOPSIS
+.EX
+include "css.m";
+
+css := load CSS CSS->PATH;
+
+Stylesheet: adt {
+ charset: string;
+ imports: list of ref Import;
+ statements: list of ref Statement;
+};
+
+Import: adt {
+ name: string;
+ media: list of string;
+};
+
+Statement: adt {
+ pick{
+ Media =>
+ media: list of string;
+ rules: list of ref Statement.Ruleset;
+ Page =>
+ pseudo: string;
+ decls: list of ref Decl;
+ Ruleset =>
+ selectors: list of Selector;
+ decls: list of ref Decl;
+ }
+};
+
+Decl: adt {
+ property: string;
+ values: list of ref Value;
+ important: int;
+};
+
+Selector: type list of (int, Simplesel); # (combinator, simplesel)
+Simplesel: type list of ref Select;
+
+Select: adt {
+ name: string;
+ pick{
+ Element or ID or Any or Class or Pseudo =>
+ # empty
+ Attrib =>
+ op: string; # "=" "~=" "|="
+ value: ref Value; # optional Ident or String
+ Pseudofn =>
+ arg: string;
+ }
+};
+
+Value: adt {
+ sep: int; # operator preceding this term
+ pick{
+ String or
+ Number or
+ Percentage or
+ Url or
+ Unicoderange =>
+ value: string;
+ Hexcolour =>
+ value: string; # as given
+ rgb: (int, int, int); # converted
+ RGB =>
+ args: cyclic list of ref Value; # as given
+ rgb: (int, int, int); # converted
+ Ident =>
+ name: string;
+ Unit =>
+ value: string; # int or float
+ units: string; # suffix giving units
+ Function =>
+ name: string;
+ args: cyclic list of ref Value;
+ }
+};
+
+init: fn(diag: int);
+parse: fn(s: string): (ref Stylesheet, string);
+parsedecl: fn(s: string): (list of ref Decl, string);
+.EE
+.SH DESCRIPTION
+.B Css
+implements a parser for the World-Wide Web Consortium's Cascading
+Style Sheet, specification 2.1.
+.PP
+.B Init
+must be called before any other operation in the module.
+If
+.I diag
+is non-zero, the module will print diagnostics on standard output for
+malformed or unrecognised items that are ignored during parsing (as
+required by the specification).
+.PP
+.B Parse
+takes a complete stylesheet in string
+.IR s ,
+parses it, and returns a tuple
+.BI ( sheet,\ err )
+where
+.I sheet
+refers to a
+.B Stylesheet
+value containing the logical content of
+.IR s ,
+as described below.
+On a fatal error,
+.I sheet
+is nil and
+.I err
+is a diagnostic.
+Most syntactic errors are ignored, as the specification requires.
+.PP
+In some applications there can be auxiliary declarations outside a stylesheet.
+.B Parsedecl
+takes a string
+.I s
+containing a sequence of declarations, and returns a tuple
+.BI ( decls,\ err )
+where
+.I decls
+is a list of references to
+.B Decl
+values, each representing a single
+.I declaration
+in
+.IR s .
+On a fatal error,
+.I decls
+is nil, and
+.I err
+is a diagnostic.
+.PP
+The adts represent an abstract syntax of the CSS grammar.
+The concrete syntax is presented below in an extended BNF,
+derived from the reference grammar,
+with each section labelled by the name of the corresponding adts.
+(Compared to the reference grammar in the
+specification, it abstracts away from the complex rules about where whitespace can appear.)
+.TP
+.B Stylesheet
+.EX
+.ft R
+\f2stylesheet\fP ::= [ '\f5@charset\fP' STRING '\f5;\fP' ] \f2import\fP* \f2statement\fP*
+.EE
+.IP
+Limbo lists represent lists of items in the grammar.
+Nil values denote optional components that are missing.
+Upper-case names such as
+IDENT,
+STRING
+and
+NUMBER
+are terminals; see the CSS specification for their
+often subtle definitions.
+They are usually represented
+by Limbo string values in the adts.
+.TP
+.B Import
+.EX
+.ft R
+\f2import\fP ::= '\f5@import\fP' (\f2STRING\fP|\f2uri\fP) [\f2medium\fP ('\f5,\fP' \f2medium\fP)*] '\f5;\fP'
+\f2uri\fP ::= '\f5url(\fP' STRING '\f5)\fP'
+.EE
+.IP
+.B Import.name
+holds the text of the
+STRING
+or
+.IR uri .
+.TP
+.B Statement
+.EX
+.ft R
+\f2statement\fP ::= \f2ruleset\fP | \f2media\fP | \f2page\fP
+\f2media\fP ::= '\f5@media\fP' \f2medium\fP ('\f5,\fP' \f2medium\fP)* '\f5{\fP' \f2ruleset\fP* '\f5}\fP'
+\f2medium\fP ::= IDENT
+\f2page\fP ::= '\f5@page\fP' [\f2pseudo_page\fP] '\f5{\fP' \f2declaration\fP ('\f5;\fP' \f2declaration\fP)* '\f5}\fP'
+\f2pseudo_page\fP ::= '\f5:\fP' IDENT
+\f2ruleset\fP ::= \f2selector\fP ('\f5,\fP' \f2selector\fP)* '\f5{\fP' \f2declaration\fP ('\f5;\fP' \f2declaration\fP)* '\f5}\fP'
+.EE
+.IP
+.B Statement
+is not in the reference grammar, but is introduced here to give a name corresponding
+to the pick adt.
+.TP
+.B Decl
+.EX
+.ft R
+\f2declaration\fP ::= \f2property\fP '\f5:\fP' \f2expr\fP ['\f5!\fP' '\f5important\fP'] | /* \f2empty\fP */
+\f2property\fP ::= IDENT
+.EE
+.B Decl.values
+is a list representing the terms of the
+.I expr
+(see below for details).
+.BR Decl 's
+field
+.B important
+is non-zero if the optional `important' priority is given.
+.TP
+.B "list of ref Value"
+.EX
+.ft R
+\f2expr\fP ::= \f2term\fP (\f2operator\fP \f2term\fP)*
+\f2operator\fP ::= '\f5/\fP' | '\f5,\fP' | /* \f2empty\fP */
+.EE
+.IP
+An
+.I expr
+is always represented as a list of references to
+.B Value
+in some containing structure
+(where
+.B Value
+represents a
+.IR term ,
+see below).
+The
+.I operator
+preceding each
+.I term
+appears as the field
+.B sep
+of the corresponding
+.BR Value ,
+where a space character represents `empty' (concatenation).
+.TP
+.BR Selector
+.EX
+.ft R
+\f2selector\fP ::= \f2simple_selector\fP (\f2combinator\fP \f2simple_selector\fP)*
+\f2combinator\fP ::= '\f5+\fP' | '\f5>\fP' | /* \f2empty\fP */
+.EE
+.IP
+.B Selector
+is just a type synonym for a list of tuples, say
+.BI ( com,\ simplesel )
+where the
+.I simplesel
+value represents
+.I simple_selector
+(see below), and the integer
+.I com
+is one of the characters space (representing `empty'),
+.RB ` > '
+or
+.RB ` + ',
+giving the combinator that preceded the simple selector.
+(The first in the list is always space.)
+.TP
+.BR Simplesel ", " Select
+.EX
+.ft R
+\f2simple_selector\fP ::= \f2element_name\fP (\f2hash\fP | \f2class\fP | \f2attrib\fP | \f2pseudo\fP)*
+ | (\f2hash\fP | \f2class\fP | \f2attrib\fP | \f2pseudo\fP)+
+\f2hash\fP ::= '\f5#\fP' NAME
+\f2class\fP ::= '\f5.\fP' IDENT
+\f2element_name\fP ::= IDENT | '\f5*\fP'
+\f2attrib\fP ::= '\f5[\fP' IDENT [('\f5=\fP' | '\f5|=\fP' | '\f5~=\fP') (IDENT | STRING)] '\f5]\fP'
+\f2pseudo\fP ::= '\f5:\fP' ( IDENT | IDENT '\f5(\fP' [IDENT] '\f5)\fP' )
+.EE
+.IP
+A
+.I simple_selector
+is represented by
+.BR Simplesel ,
+a list of references to
+.B Select
+values, each representing one
+.I element_name
+or qualifier.
+An
+.I element_name
+is represented by
+.B Select.Element
+for an
+IDENT,
+or
+.B Select.Any
+for
+.RB ` * '.
+The qualifiers are
+.I hash
+.RB ( Select.ID ),
+.I class
+.RB ( Select.Class ),
+.I attrib
+.RB ( Select.Attrib ,
+where the comparison operator is the string
+.BR op ),
+.I pseudo
+(either
+.B Select.Pseudo
+if a plain identifier, or
+.B Select.Pseudofn
+for a function with optional parameter).
+.TP
+.B Value
+.EX
+.ft R
+\f2term\fP ::= ['\f5+\fP' | '\f5-\fP'] (NUMBER | \f2percent\fP | \f2unit\fP) | STRING | IDENT | \f2uri\fP | \f2function\fP | \f2hexcolour\fP | \f2rgb\fP
+\f2function\fP ::= IDENT '\f5(\fP' \f2expr\fP '\f5)\fP'
+\f2hash\fP ::= '\f5#\fP' NAME
+\f2hexcolour\fP ::= '\f5#\fP' HEXDIGIT+
+\f2percent\fP ::= NUMBER '\f5%\fP'
+\f2unit\fP ::= NUMBER STRING
+\f2rgb\fP ::= '\f5rgb(\fP' \f2term\fP '\f5,\fP' \f2term\fP '\f5,\fP' \f2term\fP '\f5)\fP'
+\f2uri\fP ::= '\f5url(\fP' STRING '\f5)\fP'
+.EE
+.IP
+Any sign before a
+.BR Number ,
+.B Percentage
+or
+.B Unit
+appears as the first character of
+.BR value .
+All the dimensional units (LENGTH, EMS, EXS, ANGLE, TIME, FREQ and others)
+in the reference grammar are mapped to
+.BR Value.Unit ,
+with the field
+.B units
+containing the name of the relevant unit (eg,
+.LR cm ,
+.LR in ,
+etc.) in lower case.
+Values and names appear shorn of the surrounding punctuation.
+.B Value.Hexcolour
+includes the original sequence of hex digits as a string,
+and a decoding of it as an
+.B rgb
+triple.
+The arguments to the CSS
+.B rgb
+function are similarly presented in original and decoded forms, in
+.BR Value.RGB .
+Other function references are returned uninterpreted in
+.BR Value.Function .
+.SH SOURCE
+.B /appl/lib/w3c/css.b
+.SH SEE ALSO
+``Cascading Style Sheets, level 2 revision 1'',
+.B http://www.w3.org/TR/CSS21
diff --git a/man/2/w3c-xpointers b/man/2/w3c-xpointers
new file mode 100644
index 00000000..deda4e32
--- /dev/null
+++ b/man/2/w3c-xpointers
@@ -0,0 +1,382 @@
+.TH W3C-XPOINTERS 2
+.SH NAME
+w3c-xpointers \- parser for XPointers framework including XPath
+.SH SYNOPSIS
+.EX
+include "xpointers.m";
+
+xpointers := load Xpointers Xpointers->PATH;
+Xpath, Xstep: import xpointers;
+
+# special operators ('+', '-', etc represent themselves)
+One, Ole, Oge, Omul, Odiv, Omod, Oand, Oor, Oneg,
+Onodetype, Onametest, Ofilter, Opath: con ...;
+
+# axis types
+Aancestor,
+Aancestor_or_self,
+Aattribute,
+Achild,
+Adescendant,
+Adescendant_or_self,
+Afollowing,
+Afollowing_sibling,
+Anamespace,
+Aparent,
+Apreceding,
+Apreceding_sibling,
+Aself: con iota;
+
+Xstep: adt {
+ axis: int; # Aancestor, ... (above)
+ op: int; # Onametest or Onodetype
+ ns: string;
+ name: string;
+ arg: string; # optional parameter to processing-instruction
+ preds: cyclic list of ref Xpath;
+
+ text: fn(nil: self ref Xstep): string;
+ axisname: fn(i: int): string;
+};
+
+Xpath: adt {
+ pick{
+ E =>
+ op: int;
+ l, r: cyclic ref Xpath;
+ Fn =>
+ ns: string;
+ name: string;
+ args: cyclic list of ref Xpath;
+ Var =>
+ ns: string;
+ name: string;
+ Path =>
+ abs: int;
+ steps: list of ref Xstep;
+ Int =>
+ val: big;
+ Real =>
+ val: real;
+ Str =>
+ s: string;
+ }
+ text: fn(nil: self ref Xpath): string;
+};
+
+framework: fn(s: string):
+ (string, list of (string, string, string), string);
+
+# predefined schemes
+element: fn(s: string): (string, list of int, string);
+xmlns: fn(s: string): (string, string, string);
+xpointer: fn(s: string): (ref Xpath, string);
+.EE
+.SH DESCRIPTION
+.B Xpointers
+implements a parser for the World-Wide Web Consortium's XPointers framework,
+including a parser for XPath expressions.
+.PP
+.B Init
+must be called before any other operation in the module.
+.PP
+.B Framework
+parses a string
+.I s
+according to the grammar for the XPointers framework,
+and returns a tuple
+.BI ( short,\ pointers,\ err ) .
+On an error, the string
+.I err
+gives a diagnostic and the other two values are nil.
+Otherwise, if
+.I short
+is non-nil, the XPointer was a `shorthand pointer', with the given value;
+.I pointers
+will be nil.
+If a scheme-based pointer is used,
+.I short
+is nil and
+.I pointers
+has a list of tuples
+.BI ( ns,\ scheme,\ data ) ,
+each representing one pointer value.
+.I Ns
+is the XML name space for the given
+.IR scheme ;
+the default name space is represented by nil.
+.I Scheme
+is the XPointer scheme name within that name space; and
+.I data
+is the actual pointer value following the rules of that scheme.
+(They all have completely different syntax.)
+.PP
+Three common schemes are directly supported by the module,
+by functions named after the scheme.
+All of them follow the convention of returning a tuple in which
+the last element is a diagnostic string.
+On an error, all but that last element of the tuple will be nil,
+and the last element will be a non-nil string with a diagnostic.
+.PP
+.B Xmlns
+parses an XML name space definition of the form
+.IB ns = uri,
+and returns its components.
+.PP
+.B Element
+parses a value of the XPointer
+.B element
+scheme, given by the grammar:
+.IP
+.EX
+.ft I
+selector \f1::=\fP name child* \f1|\fP child+
+child \f1::=\fP '\f5/\fP' \f5[1-9][0-9]\fP*
+.EE
+.PP
+The optional
+.I name
+is an XPointer `shorthand pointer'.
+Each
+.I child
+number selects the child with that index (origin 1) at the corresponding level of the XML tree
+beneath the node selected by the
+.IR name ,
+or starting at the root of the XML tree.
+.B Element
+returns a tuple
+.BI (( name,\ path ) ,\ err )
+where
+.I name
+is the top element name or nil if none was specified,
+and
+.I path
+is a
+.B "list of int"
+giving the path of child indices.
+.PP
+The most complex scheme is
+.BR xpointer ,
+because its syntax is that of XML's elaborate XPath expression.
+.B Xpointer
+parses such an expression and returns a tuple
+.BI ( e,\ err )
+where
+.I e
+refers to an
+.B Xpath
+value that represents the abstract syntax of the XPath
+.BR Expr .
+.B Xpointer
+checks only the syntax of
+.IR s ,
+and does not check that functions are limited to those specified by the
+.B xpointer
+scheme (that is consistent with it being a parse of
+.IR s ,
+rather than an XPointer or XPath evaluator).
+.PP
+.B Xpath
+and
+.B Xstep
+together represent an abstract syntax of the XPath grammar.
+.PP
+.B Xstep
+represents the XPath
+.B Step
+grammar rule, with all abbreviations expanded to their full form:
+.IP
+.EX
+.ft I
+Step \f1::=\fP AxisName '\f5::\fP' NodeTest Predicate*
+NodeTest \f1::=\fP NameTest \f1|\fP NodeType '\f5(\fP' '\f5)\fP'
+NameTest \f1::=\fP '\f5*\fP' \f1|\fP NCName '\f5:\fP' '\f5*\fP' \f1|\fP (NCName '\f5:\fP')? NCName
+Predicate \f1::=\fP '\f5[\fP' Expr '\f5]\fP'
+.EE
+.PP
+The correspondence is as follows:
+.TF s.text()
+.PD
+.TP
+.IB s .axis
+Represents the
+.B AxisName
+by one of the constants
+.B Aancestor
+to
+.BR Aself .
+.TP
+.IB s .op
+.B Onametest
+or
+.B Onodetype
+to say which rule is represented
+.TP
+.IB s .ns
+For a
+.IR NameTest ,
+gives the XML name space;
+can be
+.L *
+for `any name space' or nil for the default name space.
+For a
+.IR NodeType ,
+gives the type:
+.BR comment ,
+.BR node ,
+.BR processing-instruction ,
+or
+.BR text .
+.TP
+.IB s .name
+Gives the
+.I name
+for a
+.IR NameTest ;
+can be
+.L *
+for `any name'.
+.TP
+.IB s .arg
+The optional literal parameter to a
+.I NodeType
+that is a
+.BR processing-instruction .
+.TP
+.IB s .preds
+A list of
+.B Xpath
+values representing the optional sequence of
+.I Predicate
+expressions
+.TP
+.IB s .text()
+Returns a string representing the
+.B Xstep
+in textual form.
+.TP
+.IB s .axisname( a )
+Returns the printable text for axis code
+.I a
+(ie,
+one of
+.B Aancestor
+to
+.BR Aself )
+.PP
+.B Xpath
+values represent an abstract syntax for an XPath expression.
+Briefly, an expression follows the grammar below (see the XPath specification for the full concrete syntax).
+.IP
+.EX
+.ft I
+.ta \w'e ::= 'u
+e ::= e '\f5or\fP' e
+ | e '\f5and\fP' e
+ | e \f1(\fP'\f5=\fP' \f1|\fP '\f5!=\fP'\f1)\fP e
+ | e \f1(\fP'\f5<\fP' \f1|\fP '\f5<=\fP' \f1|\fP '\f5>=\fP' \f1|\fP '\f5>\fP'\f1)\fP e
+ | e \f1(\fP'\f5+\fP' \f1|\fP '\f5-\fP'\f1)\fP e
+ | e \f1(\fP'\f5*\fP' \f1|\fP '\f5div\fP' \f1|\fP '\f5mod\fP'\f1)\fP e
+ | '\f5-\fP' e
+ | e '\f5|\fP' e
+ | filter
+ | path
+filter ::= primary predicate* \f1(\fP\f1(\fP'\f5/\fP' \f1|\fP '\f5//\fP'\f1)\fP relpath\f1)\fP?
+primary ::= '\f5$\fP' QName \f1|\fP '\f5(\fP' e '\f5)\fP' \f1|\fP Literal \f1|\fP Number \f1|\fP FunctionName '\f5(\fP' \f1(\fPe \f1(\fP'\f5,\fP' e\f1)\fP*\f1)\fP '\f5)\fP'
+path ::= '\f5/\fP' relpath \f1|\fP relpath
+relpath ::= relpath '\f5/\fP' relpath \f1|\fP relpath '\f5//\fP' relpath \f1|\fP Step
+.EE
+.PP
+Most of
+.I e
+is represented by a binary tree using the pick
+.BI Xpath.E( op,\ l,\ r )
+where
+.I op
+is an operator symbol (either the character itself or one of the constants
+.BR One ,
+.BR Odiv ,
+etc. for compound symbols),
+and
+.I l
+and
+.I r
+represent the operands.
+The only unary operator
+.B Oneg
+has its operand in
+.IR l .
+A
+.I filter
+uses the binary operator
+.BI Xpath.E(Ofilter ,\ e,\ pred )
+to apply each
+.I predicate
+to the preceding
+.I primary
+or
+.IR predicate .
+A
+.I filter
+also uses
+.BI Xpath.E(Opath ,\ e,\ relpath )
+to apply the optional
+.I relpath
+(represented by a value of
+.BR Xpath.Path )
+to the preceding part of the filter expression.
+.PP
+The other cases in the pick adt correspond to the various choices of
+.I path
+and
+.IR primary .
+Integer and real numbers are distinguished.
+.I Literal
+is represented by
+.BR Xpath.Str ;
+variable references (ie,
+.BI $ QName\c
+)
+are represented by
+.BR XPath.Var ,
+where
+.I ns
+gives the optional XML name space of the
+.IR name .
+.I Path
+is represented by
+.BI Xpath.Path( abs,\ steps )
+where
+.I abs is non-zero if and only if the path is absolute (starts with `/' or `//'),
+and
+.I steps
+lists the
+.B Xstep
+values corresponding to the slash-separated
+.I Steps
+in the grammar.
+Abbreviated forms such as
+.RB ` // '
+are converted by
+.B xpointer
+to their full internal form in terms of
+.RB ` / ',
+as defined by the specification,
+so there is no need to distinguish the delimiters in this representation.
+.SH SOURCE
+.B /appl/lib/w3c/xpointers.b
+.SH SEE ALSO
+``XML Path Language (XPath) Version 1.0'',
+.B http://www.w3.org/TR/xpath
+.br
+``XPointer framework'',
+.B http://www.w3.org/TR/xptr-framework/
+.br
+``XPointer element() scheme'',
+.B http://www.w3.org/TR/xptr-element/
+.br
+``XPointer xmlns() scheme'',
+.B http://www.w3.org/TR/xptr-xmlns/
+.br
+``XPointer xpointer() scheme'',
+.B http://www.w3.org/TR/xptr-xpointer/
diff --git a/man/2/wait b/man/2/wait
new file mode 100644
index 00000000..a7cf56f0
--- /dev/null
+++ b/man/2/wait
@@ -0,0 +1,100 @@
+.TH WAIT 2
+.SH NAME
+wait \- wait for child process to exit
+.SH SYNOPSIS
+.EX
+wait := load Wait Wait->PATH;
+
+Wait: module
+{
+ init: fn();
+ read: fn(fd: ref Sys->FD): (int, string, string);
+ monitor: fn(fd: ref Sys->FD): (int, chan of (int, string, string));
+ parse: fn(status: string): (int, string, string);
+};
+.EE
+.SH DESCRIPTION
+.B Wait
+helps use the
+.B wait
+file of
+.IR prog (3).
+.PP
+.B Init
+must be called to initialise the module before invoking any other function.
+.PP
+.B Read
+reads a single wait record from file descriptor
+.IR fd ,
+which must be open on some process
+.IR p 's
+.B wait
+file,
+and returns a tuple
+.BI ( pid\f5,\fP\ module\f5,\fP\ status )
+where
+.I pid
+is the process ID of a child of
+.I p
+that has exited,
+.I module
+is the name of the module that caused
+.I p
+to exit,
+and
+.I status
+is nil if
+.I pid
+ended without error or a status message otherwise.
+If reading the
+.B wait
+file resulted in end of file or error,
+.I pid
+is 0 (for end of file) or
+.B -1
+on error (and
+.I status
+is the system error string for the error).
+.PP
+.B Monitor
+provides a channel interface to the
+.B wait
+file open on
+.IR fd ;
+it allows, for instance,
+a process to use
+.B alt
+to exchange data with a process but also watch for to exit (for good or ill).
+It starts a monitor process that applies
+.B read
+to
+.I fd
+and send the resulting tuple on a channel.
+It returns a tuple
+.BI ( pid\f5,\fP\ c )
+where
+.I pid
+is the process ID of the monitor process (which can be used to kill it when done with it),
+and
+.I c
+is the channel on which the process sends each value it reads.
+The tuple has the format described above for
+.BR read .
+The monitor process exits when the wait file
+.I fd
+yields end of file or error, after sending the corresponding tuple on
+.IR c .
+.PP
+.B Parse
+takes a complete
+.I status
+string as read from a
+.B wait
+file and returns a tuple
+.BI ( pid\f5,\fP\ module\f5,\fP\ status )
+as described for
+.B read
+above.
+.SH SEE ALSO
+.IR sh (1),
+.IR prog (3)
diff --git a/man/2/wmclient b/man/2/wmclient
new file mode 100644
index 00000000..23aada28
--- /dev/null
+++ b/man/2/wmclient
@@ -0,0 +1,235 @@
+.TH WMCLIENT 2
+.SH NAME
+wmclient: makedrawcontext, window, snarfput, snarfget \-
+window manager interface for Draw-based applications.
+.SH SYNOPSIS
+.EX
+include "tk.m";
+include "wmclient.m";
+wmclient := load Wmclient Wmclient->PATH;
+
+Resize,
+Hide,
+Help,
+OK,
+Plain: con 1 << iota;
+
+Appl: con Resize | Hide;
+
+init: fn();
+makedrawcontext: fn(): ref Draw->Context;
+window: fn(ctxt: ref Draw->Context, title: string, buts: int): ref Window;
+snarfput: fn(buf: string);
+snarfget: fn(): string;
+Window: adt{
+ display: ref Draw->Display;
+ r: Draw->Rect; # full rectangle of window, including titlebar.
+ image: ref Draw->Image;
+ screenr: Draw->Rect;
+ ctxt: ref Draw->Wmcontext;
+ focused: int;
+ ctl: chan of string;
+
+ startinput: fn(w: self ref Window, devs: list of string);
+ wmctl: fn(w: self ref Window, request: string): string;
+ settitle: fn(w: self ref Window, name: string): string;
+ reshape: fn(w: self ref Window, r: Draw->Rect);
+ onscreen: fn(w: self ref Window, how: string);
+ screenr2imager: fn(w: self ref Window, sr: Draw->Rect): Draw->Rect;
+ imager2screenr: fn(w: self ref Window, ir: Draw->Rect): Draw->Rect;
+ pointer: fn(w: self ref Window, p: Draw->Pointer): int;
+};
+
+.EE
+.SH DESCRIPTION
+The
+.B Wmclient
+module provides routines for making windows controlled by
+.IR wm (1)
+containing an image that can be drawn on with the
+routines described in
+.IR draw-image (2).
+.PP
+.B Init
+should be called once to initialise the internal state of
+.BR wmclient .
+.PP
+.B Makedrawcontext
+establishes an initial connection with the window manager,
+creating a new
+.B Draw
+context suitable for creating new windows. It is only
+necessary to call this if the application has not already
+been provided with a context.
+.PP
+.B Window
+creates a new window through
+.IR ctxt
+and returns it.
+.I Title
+gives a label that will be displayed in the title bar
+of the window;
+.I buts
+determines which buttons are created in the titlebar,
+a bitwise combination of the constants
+.BR Resize ,
+.BR Help ,
+.BR OK,
+and
+.BR Hide .
+If
+.B Plain
+is given, the window is given no decoration at all.
+.PP
+When a window, say
+.IR w ,
+is first created, its size has not been determined
+and its image is not yet allocated.
+.IB W .reshape
+sets the requested rectangle for the window,
+(and requests a new image for the window
+if it has already been made visible),
+where
+.I r
+gives the requested rectangle of the new
+image, excluding window decoration, such as the
+title bar and the window border.
+An application can use
+.IB w .screenr2imager
+to find out the usable rectangle within screen
+rectangle
+.I sr
+when window decorations are taken into account.
+.IB W .imager2screenr
+converts in the other direction.
+.IB W .screenr
+contains the current rectangle of the screen containing
+the window.
+.PP
+.IB W .image
+holds the window's image when it has been successfully created;
+.IB w .ctxt
+holds the window manager context for the window, from which
+keyboard and mouse events can be received.
+No such events will be received until
+.IB w .startinput
+is called, with a list of devices (e.g.
+.BR ptr ,
+.BR kbd )
+to start input for.
+.IB W .settitle
+sets the title that is shown on the window's title bar;
+it can make the window's size (and therefore the window's image)
+change.
+.PP
+.IB W .ctl
+is a channel down which requests from the titlebar are sent.
+Messages received on it should be processed by
+the application or passed to
+.IB w \.wmctl\fR.
+Requests are formatted
+as with
+.B quoted
+in
+.IR string (2).
+The messages include:
+.TP
+.B exit
+The window should be closed.
+.IB W .wmctl
+will kill all processes in the current
+process group.
+.TP
+.B !move \fIx\fP \fIy\fP
+The user has started to try to drag the window.
+.I X
+and
+.I y
+give the location of the initial pointer click.
+.TP
+.B !size \fImindx\fP \fImindy\fP
+The user wishes to resize the window.
+.I Mindx
+and
+.I mindy
+give the minimum size acceptable for the window.
+.TP
+.B help
+The help button has been clicked.
+.TP
+.B ok
+The OK button has been clicked.
+.TP
+.B hide
+The Hide button has been clicked.
+.IB W .wmctl
+will delete the window, and an entry
+will be shown on the toolbar.
+.PP
+In order to function correctly, an application
+should process not only events from the
+title bar channel, but also events received from the window
+manager itself (via
+.IB w .ctxt.ctl\fR),\fP
+and pointer and keyboard events received from
+the window manager (via
+.IB top .ctxt.ptr
+and
+.IB top .ctxt.kbd
+respectively).
+Control events can be passed to
+.IB w .wmctl \fR;
+keyboard events can be processed by the application;
+pointer events should be passed to
+.IB w .pointer
+for processing; if this returns zero, the
+application should process the pointer event,
+otherwise the event has been consumed by the
+titlebar.
+.PP
+When created, the window is not visible;
+.IB w .onscreen
+makes it visible, and possibly chooses a
+position and a size for it.
+.I How
+specifies what sort of placement is required
+for the window; it can be one of
+.TP
+.B place
+tries to choose a suitable place on the screen
+with respect to other windows; it may size the
+window as it feels appropriate. This the default
+(if
+.I how
+is nil).
+.TP
+.B onscreen
+tries to keep the position and size the same
+as specified on the window, adjusting them only
+to bring the window fully on screen, and making sure
+that the window is no bigger than the entire display.
+.TP
+.B exact
+does not change the specified size or position
+of the window unless absolutely necessary.
+.PP
+.B Snarfget
+and
+.B snarfput
+retrieve and replace the contents of the window
+manager's snarf buffer.
+.SH FILES
+.TF /chan/snarf
+.TP
+.B /chan/snarf
+snarf buffer maintained by
+.IR wm (1)
+.TP
+.B /chan/wm
+channel for interaction with
+.IR wm (1)
+.SH SOURCE
+.B /appl/lib/wmclient.b
+.SH SEE ALSO
+.IR wm (1),
+.IR tk (2)
diff --git a/man/2/wmlib b/man/2/wmlib
new file mode 100644
index 00000000..dade0c47
--- /dev/null
+++ b/man/2/wmlib
@@ -0,0 +1,90 @@
+.TH WMLIB 2
+.SH NAME
+wmlib \-
+low level access to window manager
+.SH SYNOPSIS
+.EX
+include "sys.m";
+include "draw.m";
+include "wmlib.m";
+wmlib := load Wmlib Wmlib->PATH;
+
+init: fn();
+connect: fn(ctxt: ref Draw->Context): ref Draw->Wmcontext;
+startinput: fn(w: ref Draw->Wmcontext, devs: list of string): string;
+wmctl: fn(w: ref Draw->Wmcontext, request: string): (string, ref Draw->Image, string);
+snarfput: fn(buf: string);
+snarfget: fn(): string;
+
+.EE
+.SH DESCRIPTION
+.B Wmlib
+provides basic routines to access the window manager,
+It is used by higher level modules such as
+.IR tkclient (2)
+and
+.IR wmclient (2)
+to provide window manager access to applications.
+.PP
+.B Init
+should be called once to initialise the internal state of
+.BR Wmlib .
+.B Connect
+makes a connection to the window manager through
+.I ctxt
+(see
+.IR draw-context (2)).
+.B Startinput
+tells the window manager to start queuing events on the input
+streams named in
+.I devs
+(e.g.
+.BR ptr ,
+.BR kbd )
+so that they can be received by the application.
+.PP
+.B Wmctl
+sends
+.I request
+to the window manager.
+It returns a tuple, say (\fIname\fP, \fIimg\fP, \fIerr\fP).
+If a request fails, then
+.I name
+and
+.I img
+will be nil and the non-empty
+.I err
+gives the reason.
+If the request has resized or created an image,
+.I name
+gives the tag name of the image and
+.I img
+holds the new image.
+.B Wmlib
+interprets the
+.B exit
+request itself, by killing all processes in the current
+process group, and exiting.
+.PP
+.B Snarfget
+and
+.B snarfput
+retrieve and replace the contents of the window
+manager's snarf buffer.
+.SH FILES
+.TF /chan/snarf
+.TP
+.B /chan/snarf
+snarf buffer maintained by
+.IR wm (1)
+.TP
+.B /chan/wm
+channel for interaction with
+.IR wm (1)
+.SH SOURCE
+.B /appl/lib/wmclient.b
+.SH SEE ALSO
+.IR wm (1),
+.IR wmclient (2),
+.IR tkclient (2),
+.IR tk (2)
diff --git a/man/2/wmsrv b/man/2/wmsrv
new file mode 100644
index 00000000..5617508f
--- /dev/null
+++ b/man/2/wmsrv
@@ -0,0 +1,295 @@
+.TH WMSRV 2
+.SH NAME
+Wmsrv \- core window-manager functionality and helper functions
+.SH SYNOPSIS
+.EX
+.ps -1
+.vs -1
+include "sys.m";
+include "draw.m";
+include "wmsrv.m";
+wmsrv := load Wmsrv Wmsrv->PATH;
+Client, Window: import wmsrv;
+
+init: fn():
+ (chan of (string, chan of (string, ref Draw->Wmcontext)),
+ chan of (ref Client, chan of string),
+ chan of (ref Client, array of byte, Sys->Rwrite));
+find: fn(p: Draw->Point): ref Client;
+top: fn(): ref Client;
+
+Window: adt {
+ tag: string;
+ r: Rect;
+ img: ref Image;
+};
+
+Client: adt {
+ kbd: chan of int;
+ ptr: chan of ref Draw->Pointer;
+ ctl: chan of string;
+ stop: chan of int;
+ images: chan of (ref Draw->Point, ref Draw->Image, chan of int);
+ flags: int;
+ wins: list of ref Window;
+ znext: cyclic ref Client;
+ id: int;
+
+ window: fn(c: self ref Client, tag: string): ref Window;
+ contains: fn(c: self ref Client, p: Draw->Point): int;
+ setimage: fn(c: self ref Client, tag: string, i: ref Draw->Image): int;
+ setorigin:fn(c: self ref Client, tag: string, o: Draw->Point): int;
+ top: fn(c: self ref Client);
+ bottom: fn(c: self ref Client);
+ remove: fn(w: self ref Client);
+};
+.ps +1
+.vs +1
+.EE
+.SH DESCRIPTION
+.B Wmsrv
+acts as a kind of ``buffer'' module between an actual window-manager
+implementation and possibly misbehaving clients.
+It provides notification when clients arrive, make window-manager requests,
+and leave. For each client, it provides a set of channels that mirror those
+found in
+.BR Draw->Wmcontext ,
+(see
+.IR draw-context (2)),
+except that writing to the
+.BR Client 's
+channels is guaranteed not to block.
+Each client holds zero or more
+.BR Window s,
+each of which is tagged with an identifying string
+and which can hold the image of that window.
+A given client's windows are layered in strict order,
+most recently created at the top. Most clients will have
+only one window; others are generally used only for
+ephemeral purposes, such as pop-up menus.
+.PP
+A
+.BR Client ,
+say
+.IR c ,
+holds some channels directly equivalent to their
+.B Wmcontext
+namesakes:
+.IB c \.kbd\fR
+.IB c \.ptr\fR,
+and
+.IB c \.ctl\fR.
+The behaviour of
+.IB c \.images
+is described below.
+.B Wmsrv
+starts a new process to mediate interaction
+between the window manager and its clients;
+sending a value on
+.IB c \.stop
+causes this process to exit.
+.IB C \.wins
+gives the list of all the windows
+associated with this client;
+.IB c \.flags
+is not used by
+.IR wmsrv :
+it may be used to store arbitrary information;
+.IB c \.id
+holds a unique identifier for the client;
+it will be no larger than the largest
+number of clients that have simultaneously existed;
+.IB c \.znext
+links clients together by window depth (see
+.BR top ,
+below).
+.PP
+.B Init
+must be called before any other
+.I wmsrv
+function to initialise the
+.I wmsrv
+module. It creates the virtual file
+.BR /chan/wm ,
+and returns a tuple of channels, say (\fIwm\fP, \fIjoin\fP, \fIrq\fP).
+.I Wm
+is the channel that should be passed to prospective clients
+in the
+.B Draw->Context
+structure; communication on this channel is used
+to establish a new client connection.
+.I Join
+is used to receive notifications
+of new clients arriving. The tuple received on this channel,
+say (\fIc\fP, \fIrc\fP)
+holds the new client, and a channel on which a reply
+should be sent acknowledging the new client.
+If the string sent is non-empty, it represents an error message
+that will be returned to the client, and the client will not
+be allowed to join.
+.IB c \.ptr\fR,
+.IB c \.kbd\fR,
+and
+.IB c \.ctl
+are all direct equivalents of their
+.B Wmcontext
+namesakes; the
+behaviour of
+.IB c \.images
+is described below.
+.I Rq
+is used to receive requests made by clients to the window
+manager by writing to the file
+.B /chan/wm.
+The tuple received on
+.IR rq ,
+say (\fIc\fP, \fIdata\fP, \fIreply\fP)
+holds the client that is making the request, the
+data that has been sent, and a channel that can be used
+(as described in
+.IR sys-file2chan (2))
+to return a reply to the request,
+The request is conventionally formatted as a utf8-encoded
+string, holding a list of tokens quoted as described in
+.B quoted
+in
+.IR string (2).
+.PP
+If the first character of a window-manager request is an exclamation mark
+.RB ( ! ),
+it should be a request to change the image of a client's window
+(or create a new window).
+In this case, the first three tokens should be
+the name of the command (starting with an exclamation mark),
+the tag of the window to which the request refers, and a tag
+used by clients to match requests to replies.
+If such a request is allowed to succeed, then clients expect that
+a new image will be sent to them.
+The
+.I images
+channel in a client is used to do this (normally accessed through the
+.I setimage
+and
+.I setorigin
+methods, see below). Sending a tuple, say (\fIo\fP, \fIi\fP, \fIrc\fP)
+on
+.I images
+buffers an image to be returned to the client.
+If
+.I o
+is non-nil, the request will change the physical origin of
+.I i
+to
+.IR o ,
+otherwise
+.I i
+gives a new image (its logical origin must match its physical origin).
+Only one such request is allowed to be outstanding
+at any one time; the channel passed in
+.I rc
+will yield the value
+.B -1
+if the image from a previous request has not yet been consumed,
+in which case the current request should be caused to fail.
+.PP
+.B Wmsrv
+can maintain a record of the current
+windows and their stacking order relative to one other.
+.B Top
+returns a pointer to the client at the top of the stack;
+the other clients can be accessed, in stacking order,
+via their
+.B znext
+references.
+.B Find
+finds the top client that has a window containing
+the point
+.IR p .
+.B Wmsrv
+provides various
+.B Client
+methods that may be used to help
+implement a window manager's interface:
+.TP 10
+.IB c .window(\fItag\fP)
+Yield the
+.BR Window ,
+.IR w ,
+corresponding to
+.IR tag ,
+or
+.B nil
+if there is none.
+Note that
+.IB w \.r
+holds the actual screen rectangle of the image;
+the client is free to modify the image's logical
+coordinate system, so
+.IB w \.img.r
+cannot be relied upon to contain a value with a meaningful origin.
+.TP
+.IB c .contains(\fIp\fP)
+Return non-zero if any of the client's windows
+contain the point
+.IR p .
+.TP
+.IB c .setimage(\fItag\fP,\ \fIi\fP)
+Set the image associated with window
+.I tag
+to
+.IR i .
+If this is in response to a window manager request,
+.I i
+must be non-nil, and
+.I wmsrv
+will arrange that the new image is sent to the client.
+If this is not possible, then
+.B setimage
+will return
+.BR -1 .
+If
+.I i
+is nil, no image will be sent to the client
+and the window will be deleted.
+.TP
+.IB c .setorigin(\fItag\fP,\ \fIo\fP)
+Similar to
+.BR setimage ,
+except that only the origin of the window is changed.
+In order to enable clients to maintain their own logical
+coordinate system,
+.I wmsrv
+first sends
+.B nil
+on the
+.B Wmcontext.images
+channel, allowing the client to suspend operations
+on the image momentarily; it then sends to same
+channel, with its origin set to its actual screen origin.
+The client is then free to set the logical origin again.
+.TP
+.IB c .top()
+Raise the client's windows above the other clients' windows.
+.TP
+.IB c .bottom()
+Send the client's windows below the other clients' windows.
+.TP
+.IB c .remove()
+Remove the client and its windows from wmsrv's window stack.
+.SH FILES
+.TP 10
+.B /chan/wm
+Created by
+.I wmsrv
+using
+.IR file2chan (2)
+to serve connection requests.
+.SH SOURCE
+.B /appl/lib/wmsrv.b
+.SH SEE ALSO
+.IR wm (1),
+.IR draw-screen (2),
+.IR wmlib (2),
+.IR wmexport (1),
+.IR wmclient (2),
+.IR tkclient (2),
diff --git a/man/2/workdir b/man/2/workdir
new file mode 100644
index 00000000..ba6b3094
--- /dev/null
+++ b/man/2/workdir
@@ -0,0 +1,25 @@
+.TH WORKDIR 2
+.SH NAME
+workdir \- get the current working directory
+.SH SYNOPSIS
+.EX
+include "workdir.m";
+workdir := load Workdir Workdir->PATH;
+
+init: fn(): string;
+.EE
+.SH DESCRIPTION
+.B Workdir
+returns a string representation of the working directory
+of the invoking process.
+.PP
+When Inferno boots,
+the initial process has
+.B /
+for its working directory.
+.SH SOURCE
+.B /appl/lib/workdir.b
+.SH SEE ALSO
+.IR sys-chdir (2),
+.IR sys-fd2path (2),
+.IR sys-stat (2)
diff --git a/man/2/xml b/man/2/xml
new file mode 100644
index 00000000..8387971a
--- /dev/null
+++ b/man/2/xml
@@ -0,0 +1,266 @@
+.TH XML 2
+.SH NAME
+xml \- XML navigation
+.SH SYNOPSIS
+.EX
+include "xml.m";
+
+xml := load Xml Xml->PATH;
+Parser, Item, Location, Attributes, Mark: import xml;
+
+init: fn(): string;
+open: fn(f: string, warning: chan of (Locator, string),
+ preelem: string): (ref Parser, string);
+
+Parser: adt {
+ fileoffset: int;
+
+ next: fn(p: self ref Parser): ref Item;
+ down: fn(p: self ref Parser);
+ up: fn(p: self ref Parser);
+ mark: fn(p: self ref Parser): ref Mark;
+ atmark: fn(p: self ref Parser, m: ref Mark): int;
+ goto: fn(p: self ref Parser, m: ref Mark);
+ str2mark: fn(p: self ref Parser, s: string): ref Mark;
+};
+
+Item: adt {
+ fileoffset: int;
+ pick {
+ Tag =>
+ name: string;
+ attrs: Attributes;
+ Text =>
+ ch: string;
+ ws1: int;
+ ws2: int;
+ Process =>
+ target: string;
+ data: string;
+ Doctype =>
+ name: string;
+ public: int;
+ params: list of string;
+ Stylesheet =>
+ attrs: Attributes;
+ Error =>
+ loc: Locator;
+ msg: string;
+ }
+};
+
+Locator: adt {
+ line: int;
+ systemid: string;
+ publicid: string;
+};
+
+Attribute: adt {
+ name: string;
+ value: string;
+};
+
+Attributes: adt {
+ all: fn(a: self Attributes): list of Attribute;
+ get: fn(a: self Attributes, name: string): string;
+};
+
+Mark: adt {
+ offset: int;
+ str: fn(m: self ref Mark): string;
+};
+.EE
+.SH DESCRIPTION
+.B Xml
+provides an interface for navigating XML files (`documents'). Once loaded, the module
+must first be initialised by calling
+.BR init .
+A new parser instance is created by calling
+.BR open(\fIf\fP,\ \fIwarning\fP,\ \fIpreelem\fP) ,
+which opens the file
+.I f
+for parsing as an XML document.
+It returns a tuple, say
+.RI ( p ,\ err ).
+If there is an error opening the document,
+.I p
+is nil, and
+.I err
+contains a description of the error; otherwise
+.I p
+can be used to examine the contents of the document.
+If
+.I warning
+is not nil, non-fatal errors encountered when parsing
+will be sent on this channel - a separate process will
+be needed to received them. Each error is represented
+by a tuple, say
+.RI ( loc ,\ msg ),
+containing the location
+.IR loc ,
+and the description,
+.IR msg ,
+of the error encountered. One XML tag,
+.IR preelem ,
+may be marked for special treatment by the XML parser:
+within this tag all white space will be passed through as-is.
+.PP
+Once an XML document has been opened, the following
+.B Parser
+methods may be used to examine the items contained within:
+.TP 10
+.IB p .next()
+An XML document is represented by a tree-structure.
+.B Next
+returns the next item in the document at the current level of the tree
+within the current parent element. If there are no more such
+items, it returns
+.BR nil .
+.TP
+.IB p .down()
+.B Down
+descends into the element that has just been returned by
+.BR next ,
+which should be a
+.B Tag
+item. Subsequent items returned by
+.B next
+will be those within that tag.
+.TP
+.IB p .up()
+.B Up
+moves up one level in the XML tree.
+.TP
+.IB p .mark()
+.B Mark
+returns a mark that can be used to return later to the current
+position in the document. The underlying file must
+be seekable for this to work.
+.TP
+.IB p .goto(\fIm\fP)
+Goes back to a previously marked position,
+.IR m ,
+in the document.
+.TP
+.IB p .atmark(\fIm\fP)
+.B Atmark
+returns non-zero if the current
+position in the document is the same as that marked by
+.IR m .
+The current tree level is ignored in the comparison.
+.TP
+.IB p .str2mark(\fIs\fP)
+.B Str2mark
+turns a string as created by
+.B Mark.str
+back into a mark as returned by
+.BR Parser.mark .
+.SS Items
+Various species of items live in XML documents; they are encapsulated
+in the
+.B Item
+adt. This contains one member in common to all its subtypes:
+.BR fileoffset ,
+the position in the XML document of the start of the item.
+The various kinds of item are as follows:
+.TP
+.B Tag
+A generic XML tag.
+.B Name
+names the tag, and
+.B attrs
+holds its attributes, if any.
+.TP
+.B Text
+.B Text
+represents inline text in the XML document.
+With the exception of text inside the tag named by
+.I preelem
+in
+.BR open ,
+any runs of white space are compressed to a single space,
+and white space at the start or end of the text is elided.
+.B Ch
+contains the resulting text;
+.B ws1
+and
+.B ws2
+are non-zero if there was originally white space at the start
+or end of the text respectively.
+.TP
+.B Process
+.B Process
+represents an XML document processing directive.
+.B Target
+is the processing instruction's target, and
+.B data
+holds the rest of the text inside the directive.
+XML stylesheet directives are recognised directly and have
+their own item type.
+.TP
+.B Doctype
+.B Doctype
+should only occur at the start of an xml document,
+and represents the type of the XML document.
+.TP
+.B Stylesheet
+.B Stylesheet
+represents an XML stylesheet processing request. The
+data of the processing request is parsed as per the RFC
+into attribute-value pairs.
+.TP
+.B Error
+If an unrecoverable error occurs processing the document,
+an
+.B Error
+item is returned holding the location
+.RB ( loc ),
+and description
+.RB ( msg )
+of the error.
+This will be the last item returned by the parser.
+.PP
+The attribute-value pairs in
+.B Tag
+and
+.B Stylesheet
+items are held in an
+.B Atttributes
+adt, say
+.IR a .
+.IB A .all()
+yields a list holding all the attributes;
+.IB a .get( name )
+yields the value of the attribute
+.IR name .
+.PP
+The location returned when an error is reported is held
+inside a
+.B Locator
+adt, which holds the line number on which the error occurred,
+the ``system id'' of the document (in this implementation, its file name),
+and the "public id" of the document (not currently used).
+.PP
+A
+.B Mark
+.I m
+may be converted to a string with
+.IB m .str()\fR;\fP
+this enables marks to be written out to external storage, to index
+a large XML document, for example.
+Note that if the XML document changes, any stored marks will
+no longer be valid.
+.SH SOURCE
+.B /appl/lib/xml.b
+.SH SEE ALSO
+``Extensible Markup Language (XML) 1.0 (Second Edition)'',
+.B http://www.w3.org/TR/REC-xml
+.SH BUGS
+XML's definition makes it tricky to handle leading and trailing white space
+efficiently;
+.B ws1
+and
+.B ws2
+in
+.B Item.Text
+is the current compromise.